On SOLID Principles & Modularity
I stumbled across Uncle Bob’s SOLID principles of OOD quite a few years ago. They serve as the foundation of knowledge for designing object-oriented software. In fact, if you analyze the GOF patterns, you’ll find that virtually all of them adhere to the class design principles. I felt strongly enough about these principles that I included them in Chapter 1 of JOUP.
When used judiciously, they serve as excellent guidance in designing object-oriented software. But it’s not the SOLID class design principles I want to talk about here, at least not exclusively. Instead, it’s their less famous brethren that are often lost in the discussion of the SOLID class design principles…the principles of package design that I want to discuss.
Not Package. JAR File!
The ill fate of the package design principles is not due to their lack of value, but due to misinterpretation. As a result, the package design principles are not used nearly as widely as the SOLID class design principles. The obvious reason for this is that more teams spend time designing class relationships than anything else. Anecdotal evidence has shown this to be true. But this is not the only reason. Another surrounds their perceived value, and this is where misinterpretation of the package design principles plays a crucial role. Instead of the package design principles, they should be referred to as module design principles.
I’m unsure why the term package was initially chosen, but I postulate that at the time the principles were documented, C++ was the target language. Unfortunately, when translating these principles to Java, the mapping between the package principles and Java packages was carried over literally, and the foundation for misinterpretation was born. For example, JDepend is a tool that reports the measurements related to many of the package principles, but does so for Java packages. The literal interpretation of the package design principles when translated to Java packages diminishes their value.
Don’t get me wrong. There is value in taking care to design Java packages, but there is greater value when applying the principles to design JAR files. In fact, the principles map more clearly to JAR files than Java packages, and the Reuse Release Equivalency principle supports this point by stating:
The granule of reuse is the granule of release.
The granule of release in Java is the JAR file, not the package. The greatest value of the package design principles is not when applied to Java packages, but when applied to Java JAR files. We recognize this today, but it hasn’t always been that way, and initial interpretations along with a misleading naming convention still lead people astray. It did me, initially. But my discoveries in applying these principles are also what led me to develop JarAnalyzer a few years ago. I finally recognized the value in applying these principles to JAR files. And combining the package (can I say module now?) design principles in conjunction with the SOLID class design principles sheds an entirely new and interesting light on how we go about designing large enterprise software systems.
In his recent blog entry, Uncle Bob provides insight to how you might get started with the SOLID principles. It’s tough work. Similarly, I recall working hard to learn the GOF patterns in the mid-90’s. They twisted my brain like a pretzel, but over time, through study and application, I was able to grasp and master many of the concepts. A key element I had to learn is that the patterns don’t represent a universal truth - they shouldn’t always be used. You have to recognize where the extra flexibility is worth the increase in complexity. It’s the same with these principles. Uncle Bob makes this point clear in his discussion of the SOLID principles, as well:
These principles are heuristics. They are common-sense solutions to common problems. They are common-sense disciplines that can help you stay out of trouble. But like any heuristic, they are empirical in nature. They have been observed to work in many cases; but there is no proof that they always work, nor any proof that they should always be followed.
That being the case, what are the most important areas of the system that need a SOLID design?
Joints, Modules, & SOLID
Every system has joints, which is the point where two modules connect. It is these joints within the system that require the greatest flexibility and resiliency. The reason for this is driven by change. Change that is encapsulated within a single module poses less threat than change that ripples across many modules. This is trivial, and it’s why changing the private methods of a class are easier than changing the public methods. Likewise, change confined to a single module is easier than change that spans modules. That’s logical. So if we’re able to create well-designed modules, it makes our life a little bit easier. And using the module design principles allows us to bring greater modularity to our applications if we apply the principles when designing JAR files.
It is these joints, or module boundaries, within a system that represent the ideal opportunity to leverage the SOLID principles. Using the SOLID principles to minimize coupling between JAR files offers the biggest bang for the buck. Realistically, we cannot make an entire system open for extension but closed to modification (the Open Closed Principle). But we can use OCP at the module boundaries (aka. the joints) to create JAR files with enough design flexibility to confine change to a single module. Using the SOLID principles when designing the relationships between modules provides a low barrier point of entry for using these principles to create better designs. For instance, it’s much easier to refactor the classes if we know the refactoring is confined to a single JAR file. With a rich suite of unit tests, we can prove it has no impact to the outside world. But if we have to refactor the classes and the refactoring spans the joints of the system, well…that’s an architectural refactoring. It gets difficult and messy.
Today, technologies such as OSGi and JSR 294 aim to leverage the JAR file in bringing greater modularity to the Java platform by treating the JAR file as a first class component. It’s why these technologies are so important…they make it just a little bit easier to design really big software systems. And if we apply the SOLID principles in conjunction with the module principles, we have guidance on how to best design large software systems. As interest in designing more modular software continues to increase, and especially as OSGi continues to gain momentum, the module design principles will grow in importance.