What does maintainability mean to you?

Sometimes in my discussions with other developers, we have to agree to disagree on certain things.  One recent topic was that of maintainability, in regards to the size of classes/methods and project structures. 

I find it curious that some developers believe a single 4000 line class with single methods being hundreds of lines long is actually more maintainable than say, 40 classes with ~100 lines each and methods around 7-10 lines long.  Of course this is just a vague example, but you get my point.  Being pretty open to other ideas/views, I just simply can’t bring myself to understand this (even though long ago that’s how I used to think!). 

Chances are that a single class consisting of thousands of lines of code is in major violation of the Single Responsibility Principle (SRP) and, with no unit tests, makes future changes without introducing bugs near impossible. 

Interestingly, I also find that developers who prefer the “put everything in Logic.cs” approach (Yes, I’ve actually seen this exact filename in a production system), seem to rely very heavily on the debugger.  That’s really a shame, because there are much better and faster techniques available to discover bugs and understand how a particular class works.

Take unit testing, for example.  Yes, I’m just talking about plain old state-based unit testing, even if you don’t understand the huge benefits of TDD/BDD (which is a bigger shame).  But even unit tests alone can help break your reliance on the debugger.  One of the best things you can do when finding/fixing bugs is write a failing unit test that exposes the bug.  It’s so much faster to run a simple unit test than to step through a debugger, especially when your classes are gigantic.  And, when’s the last time your debugger acted as a regression test for you?  (I’ll take your silence as “never”…)

Another interesting observation I’ve had about large classes and methods is that they rarely have automated tests for them.  This seems very strange to me.  My confidence level in code like this, without automated tests, is extremely low.  Nevertheless, I’ve occasionally had to work with systems like this.  And I usually start by writing just a few unit tests and work from there.  But that won’t last long until you realize you’ve got some serious refactoring to do because the code is so tightly coupled to everything else.  This can make writing simple unit tests very hard.

The usual complaint I hear about keeping classes/methods small is Class/Method Explosion.  Indeed, you probably will have many more classes (and hopefully interfaces) and methods, but with proper naming and location, you can pretty easily understand the flow of logic.  And with unit tests that have descriptive names, it becomes that much easier. 

Simple Example:  If you had to change the calculation of a gold customer’s discount, wouldn’t it be much easier to find in a GoldCustomerDiscountSpecification rather than on line 1238 of the OrderService class?  Oh, and did you remember to change it on line 854 in the CustomerService class as well?  (I rest my case…)

I’m not even going to talk about SProcs that are a 1000 lines long, which sadly, I’ve also seen in production systems.  Eeek!

So I guess I’d just encourage folks to look for ways to separate responsibilities in your code and use unit tests (and even better TDD) to aid you in your efforts.  And free yourself from the debugger!

Castle MonoRail – Response To Comments/Ramblings