There Are Only Two Roles of Code

All code can be classified into two distinct roles; code that does work (algorithms) and code that coordinates work (coordinators).

The real complexity that gets introduced into a code bases is usually directly related to the creation of classes that group together both of these roles under one roof.

I’m guilty of it myself.  I would say that 90% of the code I have written does not nicely divide my classes into algorithms and coordinators.

Defining things a bit more clearly

Before I dive into why we should be dividing our code into clear algorithmic or coordinating classes, I want to take a moment to better define what I mean by algorithms and coordinators.

Most of us are familiar with common algorithms in Computer Science like a Bubble Sort or a Binary Search, but what we don’t often realize is that all of our code that does something useful contains within it an algorithm.

What I mean by this is that there is a clear distinct set of instructions or steps by which some problem is solved or some work is done.  That set of steps does not require external dependencies, it works solely on data, just like a Bubble Sort does not care what it is sorting.

Take a moment to wrap your head around this.  I had to double check myself a couple of times to make sure this conclusion was right, because it is so profound.

It is profound because it means that all the code we write is essentially just as testable, as provable and potentially as dependency free as a common sorting algorithm if only we can find the way to express it so.

What is left over in our program (if we extract out the algorithms) is just glue.

Think of it like a computer.  Computer electronics have two roles: doing work and binding together the stuff that does the work.  If you take out the CPU, the memory and all the other components that actually do some sort of work, you’ll be left with coordinators.  Wires and busses that bind together the components in the system.

Why dividing code into algorithms and coordinators is important.

So now that we understand that code could potentially be divided into two broad categories, the next question of course is why?  And can we even do it?

Let’s address why first.

The biggest benefit to pulling algorithmic code into separate classes from any coordinating code is that it allows the algorithmic code to be free of dependencies.  (Practically all dependencies.)

Once you free this algorithmic code of dependencies you’ll find 3 things immediately happen to that code:

  1. It becomes easier to unit test
  2. It becomes more reusable
  3. Its complexity is reduced

A long time ago before mocks were widely used and IoC containers were rarely used, TDD was hard.  It was really hard!

I remember when I was first standing on the street corners proclaiming that all code should be TDD with 100% code coverage.  I was thought pretty crazy at the time, because there really weren’t any mocking frameworks and no IoC containers, so if you wanted to write all your code using TDD approaches, you’d actually have to separate out your algorithms.  You’d have to write classes that had minimal dependencies if you wanted to be able to truly unit test them.

Then things got easier by getting harder.  Many developers started to realize that the reason why TDD was so hard was because in the real world we usually write code that has many dependencies.  The problem with dependencies is that we need a way to create fake versions of them.  The idea of mocking dependencies became so popular that entire architectures were based on the idea and IoC containers were brought forth.

mp900175522 thumb There Are Only Two Roles of CodeWe, as a development community, essentially swept the crumbs of difficult unit testing under the rug.  TDD and unit testing in general became ubiquitous with writing good code, but one of the most important values of TDD was left behind, the forced separation of algorithmic code from coordinating code.

TDD got easier, but only because we found a way to solve the problems of dependencies interfering with our class isolation by making it less painful to mock out and fake the dependencies rather than getting rid of them.

There is a better way!

We can still fix this problem, but we have to make a concerted effort to do so.  The current path of least resistance is to just use an IoC container and write unit tests full of mocks that break every time you do all but the most trivial refactoring on a piece of code.

Let me show you a pretty simple example, but one that I think clearly illustrates how code can be refactored to remove dependencies and clearly separate out logic.

Take a look at this simplified calculator class:

[sourcecode language=”csharp” padlinenumbers=”true”] public class Calculator
{
private readonly IStorageService storageService;
private List<int> history = new List<int>();
private int sessionNumber = 1;
private bool newSession;

public Calculator(IStorageService storageService)
{
this.storageService = storageService;
}

public int Add(int firstNumber, int secondNumber)
{
if(newSession)
{
sessionNumber++;
newSession = false;
}

var result = firstNumber + secondNumber;
history.Add(result);

return result;
}

public List<int> GetHistory()
{
if (storageService.IsServiceOnline())
return storageService.GetHistorySession(sessionNumber);

return new List<int>();
}

public int Done()
{
if (storageService.IsServiceOnline())
{
foreach(var result in history)
storageService.Store(result, sessionNumber);
}
newSession = true;
return sessionNumber;
}
}
[/sourcecode]

 

This class does simple add calculations and stores the results in a storage service while keeping track of the adding session.

It’s not extremely complicated code, but it is more than just an algorithm.  The Calculator class here is requiring a dependency on a storage service.

But this code can be rewritten to extract out the logic into another calculator class that has no dependencies and a coordinator class that really has no logic.

[sourcecode language=”csharp”] public class Calculator_Mockless
{
private readonly StorageService storageService;
private readonly BasicCalculator basicCalculator;

public Calculator_Mockless()
{
this.storageService = new StorageService();
this.basicCalculator = new BasicCalculator();
}

public int Add(int firstNumber, int secondNumber)
{
return basicCalculator.Add(firstNumber, secondNumber);
}

public List<int> GetHistory()
{
return storageService.
GetHistorySession(basicCalculator.SessionNumber);
}

public void Done()
{
foreach(var result in basicCalculator.History)
storageService
.Store(result, basicCalculator.SessionNumber);

basicCalculator.Done();
}
}

public class BasicCalculator
{
private bool newSession;

public int SessionNumber { get; private set; }

public IList<int> History { get; private set; }

public BasicCalculator()
{
History = new List<int>();
SessionNumber = 1;
}
public int Add(int firstNumber, int secondNumber)
{
if (newSession)
{
SessionNumber++;
newSession = false;
}

var result = firstNumber + secondNumber;
History.Add(result);

return result; ;
}

public void Done()
{
newSession = true;
History.Clear();
}
}
[/sourcecode]

 

Now you can see that the BasicCalculator class has no external dependencies and thus can be easily unit tested.  It is also much easier to tell what it is doing because it contains all of the real logic, while the Calculator class has now become just a coordinator, coordinating calls between the two classes.

This is of course a very basic example, but it was not contrived.  What I mean by this is that even though this example is very simple, I didn’t purposely create this code so that I could easily extract out the logic into an algorithm class.

Parting advice

I’ve found that if you focus on eliminating mocks or even just having the mindset that you will not use mocks in your code, you can produce code from the get go that clearly separates algorithm from coordination.

I’m still working on mastering this skill myself, because it is quite difficult to do, but I believe the rewards are very high for those that can do it.  In code where I have been able to separate out algorithm from coordination, I have seen much better designs that were more maintainable and easier to understand.

I’ll be talking about and showing some more ways to do this in my talk at the Warm Crocodile conference next year.

  • Pingback: Dew Drop – October 22, 2012 (#1,426) | Alvin Ashcraft's Morning Dew()

  • http://twitter.com/JasonImison Jason Imison (@JasonImison)

    I guess it depends on whether or not you consider storing the result needs to be tested etc.

  • http://codeweavers.net/author/shaunfinglas/ Shaun Finglas

    Nice post.

    This sorta sounds similar to command query separation.

    See: http://martinfowler.com/bliki/CommandQuerySeparation.html

    • http://simpleprogrammer.com jsonmez

      Thanks, I do agree it is a similar concept.

  • bebraw

    Nice post. Another pair for you to think about: data and operations. I think this is where OOP goes wrong though your mileage might vary. :)

  • http://twitter.com/daedtech Erik Dietrich (@daedtech)

    This seems kind of like a specific case of the Single Responsibility Principle (at least your example does). Calculating and storage manipulation are two very distinct responsibilities with two very different reasons to change. Can you think of an example or examples where the separation of algorithm from coordination wouldn’t be covered by SRP? (I’m not asking to make some kind of rhetorical point — just genuine curiosity).

  • Mattias

    Calculator_Mockless looks like a decorator to the Calculator class. Why not inherit from the same interface?

    • http://simpleprogrammer.com jsonmez

      In this refactoring you could. But you don’t actually need an interface anymore. We can even get rid of the IStorageService interface, because we don’t need to swap it out.

  • http://basus.me Shrutarshi Basu

    It seems to me that what you really want is functional programming: clean isolated components that can be easily combined and supplied with working data at runtime for testing. Of course you can put your functions in containers (classes) and call them methods, but it’s still essentially functional programming.

    • http://simpleprogrammer.com jsonmez

      I think you may be right, I’ve been thinking about exploring that path.

    • http://gravatar.com/mbrandewinder mbrandewinder

      I had the exact same thought – the overall thinking process described here immediately reminded me of F#, where you typically end up creating modules that expose functions (the “algorithms” part), and then composing them together. You should definitely look into F#!

    • http://twitter.com/ppetrovdotnet pip010 (@ppetrovdotnet)

      no no no, let’s complicate things using over-bloated tech : C# :P
      use anonymous this and that and this and that… :D

  • http://javarevisited.blogspot.fr Java Programmer

    Isn’t it a kind of Encapsulation? I agree with separating part which changes more often or have potential to be replace with better or faster code. Code organization is an important skill to improve re-usability and I am big fan of Java which enforces such practices.

  • http://gravatar.com/maz100 maz100

    I agree wholeheartedly. I’d go further and have a calculator that only did calculations and a separate class to manage your session and history. I’d argue that session and history has absolutely nothing to do with an addition algorithm. Then the job of your coordinating method( I use the term orchestrating to mean the same thing) is to call the calculator interface to perform a calculation and then call the session/history interface to increment the session and add the result to the history. A typical service method in my code might need to validate some inputs and then call a database, mapping the results into an object and returning that object. So it’s a case of call a validation interface, call a data access interface and call a mapping interface. If you don’t use interfaces you end up in situations where you can’t test the mapping logic without jumping through hoops to satisfy the validation logic. Great article!

  • http://practicalunittesting.com Tomek

    I think BasicCalculator should not have a hardcoded dependency on History. Instead, it should allow to register listeners and notify them about new results (in Add() method) and about the computation finish (Done() method). The current implementation should be called BasicCalculatorWhichRemembersComputationsHistory. :)

    • http://simpleprogrammer.com jsonmez

      I agree, this is just a simple example, but you are right that that history could be extracted out further.

  • http://helmbold.de Christian

    I think you could become a big fan of the Go programming language, which promotes such a programming style. There are not even classes that could mislead developers. Static duck-typing helps to keep interfaces clean and simple, because the user of the interface defines it. And in terms of your article, the user defines what interface an algorithm must fulfill.

    • http://simpleprogrammer.com jsonmez

      I need to check out Go. Been meaning to do it, so much to do, so little time. Thanks for the suggestion.

  • Pingback: The More I Know, the Less I Know « Making the Complex Simple()

  • http://jhonatantirado.wordpress.com/ nathan

    Reblogged this on Nathan.

  • MarkH

    Have a look at this book

    http://www.amazon.com/Lean-Architecture-Agile-Software-Development/dp/0470684208

    it describes a very similar approach – essentially separation of domain or business logic (in your example, the calculation bit) from the application or contextual logic (the coordination logic) and suggests a consistent approach of how it might be achieved with current programming languages. the motivation is that the two types of logic are likely to change at a very different pace (domain logic slowly, application logic more quickly) and possibly even by different teams, depending on organizational structure of the “sponsor”, so separation should make maintenance less onerous.

  • Pingback: TDD, Unit Tests and the Passage of Time | Henrik Warne's blog()

  • Pingback: There Are Only Two Roles of Code - Simple Progr...()

  • Pingback: TDD, Unit Tests and the Passage of TimeMain FunctionMain Function()