Start Fixing a God Class
5 minute read
All I want to do is edit the freaking document!
Unfortunately, so does everything. CDocument is central to what we do. Users think of documents, and so does the UI. Every piece of code reads the CDocument class…unless it modifies CDocument.
And now I need to unit test my code. Also, I want to ship my team’s code independently of the other team. But every single feature touches CDocument. Many of them change CDocument - or one of the 6 wrappers we have created around CDocument over the years to reduce changes to CDocument. Anything could break anything. There is no way to be independent.
And there’s no way out. The entire user experience is document-centric, and that means every behavior is context-dependent. And that context…is in CDocument. Part of my code has to be in CDocument in order to know what to do.
Or perhaps in your case it is a central service, a User class, or a Sale. But whatever it is, there is one, 10,000-line class that everyone needs. We have a God Class, and to gain independence, we need to fix it.
Surround your God Class with Whole Values
It seems that our goal is to remove a responsibility from the God Class. However, that goal may be impossible to achieve right now. Instead, we’re going to make stronger classes around the God Class.
In other words, we’re going to steal the other king’s pawns and use them against him!
Although every God Class creates an obvious coupling problem, it creates an even larger and less obvious problem: it protects itself with pawns. So how we are accidentally building these pawns?
- We had a new feature to write that was related to the God Class.
- Because it was related, the code reads and modifies data that is already on the God Class.
- This forces us to add or edit methods on the God Class related to the new feature. However, this gives the new concept to the God Class as well.
- The remaining half of the concept is written outside the God Class, but is just not worth making explicit. So it ends up becoming a procedure with lots of Primitive Obsession.
- You have created a new pawn.
- Since the new procedure has no clear concept, it gets tossed in with all the other unrelated procedures and into some class whose name ends with -Manager or -Utils.
- Your pawn now defends the God Class.
Any attempt to eliminate the God Class first requires fighting through an army of procedures. It never seems to get anywhere. This month’s recipe shows you how to steal your opponent’s pawns, converting them to your side. You will quickly surround the God Class with dozens of pawns, each ready to take a piece of the God Class. After that, the God Class is doomed.
Access the recipe to convert the God Class’s pawns to work against it as well as other recipes coming in the future!
Future developers will help you
As long as you finish at least part ‘../../post/fix-god-class'5 of the recipe, future developers will naturally add their features to your new class and not the God Class. Normal feature development can stop growing the God Class!
It’s not perfect. The God Class still has code that belongs on your new class. There are still lots of procedures around your two classes. But you have shifted the center of gravity a little. Future developers will even refactor bits of the God Class out and put them on your class.
Do this every couple of weeks for a quarter and your God Class will be surrounded by strong concepts. Then just do normal feature development for a year and it will fade away.
Benefits:
- Make a God Class better without having to fix everything.
- Change the default behavior of future developers.
Downsides:
- Each pawn conversion requires investing a couple hours of non-story time.
The initial change can’t be done as a way to speed up a story. The value happens across many stories and teams. Make small investments with full team support, and give time for each to start paying off before you do the next.
Demo the value to team and management…
Show three things at your sprint demo:
- Example: One specific change (procedure and God Class, then new class and God Class).
- Progress: A chart of the number of procedures that use your God Class and the number of fields in your God Class over time (starting before your change, ending after your efforts) & the number of work-hours it took you
- Impact: A quantitative measure showing the organizational cost of the God Class.
The example portion is obvious; however, progress and impact require some explanation.
Progress Measure: Calculate
Count the procedures that take your God Class as a parameter plus the number of methods on your God Class. This number is your exposure: the number of potential cross-story interactions.
Count the number of fields in the God Class. This number is your attractor: the liklihood of future stories making the exposure worse. Track both numbers over time. Demonstrating a progress measure and showing you can improve it will cause those at the demo to ask about impact. After that discussion they’ll start talking about funding if they see a high value to cost ratio.
Impact Measure: Track
Which of these matters most to your management?
- Reduced cross-team bugs.
- Improved ability for teams or features to ship independently.
Whichever you you choose is your impact measure. Now you can calculate a baseline. How much has this happened over the last quarter, and what did it cost the organization?
The chance of two stories interacting badly with each other is proportional to the product of their chances of each interacting with the God Class.
- Each improvement in the progress attractor ( pa) measure will stop one set of future stories from interacting with the God Class.
- Each improvement in the progress exposure ( pe) measure will stop one set of past stories from interacting with the God Class.
Therefore, your impact measure is proportional to the chance of a new story interacting with another new one plus the chance of it interacting with an old one. In other words, your impact measure is proportional to pa * pa + pa * pe.
That will return the conversation to the progress measure and establish your funding.