5 Lessons learned on a boring project
Some lessons I learned from staying longer on a project: chasing new frameworks and technologies isn’t the only way. Some practical takeaways!
Hello friend,
In this newsletter I want to share with you 5 lessons from a long-term project I worked on. It was the typical project I maintained for more than 6 years. With older coding patterns and practices, it's exactly the kind of project you could easily call boring.
I get excited every time I start a new project, but contributing to something over a longer period definitely has its charm. When switching projects so fast, you usually learn different technologies or at least adopt different patterns. But when you stay longer on a single project, there are other valuable lessons you learn.
I'll share a few of these with you, but before that, let me give you some context.
Tech Stack
This is a project started around 2015. The client had a first version of the app and in 2015 decided to rewrite the whole app using some modern libraries. What began as a monolith quickly became a NodeJS microservices architecture. We started deploying the app on an AWS EC2 with Docker Compose, and eventually we implemented CI/CD pipelines.
The initial app was written in jQuery I believe, but we were rewriting and improving the business model using Angular. Besides Angular, we integrated several different libraries, text editor components, UI component libraries and so on. I can't remember all of them right now, but we used plenty of external packages.
The purpose of the app
The B2B platform we were building was an interactive document editor designed for bulk document creation and distribution. The not-so-professional way to describe it is "Microsoft Word on steroids".
It was a web app deployed on AWS, with the ability to deploy it on-premise. They were designing these PDF documents in high detail, and this feature was especially attracting for customers. There were a few big companies that used the platform, and they needed custom features as well.
Lessons learned
I think working on such a complex app with some amazing teammates really helped me become the programmer I am today. Even though we didn't used the latest technologies all the time, I learned some valuable lessons that I want to share with you.
I know some of the principles might sound vague, since there can be many cases that are app specific. For each lesson, I've prepared a short list of takeaways and questions to ensure you're on the right path.
Let's get it started:
1. A demanding colleague can truly shape your career and your future
Initially, I didn't like having my code closely reviewed. It's uncomfortable to receive tens of comments on your pull request.
But this was a valuable lesson: questioning has become one of the most important skills I've acquired when it comes to writing quality code.
Having a picky reviewer made me question every little thing, every function I write, pattern I adopt or library I integrate.
I could have left, but even though it was uncomfortable, I chose to stay, and now I'm so glad I did.
🔴 Takeaway: it might be difficult, but be thankful for the opportunity to have your code closely reviewed - this doesn't happen often.
2. Knowing what the responsibility of your code is
There's a common principle that I often neglected. It's called The Single Responsibility Principle.
It's tempting to simply import one module into another or to add just another flag to your component. Especially if you work in a startup, the management wants things delivered fast. They might even encourage you to cut some corners here and there.
If it's not the component's responsibility to handle that, you should never add the extra feature.
Sooner rather than later you'll have to maintain, debug, or even add more features to that code. And guess what? It'll be very difficult, you'll patch the code even more, and all of a sudden the project becomes a really huge mess and a total headache.
You might end up with unfixable bugs, or rather bugs that once fixed, break something else in the application.
It doesn't look that bad initially, but it'll get worse and worse without you noticing it.
🔴 Takeaway: Include proper coding, refactoring and maybe even writing tests in the estimations. Don't try to impress everyone by delivering fast but writing poor-quality code.
3. Consider the team capacity when building the software architecture
This might sound weird. As a developer you might not have a chance to give your input on the team's capacity or the architecture.
But it's better to understand as soon as possible that some things simply cannot be properly done with a limited budget.
Especially nowadays, we have AI and can use it to generate code faster. That isn't production-ready code. Just because you could generate huge amounts of code doesn't mean the whole job is done.
To give you an example: since the client didn't have the budget I would have liked, instead of building a microservices infrastructure, which was the perfect scenario for the job, I built a monolith. It wasn't ideal, but it kind of worked.
🔴 Takeaway: it's better to be transparent right from the beginning about costs, implications and challenges. If the client doesn't agree, that might be a red flag, and you might want to reconsider your collaboration.
4. Isolate the mess
In an ideal world, all the apps are well structured, every little utility function is where it's supposed to be. All modules and functions have a purpose. Everything has unit tests, documentation and is regularly tested. Now, wake up! That was a dream.
Sometimes you might have to cut some corners. Saying no is not always an option. Also you might need to integrate some third-party solutions, and we all know how messy that can become.
What's the solution in this case? Isolate the mess, encapsulate that code and don't let it spread across the whole app.
This approach also works when you implement the frontend app, before the backend is ready. Simply create another layer between the frontend logic and the backend.
🔴 Takeaway: If you still need to do it, make sure you isolate and encapsulate the messy or sketchy code within well-defined boundaries, and don't let it get into every part of the app.
5. Keep the dependencies list low and up to date
This is difficult to achieve. I was fortunate enough to have a client that valued security. But even so, we were so busy and had so many microservices, different apps and modules to maintain that we couldn't keep everything up to date.
Initially, at the prototyping phase, we added various UI libraries. This might sound familiar: adding libraries for modals, popups, tooltips, and such things.
What ended up happening shortly after is that we had to spend so much time refactoring many files to remove those components and implement them on our own. There were compatibility issues, and it became so difficult to maintain. The design changed, so the library wasn't useful anymore.
🔴 Takeaway: Try to keep the right balance between third-party modules and implementing something on your own.
Let's get a bit more practical
The 5 lessons might sound interesting, but how can you apply them?
I wrote down a list of questions I try to answer every time I write code:
What's the main responsibility of the function/component/module?
Does this feature go under the scope of the function/component/module?
Can we easily maintain, fix bugs and add new features to the app if we adopt this pattern?
How long will it take to add an end-to-end new feature?
How can I isolate this library/module/script so that it doesn't pollute the rest of the app?
If in the future I need to change this logic, how big will the effort be?
How difficult is it to implement it from scratch?
Can I find open-source repositories I can get inspired by and implement a custom library instead of integrating a third-party one?
In conclusion
What was the longest project you worked on? Are there any colleagues you're grateful for who helped you level up your skills and influenced your career?
I'm so eager to read your stories. Share your story with me, and if it's interesting, it might end up in a future newsletter.
These are a few places where you can find me:
👉 I'm most active on X/Twitter!
👉 Checkout my LinkedIn account as well!
👉 Or if you prefer Instagram!
Thank you for reading this post and I hope it's been inspirational!
See you soon!
Great post as always! This is so important "make sure you isolate and encapsulate the messy or sketchy code within well-defined boundaries"