Image by Michal Jarmoluk (jarmoluk) from Pixabay
Stack em low
Paul Williams
26th Oct 2023
I propose that minimising the number of technologies in any given project is of core concern to the software engineer. Furthermore, I put forward the hypothesis that the number of technologies used is at least somewhat predictive of the readability and changeability of an implementation. If you want to take advantage of the rapidly evolving business needs, user needs, and shifting technological trends then you have to learn to evaluate and dispense with low value tooling.
I would not say the relationship is linear. Much more like a positively skewed distribution. Adding a few well chosen tools can make a world of difference but diminishing returns kicks in far quicker than people realise. Identify those few technologies that truly add value and boot as many low value ones as possible. The long term maintainability sky-rockets.
Most projects I’ve worked on involved reading and understanding someone else's code. I find projects with smaller tech stacks are easier to understand and change, even when old and somewhat archaic technologies are in use. For many, modern frontend programming is an exercise in stuffing in as many packages as your application can fit then weaving them into a Rat King. Consider a pair of smallish frontend applications that provide the same service.
The first contains three core web languages (HTML, JavaScript, CSS), a web framework, a plethora of plugins, TypeScript, a full grid system, third party state management library, a CSS preprocessor, a CSS framework, a CSS naming methodology (SASS, Tailwind, and BEM respective examples), a fully customised ESLint configuration, and a whole suite of testing libraries. Finally you need a bucket of complex abstractions to keep everything organised and aligned. The author is quite promiscuous in regards to third party packages on the belief one should never reinvent the wheel regardless of how square the present ones are. Design decisions are driven through ideology and personal opinion without any thought to weighing costs and benefits.
The second has a much tighter stack. A web framework is used alongside the core web languages and that’s about it. A few other libraries are employed to tackle difficult, costly, or critical features such as encryption. A straightforward testing library and maybe a simple preprocessor too but both are organised for easy removal or replacement. The author has made a conscious effort to weigh up the present and future benefits and costs of importing a second and third party package versus a custom implementation. The prose is mostly simple and straightforward, applying object-oriented and functional styles where utility and clarity deems ideal rather than trying to be perfectly consistent. Consistency and the author’s preferences are clearly present, but they are secondary. The design decisions and code style focus more on communicating intentions and optimising for both readability and changeability rather than rigidly following a mainstream style. Code written to be read at the expense of requiring a little extra effort to write.
You’ve been asked to pick up one of these to maintain. Which do you pick? I would shackle myself to the latter in order to avoid working on the former. Even if the programmer had been too minimalist and repetitive I’d still embrace it. For it is easier to manage and improve an under abstracted codebase than understand and untangle an overengineered one. I’ve worked on many overengineered messes, some of them my own, and learnt the hard way that the future cost is double the present benefit.
Even older projects, using libraries so old I’ve never heard of them, are easier for me to maintain than the overengineered stuff being concocted today. I think the industry has lost its understanding of the intrinsic differences between frontend and backend programming. There’s a reason frontend tools were built so dynamic and backend ones so rigid; they’re optimised for the nature of their environments. I advise using systems programming tools for systems problems and scripting tools for scripting problems. Each where they are virtuous.