SOLID Code isn't by Mark Seemann
Recently I had an interesting conversation with a developer at my current client, about how the SOLID principles would impact their code base. The client wants to write SOLID code - who doesn't? It's a beautiful acronym that fully demonstrates the power of catchy terminology.
However, when you start to outline what it actually means people become uneasy. At the point where the discussion became interesting, I had already sketched my view on encapsulation. However, the client's current code base is designed around validation at the perimeter. Most of the classes in the Domain Model are actually internal and implicitly trust input.
We were actually discussing Test-Driven Development, and I had already told them that they should only test against the public API of their code base. The discussion went something like this (I'm hoping I'm not making my ‘opponent' sound dumb, because the real developer I talked to was anything but):
Client: “That would mean that each and every class we expose must validate input!”
Client: “That would be a lot of extra work.”
Me: “Would it? Why is that?”
Client: “The input that we deal with consist of complex data structures, and we must validate that all values are present and correct.”
Me: “Assume that input is SOLID as well. This would mean that each input instance can be assumed to be in a valid state because that would be its own responsibility. Given that, what would validation really mean?”
Client: “I'm not sure I understand what you mean…”
Me: “Assuming that the input instance is a self-validating reference type, what could possibly go wrong?”
Client: “The instance might be null…”
Me: “Yes. Anything else?”
Client: “Not that I can think of…”
Me: “Me neither. This means that while you must add more code to implement proper encapsulation, it's really trivial code. It's just some Guard Clauses.”
Client: “But isn't it still gold plating?”
Me: “Not really, because we are designing for change in the general sense. We know that we can't predict specific change, but I can guarantee you that change requests will occur. Instead of trying to predict specific changes and design variability in those specific places, we simply put interfaces around everything because the cost of doing so is really low. This means that when change does happen, we already have Seams in the right places.”
Client: “How does SOLID help with that?”
Me: “A result of the Single Responsibility Principle is that each self-encapsulated class becomes really small, and there will be a lot of them.”
Client: “Lots of classes… I'm not sure I'm comfortable with that. Doesn't it make it much harder to find what you need?”
Me: “I don't think so. Each class is very small, so although you have many of them, understanding what each one does is easy. In my experience this is a lot easier than trying to figure out what a big class with thousands of lines of code does. When you have few big classes, your object model might look something like this:”
“There's a few objects and they kind of fit together to form the overall picture. However, if you need to change something, you'll need to substantially change the shape of each of those objects. That's a lot of work, and this is why such an object design isn't particularly adaptable to change.
“With SOLID, on the other hand, you have lots of small-grained objects which you can easily re-arrange to match new requirements:”
And that's when it hit me: SOLID code isn't really solid at all. I'm not a material scientist, but to me a solid indicates a rigid structure. In essence a structure where the particles are tightly locked to each other and can't easily move about.
However, when thinking about SOLID code, it actually helps to think about it more like a liquid (although perhaps a rather viscous one). Each class has much more room to maneuver because it is small and fits together with other classes in many different ways. It's clear that when you push an analogy too far, it breaks apart.
Still, a closing anecdote is appropriate…
My (then) three-year old son one day handed me a handful of Duplo bricks and asked me to build him a dragon. If you've ever tried to build anything out of Duplo you'll know that the ‘resolution' of the bricks is rather coarse-grained. Given that ‘a handful' for a three-year old isn't a lot of bricks, this was quite a challenge. Fortunately, I had an appreciative audience with quite a bit of imagination, so I was able to put the few bricks together in a way that satisfied my son.
Still, building a dragon of comparable size out of Lego bricks is much easier because the bricks have a much finer ‘resolution'. SOLID code is more comparable to Lego than Duplo.