No more middlewares, please
When it comes to programming, there is a trap on which every programmer fall: elegant code. I'm often surprised to see even experienced developers qualifying a code snippet as elegant or beautiful.
From my point of view, each time I found an API interface allowing me to create some elegant code, it ended up as a nightmare codebase, full of unmaintainable spaghetti code.
Most of those nice, elegant and cool APIs fallen in disgrace in developers minds:
- Method Chaining: I think it is the first reason why JQuery will finally died, if not yet done.
- POO: Not that object and classes are harmful but thinking everything in term of objects/classes is a non-sense. Can't remind the time I find out that a fully OOP application was easily maintainable.
- ORM/ODM: Even OOP guys find it harmful. I spent horrible moments using Mongoose. Would not recommend it to my worst enemy.
- Mixins: Everything is in the name. Mixing is the best way to get messy code.
My current statement is: if you find some code elegant, it has great chances to be the next bullshit you'll step in.
Here be middlewares
When it comes to debugging, it is just a nightmare. Your stack traces are unreadable. When you open a controller, you have to check what happens before it is invoked and what will be done next to fully understand its behavior.
You end up with lots of a god objects,
app for instance, that may or may not
contain: a query, some cookies, encoded or decoded body, that method or this
other one... It not only makes you mad when it comes to work on an Express
application but also makes the code reuse very difficult.
Indeed, to reuse a controller, you have to find out every middlewares it depends on and set them up in the Express application where you want to reuse it. Problem: There is great chances that the same middleware is already in use but with a different version. And it is not the same shitty property that is set on that shitty god object.
This is why I think middlewares are an anti-pattern. Your controller should contain the complete workflow that allows you to get a response from an HTTP request. Transforming the following usual code:
Into something way more expressive:
Since the controller is strongly tied to its dependencies, you could just copy paste it into your other projects and npm install the various modules it actually uses. Magic? No, simple, atomic, reliable code. Nothing elegant, no hype, just stupid code telling what it does.
One could argue that it introduces huge boilerplates. We are switching from a 24 lines controller to a 42 one. My advice is that the glue code that strongly tie the controller with its actual underlying logic can be considered as comments that ends up to be code.
The middleware based code, to be inclusive, should add comments telling where all that magic happens. But the fact is that commenting is a shitty way to help others to grasp your code. I personally use it only to explain something I cannot show with meaningful code. Most of the time, it's all about business constraints or legacy issues.
Also, nothing impeach you to group several stages of your workflow into a single pure function if you figure out that a particular step sequence is used in most controllers. Importing this function will always show the way for readers to find out their content.
Finally, this workflow approach is in my opinion way more adapted to HTTP. Indeed, what is an HTTP endpoint except a function that takes a request and returns a response? Why would we have to deal with something else than functions decomposing it into simple steps?
As a conclusion, I would say that good code is not smart or elegant. It is readable, reliable, naive in a word: simple. And you probably know how hard it is to do simple ;).