Musings on Software

Somewhat informed, Mostly passionate

SOLID

I never in my life have had a love-hate relationship with an acronym more than SOLID. As an OO programmer, it sounds perfect and flawless, as if you’ve been programming wrong this entire time. When I was an intern, I had my mentors speaking Solid like Gospel, phrasing questions such as “Is this good Solid code?”

Never do you hear the downsides of Solid however, and the problem isn’t the formula, but the people implementing it. Does this object have single responsibility, or do you think it has single responsibility? Anytime humans are allowed to exert their artistic opinion on top of something that is viewed a benchmark, you see a half-baked set of standards with none of the enjoy ability of the ben and jerry’s equivalent.

The industry, at least from my observations specifically as a .NET developer focus on the last letter, solving all the problems with Dependency injection. DI has it’s blessings, but isn’t the saving grace of every codebase. I personally believe the first two letters, really have the largest importance.

Single responsibility (S), is asking yourself “Is what this object about to do, what it’s meant to do?” Extending objects beyond their responsibility is one of the fastest ways to a pit of tech debt that I’ve seen in any codebase. Scale this up to enterprise levels and Services in SOA doing too many things will become the bane of architects, and a source of burn-out amongst right-minded developers. Focusing heavily on what a job is, and what achieving that job entails are very difficult; a rifle fires bullets, but the firing pin strikes the primer. Likely every dev that ever reads this codes that in their heads in different ways.

Extending that, the open-close principle seems to take the Single-responsibility principle outside for a dirty fist fight. How can something be opened to extension and have one purpose? Let’s talk about databases. Say we have a Database orchestrator, a class that handles our CRUD operations on any database our application has to interact with. For example, let’s just say we have an arbitrary set of database implementations and we need to delete a record from all of them, and this record may or may not be what this database is supposed to handle. That last sentence sounds like we should write logic into the orchestrator to do selection logic, but is that really orchestrating? Solve this extension of responsibility by building new classes with new responsibilities. My record of this type may only be stored on Dynamo, the orchestrator takes its request to a factory that returns my correct IDatabaseProvider for the specific database, which all the orchestrator knows is the right tool for the job, we achieved both by giving the job to a new object, that the orchestrator then, orchestrated.