The Best Practices That Need a Horror Story
Hatched by Jaeyeol Lee
May 21, 2026
11 min read
4 views
86%
The dangerous comfort of advice
What if the biggest mistake in software is not writing bad code, but believing that good code can be reduced to a list of rules?
That sounds strange, because software culture is full of rules. Use this pattern. Avoid that anti pattern. Always do X. Never do Y. New developers quickly learn that there is a whole industry of advice essays, commandments, and best practices waiting to turn uncertainty into certainty. The problem is not that the advice is useless. The problem is that advice feels more universal than it really is.
Software is one of the least scientifically settled professions in modern work. Many habits survive not because they are proven in every context, but because they once solved a painful problem somewhere, for someone, under some constraints. The danger begins when we forget the pain that created the rule. Then the rule stops being a tool and becomes an identity.
That is the real tension underneath nearly every piece of engineering advice: Should we optimize for correctness of principle, or usefulness in context?
The answer is almost always context. But context is inconvenient, because it does not fit on a poster.
Every best practice is a fossil of a past disaster
If you do not understand a best practice, look for the horror story that inspired it.
That single habit changes how you read the entire field. Suddenly, advice is no longer a collection of sacred truths. It is a museum of scars. Singletons often reflect the pain of uncontrolled global state. Strict code review practices often reflect the cost of letting subtle bugs reach production. Defensive programming often comes from systems where failure was expensive, dangerous, or humiliating.
This is not just a useful mnemonic. It is a deeper lens on how technical culture works. A best practice is rarely the perfect solution. It is usually a response to a recurring failure mode. In other words, each rule carries an invisible subtitle: “In the following kinds of situations, this helped enough to become memorable.”
That means two things. First, a practice without its backstory is easy to misuse. Second, a practice with its backstory becomes adaptable. If you know the original horror story, you can ask whether your current situation contains the same danger.
Consider testing. A beginner may hear “write tests” as a universal commandment. But the real question is not whether tests are good in the abstract. It is what failure are they meant to prevent? Are you worried about regression in a critical business flow? Are you protecting a library interface used by many teams? Are you documenting intent for future maintainers? Once you name the failure, the tool becomes legible. Maybe the right answer is unit tests, integration tests, property based tests, or perhaps better observability and a smaller surface area.
The same applies to architecture advice. People say “separate concerns,” but concerns are not always separable in practice. They overlap, leak, and negotiate with reality. The purest form of an idea is often not the best form for an actual system. Most ideas need modification to integrate with other ideas, because software is not a monolith of theory. It is an ecosystem of tradeoffs.
A best practice is not a law of nature. It is a story about what went wrong often enough to become memorable.
That reframe protects you from two equally common mistakes: dismissing advice too quickly, and obeying it too literally.
The trap of becoming the Right Way Person
Once you learn a few principles, it is tempting to treat them like moral truths. This is where technical maturity can quietly degrade into dogmatism.
You meet the person who has found the answer. They believe their favorite language, framework, testing style, or architectural pattern is not merely preferable, but correct in some absolute sense. The problem is not only interpersonal. It is epistemic. The moment you make your identity the Right Way, you become less able to notice when reality disagrees.
This happens because software is full of local optimizations that look like universal truths from close up. A team that values speed may adopt a loose style that would be disastrous in a safety critical system. A team that values safety may develop ceremony that would be crushing in a small experimental product. Both can be right, within limits. Both can also become self parody if exported without translation.
The intellectual discipline here is not to believe less. It is to believe more carefully.
A useful mental model is to treat practices like tools in a workshop. A hammer is excellent for nails, terrible for screws, and absurd as a philosophy. The experienced craftsperson does not worship the hammer. They ask: what is the joint, what is the load, what is the material, what failure matters most?
Software advice should be approached the same way. Ask:
- What failure is this practice trying to avoid?
- What cost does it impose?
- What kind of team, codebase, or company makes it worthwhile?
- What would a smaller or modified version look like?
Those questions turn doctrine into design.
And there is a personal cost to dogma. It narrows learning. If you are always defending a position, you stop studying the world. New developers especially need permission to try things, revise their views, and later realize they would have done some things differently. That feeling is not a sign that you failed. It is a sign that you learned.
The healthiest engineers often have a quiet relationship with regret. Not shame, but revision.
The missing skill is not coding, it is translation
The most valuable software decisions often come from conversations that do not look technical at first.
Talk to support. Talk to sales. Talk to business domain experts. Talk to the people who feel the consequences of your code long before you do. This matters because code does not exist in isolation. Every line has a user, even when that user is another developer. Every bug has a downstream story, even when it never appears in a commit message.
This is where many engineers get trapped: they think the goal is to write code that is elegant according to internal technical standards. But the deeper goal is to write code that serves a larger system of people and constraints. The best design decision is not always the most elegant one. It is the one that best serves the people who depend on the code.
That is why asking “What’s best for the developer?” is powerful, but incomplete if it stays narrow. Best for which developer? The one writing the code today? The one debugging it at 2 a.m.? The teammate joining six months from now? The external user of your library? The support engineer explaining a failure to a customer? The answer shifts depending on the human being in view.
This is also where the idea of following the spirit of the issue becomes essential. A ticket or bug report describes the surface request, but often the real job is larger. If the issue says “fix the login error message,” the spirit may be “reduce confusion during authentication failures.” That broader interpretation might suggest logging improvements, better validation, or a clearer support flow. If you only satisfy the literal wording, you may technically finish the task while leaving the actual problem intact.
In that sense, software work is less like executing instructions and more like interpreting law. The text matters, but so does intent, precedent, and the practical outcome for real people.
The literal issue is what was written. The spirit of the issue is what the system actually needs.
That distinction explains why some developers are technically productive but organizationally ineffective. They close tickets while leaving confusion behind. They ship code while generating avoidable support load. They solve the stated problem and miss the human one.
The best engineers develop a translator’s instinct. They move between languages: technical constraints, user pain, business priorities, and maintenance cost. That translation skill often matters more than any single framework.
Learning software means learning in public
There is a quiet myth that experienced developers simply know more. In reality, they usually know better how to learn.
One of the most underrated forms of learning is noticing, after the fact, that you would have done something differently. Beginners often treat this as a failure of judgment. But reflection is how judgment becomes richer. If you can look back on your work and see a better path, you have not wasted time. You have created the conditions for the next improvement.
This is why note taking on big tasks, difficult issues, and eventful situations matters so much. Memory is not just fragile, it is biased. We remember the emotional peak, the final outcome, and the story we told ourselves afterward. Without notes, we tend to confuse narrative with evidence. With notes, we can reconstruct what happened, what assumptions we made, what tradeoffs were available, and where our understanding changed.
A practical note system does more than preserve facts. It preserves decision context.
That matters because software mistakes are often not simple errors. They are mismatches between what we thought was true and what was actually true. Notes help you see the evolution of a problem: what was known at the start, what became clear later, what constraints emerged, and which solutions were rejected for good reasons. Over time, this becomes a personal database of failed hypotheses and useful patterns.
Think of it like building your own internal changelog. Not just of code, but of judgment.
This also helps explain why career growth in software is often accelerated by variety. If you only ever do one kind of programming, you may become highly efficient inside one narrow environment, but your mental models remain local. If you try different types of programming earlier in your career, you see which ideas survive translation and which ones only work under special conditions. Frontend, backend, scripting, systems, data, infrastructure, internal tools, user facing products. Each one reveals a different set of tradeoffs.
A person who has only seen one software environment may mistake its habits for universal law. A person who has seen several learns the more mature lesson: every environment is a negotiated compromise between competing goods.
A better model: practices as stories, not scripture
The deepest connection between all these ideas is this: software wisdom is not primarily a set of commands. It is a repertoire of stories about risk, tradeoff, and context.
That gives us a more useful framework for judgment.
1. Name the horror story
Before adopting a practice, ask what failure it prevents. If you cannot name the failure, you probably do not understand the practice well enough to use it responsibly.
2. Locate the beneficiaries
Ask who gains from this practice. The individual developer? The team? Future maintainers? Users? Support? Business stakeholders? Good design often means balancing those beneficiaries instead of pretending they all want the same thing.
3. Test the spirit, not just the letter
When solving a task, ask what broader outcome the issue or request is really trying to achieve. Sometimes the literal fix is enough. Often it is not.
4. Allow practices to mutate
Most ideas need modification to integrate well with other ideas. Pure forms are rarely deployable. Better to adapt a good idea than to defend an ideal one that cannot survive contact with reality.
5. Keep a record of your changing mind
Notes on hard problems, surprising failures, and eventful situations are not bureaucracy. They are training data for your future judgment.
This model has a subtle advantage: it keeps humility and agency together. You do not need to reject best practices. You only need to stop treating them as if they were timeless laws detached from their origin story.
The result is a style of engineering that is both more skeptical and more humane. Skeptical, because it asks for causes and costs. Humane, because it recognizes that code is built for and by people who live with consequences.
Key Takeaways
- Always ask for the horror story behind the rule. If you understand the failure that created a practice, you can adapt it intelligently instead of copying it blindly.
- Replace “What is the right way?” with “What problem are we preventing?” This shifts you from ideology to diagnosis.
- Interpret issues by their spirit, not just their wording. The literal request is rarely the whole job.
- Talk to people outside engineering. Support, sales, domain experts, and users reveal the real shape of the system’s pain.
- Keep notes on hard problems and changing judgments. Your future decisions improve when you preserve the context of your past ones.
The real mark of maturity
The goal is not to become the person who knows the most rules. It is to become the person who can tell when a rule applies, when it needs modification, and when it is solving the wrong problem entirely.
That is a far more difficult kind of expertise, because it requires resisting the comfort of certainty. But it is also the only kind that scales across teams, systems, and careers. The best engineers are not those who can recite the commandments. They are the ones who can hear the old horror story inside the commandment, then decide wisely whether that horror exists here.
In the end, software maturity is less about accumulating best practices than about learning to read the hidden past inside them. Once you can do that, advice stops being a cage. It becomes a conversation with experience itself.
Sources
Hatch New Ideas with Glasp AI 🐣
Glasp AI allows you to hatch new ideas based on your curated content. Let's curate and create with Glasp AI :)
Start Hatching 🐣