Why shorter methods are better

TL;DR
Longer methods are more likely to need to change when the application changes.

The Longer Story
Shorter methods protect my investment in the code, in a number of ways.

First: Testability. I expect there to be a correlation between method length (number of “statements”) and the number of (unit) test cases required to validate the method completely. In fact, as method size increases I expect the number of test cases to increase faster than linearly, in general. Thus, breaking a large method into smaller independent methods means I can test parts of my application’s behaviour independently of each other, and probably with fewer tests. All of which means I will have to invest less in creating and running the tests for a group of small methods, compared to the investment required in a large method.

Second: Cohesion. I expect there to be a strong correlation between method length and the number of unknown future requirements demanding that method to change. Thus, the investment I make in developing and testing a small method will be repaid countless times, because I will have fewer reasons in the future to break it open and undo what I did. Smaller methods are more likely to “stabilize out” and drop out of the application’s overall churn.

Third: Coupling (DRY). I expect that longer methods are more likely to duplicate the knowledge or logic found elsewhere in the same codebase. Which means, again, that the effort I invest in getting this (long) method correct could be lost if ever any of those duplicated pieces of knowledge has to change.

And finally: Understandability. A method that does very little is likely to require fewer mental gymnastics to fully understand, compared to a longer method. I am less likely to need to invest significant amounts of time on each occasion I encounter it.

The Open-Closed Principle says that we should endeavour to design our applications such that new features can be added without the need to change existing code — because that state protects the investment we’ve made in that existing, working code, and removes the risk of breaking it if we were to open it up and change it. Maybe it’s also worth thinking of the OCP as applying equally to methods.

evolvability

Dan North has introduced the term evolvability:

“As an agile process coach, my job is to increase a team’s – or in the case of an Organisational Transformation programme an entire organisation’s – ability to evolve. Taking a cue from Mother Nature, you can’t expect this to occur overnight. The weight of evidence shows that macro-mutations in the process are almost always going to be detrimental. Instead you need to evolve the organisation towards evolvability, or agility, through a series of small steps that are easy and intuitive to grasp.”

Absolutely, and although the old term “adaptability” works better for me, I do agree that the trait is best acquired through evolution. I’m also tempted to qualify a little:

An organism only needs to be evolvable if it seeks longevity and its environmental niche is volatile. Many software development organisations fall into this category – for example, look at the pace of change in the communications markets. But others probably don’t – maybe the pace of change in their niches isn’t so great, or longevity isn’t a concern for them. So while I embrace evolvability adaptability as a concept, I will check first to see whether it is needed.

grouping tests by expected outcome

Cory Foy reports on a discussion over on the TDD list that I had somehow missed. The discussion began with a look at long names for unit tests, and ended with a suggestion for grouping tests according to the expected behaviour. Cory presents this example:

public class RoomRemovedFromListWhen {
  public void lastUserLeaves() {
    //...
  }

  public void roomIsKilledByModerator() {
    //...
  }

  public void lastUserSessionTimesOut() {
    //...
  }
}

My first reaction to this was very positive, and I immediately began writing this to pass the idea on to you. But then as I mulled it over, a doubt crept in. You see, the tests are now grouped according to their outcome, rather than according to the interface they’re testing. And I believe that’s bad, because those outcomes may change independently of each other. It may be today’s policy that the room is deleted when the last user leaves, but that could change in the future. Which means this test class has several independent reasons to change, and the very grouping that seems so cute here could turn out to be a drag on the adaptability of the product. This isn’t unit testing, it’s policy testing.

This example violates a classic rule of good design: Keep things together that change together; and keep things apart when they change independently.

I wonder if this has arisen because of a confusion of terms: “behaviour” as in behaviour-driven development and “behaviour” as in outcome are different. The first is about interface design, and is a good reason to group tests. Whereas the second is about policy, and is a good reason to keep tests apart. I like the naming convention aspect of this approach, but I fear the increased cost of change may be too high a price to pay…

gravity and software adaptability

stack During my ‘hexagonal architecture’ session at XPday Benelux, the discussion gave me some clues as to why I feel the “standard” layered architecture model is sub-optimal: I realised that I feel as if I’m looking at a picture of a pile of stuff from the side. Contrast this with a hexagonal model of the same system, in which I feel as though I’m looking down on the picture.

Why is this important? And what relationship does it have to being agile?

The answer, I believe, lies in Lakoff‘s theory that metaphor shapes much of our thinking. When I look at any architecture model I subconsciously impose a point of view on the picture, because my mind relates what I see now to previous experiences. A layered model “looks like” a pile of books or building bricks; hexagonaltable a hexagonal model “looks like” an island on a map (another metaphor in itself!) or a table with chairs arranged around it. The choice of metaphor is made deep in my perceptual system, helping me to make sense of anything I see. And once the metaphor has been selected, my mind will then automatically supply it with a whole load of related beliefs, many learned as a baby. Among these are the effects of gravity and mass, together with related implications of downward dependency.

These associations cause me to believe that the things at the bottom of the pile are hard to move or change. Whereas in the hexagonal view I instinctively feel the system’s components are more loosely coupled – perhaps because they are associated only by proximity, and not by gravity.

So because of these deep-seated metaphorical associations, maybe we build less adaptable systems when we think of them in layers…?

exceptions considered harmful

I like simple rules of thumb that will help developers create better, more adaptable designs. So here’s another: Never throw an exception. And if someone throws one at you, catch it immediately and don’t pass it on.

Why? Aren’t exceptions one of the mainstays of modern programming? Joel Spolsky outlines the basic arguments against throwing exceptions:

“…I consider exceptions to be no better than “goto’s”, considered harmful since the 1960s, in that they create an abrupt jump from one point of code to another. In fact they are significantly worse than goto’s…”

But then he goes on to give advice that I consider questionable at best, by suggesting that you catch exceptions quickly and convert them into return codes. I agree that they should be caught at the earliest possible moment, but I disagree with converting them into return codes. Because although that certainly makes the mechanism visible to the reader of the code, it still represents strong coupling where there should be none. The caller – or someone further back along the call stack – has to know about, and take action in response to, someone else’s problem. It seems to me that such coupling violates the pragmatic programmers’ tell don’t ask principle.
Continue reading

pseudo-OO

In Pseudo-OO Design Dadi Ingolfsson talks about that all-too-common phenomenon – a design in which the code and the data are separate.

“This relates to the Microsoft-style of a DAL (Data Access Layer), a BLL (Business Logic Layer) and a UI, where the data that travels through the layers might be, for instance, dumb Customer objects or DataSet objects. The objects in these different layers are very procedural in nature as they usually only operate on data in objects that are sent to them rather than the data being their own. It´s what Fowler called an Anemic Domain Model. This is not OO design even though many programmers seem to think code is OO if it has classes and objects.”

By coincidence, this week I found myself workshopping agile programming with a team whose legacy C++ system is just like this. My approach to gradually improving the situation is to look for instances of the feature envy smell. Bit by bit, as we find each of these smells, we move the code into the objects where it belongs. Bit by bit, encapsulation improves. Bit by bit, the domain model emerges in the code. And very often, as we introduce abstractions to improve testability, bit by bit a hexagonal architecture emerges too.

Why is this important? Why is it bad to separate the code from the data? Because it stops the code changing at the pace of the business. Distributed behaviour and state mean that each piece of business knowledge is also distributed throughout the system. Which means that any new or changed requirement will cost more to implement.