There are many ways to make changes in an existing code base. Some are better than others.
Some teams produce what I call a festering code base. In a festering code base, the team changes the code primarily by adding code to existing methods and adding methods to existing classes. The results are predictable. Classes and methods grow malignantly, eventually becoming thousands of lines long.
Better teams produce budding code bases. Developers create new classes and methods and delegate work outward. Periodically, they collapse structure back into a simpler form, but the dominant trend is to grow the code by creating new structure.
These distinctions are qualitative, but they are measurable. You can look back at the the change history of a code base and get a sense of how changes occur. What is the ratio of new class and new method addition to change?
Budding code bases generally consist of classes that adhere to the Open/Closed Principle. The code grows outward. Festering, on the other hand, is stagnation. New code grows in the same space as old code, suffocating it.
What causes festering? Well, I think it is a direct result how of relative cost affects changes in code. It simply costs more in effort to add a method to a class than it costs to just add code to an existing method. Likewise, it costs more in effort to create a class than it costs to add methods to an existing class. The fact that we know that budding code is more cost effective over time doesn’t change the perception of the cost at the time of change.
We can be diligent and try to fight this tendency, and we should, but I wonder sometimes whether we can change the incentives by doing something clever with language design and IDE design. What would life be like if it were easier to create budding code rather than festering code? Can we change the cost structure so that this is possible? Moreover, if we can, would we just be producing another problem: overly budded code which is hard to maintain for different reasons. But, given what we know about how code often turns out today, it seems worth trying something different.
"The fact that we know that budding code is more cost effective over time doesn’t change the perception of the cost at the time of change."
You know that and I know that, but I have seen dozens of developers who either don't know it or don't believe it.
Changing how we think about building software is a challenge similar in scope and complexity to changing how we thought about smoking and driving while intoxicated. Seriously. It will take a couple of generations for the change to take hold, and even then there won't be 100% adoption or even acceptance.
The last paragraph, though, does allow some rays of hope to shine through! How would you see a language promote budding vs. festering? I could see an IDE provide some tools around near real-time code smell identification, but that would require people to actually use an IDE! I'm working in the telecom world right now, and most developers use simple text editors (let the vi/EMACS wars begin!).
Posted by: Dave Rooney | June 29, 2010 at 07:55 AM
In Clean Code, Jeff Langr says "We want our systems to be composed of many small classes, not a few large ones. Each small class encapsulates a single responsibility, has a single reason to change, and collaborates with a few others to achieve the desired system behaviors.".
To those who fear that a large number of small, single-purpose classes makes it more difficult to understand the bigger picture, he asks: "Do you want your tools organized into toolboxes with many small drawers each containing well-defined and well-labeled components? Or do you want a few drawers that you just toss everything into?".
These opposing approaches to growing one's toolbox seem to map to your two approaches to growing code: budding and festering.
When we have a new tool to add to the toolbox, the fact that we know that putting the tool in a newly labelled drawer is more cost effective over time doesn’t change the perception of the cost at the time of change, so we are always tempted to just throw the new tool in an existing draw.
Posted by: Philip_schwarz | June 29, 2010 at 03:59 PM
Nice observation! I'm thinking that it would be interesting to collect such festering-budding metrics from code bases automatically, so I filed a feature request for one code metrics tool. :)
http://jira.codehaus.org/browse/SONAR-1652
Posted by: Esko Luontola | June 30, 2010 at 01:13 AM
I agree completely.
You mention "doing something clever" with languages or IDEs to make budding desing easier than festering design.
I find that unit testing / Behaviour Driven Desing does this. It is much easier to write tests for small, single purpose classes and methods with a small amount of behaviour. As soon as you start adding a lot of behaviour to a method it gets much, much harder to test it comprehensively.
Posted by: andypaxo | June 30, 2010 at 09:49 AM
A while ago I was thinking of psychological barriers in software development on my blog (posted at http://www.codeodor.com/index.cfm/2009/3/24/Passive-Barriers-in-Software-Development/3055 ), and one of the things I thought would be cool to see was an IDE that implemented annoyance driven development.
The relevant bit from that post:
Annoyance Driven Development. This isn't one that I know how to turn on or off, but I think it would be a great feature to have in IDEs or text editors: it gets slow when your methods or classes or files get too big. This would be a great preventative tool, if it exists. I guess it falls back to using test suites and code analysis to provide instant feedback that annoys you into doing the right thing.
Posted by: Sammy Larbi | July 02, 2010 at 11:51 AM
I especially liked the concept that at the time of change, just adding code to an existing method, and not refactoring to a better structure, is perceived as more cost effective, but it’s just accumulate technical debts, that over time cost money in the form of interests. Same concept can be applied to write unit tested code: it seems to cost more at the time of change, but costs less in the long term, by flattening the curve of cost-of-change.
Posted by: Fcarucci | July 06, 2010 at 03:22 AM
Very high level very good approach.
Why do you think programmers want a file of thousands of lines of code?
They don't want. The company philosophy drives the behavior of programming. If everybody is doing the same, you just will follow them. It is easy to look one step forward. It is easy to see ten steps into the future. But is requires courage to make a stand against the mass.
I honor the guys who are willing to make a difference and try improve.
Excellent read. :)
Posted by: Jens Schöbel | July 06, 2010 at 03:54 AM
Really, excelent Post Michael, I cannot agree more. The relationship with testeable code is indeed interesting.
One little thing about what you mentioned about what we would improve with a clever IDE design or new tools. The best example i was thinking of is one of the simplest but most used refactor nowadays IDEs offer: 'RENAMING'.
Have you notice how much impact it has had (and is having) on improving readibility? and by transitivy, on maintainability?
Thanks!
Posted by: Juan Pablo Olguin | July 14, 2010 at 12:31 PM