Alternatively titled: Are you really ever going to swap out redux?
Recently I read a great article doing the rounds called “You are not Google”. The premise of the article was that a lot of what is hot and trendy in the software world is actually not the right solution for most businesses. Architectures designed for millions of concurrent users are not always the best solution for products that serve maybe a couple thousand people a day at most. Over engineering can add complexity and make your solutions worse rather than better.
I’d like to riff on this theme and discuss a similar topic at a lower level. While that article dealt with systems architecture, I’d like to apply the same philosophy to how we actually structure the software that we write day to day.
Almost from the start of learning to code, we hear about the SOLID principles, and about how good clean code should minimise coupling, facilitate high test coverage, and stick to single responsibilities. And, for the record, yes, it should do this. But…
But the reason most of us are writing software in the first place (at work at least; I’m excluding passion projects from this narrative) is that a company is paying us to do it. And the reason they are paying us is that they expect us to provide them value through the software we build. And as developers, it’s our responsibility to maximise that value. And sometimes, sometimes, religious adherence to things like loose coupling and single responsibility reduces the value of what we produce.
I would argue that too much abstraction, or too much worrying about separation of concerns, can often lead to technically excellent codebases, but codebases that are also hard to read, hard to explain to new-starts, and that can slow down the speed of development to the point where adding new code to the product becomes prohibitively expensive.
I’ve seen it happen. I’ve worked on projects where it’s happened. Striving for technical excellence can lead to solutions that are theoretically exceptional, and practically completely wrong. Some of the code that would score highest marks on a university assessment has been the result of projects that went way over budget and achieved very little.
Take for example a typical react/redux application with a store, selectors, containers (often multiple layers of containers), and components. Great pains are often taken to make sure all the pieces are as separate as possible. The theory goes that redux is just a store, react is just a rendering engine. If we make sure to keep everything distinct then if a better store comes along, say, then we can “just swap out redux for the newer better store”, and the impact will be minimal. And that would be true. But…
But you are never, honestly, in a commercial setting, ever going to actually do that. Not once in my career has a business paid me money to replace one layer in an application with another similar, but different, layer. I’ve never been asked to replace a redux store with something else, or an ORM with another ORM, or one rendering engine for another. And I haven’t been asked to do it because business does not care about the technical details, only that it works, and is cheap to maintain.
What I’ve been asked to do before is rewrite an older application for a new medium. Something like “Can you please take this desktop app and turn it into a website?”. And in theory a nicely layered product with clean separation would mean that I could just lift heaps of business logic wholesale from one application to the rewrite, but in practice that never actually happens. Because technology moves forward, and best practices change, and the new application has to be written in a different programming language to support whatever new platform we’re targeting (nobody is building web frontends in c++), or because it’s now hard to hire programmers that know how to maintain the old language (see COBOL), and so the whole thing gets rewritten, and all that perfectly architected forward-looking old code goes to waste.
Our node microservices, and our fancy modern react frontends will all go this way eventually too. They’ll be maintained, added to, and then eventually replaced wholesale. No one will swap out a layer for something else and what will end up being most important about them is the business value they produced. Did the product do what it was supposed to? Was it cheap to add new features to? Could developers go from zero to productive quickly when fixing bugs?
The takeaway from this is don’t worry so much about making the code you write as technically correct as possible, make it as business friendly as possible instead. Optimise for something that is cheap, quick to build, easy to read and easy to maintain. Sure you can separate concerns where you can, and it’s nice to see a class or component do one thing and one thing only, so do that where it makes sense. But keep business value in the front of your mind at all times. Realise that not everything has to be abstracted. Code for business outcomes, and your projects stand a much higher chance of success.