Wednesday, January 30, 2013

Code should be immutable

Change by addition, not mutation. Putting the open-closed principle into practice.

If I write a unit test and some code that satisfies that unit test, I should be reasonably confident that I will never have to change that unit of code again. I may add more units of code and I may delete old units it as soon as they become redundant, but I shouldn't put myself in a position to have to mutate an existing unit of code.

Within reason of course. Units of code aren't always atomic enough for this guidance to be considered a standard. The law of diminishing returns applies - be pragmatic in anticipating the ways the program will be required to change and pay particular attention to the probable extension points and axes of change.

I've realized a few benefits of this approach:
  • New code has fewer dependencies. I have much less risk if I introduce something new than if I modify something that exists.
  • I can have more control over when I replace an existing unit with a new unit. For example, I can run both side-by-side and compare their performance.
  • It helps me maintain a consistent velocity. Since the side effects of new code are less than changing existing code, I run into fewer unexpected problems and edge cases.
  • It gives me feedback on my code organization. If I cannot take this approach, it tends to be a good indicator of a violation of the single responsibility principle or proper encapsulation. It also means that in the future, I'll be spending all my time changing existing code to add new features and my velocity will tank.
  • I feel more creative when coding. Creating new code is more fulfilling than modifying existing code.

Some things need to be in place for this to happen successfully:
  • As mentioned above, strong and consistent application of the single responsibility principle and open-closed principle.
  • Good discipline in ensuring the units of code are of the right size. Typically it's smaller than a class, but bigger than a method. Perhaps a nested class.
  • Ability to swap an old unit with a new unit with minimal mutation (doesn't have to mean IoC - just reduce the proliferation of the unit).
  • Ability to flag redundant units for safe removal and the discipline to actually remove them.
  • Ability to measure the ratio of mutation to addition/removal and see it trend in the right direction.

Go ahead, try it on a small scale and see how you feel. Does the artificial restriction of not being able to modify your existing code cause you to think more about your design? Does it hurt your velocity or help maintain or improve it?

Keen observers will notice that this is just a spin on well established OOP principles (SRP and OCP). What I find fascinating is that code and the systems it's contained in are like fractals... the principles and hence the way they look is the same from any level of zoom.

No comments:

Post a Comment