The Sweet Spot Between Too Much and Too Little
How Senior engineers balance over-engineering and under-engineering
👋 Hi, this is Akash with this week’s newsletter. I write about leadership in software engineering. Thank you for your readership.
Knowing when to stop optimizing separates senior engineers from the rest. This week, I’m sharing practical lessons I learned by making mistakes. They will help you grow beyond Senior. Hope you enjoy this edition!
When designing a system, do you worry about how long it will stay relevant?
Are you spending weeks optimizing for future scale?
I used to get attached to the lifetime of systems I designed to measure my software engineering quality.
As I tied my success to “no bugs” and “supports insane scale”, I spent endless hours optimizing. The immediate consequence became longer development time. For seemingly simple components, I’d spend weeks on design.
It’s important to consider future issues when designing a system. You don’t want to redesign from scratch every year. But, finding the balance separated me from most senior engineers around me.
After making countless mistakes, I share what I have learned to decide when to stop. You can apply this to your projects. Using these tips, you can grow as a senior engineer.
⭐ Main Takeaways
How to avoid building software for entirely imaginary scenarios
Knowing when to spend more time on optimization
Being aware of premature optimization in code or design reviews
🤯 Learnings from Over-Engineering
In 2020, I was working on securing Chrome builds. The problem was exciting and applied to many other Google products. At my level, having an impact outside my organization was beneficial. I started speaking with several teams to understand their problems.
I was trying to solve this issue across the company. What I didn’t anticipate was that this,
The solution needs to work across environments
Made the problem unnecessarily complex and difficult
Invited opinions from a developer group of >5000 engineers
The intention behind this was efficiency. Solving a common problem together is excellent. But I was spending too much time on flexibility. I’d spend time,
Optimizing our systems for latency beyond Chrome’s requirements
Abstracting Chrome concepts from the core to make the framework flexible
Developing something that is completely outside what we needed for our use case
All this time, my goal was to deliver it for Chrome. A design document would take more than a quarter to review. After chatting with leadership teams and observing the slow progress, we decided to focus on the immediate problem. We had flexibility in the background, but we decided to prioritize Chrome.
My situation wasn’t unique. As I’ve mentored others over the years, many struggle with this. You can avoid optimizing your systems prematurely by,
Separating “wants” from “needs”. When you write your design, clearly separate “must” and “good to have” requirements.
Optimizing the right things. Start by evaluating your systems objectively. I have made the mistake of guessing areas to improve. If you focus on optimizing 20% of your code that contributes to 80% of performance, your efforts will be worth it.
Keep it simple. Elegant solutions are simple. Keeping this in mind will help you pass on over-engineering.
🩹 Learnings from Under-Engineering
Do you feel the speed and quality of engineering work against each other?
Many times, we find ourselves against unrealistic deadlines. We compromise on the solution to get something out the door. I was in a similar situation in 2022. My goal was to design a system for physical machines, and I did just that. However, while the remaining 60% of the fleet was in the cloud, my solution wouldn’t work.
After a couple of quarters, the assumption that “we need a solution only for physical machines” wasn’t true. When I returned to the board, I realized we needed to start from scratch. For context, the scale changed from 10K to 100K (QPS).
Scalability and future-proofing your designs are essential. Otherwise, we will find ourselves working on the same problem for longer. In this case, I ignored an immediate future need that cost me two quarters. It wasn’t the only time. I’ve made this mistake many times, but you don’t have to,
Navigate “low-hanging fruits” carefully. Quick wins are attractive and sometimes helpful. But, focusing on them is a sign of under-engineering.
Design, get feedback, and develop. Don’t skip to implementation. Sometimes, reviews take longer, which might make us avoid them. Don’t compromise quality for speed.
Anticipate the next version of requirements. Focusing on the immediate need is critical, but also think about the next version. It will help you design systems with scalability in mind.
⚖️ Balancing the Scale When Working With Others
The problem of overengineering doesn’t apply to our work. It also affects how we work with others. We need to be careful when reviewing others' code and design.
Those endless threads on unimportant things on a pull request or design review aren’t helping anybody.
Neither of these approaches is the right one. As a senior engineer, I always used to nitpick, thinking it was my responsibility as a mentor. I’d look for potential future problems. That wasn’t the problem. The problem was going a bit too far.
I learned to,
Evaluate the value of feedback. Before sharing my opinions, writing down the “why” made a huge difference.
“Does this design support use case X? It’s going to be important soon”
“Caching at the request level is going to be crucial; we have a tight budget on latency”
“Do you think we should abstract the implementation details? Module X is where we tend to put all utility methods”
Make proposals actionable. Including the “how” when sharing ideas makes it easy for others to evaluate.
“Did we consider race condition? Checkout module X which provides utilities you can use”
“Nit: Can you add a brief description for this method? Checkout link A for the style guide”
“Maybe we can break this down further? What do you think about A and B?”
Context matters. When working with other teams, checking their goals and priorities is important. Optimization isn’t going to help during a production outage.
🌟 🔍 Parting Thoughts
Every engineer needs help balancing over-optimization and under-consideration. There’s no right way to do it, but it is important to understand the trade-offs when making these choices. We covered two scenarios out of my countless mistakes. The trick is to understand the context and ask the right questions.
You can apply them at work to find the sweet spot. A good balance will help you grow much faster in your career.
How do you avoid overdoing it or cutting corners? Share them in the comments!
🐦🔥 This Week’s Favorites
Secrets behind newsletter success from
byHow to build high-performing teams from
byScale to 2.5B users with MySQL from
byIgnoring security alerts (I know, right?) from
by
👋 💬 Get In Touch
Want to chat? Find me on LinkedIn.
If you want me to cover a particular area of leadership, you can reach out directly to akash@chromium.org.
If you enjoyed this content, please 🔁 share it with friends and consider 🔔 subscribing if you haven’t already. Your 💙 response really motivates me to keep going.
Explain in excellent way
Nice article! Something similar happened to me in the last few years.
In my case, I also struggled with stakeholders' expectations. Trying to set clear boundaries to what were the expectations for the solution helped me to find a balance of what I had to do in some situations. But, it is not as easy as it sounds.
Thanks for the article!