Reuse or separate?

As programmers we’re taught to constantly look for opportunities to reuse. The mantra being less duplication of effort meaning less work. Backed up by the DRY principle and just about every book on programming it can be difficult to take the opposite stand: Keeping things separated. The criteria used for reuse is often the same. Things look structurally similar so they are the same thing. And since you shouldn’t repeat yourself reuse it!

As an example take the case of an elastic search index used to populate a web page and introducing another web page that needs the “same data”. Great case for reuse of the index right? What if the data that is needed differs slightly by a few columns in the beginning. Maybe a few more columns in a months time. Developers reasoning about the page and the data will have a harder time since they have to juggle unrelated things. The structure of the data or code is one aspect and often the only criteria use for reuse. But more important differences potentially exist that dictates separation. On the first web page we might only present the data and on the second we might have to make certain columns full text searchable. Doing that will require more disk space and if that page is much less visited than the page that only presents we might not have the same requirements for replication for the sake of scalability. So what looks superficially identical turns out to be two very different things meaning reuse will introduce an dependency that hurts more than it benefits.

The Go programming language language has a nice little proverb:

“A little copying is better than a little dependency”.

Advertisements

How not to structure project folders

Imagine looking at an overview of an apartment building, while trying to get some sense of how the individual apartments are structured:

IMG_0172.JPG

Does this look familiar? No? What about this:

IMG_0174.GIF

Or this:

IMG_0176.PNG

The common theme here being project folders defined by the type of the content. It’s difficult to see what the software actually does. That requires an intimate knowledge of a large part of the source code files. Grouping by type quickly gets out of hand as the project grows. Imagine having fifteen or twenty controller classes that is somehow related to a dozen or so views and viewmodels. Sadly some frameworks that operate by convention over configuration forces you into grouping by type, so that the framework is able to instantiate an appropriate controller etc. If you are not using such a framework you really have no excuse for using this kind of project structure.

An alternative to grouping by type is grouping by software feature. Of course the two can be mixed. Grouping by what the software actually does enables a developer to much quicker gain an understanding of the codebase. Examples of features might be ‘Add item to shopping cart’ or ‘Send mail to customer support’.

Grouping by feature requires constant work as features evolve and overlap. The issue of grouping is not solved a priori as in the case of grouping by type. Furthermore, renaming and moving files and folders is something that is handled poorly by several version control systems. Nevertheless doing these types of refactorings is something that belongs in the skillset of an software engineer.

Power over new()!

In this blog post I’ll show two examples of programming languages that has a different take on new(). As mentioned in an earlier blog post the standard implementation has several problems including hindering testability. The problems are rooted in the lack of flexibility caused by new() pointing to a specific concrete class. A wellknown pattern for alleviating this inflexibility, that requires a little upfront planning, is the Factory Method design pattern. An example:

public Foo Create()

At first glance this might seem indistinguishable from creating Foo directly, but the method allows us to return a cached version of Foo, a singleton, or perhaps a proxy or even a subclass of Foo. In other words, we’ve avoided settling on the instantiation of a specific concrete class.

The programming language Dart has built-in support for this pattern and doesn’t require any preplanning for realising it:

 
var foo = new Foo()

class Foo
{
  factory Foo()
  {
    // return cached version of Foo etc..
  }
}

In the example new() actually invokes the factory method. The factory method can be introduced at any point during the lifetime of Foo. This means we can implement the pattern without changing all the places new Foo() is called.

The next language gives us even more power over new(). Let’s imagine we are heavy users of a webframework for which we don’t have access to the source code. A critical part of our application needs to change and to be confident about the changes we need tests. Unfortunately our code is a mess and uses framework classes directly that depends on state from a webrequest. How do we realize the test without introducing wrappers of the framework classes and restructuring our application?

This is possible in the newspeak programming language:

	
class Module = Foo ()(
   class Foo = super FooMock 
   // implementation of FooMock folllows
)

The code above extends and overrides part of the class Foo from the webframework library with FooMock in the containing Module. All uses of Foo will now use FooMock instead. In this case an implementation could count calls to Foo and examine input values for assertion of behaviour in our newly created unit tests. Note that this extends and overrides Foo without changing existing code in our application, we only need to add the new definition. No dependency injection needed which requires preplanning!

Javascript is the most testable mainstream language.. Say what!?

As mentioned in a earlier blog post, observability is a crucial aspect of being able to test the outcome of a method call. Control of the system or objects under test is just as important. Control in this case means power over new(). Lets look at the most simple example:

class TestMe
{
	internal TestMe()
}

No control over the instantiation of the class, which means we cannot create an isolated test of the class in a separate assembly. Other flavours of this lack of power over instantiation includes private constructors, private or internal factory methods etc.

Moving on to a different aspect of controllability:

class Foo
{
  private IBar bar = new Bar()
  
  public void DoSomethingWithBar()
  {
    bar.DoSomething()
  }
}

Here the interaction with bar is unobservable since we are not able to replace bar with our own test double or mock. Another consequence is that Foo cannot be tested in isolation. The problem being that new is not late-bound, it binds to a specific concrete class! In this case Bar. The use of new forces us to use a specific class and leaves us with no way of pointing the code to our own test class. Imagine removing the capability of late-bound methods, as realised by different implementations of the same interfaces or virtual methods that are overridden in subclasses. This would remove a lot of the power of OO. The new operator is seriously flawed in this respect.

Dependency injection can be seen as one way of mitigating the problems with new by simple removing its usage! It moves the choice of which class to instantiate to runtime, in other words, the class is late-bound.

The problem completely goes away in a dynamically typed language where monkey patching is available such as Javascript:

function testFoo()
{
  var foo = new Foo()
  foo.bar = createMockOfBar()
  ...  continue test and assert interaction with bar ..
}

This means any part of an object graph can be replaced ad nauseaum, resulting in complete control and countless options for observing the result and interactions of methods under test, which leaves room for any experiment or test imaginable.

Analyzing Testability, Part 2.

This post will expand on points made in Part 1. Previously we identified four categories of methods with different characteristics concerning direct observability. The first category of methods contains parameters and a non void return type in its signature, such as:

int Abs(int x)

All other things being equal, this category of methods is more easily tested. Since we can observe a result directly and control the test input directly. If the method is side effects free we have a pure function which is the cream of the crop regarding testability. The same input will always produce the same output. You should be writing the most important business logic in pure functions for maximum certainty of its behaviour.

The second category by example:

int Next()

Necessarily requires a more involved test setup since we must control its input by other means than direct parameterization. Of course we might be so lucky that Next() is part of a create-set-call pattern that allows us to control the parameterization indirectly. E.g

var c = new SomeCollection() // create

c.SetElementAt(0, 4) // set
c.SetElementAt(1, 7) // set

var result = c.Next() // call

Assert.AreEqual(4, result)

The following category doesn’t provide a directly observable result but lets us parameterize the method invocation:

void SetStateExecuting(Task task)

So how do we observe the result of an experiment? Easy as pie, we just write this (example is from stackoverflow and slightly edited..):


[Test]
public void SetStateExecuting_Should_Set_State_To_Pause()
{
var task = new Task { ID = 1, TimeZone = -660, GlobalState = TaskState.Paused };
task.Expect(p => p.StateUpdate(task.ID, task.TimeZone, TaskState.Paused));
_mockRepository.ReplayAll();
_systemUnderTest.SetStateExecuting(task);
_task.AssertWasNotCalled(p => p.GlobalStateUpdate(task.ID, TaskState.Executing));
_mockRepository.VerifyAll();
}

I’m sure you can spot the problem that this stackoverflow user is combatting? He is mixing the old Record/Replay pattern and the new AAA pattern in Rhino Mocks. This test style tends to be fragile since we concern ourselves with how SetStateExecuting is implemented. For example in the form of a call to AssertWasNotCalled that asserts that a specific method was called. If the method in question changes it signature, the test will break.

The last category of methods, where no parameters are defined and the return type is void, we have no way of observing directly. E.g. void DoSomething(). We have to know where to look for changes in state in the surrounding class, or use a mocking framework as the previous example. In other words, knowledge of the behavior is harder to come by and the risk of fragile tests has increased.

Analyzing Testability, Part 1.

A cornerstone of Science is the Experiment. The experiment serves to test a hypothesis which is an explanation of some phenomenon that is yet to be accepted as scientific knowledge. For it to be a scientific hypothesis it must be falsifiable or testable as opposed to the hypothesis “In the beginning, God created the heavens and the earth”.  A typical formulation is the If-then shaped hypothesis. Such as “If I raise the temperature of a cup of water, then the amount of sugar that can be dissolved in it will be increased.” In software we have unit tests which serves a similar purpose, that is, produce trustworthy knowledge of the functional behaviour of the software under test. Imagine a test named Abs_should_return_positive_number(). The hypothesis in this case might be “If i apply the function Abs with the argument of -2 the return value will be 2”. Generalising this statement will result in the more interesting “For any input x, if i apply the function Abs the return value will be the absolute value of x”. This is expressible in several unit test frameworks as a parameterized unit test. E.g JUnit:


@Theory
public void Abs_always_returns_absolute_value(int x)

Sadly it’s left to the developer to supply the actual values. Automatically supplying the values is an area of active research and a few tools have been built such as Pex from Microsoft Research.
An important aspect of a controlled experiment is the need to isolate the system under test and the ability to observe output or effects. Let’s start with the observability of methods. The following 4 methods differs fundamentally in how we can observe their behaviour.


public int Abs(int x)
public int Next()
public void Print(object x)
public void MutateSomething()

Abs lets us easily observe the result from supplying a parameter x whose creation is under our control. This lets us easily setup different tests and verify the expected output. Looking at Next we see that it lets us observe the result, but without control of its context, such as a class or module, we have a difficult time of distinguishing between different test runs or experiments. This leads us to Print where no result is directly observable, but we may be able to observe sideeffects through the supplied parameter x. If you prefer verbose, complicated mocking frameworks to exercise your coding skills this is the shape of methods you should prefer. The last method MutateSomething is unobservable on its own.

In conclusion, prefer methods with well defined inputs and outputs, in the parts of your software where knowing the important parts of the functional behaviour should be cheap and easy to come by.