Learn OOD - to unlearn it again
One topic we regularly teach in workshops for our customers is object oriented design (ODD), i.e. the art of crafting classes/interfaces in a way that the result is an easy-to-understand, maintainable and flexible code base. With the agile focus on shipping working software, some might consider the skill of OOD less important. One popular argument is that quick reaction to change is more important than designing objects and their interaction carefully. I personally look at it the exact other way around. This blog post summarizes why you need to learn OOD first, in order to avoid it to some degree again.
Learning OOD the classical way
Back in the days where the waterfall project methodology was most wide spread, object oriented design was a primary skill for software developers: After analyzing the tremendous functional specification, lots of class diagrams were created, itemizing each and every object in order to provide a full way navigation for the actual implementors.
Developers needed to understand interaction between objects in perfect detail, modeling business processes to their long tail and infrastructure alike. Applying a design pattern wherever possible in a UML diagram was considered the holy grail in many software development projects back then.
Junior developers those days were left to do the actual implementation of the upfront design, occasionally leaving a small component unspecified to allow them to try out the skills they learned from watching the seniors' design.
One of the results of this way to handle projects was a massive risk to over-engineer the system, taking away the flexibility for spontaneous change requests and leading to a long time to market. These are two of the reasons that led to the agile movement, from a technical perspective - leaving the even more important social aspects aside here.
OOD in fast pace and agile
With the rise of agile, the way we handle projects changed drastically: Instead of creating a full system design upfront, teams start with a small set of features, rolling these out to the user as fast as possible and iteratively refining the software together with the customer. Shipping working software is one of the values in the agile manifesto, while clean code is not.
As can be seen in many projects, working at the fast feature pace often led to big ball of mud (BBOM) code bases, which reduced the agility of the project day by day, eventually leading to the stage where changes are costly and developers demanded yet another re-write to free themselves of legacy hell. This is what can be described as under-engineering.
Luckily, the area of automatic testing and clean code rose alike with the demand for agility, restraining us from just hacking away, in the best case. And especially unit testing requires you to slice your code carefully into fine-grained objects, which in turn requires a deep understanding of OOD.
Refactoring is the key
The solution to the mismatch of fast change and clean code is the art of refactoring. Instead of creating a full blown object design upfront, we nowadays let the code flow for some time until we realize that there is a need for cleanup. We then hopefully take the time to rip the created code apart carefully and to restructure it into a nicely crafted object structure, without moving into the direction of over-engineering.
But being able to refactor requires again a deep knowledge of how structures can be crafted in a clean and maintainable way, how objects should interact to stay flexible. In addition, a particularly good test coverage is needed to enable that process of changing the underlying structure of a system without breaking its business processes (refactoring).
Learning OOD to unlearn it
Today's software projects require us to react flexible to emerging changes. This can be achieved by letting the object design of a system emerge instead of attempting to craft it upfront. Automatic testing and continuous refactoring are the key methodologies to master this balance act. Both topics require a deep knowledge about how objects relate to each other, about how to craft them in a sensible way and how to slice the code to extract dependencies. But this is essentially what we call object oriented design.
This comprehension leads to what we experienced with many development teams during the past years: in order to enable a team to follow the described development path, knowledge about clean code and various topics object oriented design (like SOLID and design patterns) is an essential basis. Otherwise, the developers will not be able to test responsibly and to perform refactorings successfully.
Honing OOD skills requires a pretty good deal of training and practice. Experimenting with object relations, trying to get it right from scratch and iterating learning cycles are absolutely necessary. But once a developer moves in this direction, evidence shows that he automatically begins to over-engineer his code. It is natural and important to undergo this phase of learning, because it is the only way to build up experience and finally acquire a intuitive understanding of how objects relate to each other.
Once this level of perception is reached, the developer needs to restrain himself again. He needs to unlearn parts of what he learned before, in order to let the code flow in a controlled manner, without planning each and every detail and without creating a large object oriented design upfront.
"Unlearn" is of course not the ideal term here, because forgetting the knowledge would be a disaster. Furthermore, refactoring the code requires exactly that know-how and experience. Assessing which code can safely be let slide until refactoring is required and encapsulating that code behind a thin and safe abstraction is essential in order to not end up in a BBOM. Especially for being able to apply a sensible test mix (which is another complex topic in itself) the latter point is highly important.
So there is no way around that learning process, which is illustrated in the following graphic:
Of course, undergoing this process takes time, and failures are required to learn properly. Therefore, junior developers need proper guidance from good seniors - on technical, social and mentoring levels - to go through that process on the job. Pair programming, coding dojos, code retreats and code review can support this process and speed it up to some degree.
Conclusion / TL;DR
In order to master agility, fast feature pace and high quality code at the same time, every developer needs to learn the art of refactoring and automated testing. This in turn requires a high skill level in object oriented design, which can only be reached through a good deal of training and practice. Undergoing a phase of over-engineering during this learning process is natural and even desired to enable the developer to deliver his full potential.