Principles and why they’re so important

Marek Hanzal
6 min readNov 23, 2023

--

You may find this less important, or just “do not bother me with this”, but it really pays off, when you stick with some concepts and principles. And it’s not that hard.

Photo by Nasser Eledroos on Unsplash

Intro

I’m sorry, but this article is reaaaa…aaa…aaaallyy long. Prepare for that — it has sections, so you can read them part by part.

Don’t bother me with the rules

Next is quite a long talk, but I want to put it in the light of practical example, because theory is boring and you would not read it. Probably.

Yes, rules aren’t probably most beloved things around, but in programming, they play quite a big role — let’s pick some piece of code as an example:

What happened now are (probably) number of processes in your head:

  • what the fuck is the formatting…
  • …because now you’re running tsc in your head…
  • …trying to understand what you see

This takes quite a bunch of your mental energy during the day. Another example:

This is exactly the same piece of code, so:

  • what the fuck is the formatting (again)…
  • …running tsc (again), but now with prettier…
  • …trying to update your internal AST to understand the thing

But this article is not about formatting. It’s about rules, principles.

And NOW imagine those two images are from the same repository. You probably know, where I’m walking now. You see that? If there is a rule (in this case for formatting), you can offload a lot of mental effort.

It doesn’t matter, if a brace is here or there, but what’s important, it must be all the times on the same place. Because during a day you would see a lot of code which you must parse and that costs a lot of your energy.

Now you know the basic reasoning I’ve, so let’s deep dive, next are a few principles I like or I would like to comment.

Single Responsibility Principle

This one is first and probably most important one. Let’s get some another example:

  • I’ve a repository (for database abstraction, CRUD stuff, queries and so on)
  • Basic features: map DTO to internal queries, do mutations (CxUD), provide counts (SELECT COUNT(*) …)

When you implement all the stuff, it looks like everything is SRPious, but you’ll end up with quite a bunch of unrelated code:

  • Repository contains code which translates DTOs (so code for data fetching)
  • There is a code for create/update/delete (this trio is quite OK together)
  • You’ve also have code for counting

What you’ll get? Nothing SRPecial but a mess. Even the API from the outside is quite big. Enough complaints, what we can do about that?

Break down pieces, use composition (If you’re curious, this is a historical snapshot of that said repository).

Now all the responsibilities are clearly defined, so you are not messed up, when you want to use this tool.

I’ve provided an example code connected to a specific commit, so it won’t dissapear, but also it will get old by the time. It’s provided only to back my toughts and give you some insight, what SRP means in practice.

That’s all here, the repository example is expressive enough as the idea covers even much simpler situations.

Photo by Todd Quackenbush on Unsplash

(Random image of a tree to reset your attention)

Dependency Injection

This may be a bit controversal. I’m still on the wave of Node.js, no Java or PHP or whatever. So, really I’m talking about DI? Yes, get over it.

Node.js backend (including Next.jsyou know, it’s still Node.js minus Edge stuff) deserves DI too. If you wonder why, read SRP section again.

Examples are cool, se here we go:

I like the repository example, so imagine Repository implementation

  • It has dependency on a connection (because you don’t want to export const connection = … and then directly import it into “some” file)
  • You want to refer to a connection by an identifier instead of using direct name (so you can exchange it for something else — cha! Hello Liskov!)
  • The same is for the repository itself, but unlikely to happen (unless you like to write tests)
  • Now let’s say we’ve a service using said repository — again, we’re not referencing it directly by a file import (you really want to do new Repository(new Connection())…? You can use repository identifier from a container to inject it into a service

“But I can write small functions, blablabla”

Yes, you can. Have you ever tried that without any heavy P.I.T.A? Because there is another principle you would break — tight coupling of functions (meaning any kind of executed code).

That’s the thing you really don’t want, because for example, when you’ve a package Foo and Bar , you have to create hard dependency between them instead of just saying to a container “bro, I wanna service “Bar”, doesn’t matter where you’ll get it” (soft dependency, because there is FooBar connecting these two).

There is a bit of overhead using DI container, sometimes it’s hard to find a good quality one, also you need to think in a bit different way, but you can still functions or create serivces like “big brothers have”.

Try it. It’s simpler than you think and it may give you surprisingly cool results, making you more happy with the code. Or hate me if you want.

Photo by Kalen Emsley on Unsplash

(More trees. And mountains; do I still have your attention?)

Keep It Stupid Simple

KISS, nice word. Until here I was talking about principles you should use as I think they can help simplify your codebase.

But this one, this is different story. It’s at the end, because after SRP and DI, you’ll end up with the stuff, which may be cleaner, more separated, but it also may be complicated than at the beginning (but less then without them).

For DI, you have to setup a container. You have to define identifiers for your services/functions. When you separate things, there are a lot of files. It has a cost (sorry, no rainbows or unicorns). So we cannot talk about “KISS” as it’s more like “somehow KISS”. It IS simpler, but more complicated.

The take from here is: take the rules, use them, but don’t be hardcore with them as it may hurt your work (or your colleagues may hurt you). As you can see, if you want to take everything literally, some of the principles goes in opposition to each other (like KISS here).

At the end of the day, your clear mind and fresh head is the best tool to use, so you can finally choose, what to use — or how hard to apply different approaches.

If you go through my codebase, you’ll find a lot of places which could break the rules, but overall design stays same. Sometimes it’s much harder to keep the rules on the track than make a workaround.

The Others

This is not a comprehensive guide over SOLID. Nope, because that’s really theoretical material and probably “nobody” can explain them in the real world. Or simple doesn’t care. I’m not telling it’s not important, but I’m just skipping them as those important are already mentioned above.

Photo by Matt Duncan on Unsplash

(Now it’s up to you, which path you’ll take — do you see choices on the picture? — you know I’m joking)

Epilogue

…just because I don’t want to end every story with “Conclusion

So are they principles and rules important? You’ve some examples here, so now you’re probably thinking about it. Choose responsibly and teach the others. Responsibly. It’s better to have a material to create an opinion than hardcore fans of some opinion.

Now it’s time for you to open your favourite vim… IDE and try all that stuff yourself!

--

--

Marek Hanzal
Marek Hanzal

Written by Marek Hanzal

I love programming and getting new knowledge. I'm fullstack web-dev, quite a crazy man with a lot of things to say.