One thing that we know for certain is that codebases grow with time. We add code to them continually. When we think about this, it's easy to become bleak. Each of the classes in a codebase is something that we need to understand. At a certain point a team can no longer "keep the system in their heads" and they have to do a bit of spelunking to figure out what they have and where they should put their changes. Changes may end up in the wrong areas, simply because we are not sure of the right place. We start to introduce errors because we are not aware of other relevant code.
Given that these are the forces that we live with, do we have anything on our side? Anything that helps us scale up in a nice way?
One thing that helps is class closure - when our classes focus on a single responsibility, we often end up in a situation where the chance of the changing them is extremely low.
The other day, I started taking two measurements from some git repositories that I had on hand. I measured the number of classes added each month to each codebase, and I measured the number of classes closed each month.
Here is a graph for the codebase of RSpec from about 2005 to 2010. The blue line is cumulative class additions over the months, and the green line is cumulative class closures. The increment on the X axis is months.
To understand this graph it helps to understand how I calculate class closure. A class is closed on the date at which no further modifications happen to it from that date to the present. This means that the closer we come to the present, the less accurate our sense of closure is. After all, we could modify any of those classes tomorrow. But, even with this oddness, there are some interesting things to see.
The distance between the blue and green line indicates the number of classes in the "active set": the number of classes that have been added and (at that date) will still be changed at some point before the present. It appears that RSpec has had a very small active set over its lifetime. In fact it the maximum active set over its lifetime is about 201. That is pretty good for a project with 1034 classes.This seems to indicate that the developers were writing code in a way which tended to bring classes to closure quickly.
Another observation, it appears that there was a massive change in direction in the code base around the middle of its timeline: a large number of new classes were added, and the active set became rather large for a while.
The total picture for RSpec is much nicer than some other projects I've looked at. Here is a chart for a project that brought classes to closure much less quickly:
The project contains close to 5000 classes and and at one point the number of active classes was 2121.
There may be additional forces at play hiding in the context. The second project may be suffering from code quality problems or it may simply be developed in a domain that's not well understood.
It is interesting that the number of classes on both projects seems to have asymptotes. It could be a lifecycle of collaboration, or an indication that the domains for these projects have been well explored.
Posted by: Paul Slusarz | December 01, 2012 at 11:19 PM
Paul, yes, that that could be the issue - unexplored domain, but it could also be an issue of coding style. When adding a second responsibility to a class, we often have a choice about whether to do it or start someplace else. In any case, I think you are right - there's no need to judge.
Re the asymptotes, that is a good point. I'll look into it.
Posted by: Michael Feathers | December 02, 2012 at 05:33 PM
An interesting metric. The complete history of the gap between the two lines could vary as each check in occurs.
The check ins that close off many classes could be considered to be responsible for some of the difference between the two graphs.
If we measure the time classes are active by the area between the two graphs, then the difference between the value of the area before and after would be a measure of the size of the refactor.
Posted by: Tom Mullen | December 03, 2012 at 01:12 AM
What script/tool did you use to generate the data for your graphs?
Posted by: Ericsmalling | December 06, 2012 at 01:42 PM
Eric: It was a lot of fiddling in irb using this set of tools I wrote: https://github.com/michaelfeathers/delta-flora
Posted by: Michael Feathers | December 06, 2012 at 03:12 PM
Michael, I'm coming back to this old post to see if you would recommend any reading on the loosely defined subject of Code Archeology. I have put in an "unsession" proposal for this year's Strange Loop and could use some guidance. Leaving contact email in the form.
Posted by: Paul Slusarz | August 17, 2013 at 05:41 PM