5 ms·
I wholeheartedly agree with "don't immediately jump on the modularize and abstract everything right away". I think that "modularization and abstraction is alwa
by slooonz 6y ago
I wholeheartedly agree with "don't immediately jump on the modularize and abstract everything right away".
I think that "modularization and abstraction is always and uniformly good" is one of the big lies of our profession. It’s easy to see how it’s attractive : programming is intellectual work, and displaying capacity of abstraction is rewarding. I was extremely enthusiastic about that stuff when I was young, too. Then I got to school to get a CS degree, and it only reinforced it.
Now that I have some years of experience, let me talk to you about my last job. It’s a web app like most of us (I think) are doing. Backend in node. Frontend in react. The client was extremely unhappy about the delays and cost of their current contractor (weeks and 4-digit invoices for simple features), they wanted us to in charge of the app.
As soon as I received the source code, I looked at the backend part. It was incredibly clean for the standards of my younger self and CS teachers. Each class in his own file. You had one routes/_index.ts file that just included routes/users/_index.ts for /users, routes/blog/_index.ts for /blog, and so on (recursively: you would have routes/blog/comments/_index.ts too). routes/*.ts would be just that, declaring routes. Code was cleanly separated and implemented in controllers (controllers/users/_index.ts, and so one). Of course the controller didn't directly used the ORM, there was intermediate DAO classes to do that.
Very clean. Also, changing the slightest things required to go through 5-6 files. May god save your soul if you wanted to change more complex stuff.
I discarded everything. Most of the code now lies in /app.ts, which contains all routes. Each route is directly implemented in this file (no separate controllers) and directly calls the ORM (no DAO), except one which does complicated stuff and has his own implementation file.
Loccount on my "ugly, not modular" backend, which, incidentally, has many more features (that the client wanted for months but the previous contractor couldn’t implement for a reasonable price/time). And ~1/3rd of those lines are just some CSS assets moved from the frontend to the backend because we needed them for the mailing list:
all SLOC=2284 (100.00%) LLOC=0 in 13 files
Loccount on the "very clean" backend of the previous contractor:
all SLOC=12507 (100.00%) LLOC=0 in 262 files
Now, don’t get me wrong. Abstraction and modularization are not uniformly and always bad. But they have to make sense. Don’t write and organize a 2k LOC project the same way you would write and organize a 100k LOC project — or you’ll end up with a 500% overhead in LOC that WILL translate to a 500% higher burden of maintenance.
I just wish school taught me that, or that my younger self could have been clever enough to see it by himself.
- asgard1024 6y agoI would question your assumption that "clean code" that you describe is really modularization and abstraction. (In particular, separating everything into small scattered pieces, which is IMHO a horrible Java habit that I have to endure now.) I mean, both modules and abstractions should have purpose. The purpose of modules is to "do one task well" so to speak. So if for a typical change you need to modify several of them, you're not modularizing it right. The purpose of abstraction is to provide another "language" which lets you forget certain technical details, while clarifying the bigger picture. Again, unless this language has been designed wrong, you shouldn't have to touch the abstraction. Addendum: Of course, there is also the classic https://gbracha.blogspot.com/2011/06/types-are-anti-modular.html https://gbracha.blogspot.com/2011/06/types-are-anti-modular.... (and we can consider types to be a form of abstraction), so to some extend these things go against one another.
- kqr 6y ago> Also, changing the slightest things required to go through 5-6 files. That is a sign it was incorrectly modularised. Good modularisation means high cohesion and low coupling. Having to make changes in multiple files means the opposite. Don't rack on modularisation (great concept!) when your only experiences are of bad implementations of it. (Which is not surprising, because most people do get it wrong.) Maybe the takeaway is "better not do it at all than do it incorrectly." More concretely, the code you describe seems to have suffered from the awful common implementation of the model-view-controller pattern, where module boundaries are based on technical implementation details (routes are their own module, pages their own, controllers their own, etc.) This looks "clean" when you are inexperienced, but it is contrary to all good modularisation. Module boundaries should be based on business domain concepts, not implementation details.
- gcpwnd 6y agoThat sounds like myriads of programmers have done it wrong for decades. Can you elaborate on this and maybe add a few sources?
- BurningFrog 6y ago