Rethinking best developer practices
Published 2/19/2024
SRP (Single Responsibility Principle)
The single responsibility principle (SRP) is a common way to check whether your function, library, etc. is doing more than it should. “It should do one thing, and one thing well”.
In general, this is a good principle to follow. A function like “saveUser” should not be responsible for also sending out emails. It’s a good feeling to be able to trust that the code is doing its job as expected.
But SRP should not be in the way of creating a user-friendly API. What you often find is that libraries are too focused on the first half of the phrase “doing only one thing”, and neglect the second half “doing it well”.
For example, if you create a routing library, and most users need to be able to accept JSON, don’t make them install additional libraries to do so. Pay attention to user integrations and developer experience, and pave the way for them. Otherwise, while your library is only doing one thing, it’s not doing it particularly well.
Use the best tool for the job
This is such a common thing to hear, it has to be true, right?
It depends. If you develop a feature that requires a new type of technical solution, instead of adding even more software to your stack, at least consider using the existing software you already have at your disposal to solve your problem.
You might get slight benefits with “the best tool”, but is that benefit worth it for the needs of your application? That’s what you have to figure out. Be it web-sockets vs. polling, queues vs. cron jobs, SQL vs. Redis, sessions vs. JWT, SCSS vs. CSS, etc.
Every new software you introduce comes with costs as well. Its basics, best practices, edge cases, and constraints have to be understood by the team. It has to be documented, extra knowledge has to be transferred to new employees, it has to be kept secure and up to date, it may require an additional build step, it makes local development harder/slower, it increases the global complexity, it may be difficult to add automated test to it, it may require more servers/memory/CPU, additional monitoring, it can introduce another source of failure, it might cause unexpected outages in the middle of the night, etc.
Try using less software instead.
DRY (Don't repeat yourself)
The right abstractions in the right places are great.
Without them, you constantly have to make decisions about small things and repeat yourself in many places.
But you don’t want to abstract too early, so what’s a good rule of thumb on knowing when to make that abstraction?
WUSALT > WET > DRY
There is a common term in software development called DRY (Don’t repeat yourself). This, however, is often the wrong approach.
Instead, go WET (Write everything twice).
I guess that’s also not 100% correct. If you are skilled in the language, framework and domain, then there are many things you may as well write DRY right away.
But WUSALT (Write unfamiliar stuff at least twice) is not as catchy an abbreviation.
Generally, DRY code can easily lead to premature abstractions. And once you need similar functionality, you realize that your abstraction has not considered all these additional use cases, and you have to rewrite it from scratch. Only that this time you first have to un-structure the old abstraction before you can restructure. Un-structuring is often a lot harder than structuring it.
By writing things at least twice, you get exposed to these additional use cases.
Best of all, maybe that “second time” will never come and you saved yourself a lot of time by not writing that abstraction.
These three sections are excerpted from my e-book Intent-Driven Development which will teach you how to simplify the day-to-day code you run into and the balance between over- and under-engineering. Get it over at https://michaelzanggl.com/intent.