In a 2016 TED interview, Linus Torvalds was asked what separates a great programmer from a merely competent one. He didn't say "more knowledge." He didn't say "faster typing." He didn't say "more years of experience." He said "good taste."
The example he gave was deliberately small. He showed two versions of a linked-list removal function. The first version had eight or nine lines of code, including a conditional check for whether the item to be removed was the first item in the list — the "edge case" that everyone who's been taught linked lists learns to handle separately.
The second version had four lines. No special case. The function worked correctly on every element including the first one because the structure of the code — using a pointer to a pointer — made the first element no longer an edge case. The conditional disappeared. The bug surface disappeared with it.
Torvalds described the second version as having "good taste." The first version, he said, was written by someone who could be a perfectly capable programmer, who would produce correct code, who would get the job done. The second version was written by someone who understood the problem in a way that made the special case dissolve.
This article isn't about linked lists. It's about why the distinction Torvalds was naming — between competence and taste — is the difference between developers whose careers plateau and developers whose careers compound, between code that works and code that endures, between getting features shipped and building systems that don't have to be rebuilt every two years.

What Torvalds Actually Meant
The word "taste" is loose enough to be misread in several ways. Programmers hearing it for the first time often interpret it as:
- Aesthetic preference — choosing tabs vs spaces, preferring functional vs object-oriented style.
- Style guide compliance — code that follows the team's conventions, variable naming that matches the codebase.
- Cleanliness — short functions, few comments, minimal nesting.
- Cleverness — compressed expressions, functional one-liners, the smallest possible solution.
None of these is what Torvalds was naming. He was naming something specific and harder to articulate: the ability to see a problem clearly enough that the complications you initially thought were inherent turn out to be artifacts of how you were thinking about the problem.
The good-taste version of the linked-list code wasn't shorter because the programmer was good at code golf. It was shorter because the programmer understood that "the first element" wasn't actually a special case — it was only special if you thought about the list as nodes-with-prev/next-pointers. If you thought about it as positions-in-a-chain-of-pointers, the first element was the same as any other element. The special case existed in one mental model and didn't exist in the other.
The taste was in the mental model. The code was just the visible artifact.
Why this distinction matters operationally
The practical consequence of this distinction is consistent across every engineering domain. The programmer who handles the linked-list edge case explicitly will:
- Write more code to maintain
- Have more places where bugs can hide
- Take longer to debug when something does go wrong
- Be harder to evolve when requirements change
The programmer with the better mental model produces less code, fewer bug surfaces, faster debugging, and easier evolution. They're not faster because they type faster. They're faster because they don't have to do the work the other programmer creates.
Multiply this across thousands of decisions over a multi-year codebase, and the difference between the two programmers isn't 20% — it's an order of magnitude. The compounding is what makes taste so valuable and so misunderstood.
The Patterns That Distinguish Taste From Skill
Skill in software engineering is the ability to make something work. You can identify it through observable behaviors — the programmer can build the feature, debug the issue, integrate the API, structure the database. Skill is verifiable.
Taste is the ability to make something work in a way that doesn't create downstream problems. It's harder to identify because the absence of future problems is invisible. You can only recognize taste retrospectively, or by recognizing the patterns it produces in real time.
The patterns that consistently distinguish tasteful engineering from merely skilled engineering:
Recognizing when not to write code
A skilled engineer asked to add a feature builds the feature. A tasteful engineer asked to add a feature first asks whether the feature should be added — whether the problem the feature is supposed to solve actually exists, whether existing functionality already addresses it, whether the request is a symptom of a different underlying issue. The most efficient implementation of a feature is sometimes the decision not to build it.
Choosing the structure before the algorithm
The skilled engineer picks a data structure that can support the operations needed. The tasteful engineer picks the data structure that makes the operations needed turn out to be the natural operations the structure already supports. The Torvalds linked-list example is exactly this — by changing the conceptual structure, the edge case stops being special.
Recognizing duplication that isn't visible
The skilled engineer notices when the same code appears in two places and extracts it. The tasteful engineer notices when two pieces of code are doing the same conceptual work but look different — different variable names, different control flow, different parameters — and recognizes the underlying sameness. The skilled engineer reduces line-level duplication; the tasteful engineer reduces conceptual duplication.
Knowing what to make hard and what to make easy
A system has affordances — operations it makes easy and operations it makes hard. The skilled engineer makes the operations needed today easy. The tasteful engineer thinks about which operations should be easy permanently (the ones that should happen frequently and reliably) and which should be hard (the ones that are dangerous, irreversible, or rarely needed). The asymmetry of difficulty becomes a design tool.
Knowing when to use convention vs invention
The skilled engineer can implement custom solutions for unique problems. The tasteful engineer recognizes when an apparently unique problem is actually the standard pattern in disguise — when the right answer is the boring conventional solution rather than the clever custom one. Knowing when to be inventive and when to be conventional is itself an act of taste.

Why Skill Plateaus and Taste Compounds
There's an observable career pattern that the skill-versus-taste distinction explains. Some engineers become capable in their first five years and stay roughly at that capability level for the next two decades. Others become capable in their first five years and continue improving for the next two decades — they're noticeably better at year ten than at year five, and noticeably better at year twenty than at year ten.
The first group has been developing skill. The second has been developing taste.
The reason is mechanical. Skill plateaus because there are only so many programming techniques to learn, only so many language features to master, only so many algorithms to internalize. The body of explicit knowledge is finite. Once you've covered it, additional time doesn't add much.
Taste doesn't plateau because what it's measuring is judgment — judgment about which trade-offs to make, which patterns apply to which contexts, which abstractions hold up and which collapse, which simplifications are honest and which are illusions. Judgment improves with exposure to more problems, more contexts, more failures, more code reviews, more production incidents. There's no upper bound. Twenty years of exposure produces qualitatively different judgment from five years.
What this means for the career arc
If you're early in your career — first five years, maybe up to seven — the highest-leverage work is mostly skill building. Learn the languages, the frameworks, the patterns, the tools. Build things and make them work. The investment in raw capability pays back fast.
Somewhere around years five to seven, the returns on additional skill investment start diminishing. The next investment isn't another framework — it's exposure to enough variety of problems that you start developing the judgment that turns into taste. This is also the career stage where engineers often misdiagnose their next move. They assume they need to specialize deeper into the technical stack they know. The empirical pattern is the opposite — what they need is breadth of exposure to develop judgment, not depth into one more technology.
The exposure problem
The hard part is that taste develops from exposure to a particular kind of experience: working with people who already have taste, on problems where the consequences of bad decisions become visible.
If you're in an environment where code review is rubber-stamped, bad decisions get masked by infrastructure scale, senior engineers don't articulate why they make the choices they make, and production incidents are blamed on individuals rather than analyzed for systemic causes — then you can spend ten years there and develop very little taste despite getting a lot of experience.
If you're in an environment where code review involves real disagreement, architectural decisions are documented and revisited as their consequences emerge, production incidents produce careful blameless retrospectives, and engineers actively name the patterns they see across systems — then five years there produces substantially more taste than ten years in the first environment.
The variable that matters isn't time. It's whether the time is spent in feedback loops that produce judgment.

How Taste Actually Develops (Concrete Practices)
The good news is that taste isn't innate. It develops through specific recognizable practices. The bad news is that the practices are mostly slow, uncomfortable, and not easily replaced by a course or a certification.
Reading code written by people with more taste than you
Not reading articles about code. Reading actual production code by senior engineers, with attention to the choices that aren't immediately obvious. Why did they use this data structure? Why is this function separated from that one? Why is this code duplicated rather than extracted? Why is this seemingly simple thing in this seemingly complex way?
Each "why" question, when answered, is a unit of taste development. The cumulative effect over years is what creates the judgment.
The corollary: spend significant time in well-curated open-source codebases. Linux kernel for systems-level. SQLite for database design. Redis for high-performance data structures. React for frontend patterns. Stripe's public APIs for API design. Each has different taste signatures worth studying.
Writing code with people who will disagree with you
The single most undervalued professional environment for taste development is one where code review involves real disagreement. Not nitpicks. Disagreements where the reviewer would have made a different decision, where they articulate why, and where the writer either has to accept the change or articulate why their version is better.
The friction is the developmental signal. Environments without it produce skilled engineers who learned to ship features but never had their decisions challenged in ways that exposed the underlying mental models.
Maintaining code you wrote years ago
The single most powerful taste-development feedback loop is returning to code you wrote three years ago and seeing whether it survived. The bugs you didn't anticipate. The performance issues you didn't predict. The integration points that became friction. The abstractions that turned out not to hold.
Each instance is data about the difference between the model you had in your head when you wrote the code and the model that turned out to be true. That difference is exactly what taste corrects.
The implication: avoid jobs where you ship code and never see it again. Look for jobs where you'll be maintaining your own decisions for years. The maintenance is the education.
Reading post-incident retrospectives
Every interesting outage produces a story about how someone's mental model of a system was wrong. Public post-mortems from companies like Stripe, Cloudflare, GitHub, and others are dense with taste-development material. Each one describes a place where a competent decision turned out to be wrong because of some property of the system that wasn't apparent until it failed.
Reading these is uncomfortable because they're case studies in engineers who looked perfectly capable making decisions that turned out to be wrong. They're also the most concentrated form of taste-development material available, because each one is the consequence of a missing piece of judgment.
Sitting with bad code without immediately rewriting it
The instinct of skilled engineers encountering code they don't like is to rewrite it. The taste-developing practice is to sit with the bad code long enough to understand why it ended up that way. Sometimes the previous engineer was wrong. Often they were addressing constraints you don't see — performance, deployment, organizational, historical.
The corollary: judging old code is easy and rarely instructive. Understanding old code is hard and almost always instructive.

Where Taste Shows Up in Specific Decisions
Abstract claims about taste are unsatisfying. The patterns are more recognizable in specific decision categories where tasteful engineers consistently differ from merely capable ones:
API design
The skilled engineer designs an API that supports the operations the consumer needs. The tasteful engineer designs an API where the operations the consumer needs are easy and the operations the consumer shouldn't do are hard or impossible. The asymmetry of difficulty becomes a design tool.
Tasteful API design also recognizes that an API is a contract that has to be maintained essentially forever. Every parameter you add is a parameter you can't remove. Every method you expose is a method consumers will rely on. The discipline to make APIs small at the start so they can grow later is taste — the discipline to keep them large at the start is the lack of it.
Error handling
The skilled engineer handles errors that occur. The tasteful engineer thinks about which errors should propagate (because they indicate something the caller should know about), which should be retried automatically (because they're transient), which should crash loudly (because continuing would corrupt state), and which should fail silently (because they don't matter). The choice between these is taste, and getting it wrong has different consequences in each direction.
Database schema design
The skilled engineer designs a schema that stores the data needed and supports the queries needed today. The tasteful engineer designs a schema that will accommodate the queries that don't exist yet, that doesn't lock the application into choices that will be hard to reverse, that separates the data model from the access patterns in ways that allow each to evolve. The schema is the part that's hardest to change later; taste recognizes that and treats schema decisions with appropriate gravity.
Naming
The skilled engineer picks names that describe what something is. The tasteful engineer picks names that describe what something means in the domain — names that survive refactoring because they reference business reality rather than implementation. The function called fetchUser is implementation-coupled; the function called loadCurrentAuthenticatedActor describes a domain concept that will still be coherent after the implementation changes.
Naming is the cheapest decision and the most consequential one. Every later reader of the code experiences the names. Tasteful naming compounds over years.
Abstraction boundaries
The skilled engineer creates abstractions that hide implementation details. The tasteful engineer creates abstractions whose surface area matches conceptual boundaries that won't shift. The first kind of abstraction often leaks — the implementation details bleed through, the abstraction has to be revised when underlying mechanics change. The second kind of abstraction tends to hold up because it's tracking a real domain distinction, not an implementation accident.

The Honest Limits of Taste Talk
Three honest cautions about this entire conversation:
Taste is contextual, not universal
What counts as tasteful in one context is wrong in another. The taste appropriate for embedded systems differs from the taste appropriate for distributed systems. The taste appropriate for high-frequency trading code is different from web application code. The good-taste linked-list implementation Torvalds showed was specifically good in C, where pointer manipulation is the natural idiom. In a language without explicit pointers, the equivalent solution looks different.
Engineers who develop strong taste in one context and try to apply it universally produce work that's tasteful in their domain and tone-deaf in others. The deeper taste includes recognizing what context you're in.
Taste without skill is opinion
The patterns described here are taste added to skill, not taste instead of skill. An engineer who can talk about good API design but can't write a working API isn't tasteful — they're just opinionated. The skill is the foundation. The taste is what compounds on top of it.
The Torvalds version of "good taste matters more than skill" was made by someone with extraordinary skill. He wasn't dismissing skill — he was naming what differentiates among already-skilled engineers. That qualifier matters.
Taste is partly luck
The engineers who develop strong taste were lucky enough to be in environments that produced it. They had managers who reviewed code carefully. They worked on problems where bad decisions had visible consequences. They had peers who disagreed productively. None of these are universally available.
If you're early in your career and you're in an environment that isn't producing the feedback loops, the move isn't to feel inadequate. It's to actively seek out environments that will — open source contributions, side projects with reviewers who care, mentor relationships, deliberate study of well-regarded codebases. The luck is partly engineerable.

Where This Knowledge Stops Being Enough
Understanding the distinction between skill and taste, and what actually produces taste over time, is the conceptual entry point. The questions that come next are the ones that determine whether someone moves from "I see what this means" to "I'm in feedback loops that produce it":
- How do you choose an early-career environment that actually develops taste — recognizing the difference between teams that ship code and teams that build the judgment that ships better code over years, and identifying the signals during interviews that distinguish them?
- How do you participate in code review and architecture discussions in ways that develop your judgment rather than just demonstrate your current level — what questions to ask, what disagreements to engage, what to push back on and what to learn from?
- How do you build a personal practice that compounds over years — choosing which open-source codebases to study deeply, which retrospectives to dissect, which problems to attempt repeatedly to see your own improvement, and which mentors to seek out?
These are exactly the questions covered in Meritshot's Full Stack Development and Data Science programs, where the curriculum is designed around the principles in this article: real production codebases as study material, code review that produces real disagreement and discussion, projects that you maintain long enough to see the consequences of your decisions, and mentorship from practitioners who can articulate the judgment behind their choices. If you've reached the end of this article and the next question forming in your head is "so where do I actually find the feedback loops that produce taste" — that's the conversation Meritshot is built to continue.





