In the first years of my career, I was fascinated by building products. I could masterfully chain together libraries and integrate third-party services. But I knew little about separation of concerns, boundaries or design patterns.
CRUD applications were my bread and butter, and the startups that employed me cared little about software design.
Then, as it always happens, my career got turned around in a single afternoon. I was looking through a Node.js service, and one line, in particular, grabbed my attention.
It was just a function that validated a user’s permissions, but it was written in such a simple yet expressive way that I had to stop for a moment.
abortUnless(user).canDelete(entity)
I had only seen validation done as a long series of conditional checks. This line was nothing more than an abstraction that hid the complexity and decision-making. But it was a well-designed one - readable, reusable, and extensible.
Instead of being packaged in a class, the functions are chained, and they read like a simple English sentence. The mental load of going through this line is much lower than having to read a set of conditionals or a class that keeps internal state.
We can extend the functionality by adding another method to the object returned from abortUnless
. Each validation method returns the same object, so we can chain multiple together and create complex validation flows. The first one that fails will throw an error and cancel the execution.
I learned that this is inspired by the Builder Pattern. Up until that moment, I thought of design patterns as something only used in enterprise environments.
But with some creativity, we can apply a well-known solution and save ourselves from reinventing the wheel.
Depending on the business logic, a user may be able to create and edit entities but not delete them. Instead of naming it something generic like canManage
or isAdmin
and leaking business logic, the API describes the high level concept.
But this line is a great example of the single responsibility principle.
abortUnless(user).canDelete(entity)
This code doesn’t deal with returning a response or setting up status codes. It only validates and throws an error. How it’s handled is up to the caller. It’s not the blend of transport, business, and data access logic that I was used to.
So What Changed?
It was just one line in a large application, a needle in a haystack. I don’t know who wrote it. Maybe they just copied the idea from an answer in Stack Overflow. Maybe they stumbled upon it in another codebase.
But someone somewhere put effort into this design, and it turned me from a developer into a craftsman.
It wasn’t just the way I coded that changed. I decided to leave the startup scene and work for a company with a strong engineering culture. One in which you get claps for making a good API, not for shipping a burning pile of code on a tight deadline.
All those decisions and considerations, all those thoughts put into the design. In the end they amount to little more than a line of code here and there that you can leave unnoticed.
But they’re still there and they do make everything better.
In my home country, they say that you don’t learn a craft - you steal it. You watch what better people do and you mimic their work until you develop a taste of your own. This is what I did after I saw that line.