Thoughts on "The Worst Kind of Programmer"
Here are my takeaways after reading the original article, The Worst Kind of Programmer.
The author clearly had similar firsthand experiences, so his personal bias comes through quite strongly. That said, I think there are many points worth discussing and learning from, so I’m jotting down my thoughts here.
In the article, the author mentions a frontend lead from a past project who enthusiastically designed the project’s architecture using Angular, Nx, and Rx. Meanwhile, the backend tech lead kept piling various libraries on top of Spring Boot—essentially reaching for whatever technologies were cool and trendy.
As the project’s requirements grew, this frontend lead kept tweaking the architecture, attempting to decouple business logic from the technical core, and only assigned simpler tasks to junior developers, such as writing API documentation and unit tests.
Eventually, the frontend lead resigned. The team found themselves unable to maintain the overly complex codebase and had to bring in an expert to put out fires and sustain development output. Still, the sheer complexity of the architecture continued to bottleneck velocity. In the end, whether refactoring or rewriting from scratch, the cost was staggering.
What Went Wrong?
From my perspective, this is actually the kind of mistake made by engineers who lack experience. (A lot like my past self—forgive me, I repent 🙏.)
In the scenario above, the frontend lead worked hard and perhaps managed to add an impressive highlight to his resume before dusting off his hands and moving on. In reality, however, he crippled the entire team’s development velocity.
This is why I’ve always believed that over-engineering right from the start is the root of all evil. It’s not that you should never use new frameworks; rather, hastily adopting a new framework or library after reading just a few blog posts might seem harmless at first, but its long-term impact on the project can be devastating.
Great engineering should always pursue simple, just-enough solutions. An analogy I really like is the evolution of the piano’s striking mechanism (action). The best explanation I’ve seen is in this video by Mark Rober—the animation makes it remarkably easy to understand.
Why does a piano’s action look so complex? Why can’t you just strike the string directly with something? How do you ensure the note sustains while holding the key down and only dampens when released?
These mechanisms all evolved step by step from simple questions into what they are today, rather than being solved all at once at the very beginning. Once you understand the “why,” you can’t help but marvel at how perfectly balanced the design is. The same applies to software development: instead of throwing every framework into the mix from day one, you should iterate toward the optimal solution based on the concrete problems in front of you.
There are a few points toward the end of the article that I don’t entirely agree with. For example, he mentions things like the ability to solve abstract problems, working long hours, and passion for software development—I think these are actually great qualities. Of course, working long hours naturally shifts across different life stages when you want to redirect your energy toward other priorities.
Another metric that often gets overlooked is whether the code is “easy to modify and delete.”
When I touch a piece of code, can I confidently delete a section without setting off a domino effect? Is the architecture designed so that an implementation can be easily swapped out? Furthermore, when someone else needs to make changes, can they quickly grasp the intent and modify it in the same pattern? From this perspective, I really like the adapter pattern: once the interface is nailed down, you can implement the underlying logic however you see fit.
Some people are excessively strict during code reviews, often criticizing based on personal preference and taste rather than focusing on the overall functional design or offering suggestions to improve readability.
Not to mention nitpicking over formatting. If you find that most arguments in your team revolve around style and formatting, it’s high time to review whether your ESLint or Prettier configurations are set up properly.
Communication
I believe that before making any major technical decisions within a team, there should at least be an open discussion first.
Not everyone has to agree, but there’s no need to treat the rest of the team like idiots or assume your solution is the only brilliant one. Under normal circumstances, everyone wants to make the product better and the development workflow smoother.
There are two things to keep in mind here:
- Sometimes team members instinctively push back against new proposals simply because they are comfortable with the current way of doing things. In such cases, provide the context and explain why you believe the new approach is superior.
- As a more senior member of the team, when you see a new proposal, offer more historical context and background info for consideration.
Jeff Bezos mentioned this on Lex Fridman’s podcast—disagree and commit.
I absolutely love this philosophy.
Disagree, but commit fully. To prevent endless debates where everyone keeps throwing opinions around without resolution, once a decision is made, you back it with full commitment even if you disagreed. At least the project keeps moving forward instead of spinning its wheels. That’s a great mindset.
Especially when the team is made up of smart people, points of disagreement should usually only be a small fraction. (Assuming, of course, that you have a stellar team.)
Disagree and commit is a really important principle that saves a lot of arguing. There will be disagreements in any endeavor in life where you have teammates. In society, and inside companies, we have a bunch of mechanisms we use to resolve disputes. And a lot of them are really bad. An example of a really bad way of coming to an agreement is compromise.
Here, Bezos points out that the worst way to resolve a dispute is compromise—the result of splitting the difference is usually a stitched-together Frankenstein monster.
This resonates with me deeply. Sometimes, when you don’t have enough authority or haven’t established your track record yet, you are indeed forced to accept compromises. It also got me thinking about how much of software development operates in a mode where requirements are handed down, evaluated, and then implemented by the dev team—rarely is the dev team actively involved in the ideation process itself.
This leads to a situation where engineers have solid technical skills, yet struggle to build a viable product on their own, or end up building something users don’t actually want. That’s one of the challenges I’ve been grappling with recently. How do you all approach this?
Related Posts
- How to Prepare for Software Engineering Interviews Preparing for tech interviews has always been challenging. One of the most frustrating parts is the heavily one-sided power dynamic. As a candidate, it's hard to gauge their actual standards, and it's easy to spiral into self-doubt afterward. Let's talk about it.
- Words That Changed My Outlook on Life Feynman, Chaplin, and the movie Hyakumeter: from an insecure boy to someone capable of helping others, sharing the reflections and life philosophies that shaped me most.
- N Benefits of an Independent Website Why spend time running your own blog in an era dominated by short-form video and social media? Here are my thoughts after nearly a decade of blogging.
- Reflections on Fitness and Weight Training Sharing my thoughts and journey with weight training over the past period.