I bet you’ve been in, or at least have witnessed, the situation when somebody needs to resolve a software engineering task but the journey to its completion resembles something from Jules Verne’s books. Sometimes it feels as if us, developers, would happily build almost anything but the thing we are supposed to. On top of that the outcome might not even resemble the initial goal as it magically slipped into a cognitive backlog.
I thought it might be fun to compile a list with the scenarios where I and the team I’ve been apart of or worked with put in the extra effort almost for nothing. You can call it over-engineering, lack of focus, lack of leadership. These are no individual missteps, they are approved by tech leads or favorably reviewed by peers. The article is a quasi-rant.
Bellow, what is labeled as Approach is the path chosen at that time and what is labeled as Better is the way I’d do it after the valuable lessons learned.
Approach: Server that saved the original data in a relational schema. Request were translated to SQL to access data. N-layer architecture and all that.
Better: Save the data as dumb bytes with the request URL as key. Or use a CND service and configure its caching rules.
Approach: Architected a wanna be re-usable and general internal library that needed close to ten imbricated lines of code at startup for each thing you’d need to cache or log.
Better: Use an existing library, maybe the framework already has an approach for this. In OOP languages, remember that you could override an existing method or use a new implementation of the same interface. Apart from testing, you’d want to leverage slapping an
interface before each
class, wouldn’t you?
Approach: A GraphQL server that has three or four types defined. All good but no nested queries were enabled. No graph. Requests and responses resembled the ones of a RESTful API.
Better: When dealing with small domains start small. Building clean RESTul services might take you where you want with flying colors.
Approach: Created a core customizable table component that would supposedly cover all business cases, present and future. The verbosity of this component’s parameters surpassed the one of HTML.
Better: Keep your overly zealous self in check, try not to mechanically apply the DRY principle. Plenty of times you gain more by allowing some decoupled duplication.
Approach: Re-Implemented ReactJS with almost the same API from before the JSX era.
Better: Just use React, Preact, Angular, Vue, Svelte (all the highly searched keywords).
Approach: Used patters such as the Builder pattern or the Factory patter. Better: Just use React. Longer version: Invest a couple of days more in learning React. You’ll see that it’s actually a component factory by itself. Components can be, well, composed as functions can. Even when declaring them as classes or having local state, it’s not rocket science.
Approach: Micro-frontends. All of a the sudden people were prototyping and attending meetings about this topic. Some said we’d need to roll our own micro-frontends framework if we wouldn’t find something that suits us.
Better: Deploy the UI component’s code to a CDN or package registry and fetch it with a
script tag or import it in the application bundle. As you would do with any other widget. Repeat for every solution.
I’ll leave some examples out for a potentially part two.
It’s not always that bad. Sometimes experimenting with ways of doing things yields a brand new product or an useful open-source tool. However, as with any other programming endeavour, do draw boundaries between what’s nice to have and needed, time-box it, separate it as much as possible. These are important primarily if somebody else is paying you to complete the project, which is often the case.