Too Many Private Methods
The refactoring in the previous article stopped at breaking down a big public method into several smaller and private ones. While the violation of the single responsibility principle on the function level was reduced, the violation on the object level stayed the same. This is a code smell that can be called Too Many Private Methods.
The fact that an object does too many things is often not obvious right away. That’s where the Extract Method refactoring performed in the aforementioned article became handy. Seven private methods of the VendingMachine started screaming too many roles of the object.
Code Rot
The single responsibility principle violation on the object level always goes together with testability problems. When a lot is happening in an object privately, there’s a desire to reveal its internals for testing. The so precious object’s encapsulation weakens leading to more complicated future refactoring and fragile tests. Both of these, in turn, result in a situation when nobody wants to change the code even when it really needs a change, making the code rot.
Big Building Blocks
Another problem that arises when the principle on the object level is violated is the bigger object size. In object-oriented programming, the software is composed of building blocks represented by objects. The smaller and more focused those blocks are, the easier it is to build a structure from them and, more importantly, to adapt the existing structure to the new requirements.
Extract Class
How can the new VendingMachine’s code smell be eliminated? An object does more than one thing if there are several reasons for it to change. The VendingMachine will have to be changed if the overall vending process changes. This seems to be its primary responsibility. The object will also have to be changed if the details of the inventory implementation change. And that is a candidate for an extraction.
The VendingMachine now depends on the Inventory expressed as a protocol. Not only is the inventory logic now encapsulated in a separate, smaller piece of code—the SimpleInventory object—but the VendingMachine has also become more testable. It is trivial to write a test double implementing the Inventory protocol and use it in tests instead of a real inventory.
Conclusion
The single responsibility principle helps structure code better. It stimulates the creation of smaller and more composable building blocks. The principle can be applied on several levels. Applying it on the function level makes it easier to reveal the principle violation on the object level. Adhering to the principle on the object level keeps the objects small, self-contained, and better encapsulated. Building complex and testable structures from such objects becomes much easier.