Skip to main content

The Backlog Is Not a Dumping Ground: Managing the Backlog of a Large Software Product

A well-managed backlog is the single most leveraged artifact in product development. When it works, teams ship the right things at a sustainable pace. When it doesn’t, the organization drowns in a swamp of stale tickets, conflicting priorities, and interminable planning meetings. For large software products, where dozens of teams feed from the same corpus of work, the cost of poor backlog hygiene is enormous and mostly invisible.

The Backlog at Scale Is a Different Animal
#

On a small team, the backlog is a conversation. The product owner and a handful of engineers look at a list, discuss what matters most, and pick up work. At scale, the backlog becomes an information system. It mediates between strategy and execution, between stakeholders who want things and teams who build things, and between the present state of the product and its future state.

The Scrum Guide defines the product backlog as “an emergent, ordered list of what is needed to improve the product” and notes that it is the single source of work for the team. That definition is clean and useful, but in practice, large organizations layer in program backlogs, initiative backlogs, discovery backlogs, and technical debt backlogs. The first challenge is deciding what structure you need and resisting the urge to create a new list every time someone feels their priorities aren’t getting enough visibility.

Marty Cagan, “Inspired” argues that the strongest product teams maintain a clear distinction between product discovery (figuring out what to build) and product delivery (building it), and that conflating the two is a root cause of bloated backlogs. Items land in the backlog before anyone has validated that they are worth building. The backlog becomes a wish list rather than a commitment queue.

Four Principles That Change Everything
#

Most backlog dysfunction traces back to violations of one of four principles.

1. The Backlog Is Ordered, Not Merely Prioritized
#

“Prioritized” suggests labels like “high,” “medium,” and “low.” Those labels are nearly useless because everything ends up “high.” Ordered means the backlog is a ranked list: item 1 is more important than item 2, which is more important than item 3. A strict ordering is harder to produce, and that difficulty is the point. Forcing a strict ordering surfaces the trade-offs that stakeholders would otherwise avoid.

Woody Zuill’s approach of “pulling” work rather than “pushing” it is relevant here. When the backlog is strictly ordered, teams pull from the top. No cherry-picking, no lobbying for the pet feature. The rank order is the contract.

At scale, this principle applies at every level. Initiatives within a program are ordered. Epics within an initiative are ordered. Stories within a sprint are ordered. If you cannot say which of two items matters more, you are not ready to put both in the backlog.

2. Only Refined Items Belong in the Delivery Backlog
#

Jeff Patton’s user story mapping technique provides a framework for separating discovery from delivery. The “backbone” of user activities and the stories beneath them form a map of the product’s possible future. Only stories that have been discussed, estimated, and accepted by the team belong in the sprint-level delivery backlog. Everything else lives in a discovery or discovery-adjacent artifact.

Separating discovery from delivery is a critical structural choice. Many organizations dump every idea, bug report, customer request, and technical improvement into the same GitHub project. Within months, that project contains thousands of items in no particular order. The team treats it as a write-only data structure.

A practical pattern: maintain two lists. The product backlog contains everything the team might ever work on, loosely grouped by theme. The sprint backlog (or “ready” queue) contains only items that meet a definition of ready: they have acceptance criteria, they are small enough to complete in a single sprint, and the team has discussed them. Nothing moves from the product backlog to the sprint backlog without passing through a refinement session.

The Scrum Guide calls this ongoing activity “backlog refinement,” and regular sessions where the team reviews the top portion of the backlog, splits large items, and ensures alignment with the product goal are essential. The key discipline is not the ceremony itself but the agreement that unrefined items will not be scheduled.

3. Prioritization Frameworks Are a Means, Not an End
#

Several frameworks exist to help teams rank backlog items:

Framework Mechanism Best suited for
RICE (Reach, Impact, Confidence, Effort) Numerical score combining reach, impact, confidence, and effort Product teams comparing features across different domains
WSJF (Weighted Shortest Job First) Cost of delay divided by job size Organizations using SAFe or managing program-level backlogs
Opportunity Scoring Measures importance and satisfaction for each outcome Discovery-phase prioritization when outcomes are unclear
ICE (Impact, Confidence, Ease) Lightweight scoring for rapid triage Fast-moving teams that need quick decisions

These frameworks are useful because they make the prioritization criteria explicit. They are dangerous when teams treat the resulting score as an oracle. A RICE score is only as good as the estimates that feed it, and those estimates are often wrong.

The right approach is to pick one framework that matches your organization’s needs, use it consistently, and revisit the scoring regularly. The conversation that happens when two stakeholders disagree about a score is where the real value lives. The number itself is a forcing function, not a decision.

4. Say No Early and Often
#

The most important word in backlog management is “no.” Every item in the backlog carries a cognitive tax. Engineers scroll past it in planning. Product managers feel obligated to explain why it hasn’t been done. Stakeholders check on it periodically. The larger the backlog, the more time the team spends managing the backlog instead of working from it.

Derek Sivers’ “hell yeah or no” heuristic applies here. If an item does not clearly advance the product’s current goals, it should be declined, archived, or moved to a separate “someday” list that nobody is expected to maintain. A product backlog with 30 well-ordered items is more useful than one with 300 loosely grouped items.

At scale, this principle requires organizational courage. Every stakeholder believes their request is important. The product manager’s job is to say no to the things that are less important than the current top priority, even when that is uncomfortable. Cagan frames this as the difference between product teams (who are empowered to solve problems) and feature teams (who are handed a list to implement). Empowered teams can say no because they understand the problem they are solving and can judge whether a given request moves the needle.

Structural Patterns for Large Products
#

When a product involves multiple teams, shared infrastructure, and cross-cutting concerns, the backlog structure needs to accommodate complexity without collapsing under it.

The Tiered Backlog
#

Large products benefit from a tiered backlog structure:

  1. Strategic tier: Outcomes, OKRs, or product goals for the quarter. Owned by leadership and product management. Updated quarterly.
  2. Initiative tier: Named efforts that advance a strategic outcome. Owned by product managers. Updated monthly.
  3. Delivery tier: Epics and stories that decompose an initiative. Owned by individual teams. Updated continuously.

Each tier feeds the one below it. The strategic tier determines which initiatives enter the initiative tier. The initiative tier determines which epics and stories appear in the delivery tier. Information flows up through demos, retrospectives, and metrics.

The critical rule: no item in a lower tier can exist without a parent in the tier above it. Orphaned work is the primary source of backlog bloat. If someone wants to add a story that doesn’t map to an active initiative, the answer is either to create an initiative (which triggers the prioritization process) or to decline the story.

The Obeya Room Pattern
#

Borrowed from lean manufacturing and popularized by Toyota, the Obeya (“big room”) is a physical or virtual space where cross-functional representatives meet regularly to review the state of the product. The backlog is visualized on the wall (or in a shared tool), and the group discusses priorities, blockers, and dependencies in real time.

For large products, the Obeya pattern addresses a problem that no tool solves: alignment. When eight teams are pulling from the same backlog, local optimization is the default. Each team optimizes for its own velocity and its own priorities. The Obeya creates a forum where global optimization can happen.

The Regular Grooming Rhythm
#

A weekly or biweekly refinement session where the product manager and the team review the top 10-15 items in the backlog is a widely recommended practice. The goal is not to estimate everything but to ensure that the next two to three sprints’ worth of work is well understood.

For large products, this rhythm needs to exist at every tier. Leadership reviews the strategic tier quarterly. Product managers review the initiative tier monthly. Teams refine the delivery tier weekly. The cadence prevents the backlog from becoming stale and ensures that the most important items are always the most visible.

Common Failure Modes
#

The infinite backlog. A backlog that never shrinks is not a backlog; it is a suggestion box. If the backlog has more than a few hundred items, most of them are irrelevant. Archive aggressively.

The stakeholder lobby. In large organizations, stakeholders learn to mark everything as “critical” or to escalate directly to engineering managers. The ordered backlog is the defense against the stakeholder lobby. If the item is not in the top of the ranked list, it does not get worked on, regardless of who asked for it.

The technical debt blind spot. Product backlogs tend to favor features because features have visible stakeholders. Technical debt has no natural advocate. The solution is to allocate a fixed percentage of capacity (often 20-30%) to technical improvement and to make that allocation explicit in the backlog.

The estimation charade. Spending hours estimating items that are months away from being worked on is waste. Estimate just enough to support prioritization, and re-estimate when the item moves into the delivery backlog. Ron Jeffries, “Story Points Revisited” argues, as one of the originators of story points, that estimation should serve planning, not become an end in itself.

Conflating bugs and features. A bug is a commitment to fix something that was promised. A feature is a new investment. Mixing bugs and features in the same backlog without distinguishing between them leads to either under-investment in new value (because bugs always feel urgent) or neglect of quality (because features always feel more strategic). Separate them, fund them differently, and track them separately.

What to Do Next
#

If your backlog is currently a mess, here is a sequence that works:

  1. Archive everything older than six months that has not been touched. If it mattered, someone would have advocated for it. You can always pull items out of the archive.
  2. Identify the current product goal. If you cannot state it in one sentence, you are not ready to prioritize the backlog.
  3. Map every remaining item to the goal. Items that don’t map go to a separate “someday” list.
  4. Force-rank the top 20 items. No ties. This exercise will surface every disagreement about priorities, which is exactly what you need.
  5. Refine the top 5-10 items until they meet your definition of ready. Only these items are eligible for the next sprint.
  6. Set a weekly refinement cadence and protect it. The backlog decays without maintenance.

A healthy backlog is small, ordered, and refined. It reflects a clear product goal and a shared understanding of what matters most. Maintaining the backlog is not glamorous work, but it is the work that makes everything else possible.


What I've built and what I need: May 2026

The past month has been about turning repetitive workflows into reusable skills, and the gaps that remain are mostly about making those skills smarter, not more numerous.

What I Have Been Working On
#

Built a full SDLC skill pipeline. I shipped a comprehensive software development lifecycle orchestrator in agents that chains over 20 sub-skills, from issue creation through learnings capture. It handles phase contracts, backtracking when upstream artifacts are incomplete, and fast paths for small work like bug fixes and config changes. The pipeline tracks artifact status via YAML frontmatter and stores everything under .sdlc/ with a consistent directory structure.

Made issue tracking actually useful. I have been using create-issue heavily over the past month to track gaps in the software I am building. It is not perfect, but it beats not tracking the work, and it captures more context than I would take the time to write by hand.

Automated PR descriptions. I use create-pr-description to generate PR descriptions based on code changes and intent. Writing those manually was slow and inconsistent; now the descriptions reflect what actually changed without the manual effort.

What I Currently Need
#

Battle test the SDLC pipeline. The SDLC skill is built but has not been stress-tested end to end on real feature work. I need to run it through enough real scenarios to surface the gaps between the design and practical use.

Scheduled issue-to-PR automation in openchamber. Openchamber can already create a worktree per directory and execute a prompt, but it does not run on a regular schedule. I need it to pick up new issues, execute the full pipeline, and open PRs without manual triggering.

Automated issue triaging in open source projects. I built a triage-issues skill but have not used it on my own repositories. The goal is to reduce the burden of going through issues to identify duplicates and decide whether they should be acted on.

Memory that agents manage automatically. Right now memory requires explicit reads and writes. I need agents to store, retrieve, and decay knowledge across sessions without me prompting them to do it.

Contextual Slack support. I need a way for users asking for help on Slack to receive contextually relevant information, and for the system to learn from human-to-human interactions and the answers people give each other. I started building slack-cached to cache and query Slack conversations.

Automatic context clearing between execution and review. Running implementation and review in the same context introduces bias. I need a mechanism, likely using forked subagents, to /clear between execution and review automatically so the reviewer starts fresh.

Accuracy pass on daily summaries. I have accumulated daily summaries that contain inaccuracies. I need something to go through them and correct what is wrong, rather than letting bad data compound over time.

Incremental PR description updates. When I update a PR after the description is written, I need create-pr-description to adjust minimally, appending or amending what changed, rather than regenerating the whole thing from scratch.

Skill usage tracking. I need to know how often each skill is invoked and when. Without that data, I cannot tell which skills are earning their keep and which are dead weight.

Replying to inline PR comments. gh does not support replying to inline review comments programmatically. Tools like gh-pr-review exist but feel awkward for what should be a straightforward operation. I need a clean way to post inline replies as part of the review and feedback skills. I started building ghx to address this gap.


Software Engineering Teams in the Age of AI: Smaller, Sharper, Intentionally Imperfect

LLM-powered coding assistants have changed what an individual engineer can produce in a day. The harder question is what this means for how teams should be organized, how they should work together, and which of their existing processes still earn their keep. My answer is counterintuitive: the teams that thrive will not be the ones that adopt AI fastest or eliminate the most process. They will be the ones that correctly distinguish between friction that wastes time and friction that prevents mistakes.

What Actually Changed
#

AI-assisted development compresses the time from idea to working code. An engineer with a capable LLM can prototype a feature in hours that used to take days. Boilerplate, tests, documentation scaffolding, and CRUD endpoints all move closer to free.

But the things that remain expensive have not changed at all. Deciding whether to build a feature, choosing the right abstraction, understanding the domain deeply, and aligning technical work with business goals are as hard as they ever were. In many ways the expensive parts are harder now, because the temptation to just generate and ship is stronger.

This creates a specific tension for teams. When individuals can produce more code, the bottleneck shifts from production to coordination and judgment. Team design has to account for this shift, not ignore it.

Team Size: Follow the Problem Boundary
#

There is a persistent urge to declare an ideal team size. Amazon popularized the “two-pizza team” heuristic. Agile methodology settled on 3 to 9. Various management frameworks have their own magic numbers.

AI does not provide a new magic number, but it does tilt the calculus toward smaller teams.

Here is why. Communication overhead scales quadratically with team size. A team of 4 has 6 communication channels. A team of 8 has 28. When each individual ships faster because of AI assistance, the team hits the coordination ceiling sooner. The marginal output of the fifth or sixth engineer starts getting eaten by the cost of keeping everyone aligned.

Smaller teams also benefit from clearer ownership. When three people own a service, there is no ambiguity about who is responsible for it. When ten people own a service, everyone assumes someone else is handling the monitoring, the tests, the deployment pipeline.

But smaller is not always better, and this is where the nuance matters.

A team that is too small for its domain will fragment its attention across too many concerns. Three engineers trying to own a payments system, a notification platform, and a data pipeline will do none of them well. They will produce code quickly with AI assistance, but they will produce the wrong code, in the wrong abstractions, because no one has the mental space to think deeply about any one domain.

The heuristic I would use is not a fixed number. It is the smallest team that can own a coherent domain end-to-end. In practice this often lands between 3 and 5 people, but the number should follow the problem boundary, not the other way around.

A team of 3 that owns a single well-bounded service is better than a team of 8 that owns six loosely related ones. But a team of 6 that owns a genuinely integrated platform is better than splitting that platform across two teams of 3 that now have to coordinate across a boundary that should not exist.

Friction: Some of It Is Structural
#

The instinct when a new efficiency tool arrives is to use it to remove every source of friction. AI makes code review faster, so why not automate it? AI can summarize meetings, so why not eliminate them? AI can write documentation, so why not stop requiring it?

This instinct is partially right. A lot of process friction is genuine waste. Waiting three days for a manager to approve a deployment that could be automated. Holding a 30-minute standup where eleven people say “yesterday I worked on tickets, today I will work on tickets.” Filing a Jira ticket for a one-line config change.

But some friction serves a purpose, and removing that friction silently degrades the team’s output quality over time.

Code review is the clearest example. Before AI, code review served multiple functions: catching bugs, enforcing style, sharing knowledge, and forcing the author to think about their code one more time before it shipped. AI can handle the style and formatting portion completely. It can catch obvious bugs. What AI cannot do is evaluate whether the code solves the right problem, whether the abstraction will survive the next feature request, or whether the approach is consistent with how the rest of the system works.

In fact, code review becomes more important with AI-generated code, not less. When a human writes every line, you can assume the author thought about each line at some level, even if imperfectly. When an LLM generates code, the author may not have read every line carefully. The reviewer can no longer rely on the author’s intent as a safety net. The reviewer has to verify both correctness and intent independently.

This is harder work than traditional code review. It means reviews should be slower, not faster. The process should have more friction, not less. What should change is what the friction is applied to: less time on style, more time on substance.

The same principle applies to other forms of deliberation.

Sprint planning, done well, is the moment when the team asks “are we working on the right things?” That is productive friction. Sprint planning, done poorly, is an hour of reading ticket descriptions aloud. That is waste.

Architecture discussions are productive friction when they prevent the team from building on a flawed foundation. Architecture discussions are waste when they become philosophical debates that never converge on a decision.

The discipline is in telling the difference. The test I use: does a given process force someone to think about something they would otherwise skip? If yes, keep the process, even if it feels slow. If no, automate the process or remove it.

Processes Worth Keeping
#

Beyond code review, a few processes become more valuable in an AI-accelerated environment.

Architecture decision records (ADRs). When code is cheap to produce, the cost of building on the wrong abstraction is disproportionately high. A one-page document that captures what was decided, why, and what alternatives were considered is worth more than the five minutes it takes to write. AI can draft these from a conversation, but the team still needs to have the conversation.

Incident retrospectives. Retrospectives are one of the few processes that compound knowledge over time. When a production incident occurs, the team that writes down what happened, why, and what the team will change gets progressively harder to break. The team that fixes the bug and moves on repeats the same class of mistake forever. AI can assist with drafting the timeline from logs and alerts, but the insight about what to change has to come from the people who were in the room.

Onboarding. Onboarding is paradoxically harder in AI-heavy teams. Historically, junior engineers built deep familiarity with a codebase by writing code in it, struggling with its conventions, and learning its quirks through repetition. When AI handles much of the writing, that struggle disappears, and with it, the learning. Teams need to be more intentional about how they transfer knowledge. Structured pairing, documented design decisions, and explicit mentorship become more important, not less.

Specification before implementation. The ability to write a clear specification is now the highest-leverage skill in software engineering. A precise spec turns an LLM from a mediocre pair programmer into a highly effective one. A vague spec turns the LLM into a hallucination engine. Teams that invest in specification quality will outproduce teams that skip straight to prompting.

Processes Worth Eliminating
#

Some processes survive on inertia alone. AI gives permission to rethink them.

Status meetings that are not decisions. If a standup is just a round-robin of activity reports, replace the standup with an AI-generated summary of yesterday’s commits, PRs, and tickets. Reserve synchronous time for discussions that require back-and-forth. Most status updates do not require back-and-forth.

Granular task estimation. When AI can generate implementation drafts, estimating individual tasks in story points becomes less accurate and less useful. The time spent decomposing work into one-point, two-point, and three-point tickets is time not spent on the actual work. Replace granular estimation with outcome-level planning: what do we want to ship this cycle, and are we on track?

Manual test writing for boilerplate. AI handles test scaffolding well. Engineers should focus on test design (what cases matter, what edge cases exist, what invariants must hold) and let the tooling handle the mechanical work of writing assertions and setup code. The test plan is the valuable artifact. The test file is increasingly a commodity.

Elaborate approval workflows. If a change passes CI, passes automated security scanning, and passes peer review, the change should not also need approval from a manager who has not read the code. Every gate that does not add information is pure delay.

The Structure of a Team That Gets This Right
#

Bringing these threads together, here is the team I would design for this era.

Four or five people who own a clear domain. They spend less time writing boilerplate and more time debating trade-offs. Their code reviews are rigorous about intent and lightweight about style. They write ADRs for non-obvious decisions and skip ADRs for obvious ones. They do not hold meetings that could be a paragraph of text. They write specifications before they prompt.

They treat AI as an amplifier of judgment, not a replacement for it. The judgment is still the team’s job. The tooling just makes the execution of that judgment faster.

What Does Not Change
#

For all the shifts, some things are stubbornly constant.

Trust between team members cannot be generated by a language model. Psychological safety, the ability to say “I think this approach is wrong” without fear, remains the single strongest predictor of team performance. A team of mediocre engineers who trust each other will outperform a team of brilliant engineers who do not trust each other, with or without AI assistance.

Shared understanding of the problem domain cannot be delegated to tooling. If no one on the team deeply understands the business context, the code will be technically correct and strategically wrong, faster than ever.

And the discipline to build less, not more, remains the hardest skill. When implementation is nearly free, the temptation to overbuild is constant. The teams that thrive will be the ones where someone at the table says “we don’t need this,” and the rest of the team listens.


The case for static priorities

Most teams that adopt a P0-P5 priority scale make the same mistake: they treat priority as a ranking, not a classification. The moment all P0s are resolved, someone suggests “promoting” P1s to P0. This feels logical. It is wrong, and in this article I want to defend the alternative: a static system where a priority label describes the work itself and never moves just because the queue in front of the work emptied.

Priority is a property of the work, not its position in the queue
#

P0 means something specific: the production database is corrupted, customers cannot check out, a security vulnerability is being actively exploited. P0 work has an operational definition. The label describes the nature and consequence of the task.

A P1 task is important work that should be done this quarter: a feature the largest customer has been requesting, a refactor that will unblock two teams, a performance optimization that will cut infrastructure costs by 30%. Completing the P0s does not transform a P1 into an existential crisis. The task has not changed. The task’s urgency has not changed. Calling the task P0 adds no information and removes the ability to distinguish the task from actual emergencies.

If everything becomes P0, nothing is P0
#

Priority inflation is the fastest way to destroy a prioritization system. Once a team learns that P0 simply means “next thing we’re working on,” the label stops meaning anything. When a real P0 arrives and the database is on fire, the team needs everyone to drop what they are doing, but the word no longer carries weight because promotion has diluted the word.

Consider what happens when you tell a team “this is P0” in a healthy system: people stop what they are doing, context-switch, and focus on the emergency. That response depends on P0 being rare and meaningfully different from everything else. If the backlog contains forty items that were “promoted” to P0, the next real emergency gets the same response as a feature request.

A static system is a shared vocabulary
#

The value of a priority scale is communication. When an engineer files a bug as P1, a product manager should immediately understand the rough timeframe and severity without reading the full description. When a support rep escalates a ticket to P0, the on-call engineer should know to wake up.

This shared understanding requires stable definitions. If P0 means “site is down” on Monday but “most important remaining backlog item” on Wednesday, the label communicates nothing about the work itself, only about where the work sits relative to other work. That is what a sorted list already tells you. The priority label should add something a list cannot: the kind of impact the task has.

Why not use importance × urgency?
#

The Eisenhower Matrix (important/urgent, important/not urgent, not important/urgent, not important/not urgent) is the most common alternative to a priority scale. The matrix is appealing because the matrix is simple: two dimensions, four quadrants, done. But the matrix breaks down in practice for several reasons.

Everything a team is asked to do is important. If a task were truly unimportant, the task would not be in the backlog. As a result, most tasks cluster in the “important” row, and the entire burden of differentiation falls on the urgency axis. The matrix has effectively collapsed back to a single dimension, but with less granularity than P0-P5.

Four buckets are too coarse. Within “important and not urgent” sits everything from “refactor the authentication system this quarter” to “update the README someday.” The quadrant gives you no way to distinguish these. P0-P5 gives you six levels, each with an attached timeframe and commitment level. The matrix tells you “schedule it.” The priority scale tells you “schedule it this quarter.”

Urgency is ambiguous at the boundaries. Is a customer feature request urgent because the customer is asking today, or not urgent because there is no deadline? Is a tech debt refactor urgent because the refactor slows down every sprint, or not urgent because nothing is currently broken? These edge cases generate the same kind of debate that multi-dimensional systems create, but the matrix offers only two positions: urgent or not. P0-P5 lets you express degrees of time sensitivity without a separate axis.

The matrix is a decision framework, not a communication protocol. “Important and urgent” describes a reasoning process. P0 describes a shared organizational response: drop everything, wake people up, ship a fix today. The priority label carries both classification and implied action. The matrix carries only classification, leaving the action unspecified.

The Eisenhower Matrix is a good tool for personal time management. For team-scale prioritization of a shared backlog, a single priority scale with pre-agreed definitions communicates faster and differentiates better.

Why not decompose into impact, urgency, and risk?
#

A related objection: instead of a single P0-P5 label, why not rate each task on multiple dimensions? If each dimension only has two or three values, assessment is quick.

Assessment is indeed quick. The problem is the decision rule. Once you have impact × urgency × risk, you need a policy for how the dimensions combine. Does high impact + medium urgency + low risk come before medium impact + high urgency + low risk? Every disagreement becomes a debate about weights instead of a quick “this is P1” call.

The P0-P5 scale is that policy pre-baked. Someone already decided the mapping. The team classifies and moves on.

That said, if a team consistently disagrees on priority labels, the disagreement itself is useful. The disagreement surfaces the underlying dimensions naturally. The debate about impact, urgency, and risk is the conversation you have when the single label fails, not the default workflow. A single priority label is the fast path. Decomposed dimensions are the escalation path.

Working on P1s does not require calling them P0
#

Here is the practical concern: after the P0s are done, what should the team work on? P1s, obviously. Nothing needs to be renamed to start working on the P1s.

A static priority system separates two decisions:

  1. What is this task? (classification: P0 through P5)
  2. What should we work on next? (scheduling: pick the highest-priority task that is unblocked and aligned with current goals)

Dynamic systems conflate the two decisions. By making priority a function of backlog state, a dynamic system loses the ability to classify independently of schedule. A task’s priority no longer tells you what kind of work the task represents. The label only records where the task ranked at the moment of labeling.

Re-labeling has a real cost
#

Every time items are promoted after higher-priority work completes, the team pays a coordination cost. Someone has to decide which P1s become P0s. That decision requires a meeting, or at least a Slack thread, or a product manager’s judgment call. The larger the team, the more expensive the relabeling becomes.

In a static system, this cost is zero. The team finishes the P0s, picks up the next highest-priority task, and keeps building. No ceremony, no relabeling, no debate about whether a P1 has “earned” its promotion.

Static priorities enable proportional allocation
#

Healthy teams do not just work on the highest-priority item. These teams allocate capacity across priority levels: 10% on P0 (emergencies, when they arise), 60% on P1 (core roadmap), 20% on P2 (improvements), 10% on P3-P5 (maintenance, tech debt, experiments).

This kind of planning is only possible with stable definitions. If P1s keep becoming P0s, the team cannot reason about where the team’s time is going. Velocity metrics become meaningless because the definition of each bucket shifts under the team.

Truthful labeling forces truthful conversations
#

A static system forces the team to be realistic about what the team is not doing.

In a dynamic system, everything important eventually becomes P0, so nothing is ever explicitly deprioritized. A stakeholder asks “when will you do X?” and the answer is “it’s P1, we’ll get to it after the current P0s.” The answer is real but uncomfortable. The discomfort is the point.

When a P2 feature stays P2 for three quarters, the organization has a clear signal: this work is not important enough to displace P1 work. That signal triggers a useful conversation: should we increase staffing, should we drop the feature, or should we accept that the feature will not happen soon?

In a dynamic system, the same feature would have been promoted to P1, then P0, and done without anyone confronting the question of whether the feature was worth doing at all.

When priorities should change
#

A static system does not mean priorities are frozen forever. Priorities should change when the task itself changes, not when the backlog above the task empties.

A P2 performance issue becomes P1 when a major customer threatens to churn over the issue. The task’s context changed. A P3 experiment becomes P1 when early results show the experiment could replace a critical dependency. New information arrived. A P1 feature becomes P0 when a competitor launches the feature and the sales team starts losing deals. The market shifted.

These are legitimate priority changes because the nature and consequence of the work actually changed. These changes are not promotions based on queue position.

The scale
#

For reference, a well-defined static scale looks something like this:

  • P0: Critical. Production is down, data is at risk, or customers are blocked. Drop everything.
  • P1: High. Important work with clear business impact. Should be done this quarter.
  • P2: Medium. Valuable but not time-sensitive. Should be done within the next two quarters.
  • P3: Low. Nice to have. Will do if capacity allows.
  • P4: Minimal. Logged for consideration. No commitment to do.
  • P5: Rejected or deferred indefinitely. Kept for historical reference.

Each level describes a timeframe, a level of commitment, and a resource allocation. None of the definitions reference other tasks in the backlog.

What to do instead of promoting
#

When the P0s are finished and work moves on to P1s, do not relabel. Instead:

  1. Sort P1s by dependencies and impact. Within a priority level, use a secondary criterion to decide order.
  2. Pick the top P1 and start. No ceremony needed.
  3. If the P1s run out, start on P2s. The system is working as intended.

The priority label told you the task was important-but-not-critical work. It still is. The fact that nothing more urgent remains does not change the nature of the work.

The one-sentence version
#

Priority describes what a task is, not when you will get to the task. Keep the label stable, sort within levels, and let the schedule be the schedule.


The Shifting Bottleneck: From Writing Code to Questioning Everything

Every time AI removes a bottleneck in software development, the next one appears one level higher up the decision chain. The constraint never disappears, it just moves.

The Five Stages
#

1. Producing code
#

For decades, the bottleneck was typing. Writing code was slow. Understanding codebases was slow. Every feature required a human to translate intent into syntax, one keystroke at a time. We built IDEs, autocompletion, linters, and refactoring tools to speed this up, but the fundamental constraint remained: humans had to write the code.

Then LLMs arrived and that constraint dissolved almost overnight. GitHub Copilot, Cursor, Claude Code, and a dozen other tools made it trivial to generate working code from a description. The bottleneck moved.

2. Verifying generated code
#

When code writes itself, your job shifts from author to reviewer. You no longer ask “how do I implement this?” but “does this implementation do what I want?”

Verification is a fundamentally different skill. Reviewing code you didn’t write requires reading with suspicion. Every function could contain a subtle bug, a hallucinated API call, or a plausible-sounding but incorrect assumption. The code looks right, the tests pass, but does it actually solve the problem?

The verification bottleneck is harder than the production bottleneck because verification is an underconstrained problem. There are infinitely many ways code can be wrong, and no finite checklist catches them all.

3. Deciding what to implement
#

Once you can generate and verify code quickly enough, a new question surfaces: should this be built at all?

Not every feature deserves implementation. Not every bug deserves a fix. The cost of writing code approaches zero, but the cost of maintaining code, shipping code, and supporting code does not. Every line of code is a liability. Every feature adds surface area for bugs, increases cognitive load, and constrains future decisions.

The bottleneck shifts from “can we build it?” to “should we build it?” Deciding what to implement is product thinking, not engineering. Engineers who spent careers optimizing for execution speed now find themselves needing to develop judgment about what is worth executing.

4. Deciding what to build
#

Push further: should this product exist at all?

Before LLMs, the cost of building a product was a natural filter. If it took six months and a team of five to build an MVP, you had to be reasonably confident the market wanted it. Now that an MVP can be built in an afternoon, the cost of building is no longer the filter. The filter is the cost of being wrong about product-market fit.

The bottleneck now sits in strategy. Understanding users, identifying real problems, and choosing which market to enter are now the scarce skills. Anyone can build the product. Figuring out which product to build is the hard part.

5. Questioning automation itself
#

And then you arrive at the final question: should we have automated ourselves at all?

This is not a joke. Every layer of automation removes human involvement from a layer of decision-making. When code writes itself, verifies itself, decides what to build, and decides whether to build it, what is left for the human?

There is a genuine question about whether the end state of this trajectory is human irrelevance. Not because AI became malevolent, but because we systematically removed every reason for a human to be involved. Each step was rational. Each bottleneck was real. Each automation was justified. And yet the cumulative effect is a slow unwinding of human agency in the creative process.

The Bottleneck Elevator
#

This pattern has a name in systems thinking: the theory of constraints. In any system, improving one stage of a pipeline exposes the next bottleneck downstream. In software development, the pipeline runs upward through abstraction layers:

Existential → Product → Feature → Verification → Production

AI has been climbing this stack from the bottom. Each time it solves one level, the next level becomes the limiting factor. The work doesn’t decrease, it transforms.

What to Do Next
#

If you are a software developer today, your career trajectory is being pulled up this stack whether you like it or not.

If you are still at Stage 1 (producing code), you are already behind. Adopt AI coding tools now. The gap between developers who use LLMs and those who don’t is widening every month.

If you are at Stage 2 (verifying code), invest in specification skills. The ability to write precise, testable requirements is what separates effective AI-assisted developers from those who spend all day reviewing hallucinated nonsense.

If you are at Stage 3 (deciding what to implement), develop product judgment. Understanding trade-offs, opportunity cost, and the difference between “can build” and “should build” is your leverage.

If you are at Stage 4 (deciding what to build), you are in the right place for now. Strategy, market understanding, and user empathy are the current frontier.

If you are at Stage 5, you have seen the full picture. The question is not whether automation will continue climbing, it will. The question is what humans should do with the freedom that comes from not being the bottleneck.

The Real Answer
#

I don’t have a clean answer for Stage 5. Neither does anyone else. The optimists say we will find new creative work that we cannot yet imagine, the same way we always have after every technological revolution. The pessimists say this time is different because AI doesn’t just replace manual labor, it replaces cognitive labor, and eventually all of it. Both positions are old positions in the technological unemployment debate, and neither side has settled it.

What I can observe is that the bottleneck will keep shifting. Whatever you think the final constraint is, solving it will reveal another one behind it. The work of a developer is not to write code, it is to stand at the current bottleneck and push.

The bottleneck will move. Your job is to move with it.


Code Factories: The RollerCoaster Tycoon Perspective

You start with an empty plot of land, a small bank loan, and an objective to attract 600 guests by the end of year two.

That’s RollerCoaster Tycoon. It’s also your first day as a startup founder.

In RollerCoaster Tycoon, you build a theme park from nothing. You lay down paths, construct rides, hire staff, set prices, manage finances, and try to keep thousands of guests happy simultaneously. You watch little pixelated people queue for attractions, complain about litter, get sick on rides, and leave when they’ve had enough.

Building a software product is the same game with different sprites. The question is whether your park guests are leaving happy or leaving forever.

Ride Design: Feature Development
#

In RollerCoaster Tycoon, every ride is a design problem.

A roller coaster starts as blank track on a canvas. You choose the lift hill height, the drop angle, the number of inversions, the banking on turns. Each decision affects three metrics: excitement, intensity, and nausea.

Excitement is what attracts guests. Intensity is the thrill level: some guests love it, some won’t ride. Nausea is the cost: too much and guests vomit on your paths.

Feature development has the same three metrics.

Excitement is user value, the feature that solves a real problem, delivers a delightful experience, or unlocks new capability. Intensity is complexity, the learning curve, the configuration surface, the cognitive load on users. Nausea is maintenance burden, the edge cases, the performance overhead, the support tickets.

A roller coaster with high excitement and moderate intensity is the ideal ride. Guests line up for it, enjoy it, and ride again. A feature with high value and manageable complexity is the ideal feature. Users adopt it, benefit from it, and recommend it.

A roller coaster with maximum intensity and maximum nausea empties the queue. Guests try it once, throw up, and never return. A feature with maximum complexity and maximum maintenance burden empties the user base. Users try it once, get confused, and never return.

The RollerCoaster Tycoon lesson: optimize for excitement, manage intensity, minimize nausea. In software: optimize for value, manage complexity, minimize burden.

Park Layout: Information Architecture
#

In RollerCoaster Tycoon, path layout determines everything.

Guests follow paths. They can only reach rides that are connected to the path network. If a ride is hidden behind another ride with no path leading to it, it might as well not exist. If the path network is a tangled mess, guests get lost, frustrated, and leave.

Your information architecture is your path layout.

Users follow navigation. They can only find features that are connected to the navigation flow. If a feature is buried three menus deep with no link to it, it might as well not exist. If the navigation is a tangled mess, users get lost, frustrated, and leave.

RollerCoaster Tycoon teaches a specific layout pattern: the hub-and-spoke.

A central plaza connects to several themed areas. Each themed area contains related rides. Signs guide guests from the hub to the areas they want. The layout is intuitive, discoverable, and scalable: add a new spoke when you add a new area.

Good information architecture is hub-and-spoke.

A homepage or dashboard connects to major feature areas. Each area contains related functionality. Breadcrumbs and search guide users to what they need. The layout is intuitive, discoverable, and scalable: add a new section when you add a new feature area.

Parks with random path layouts have low guest counts and low ratings. Products with random navigation have low engagement and low retention.

Guest Happiness: User Satisfaction
#

Every guest in RollerCoaster Tycoon has a happiness meter.

It starts high when they enter the park. Every good ride increases it. Every long queue decreases it. Every piece of litter they see decreases it. Every overpriced item decreases it. When happiness drops below a threshold, the guest leaves and the park rating drops.

User satisfaction works the same way.

Every smooth interaction increases it. Every loading spinner decreases it. Every confusing error message decreases it. Every unexpected price increase decreases it. When satisfaction drops below a threshold, the user churns and the review rating drops.

RollerCoaster Tycoon teaches that guest happiness is a composite of many small factors, not one big one.

No single ride makes guests happy. Happiness is the combination of good rides, short queues, clean paths, reasonable prices, attractive scenery, and available amenities. Fix one problem while ignoring the others and happiness barely moves.

User satisfaction is equally composite. No single feature makes users happy. Satisfaction is the combination of useful features, fast performance, clear error messages, fair pricing, good design, and responsive support. Fix one problem while ignoring the others and satisfaction barely moves.

The park with the highest rating isn’t the one with the best roller coaster. It’s the one where everything works well together. The product with the highest satisfaction isn’t the one with the best feature. It’s the one where everything works well together.

Queue Management: Performance Optimization
#

In RollerCoaster Tycoon, queues are the visual indicator of a problem.

A long queue means guests are waiting. Waiting guests are unhappy guests. Unhappy guests leave bad reviews and reduce the park rating.

The solutions are straightforward: increase ride capacity, add more rides, or optimize throughput. Run three trains instead of two. Synchronize the dispatch timing. Build a second coaster nearby to distribute the load.

Performance bottlenecks are queues.

A slow API response means requests are waiting. Waiting requests are unhappy users. Unhappy users abandon carts, close tabs, and leave bad reviews.

The solutions are equally straightforward: increase capacity, add more instances, or optimize throughput. Scale horizontally with more servers. Cache frequently requested data. Build a read replica to distribute the load.

RollerCoaster Tycoon also teaches a subtler lesson about queues: the perception of waiting matters as much as the actual wait.

Rides with themed queue lines (tunnels with decorations, TV screens playing videos, interactive elements) have higher guest satisfaction than rides with bare concrete queues, even when the wait time is identical.

The software equivalent is perceived performance.

A page that loads a skeleton UI immediately and fills in content progressively feels faster than a page that shows nothing for two seconds and then renders everything at once. The actual load time is the same. The perceived load time is dramatically different.

Theme your queue lines. Show progress indicators, skeleton screens, and optimistic updates. The wait is the same. The experience is better.

Staff Management: Team Operations
#

Your park needs staff.

Handymen sweep litter and empty trash cans. Mechanics inspect and repair broken rides. Security guards catch vandals and keep the peace. Entertainers make guests happy in queue lines.

Each staff member has a patrol zone. Set the zone too large and they can’t cover it all; litter accumulates in the corners. Set the zone too small and they cluster in one area while the rest of the park deteriorates. Hire too few and the park falls apart. Hire too many and the payroll drains your budget.

Engineering teams have the same dynamics.

SREs are mechanics: they inspect, repair, and prevent production failures. Support engineers are handymen: they clean up tickets, triage issues, and keep the user experience tidy. Security engineers are security guards: they find vulnerabilities, respond to incidents, and keep the codebase safe. Developer advocates are entertainers: they engage the community, write documentation, and make the developer experience enjoyable.

The patrol zone problem is the on-call rotation problem.

Give an on-call engineer too many services and they can’t respond to incidents fast enough; errors accumulate. Give them too few and they sit idle while other on-call engineers are overwhelmed. Too few engineers on rotation and the team burns out. Too many and context is spread thin.

RollerCoaster Tycoon also teaches that staff training matters.

A trained mechanic repairs rides faster. A trained handyman cleans more efficiently. In software, the equivalent is runbooks, incident playbooks, and onboarding documentation. A trained on-call engineer resolves incidents faster because they’ve seen the failure modes before and know the recovery steps.

Invest in your staff or watch your park deteriorate.

Ride Breakdowns: Production Incidents
#

Every ride in RollerCoaster Tycoon has a reliability rating.

New rides are highly reliable. As they age, reliability drops. The more a ride runs, the more likely it breaks down. A broken ride closes. Guests in the queue leave unhappy. The mechanic has to walk across the park, inspect the ride, and repair it.

During the downtime, the queue grows, the guests complain, and the park rating drops.

Production incidents are ride breakdowns.

New services are highly reliable. As they age, complexity accumulates. The more a service runs, the more likely an edge case triggers a failure. A failed service goes down. Users in the middle of a workflow are interrupted. The on-call engineer has to investigate, diagnose, and fix the issue.

During the downtime, error rates spike, users complain, and the product reputation drops.

RollerCoaster Tycoon’s solution to breakdowns is preventive maintenance.

Mechanics can be assigned to inspect rides before they break. Regular inspections increase reliability and reduce the frequency of breakdowns. The cost is the mechanic’s time; time spent inspecting is time not spent repairing. But the net effect is positive: fewer breakdowns, shorter downtimes, happier guests.

The software equivalent is proactive reliability engineering.

Chaos engineering, load testing, dependency auditing, and synthetic monitoring are preventive inspections. The cost is engineering time; time spent testing reliability is time not spent building features. But the net effect is positive: fewer incidents, shorter outages, happier users.

Parks that skip inspections have spectacular breakdowns at the worst moments. Services that skip reliability testing have spectacular outages during peak traffic.

Research: Technical Exploration
#

RollerCoaster Tycoon has a research system.

You allocate funding to research and over time, new rides, scenery, and improvements become available. More funding accelerates research. Less funding slows it. No funding means you’re stuck with what you have.

The tension is real: every dollar spent on research is a dollar not spent on building rides right now. But without research, you can’t build the rides that attract guests later.

Technology exploration is research.

Every hour spent evaluating a new framework, prototyping a new architecture, or experimenting with a new tool is an hour not spent shipping features right now. But without exploration, you can’t build the features that attract users later.

RollerCoaster Tycoon teaches that research should be funded consistently, not in bursts.

A player who sets research to maximum at the start and then cuts it to zero runs out of new content mid-game. A player who funds research at a moderate, steady rate unlocks new rides throughout the game.

The software equivalent: invest in exploration consistently, not just when the team is between projects.

A team that dedicates 10% of every sprint to technical exploration (trying new tools, reading papers, prototyping ideas) continuously discovers improvements. A team that only explores during quarterly hackathons discovers nothing for three months at a time.

Consistent research wins. Burst research wastes the intervals between bursts.

Scenario Objectives: Sprint Goals and OKRs
#

Every RollerCoaster Tycoon scenario has an objective.

“Have 600 guests in your park by the end of year two.” “Achieve a park rating of 700 by October, year three.” “Build ten roller coasters with an excitement rating above 6.00.” “Repay your loan and achieve a monthly profit of $1,000.”

The objectives are specific, measurable, and time-bound. They force you to prioritize; you can’t do everything, so you do what matters for the objective.

Sprint goals and OKRs are scenario objectives.

“Ship the new checkout flow by end of sprint.” “Reduce p95 latency below 200ms by end of quarter.” “Increase test coverage to 80% by end of year.” “Reduce onboarding time for new engineers by 50%.”

RollerCoaster Tycoon teaches something critical about objectives: the scenario ends.

When you achieve the objective, the scenario is complete. You can keep playing (most players do) but the pressure is off. The objective gave the gameplay structure. Without it, you’d build aimlessly and the park would suffer.

Sprint goals give development structure. Without them, teams build aimlessly and the product suffers.

But RollerCoaster Tycoon also teaches that the wrong objective leads to the wrong park.

An objective that demands 1,000 guests by year one forces you to build cheap, low-quality rides to attract crowds fast. The park fills up but the rating is terrible. An objective that demands a park rating of 900 forces you to build slowly and carefully. The rating is excellent but the guest count is low.

Software objectives have the same distortion effect.

An objective that measures lines of code produces lots of code. An objective that measures features shipped produces lots of features. Neither guarantees quality, user satisfaction, or business value. The metric you optimize is the park you get.

Choose your scenario objective carefully. It will determine everything you build.

Loan Management: Technical Debt
#

Many RollerCoaster Tycoon scenarios start you in debt.

You’ve borrowed money to buy the land and build the first rides. The loan accrues interest every month. The longer you carry it, the more it costs.

You can invest in rides to generate revenue and pay it off slowly. Or you can cut spending, build cheap rides, and pay it off quickly. The first strategy grows the park but increases the total interest paid. The second strategy limits growth but reduces the financial burden.

Technical debt is a loan.

You borrowed time by taking shortcuts, skipping tests, ignoring architecture, hardcoding values. The debt accrues interest every sprint. The longer you carry it, the more it costs in debugging, refactoring, and developer frustration.

You can invest in features to grow the product and pay down debt slowly. Or you can pause features, refactor aggressively, and pay it down quickly.

RollerCoaster Tycoon teaches that the optimal strategy depends on the interest rate.

A low-interest loan is fine to carry; the revenue from new rides exceeds the interest cost. A high-interest loan is an emergency: it consumes revenue faster than the park can generate it.

Low-interest technical debt (a slightly messy module that rarely changes) is fine to carry. The velocity gained by shipping features exceeds the cost of the debt. High-interest technical debt (a critical module that breaks every sprint) is an emergency. It consumes velocity faster than the team can generate it.

Know your interest rate. Manage accordingly.

Park Value: Technical Assets
#

RollerCoaster Tycoon tracks your park value, the combined worth of all your rides, scenery, and infrastructure.

It’s not the same as cash in the bank. You can have high park value and no cash if you spent everything on construction. You can have high cash and low park value if you haven’t built anything.

Park value represents what you’ve built, not what you have. It compounds: every ride you build increases the value, and the more valuable the park, the more guests it attracts, which generates more revenue for building more rides.

Technical assets are park value.

Your component library, your CI/CD pipeline, your monitoring infrastructure, your documentation, your test suite: these are rides you’ve built. They represent what you’ve constructed, not what you have in the backlog.

A team with high technical assets and an empty backlog is well positioned: they can build anything quickly. A team with low technical assets and a full backlog is in trouble: everything they try to build requires starting from scratch.

Park value compounds the same way. A park with ten rides attracts more guests than one with two, generating more revenue to build more rides. A codebase with ten reusable components ships faster than one with two, generating more time to build more components.

The RollerCoaster Tycoon lesson: invest in park value, not just cash flow. Build rides that attract guests. Build infrastructure that attracts velocity.

Scenery and Theming: Design and UX
#

In RollerCoaster Tycoon, scenery affects guest happiness.

Trees, fountains, gardens, statues, themed decorations: guests notice them. A ride surrounded by matching scenery gets an excitement bonus. A path lined with trees and benches keeps guests happy while they walk. A park with no scenery is functional but joyless.

Design and UX are scenery.

A functional interface without thoughtful design is a park without trees. Users can complete their tasks but they don’t enjoy them. There’s no delight, no personality, no sense that someone cared about the experience.

RollerCoaster Tycoon teaches that scenery is most effective when it’s themed.

A pirate-themed roller coaster surrounded by pirate scenery (ships, treasure chests, palm trees) gets a higher excitement bonus than the same ride surrounded by random, unrelated decorations. Consistency matters more than quantity.

Design systems are theming.

A consistent design system (typography, colors, spacing, components) creates a cohesive experience. Users don’t have to relearn the interface on every page. The product feels intentional, polished, professional.

A product with random design choices (different button styles, inconsistent spacing, clashing colors) is a park with random scenery. Each element might look fine on its own. Together, they’re incoherent.

Theme your park. Theme your product.

Marketing: Developer Relations and Product Marketing
#

RollerCoaster Tycoon lets you run marketing campaigns.

Advertising for the park increases guest count. You can target local, national, or international audiences at increasing cost. More marketing brings more guests, but if the park isn’t ready for them, they arrive to long queues, dirty paths, and broken rides. They leave unhappy and the marketing was wasted.

Product marketing and developer relations work the same way.

A successful marketing campaign brings users. But if the product isn’t ready (if the onboarding is rough, the documentation is thin, the performance is slow) users arrive to a bad experience. They leave unhappy and the marketing was wasted.

RollerCoaster Tycoon teaches the sequence: build the park first, then market it.

Players who spend their initial budget on marketing instead of rides attract guests to an empty park. The guests find nothing to do and leave. The money is gone and the park rating is worse than if they’d never marketed at all.

Startups learn this the hard way. Marketing before product-market fit brings users to a product that doesn’t serve them. The users leave, the analytics look terrible, and the brand is damaged.

Build the ride first. Then put up the billboard.

Terrain Constraints: Legacy Systems
#

Some RollerCoaster Tycoon scenarios give you a blank, flat parcel of land. These are the easy scenarios. You build what you want, where you want, with no constraints.

Most scenarios aren’t like that.

You get a mountainous plot with a river running through it. Or a partially built park with existing paths and rides you can’t remove. Or an underground cavern with limited space. The terrain constrains every decision. You can’t build a flat coaster on a mountain. You can’t extend a path across a river without a bridge. You have to work with what you’ve got.

Legacy codebases are constrained terrain.

The ideal software project starts from nothing: blank repository, no dependencies, no constraints. Most projects aren’t like that.

You inherit a codebase with a decade of decisions baked in. A database schema that can’t be changed without migrating millions of rows. An API contract that external clients depend on. A build system that nobody fully understands. The legacy constrains every decision.

RollerCoaster Tycoon teaches that constrained terrain isn’t a disadvantage: it’s a design prompt.

The best coasters in the game are built on mountains, using the elevation changes to create drops and turns that flat terrain can’t support. The constraint forces creativity. The result is better than what flat terrain would have produced.

The best software architectures emerge from constrained codebases. The legacy forces you to think carefully about abstractions, boundaries, and migration paths. The result is often more robust than a greenfield design that never faced real constraints.

Don’t wish for flat terrain. Build better coasters on the mountain.

Ride Synchronization: Service Coordination
#

In RollerCoaster Tycoon, you can build ride sequences.

A log flume that ends near a roller coaster entrance. A transport ride that shuttles guests from the back of the park to the front. A path that naturally guides guests through a series of attractions in order.

When rides are well-connected, guests flow through the park naturally, experiencing each attraction in sequence. When rides are disconnected, guests wander, backtrack, and miss attractions they would have enjoyed.

Microservice coordination is ride synchronization.

A well-orchestrated service mesh lets data flow through the system naturally, each service processing requests in sequence. A poorly connected architecture forces data to backtrack, retry, and miss services that should have been involved.

RollerCoaster Tycoon also teaches that you can’t force guests through a sequence.

You can build a path that leads from Ride A to Ride B, but if the guest is tired, hungry, or has already ridden Ride A, they’ll skip Ride B and look for food instead. The sequence must be optional, not mandatory.

Service orchestration must be the same. Each service should work independently. Coordination is an optimization, not a requirement. If Service A is down, Service B should still function, even if degraded.

Guests who are forced through a sequence they don’t want rebel. Services that are forced into tight coupling fail together.

Build the path. Let the guest choose.

The Late Game: Software Factories
#

In RollerCoaster Tycoon’s late game, something shifts.

Your park is established. Rides are built, staff is hired, research is funded, guests are flowing. You stop placing individual track pieces and start thinking about the park as a system.

You notice that the path near the pirate coaster always gets congested, so you widen it. You notice that guests cluster near the food court at noon, so you add another food stall. You notice that the park rating dips every time it rains, so you build more indoor attractions.

You’re no longer building rides. You’re optimizing a system.

Software factories are the late game of development.

Your CI/CD pipeline is established. Your monitoring is running. Your team is staffed, your architecture is sound, your users are flowing. You stop writing individual functions and start thinking about the development process as a system.

You notice that deploys always cause a spike in errors, so you add automated smoke tests. You notice that code review is the bottleneck, so you add AI-assisted review tooling. You notice that onboarding takes too long, so you build interactive tutorials.

You’re no longer writing code. You’re optimizing a system that writes code.

In RollerCoaster Tycoon, the late game players build mega-parks, sprawling empires with dozens of rides, thousands of guests, and perfect ratings. They didn’t get there by building one perfect ride. They got there by building a system where every ride supports every other ride.

In software, the late game teams build software factories, sprawling systems where AI agents write code, tests run automatically, deployments ship continuously, and incidents heal themselves. They didn’t get there by writing one perfect feature. They got there by building a system where every tool supports every other tool.

The park guest who walks into a mega-park sees rides. The developer who walks into a software factory sees features. Neither sees the decades of system optimization that made it all possible.

The Lesson
#

RollerCoaster Tycoon is a game about building something that delights people.

You start with empty land and an objective. You end with a park that thousands of guests enjoy. The satisfaction isn’t in any single ride: it’s in the system that makes every ride better.

Software development is the same game.

You start with an empty repository and a requirement. You end with a product that thousands of users rely on. The satisfaction isn’t in any single feature: it’s in the system that makes every feature better.

In RollerCoaster Tycoon, the parks that endure aren’t the ones with the tallest coaster or the most rides. They’re the ones where everything works together: the paths flow, the queues are short, the staff is attentive, the scenery is beautiful, and every guest leaves happy.

In software, the products that endure aren’t the ones with the most features or the latest technology. They’re the ones where everything works together: the architecture is clean, the performance is fast, the support is responsive, the design is consistent, and every user leaves satisfied.

If you’re still building rides one track piece at a time, it’s time to think about the park. If you’re still writing features one line at a time, it’s time to think about the factory.

The park is open.

See also
#


Code Factories: The Stock Market Perspective

You open your terminal, pull the latest commit, and run the test suite.

Some pass. Some fail. You investigate.

That’s software development. It’s also trading.

In the stock market, you analyze data, place orders, and manage risk. You develop strategies, backtest them, and deploy capital. You react to earnings reports, economic data, and competitor moves. The market never sleeps. The ticker never stops.

Building a software factory is the same game with different instruments. The question is whether you’re trading or being traded.

IPO: Your First Deploy
#

A company goes public through an initial public offering. Months of preparation (financial audits, legal filings, roadshow pitches) all leading to the moment the ticker appears on an exchange and anyone can buy shares.

Your first production deploy is your IPO.

You’ve spent months writing code, running tests in staging, doing code reviews. None of it matters until real users touch real software in a real environment. The moment you deploy to production, you’re public. Users will do things you never expected. Edge cases you never imagined will surface. The market (your users) will render its verdict.

Companies that rush their IPO get hammered. The valuation drops. The stock tanks. The reputation suffers. Teams that rush their first deploy get paged at 3 AM. The errors spike. The users complain. The reputation suffers.

The lesson is the same in both: prepare thoroughly, but don’t wait for perfection. There is never a perfect time to go public. There is never a perfect time to ship. The companies that wait too long get beaten by faster competitors. The teams that wait too long get beaten by faster teams.

Ship. Then iterate.

Market Capitalization: Lines of Code
#

A company’s market cap (share price times shares outstanding) is the simplest measure of its size. It tells you how much the market values the company right now. It tells you nothing about whether the company is well-run, profitable, or sustainable.

Lines of code is the market cap of software.

It tells you how big the codebase is. It tells you nothing about whether the code is well-written, tested, or maintainable. Just as a company with a billion-dollar market cap can be hemorrhaging cash, a codebase with a million lines can be hemorrhaging bugs.

Investors learned long ago that market cap is a starting point, not a conclusion. They look deeper: revenue, margins, growth rate, debt levels. Software teams need to look deeper too: test coverage, deployment frequency, mean time to recovery, change failure rate.

The stock that doubles on hype and collapses on earnings is the codebase that doubles in size on features and collapses under technical debt.

Bull and Bear Markets: Feature Velocity
#

Bull markets are euphoric. Stocks go up. Everyone is a genius. Companies raise money easily, hire aggressively, and expand recklessly. Risk appetite is high. Valuations detach from fundamentals.

Bear markets are brutal. Stocks go down. Nobody is a genius. Companies lay off workers, cut projects, and conserve cash. Risk appetite vanishes. Valuations collapse below reasonable levels.

Software projects have the same cycles.

In a bull phase, the product is winning. Features ship fast. Users are happy. Management approves every hire and every request. The team grows. Velocity increases. Everything feels possible.

In a bear phase, the product is struggling. Bugs pile up. Deadlines are missed. Hiring freezes. The team shrinks. Velocity decreases. Everything feels impossible.

The best investors don’t change their strategy based on the market. They have a strategy that works in both environments. They buy quality companies in bull markets and hold them through bear markets. They use bear markets to accumulate positions in companies they believe in.

The best software teams do the same. They invest in infrastructure during bull phases so they can survive bear phases. They maintain code quality when it’s tempting to cut corners. They use slow periods to pay down technical debt, refactor, and build the foundation for the next bull run.

Teams that only build features during the good times and cut everything during the bad times are like investors who buy at the top and sell at the bottom.

Diversification: Your Tech Stack
#

Financial advisors agree on almost nothing, but they agree on this: diversify your portfolio. Don’t put all your money in one stock, one sector, or one asset class. If that one bet fails, you lose everything.

Technology diversification works the same way.

A team that only knows one language, one framework, and one database is a portfolio with one stock. If that technology becomes obsolete, the team becomes obsolete. If that framework has a critical vulnerability, every service is vulnerable. If that database hits a scaling wall, every feature hits the wall.

But diversification has a cost. A portfolio with 200 stocks is harder to manage than one with 20. A codebase with 15 programming languages is harder to maintain than one with 3.

The best investors hold enough positions to be diversified but few enough to understand each one deeply. The best software teams use enough technologies to avoid single points of failure but few enough to develop deep expertise in each.

The index fund approach (owning a little bit of everything) works in finance. In software, it’s called using industry standards: well-supported languages, proven databases, battle-tested frameworks. You don’t pick the most exciting technology. You pick the one that won’t go to zero.

Short Selling: Technical Debt
#

Short selling is borrowing a stock, selling it, and hoping the price drops so you can buy it back cheaper. You profit from decline. The risk is unlimited; the stock can theoretically go to infinity, and your losses grow with it.

Taking on technical debt is short selling your future productivity.

You borrow time now (by skipping tests, ignoring architecture, hardcoding values) and you pay it back later with interest. If the project gets cancelled or rewritten before the debt comes due, you profit. If the project succeeds and grows, the debt compounds. Every feature becomes harder to ship. Every bug becomes harder to fix. Every new engineer takes longer to onboard.

Like short selling, technical debt can be rational. Traders short overvalued stocks. Engineers take on debt when the feature must ship this week or the company might not exist next month. The trade is calculated: the survival benefit of shipping now outweighs the cost of the debt later.

But just as most short sellers lose money in the long run, most teams that habitually take on technical debt ship slower in the long run. The interest payments (debugging, refactoring, working around hacks) consume an ever-larger share of development time.

The markets have a saying: the market can remain irrational longer than you can remain solvent. Software has an equivalent: the codebase can remain broken longer than your team can remain patient.

Dividends: Documentation and Tests
#

Dividends are payments a company makes to its shareholders from its profits. They’re not flashy. They don’t make headlines. But they compound. A stock that pays a 3% dividend and reinvests it grows dramatically over decades. Dividends are the quiet engine of long-term wealth.

Documentation and tests are dividends.

They don’t ship features. They don’t impress stakeholders in demos. But they compound. Every test written makes the next refactor safer. Every document written makes the next onboarding faster. Every API description written makes the next integration smoother.

Companies that cut dividends to fund growth sometimes succeed. More often, they lose the trust of long-term investors and find it harder to raise capital when they need it. Teams that skip documentation and tests to ship features sometimes succeed. More often, they lose the ability to make changes confidently and find every feature takes longer than the last.

The best dividend stocks aren’t the ones with the highest yield. They’re the ones with the most consistent, most reliable, most growing dividends. The best codebases aren’t the ones with the most tests. They’re the ones with the most consistent, most reliable, most growing test coverage.

Compound interest is the eighth wonder of the world. Compound documentation is the ninth.

Market Orders vs Limit Orders: Deployment Strategies
#

A market order says: buy this stock now, at whatever price the market is offering. Fast. Guaranteed execution. No price guarantee.

A limit order says: buy this stock, but only if the price is at or below my limit. Slower. Not guaranteed to execute. Price guaranteed.

A market order is deploying to production on a Friday afternoon. Fast. The feature is live. No safety guarantee.

A limit order is deploying through a canary release: route 5% of traffic to the new version, monitor for errors, and only proceed if everything looks good. Slower. Not guaranteed to finish today. Safety guaranteed.

Most retail investors use market orders because they’re simple and immediate. Most retail developers deploy all at once because it’s simple and immediate.

Professional traders use limit orders to control their risk. Professional engineering teams use progressive deployments to control theirs.

The stock that gaps down 10% on bad earnings is the deploy that errors 10% of requests on a bad commit. The trader who used a limit order avoided the gap. The team that used a canary deployment avoided the outage.

Earnings Season: Sprint Reviews
#

Every quarter, public companies report earnings. Revenue, profit, guidance. Analysts dissect every number. The stock moves based on whether the results meet, beat, or miss expectations.

It doesn’t matter whether the company is doing well in absolute terms. It matters whether the company is doing well relative to expectations. A company that doubles revenue but was expected to triple it sees its stock drop. A company that loses money but loses less than expected sees its stock rise.

Sprint reviews are earnings season.

Every sprint, the team reports what it shipped. Stakeholders dissect every feature. Morale moves based on whether the results meet, beat, or miss expectations.

It doesn’t matter whether the team is productive in absolute terms. It matters whether the team is productive relative to expectations. A team that ships five features but committed to seven feels like it failed. A team that ships three features but committed to two feels like it succeeded.

The earnings lesson for companies is straightforward: underpromise and overdeliver. The sprint lesson for teams is the same. The company that guides conservatively and beats expectations rewards its shareholders. The team that commits conservatively and beats its sprint rewards its morale.

Companies that inflate guidance to pump the stock eventually miss and crash. Teams that inflate commitments to impress stakeholders eventually miss and burn out.

Volatility: Production Incidents
#

Volatility is how much a stock’s price moves up or down. High volatility means large, unpredictable swings. Low volatility means small, predictable movements.

Traders love volatility: it creates opportunity. Investors hate volatility: it creates anxiety. Both are describing the same phenomenon from different perspectives.

Production incidents are volatility.

High incident volatility means the system swings between working and broken with little warning. The on-call engineer gets paged at random hours. The deploy button feels like a slot machine. Nobody knows whether today will be a quiet day or a fire-fighting day.

Low incident volatility means the system is stable and predictable. Deploys are boring. Pages are rare. The team can plan its work with confidence.

The paradox of volatility is that it’s both a risk and a reward. Traders who can predict volatile movements profit handsomely. Engineers who can diagnose and fix incidents quickly become heroes. But predictability is worth more than heroism. The trader who consistently earns 10% a year beats the trader who swings between +50% and -40%. The team that consistently ships without incidents beats the team that heroically recovers from weekly outages.

The VIX (the stock market’s volatility index) is often called the fear index. Your incident frequency is your VIX. If it’s high, your team is afraid to deploy. If it’s low, your team deploys confidently.

Fundamental Analysis vs Technical Analysis: Code Reviews
#

Fundamental analysts study the company, its financials, its management, its competitive position, its growth prospects. They believe the stock price will eventually reflect the company’s true value.

Technical analysts study the chart, price movements, volume, trends, patterns. They believe the price already reflects everything worth knowing and the pattern predicts what comes next.

Both approaches have merits. Both have blind spots.

Code review has the same split.

The fundamental reviewer reads every line, understands the design decisions, evaluates the architecture, and checks whether the implementation matches the specification. They’re thorough but slow.

The technical reviewer looks at the diff, the changes, the patterns, the test coverage, the style. They’re fast but can miss design flaws that aren’t visible in the diff.

The best investors combine both. They use technical analysis for timing and fundamental analysis for selection. The best code reviewers combine both too. They look at the diff for quick feedback and the architecture for deeper understanding.

Investors who only use technical analysis get caught in pump-and-dump schemes. Reviewers who only look at diffs get caught by changes that look correct in isolation but break the system in context.

Insider Trading: Knowledge Silos
#

Insider trading is trading on information that isn’t public yet. It’s illegal in finance because it’s unfair: the insider has an advantage that ordinary investors don’t.

Knowledge silos are insider trading in software.

The engineer who has been on the team for five years and knows every quirk of the legacy system has information that new team members don’t. They can diagnose problems faster, estimate tasks more accurately, and avoid pitfalls that would trap anyone else. They have an unfair advantage.

Unlike the stock market, this isn’t illegal. But it is dangerous.

When the insider leaves (the senior engineer quits, the architect retires, the founding developer moves on) the team loses access to all that private information. The stock drops. The system becomes incomprehensible.

The solution in finance is regulation: insiders must disclose their trades. The solution in software is documentation: experts must disclose their knowledge. Run books, architecture decision records, onboarding guides, code comments: these are the SEC filings of software. They level the playing field.

Teams that don’t document are teams where insider trading is the norm. And when the insider leaves, everyone else is left holding the bag.

Market Crashes: Cascading Failures
#

On October 19, 1987, the Dow Jones dropped 22.6% in a single day. No single event caused it. Program trading, portfolio insurance, and panic selling created a feedback loop. Each drop triggered more selling, which triggered more drops. The system ate itself.

Cascading production failures are market crashes.

A database slows down, which causes API timeouts, which cause retry storms, which overload the load balancer, which drops health checks, which trigger auto-scaling, which overwhelms the database further. No single component failed. The system ate itself.

The 1987 crash led to circuit breakers, automatic trading halts when the market drops too fast. They don’t prevent the underlying problem. They prevent the feedback loop. They give humans time to intervene.

Circuit breakers in software work the same way. Rate limits prevent retry storms. Bulkheads prevent failures from spreading between services. Timeouts prevent cascading hangs. They don’t prevent the database from being slow. They prevent the slowness from becoming an outage.

Markets without circuit breakers crash faster and recover slower. Systems without circuit breakers fail faster and recover slower.

Index Funds: Standardized Infrastructure
#

Index funds track a market index, the S&P 500, the NASDAQ, the total market. They don’t try to beat the market. They try to be the market. Low fees. Broad diversification. Consistent returns. They’ve outperformed most actively managed funds over any reasonable time period.

Standardized infrastructure is the index fund of software.

You don’t try to build the most optimized database layer, the most custom CI/CD pipeline, the most bespoke deployment system. You use the standard: Kubernetes for orchestration, GitHub Actions for CI/CD, Terraform for infrastructure as code. Not because they’re the best in every dimension. Because they’re good enough in every dimension and they free your team to focus on what actually differentiates your product.

Actively managed funds charge higher fees for the promise of beating the market. Most don’t. Custom infrastructure demands more maintenance for the promise of better performance. Most of the time, it isn’t worth it.

The index fund lesson: stop trying to be clever. Accept market returns and spend your energy where it matters. The infrastructure lesson: stop building custom solutions for solved problems. Accept industry standards and spend your engineering effort on the product.

Warren Buffett’s advice to most investors is to buy a low-cost index fund and do nothing. The equivalent advice to most engineering teams is to adopt standard tooling and focus on shipping.

Margin Trading: Overcommitment
#

Margin trading is borrowing money from your broker to buy more stock than you can afford. It amplifies gains when you’re right. It amplifies losses when you’re wrong. If the position moves against you enough, you get a margin call: the broker demands more collateral or forces you to sell at a loss.

Overcommitting your team is margin trading.

You borrow future capacity (by promising more features than the team can deliver) to please stakeholders now. When the estimates are right, the team delivers and everyone is happy. When the estimates are wrong (and they’re often wrong) the team gets a margin call. Deadlines are missed. Quality drops. People burn out.

The margin call in software is the sprint where nothing ships. The team spent two weeks paying back the borrowed time from the previous three sprints. They were debugging instead of building. Refactoring instead of featuring. Recovering instead of advancing.

Professional traders use margin carefully, with strict risk limits. Professional engineering managers use overcommitment carefully, with buffers and contingency plans.

Amateur traders get wiped out by margin calls. Amateur teams get burned out by death marches.

Warren Buffett: The Principal Engineer
#

Warren Buffett has been investing for over seven decades. He doesn’t trade. He doesn’t use leverage. He doesn’t chase trends. He reads annual reports, understands businesses deeply, and makes a few large, concentrated bets on companies he understands.

Then he waits.

His holding period, he famously said, is forever. His edge isn’t speed or information. It’s patience and judgment.

The principal engineer is the Warren Buffett of software.

They don’t chase the latest framework. They don’t rewrite systems that work. They read codebases deeply, understand the architecture completely, and make a few large, concentrated decisions about the systems that matter most.

Then they wait.

Their edge isn’t typing speed or commit frequency. It’s judgment and patience. They know which changes are worth making and which changes will look foolish in six months. They know which abstractions will last and which will be torn out next quarter.

Buffett’s company, Berkshire Hathaway, has outperformed the market for decades by doing less, not more. The principal engineer outperforms the rest of the team not by writing more code, but by writing the right code.

The market rewards activity in the short term and wisdom in the long term. Software rewards the same.

Market Efficiency: The Myth of the Perfect System
#

The efficient market hypothesis says that stock prices reflect all available information. If a stock is undervalued, someone will buy it and push the price up. If it’s overvalued, someone will sell it and push the price down. In an efficient market, you can’t consistently beat the market because the market already knows everything you know.

Markets aren’t perfectly efficient. They’re efficient enough to humiliate most people who think they can beat them.

Software systems aren’t perfectly reliable. They’re reliable enough to humiliate most teams who think they’ve eliminated all failure modes.

The efficient market hypothesis teaches investors to be humble. No matter how smart you are, the collective wisdom of millions of market participants has already been priced in. Your edge, if you have one, is small and temporary.

The software equivalent teaches engineers to be humble. No matter how well you design the system, the collective chaos of users, dependencies, networks, and hardware will find the gaps. Your reliability, if you’ve achieved it, is temporary and requires constant maintenance.

Investors who believe they’ve found a system that can’t lose discover that markets change. Engineers who believe they’ve built a system that can’t fail discover that failure modes evolve.

The market adapts. The system adapts. Stay humble or get humbled.

The Late Game: Algorithmic Trading
#

In modern markets, the majority of trading volume comes from algorithms. Machines that analyze data, identify patterns, and execute trades in microseconds. They don’t sleep. They don’t panic. They don’t get greedy or fearful. They follow their programming with mechanical precision.

The humans who built these algorithms don’t trade. They design the systems that trade. They monitor the systems, adjust parameters, and intervene when the algorithms encounter situations they weren’t designed for. But they don’t place orders themselves.

Software factories are algorithmic trading.

AI agents write code, run tests, deploy services, and respond to incidents with increasing autonomy. They don’t get tired. They don’t get bored. They don’t introduce off-by-one errors at 5 PM on a Friday.

The engineers who built these systems don’t write code for production. They design the systems that write code. They monitor the agents, adjust prompts, and intervene when the AI encounters problems it wasn’t trained for. But they don’t write the production code themselves.

Algorithmic trading didn’t eliminate human traders overnight. The first algorithms were simple: arbitrage, market making, basic pattern recognition. They handled the routine and left the complex decisions to humans. Over time, the algorithms got better and handled more of the complexity.

Software factories won’t eliminate human engineers overnight. The first AI agents are simple: boilerplate generation, test writing, basic bug fixes. They handle the routine and leave the complex decisions to humans. Over time, the agents will get better and handle more of the complexity.

The traders who survived the algorithmic revolution were the ones who learned to work with the algorithms, not against them. They moved up the stack, from executing trades to designing strategies. The engineers who will survive the AI revolution are the ones who learn to work with AI agents, not against them. They’ll move up the stack, from writing code to designing systems.

The Lesson
#

The stock market is a system for allocating capital to its most productive use. Prices emerge from millions of participants making independent decisions based on incomplete information. Nobody controls the market. Everyone participates in it.

Software development is a system for allocating engineering effort to its most productive use. Priorities emerge from teams making decisions based on incomplete information about users, technology, and the future. Nobody controls the outcome. Everyone contributes to it.

The market doesn’t care about your feelings. Your codebase doesn’t care about your intentions. Both respond to what you do, not what you mean to do.

In both domains, the winners are the ones who manage risk, compound knowledge, stay humble, and play the long game. The losers are the ones who chase hype, take on debt they can’t repay, confuse activity with progress, and believe this time is different.

This time is never different.

The market remains. The codebase remains. The best you can do is show up every day, make good decisions, and let compounding do its work.

If you’re still hand-trading in a world of algorithms, it’s time to automate. If you’re still hand-coding in a world of software factories, it’s time to build.

The market is open.

See also
#


Code Factories: The World of Warcraft Perspective

I create a character, spawn in a starting zone with a rusty sword and a vague quest to kill boars.

That’s World of Warcraft. It’s also my first day as a software developer.

In World of Warcraft, I choose a race and a class, then spend hundreds of hours leveling through zones, running dungeons, completing quests, and eventually organizing twenty-five people to coordinate a raid boss fight where one mistake kills everyone. The game is about progression, from nothing to something, from solo to coordinated, from chaos to precision.

Software development follows the same arc. The question is what level my team is playing at.

Leveling: Developer Growth
#

In WoW, every character starts at level 1. I have two abilities, no gear, and no idea what I’m doing. I kill wolves for experience. I die to enemies I’ll later defeat in one hit. I slowly unlock new abilities, talent points, and gear slots.

The leveling process isn’t a tutorial: it’s the actual game. Every level teaches me something about my class. By the time I reach the level cap, I’ve internalized dozens of mechanics through repetition.

Developer onboarding is leveling.

Junior developers start with two abilities: write code and Google errors. They fix simple bugs. They write basic functions. They die to merge conflicts they’ll later resolve in seconds.

Each project, each codebase, each production incident is experience points. Nobody becomes a senior developer by reading about architecture. People become senior developers by leveling through enough bad architectures to recognize a good one.

The WoW lesson: there are no shortcuts to the level cap. Boosted characters (players who pay to skip leveling) arrive at max level without understanding their class. Developers who skip fundamentals (jumping straight into frameworks without understanding the language, or into architecture without understanding systems) are boosted characters. They have the gear but not the skill.

Talent Trees: Specialization
#

At level 10, WoW lets me choose a specialization. A Paladin can be a tank, a healer, or a damage dealer. A Mage can specialize in fire, frost, or arcane. Each talent tree changes how the class plays entirely.

Career specialization is the same.

The backend talent tree: databases, distributed systems, API design, performance optimization. The frontend talent tree: UI components, state management, accessibility, rendering performance. The DevOps talent tree: CI/CD, container orchestration, monitoring, infrastructure as code.

In WoW, I can respec: pay gold, reset my talent points, and pick a new tree. In software, I can respec too. A backend developer can learn frontend. A frontend developer can learn DevOps. The cost isn’t gold: it’s time.

But WoW teaches something important about talent trees: depth beats breadth early on.

A player who spreads talent points across all three trees is weaker than one who commits to one. A developer who tries to master everything is weaker than one who goes deep on one domain first, then branches out later.

Specialize. Then generalize.

Questing: Tickets and Tasks
#

Quests in WoW are simple: accept task, complete objective, turn in for reward.

Kill ten wolves. Collect fifteen herbs. Escort an NPC across a danger zone. The objectives are clear. The rewards are predictable. The difficulty scales with level.

Tickets are quests.

A Jira ticket says: implement this feature, fix this bug, refactor this module. The objective is clear, or it should be. The reward is a shipped product.

But WoW also teaches that not all quests are worth doing.

Some quests send players across the map for minimal experience. Some quest chains look tedious but unlock a dungeon. The experienced player knows which quests to skip and which to prioritize.

The experienced developer knows the same thing. Not every ticket deserves the same investment. Some are quick wins with high impact. Some are rabbit holes that consume days for negligible value. The skill isn’t in completing the quest: it’s in choosing the right quests.

Dungeons: Sprint Delivery
#

At level 15, I enter my first dungeon.

Five players. One tank. One healer. Three damage dealers. A dungeon is a structured challenge that cannot be completed alone. I need a group, each performing their role, communicating through pulls and boss fights.

Dungeons are sprints.

A small team, a defined scope, a clear objective, a fixed timeframe. The tank sets the pace, pulling groups of enemies, controlling the flow. The healer keeps everyone alive, handling the unexpected, patching mistakes. The damage dealers execute, killing targets, following priority, managing resources.

A sprint works the same way.

The tech lead is the tank: they scope the work, set priorities, manage risk. The more senior developers are the healers: they catch issues in review, patch architectural problems, keep the codebase healthy. The team executes, writing features, fixing bugs, shipping code.

WoW teaches a critical dungeon lesson: the group moves at the pace of its weakest coordinated member.

One player who doesn’t know the strategy, doesn’t listen to the leader, or attacks the wrong target can wipe the group (get everyone killed). In a sprint, one developer who misunderstands the requirement, skips code review, or deploys without testing can derail the whole release.

Communication isn’t optional. It’s the difference between a smooth run and a wipe.

Raids: Large-Scale Projects
#

Raids are WoW’s endgame content.

Ten, twenty, or forty players coordinating to defeat bosses with complex mechanics. One person stands in the wrong spot and the entire raid dies. One healer misses a healing rotation and the tank falls. One damage dealer ignores a mechanic and the boss enrages.

Raids are large-scale projects.

Multiple teams coordinating across a shared objective. One service goes down and the whole product suffers. One team misses their deadline and the launch slips. One undocumented dependency surfaces and everything breaks.

The raid leader is the engineering manager.

They don’t play the game for the team: they coordinate. They call out mechanics before they happen. They adjust the strategy when something goes wrong. They decide who sits out when the group is too large.

Good raid leaders don’t micromanage individual players. They trust each player to execute their role while they focus on the big picture. Good engineering managers do the same: they set direction, remove blockers, and let engineers engineer.

WoW raids also teach preparation.

I don’t walk into a raid unprepared. I bring flasks, food buffs, enchanted gear, and consumables. I’ve studied the boss mechanics on forums and in videos. I’ve done the prerequisite attunement quests.

Large projects require the same preparation. I don’t walk into a rewrite without understanding the current system. I don’t migrate a database without load testing. I don’t launch a product without a rollback plan.

Underprepared raids wipe. Underprepared projects fail.

Tank, Healer, DPS: Team Roles
#

WoW’s holy trinity (tank, healer, damage dealer) is the foundation of every group activity.

The tank takes the hits. They stand in front of the boss, absorb damage, and keep threat so nobody else gets attacked. Without a tank, the group dies instantly.

The healer keeps everyone alive. They undo damage, cleanse debuffs, and resurrect the dead. Without a healer, the tank dies and the group follows.

The damage dealers kill the boss. They do the actual work of reducing the boss’s health to zero. Without damage dealers, the encounter never ends.

Engineering teams have the same trinity.

The incident responder is the tank: they take the hits when production goes down. They absorb the pressure, communicate with stakeholders, and keep the problem focused so others can work.

The code reviewer is the healer: they catch bugs before they ship, suggest improvements, and mentor through feedback. They keep the codebase healthy.

The feature developer is the damage dealer: they write the code that ships the product. They push the project forward, sprint after sprint.

Every role is essential. Every role is underappreciated by the other roles. Damage dealers complain about long queue times because there aren’t enough tanks and healers. Tanks and healers complain that damage dealers are replaceable.

In software, everyone has complained about both sides. Feature developers complain that code review is slow. Code reviewers complain that features are rushed. The truth is the same as in WoW: a team needs all three, and disrespecting any role is how the team wipes.

Gear and Item Level: Tools and Experience
#

In WoW, gear matters. A level 60 character in quest greens (common-quality gear from quests) loses to a level 55 character in raid epics (rare-quality gear from raids). Item level (the numerical representation of gear quality) determines whether I’m invited to groups, accepted into raids, or competitive in PvP.

But gear is a multiplier, not a substitute.

A player in the best gear who doesn’t know their rotation (the optimal sequence of abilities) does less damage than a skilled player in mediocre gear. The game rewards both (players need skill to earn gear, and gear amplifies skill) but skill is the foundation.

Developer tools and experience are gear.

A senior engineer with modern tooling (AI-assisted IDEs, comprehensive test frameworks, powerful debuggers) ships faster than one without. But a senior engineer with bad tools still outperforms a junior engineer with the best tools.

The mistake teams make is treating tools like gear drops (equip them and instantly get stronger).

Tools don’t work that way. Neither does gear.

In WoW, I earn gear through repeated runs, understanding mechanics, and gradual improvement. In software, I earn proficiency with tools through repeated use, understanding trade-offs, and gradual improvement.

Buying the most expensive IDE doesn’t make anyone a better developer. Equipping raid gear doesn’t make anyone a better player. Using the gear effectively does.

Boss Mechanics: Complex Bugs
#

Every raid boss in WoW has mechanics.

Don’t stand in the fire. Switch targets when extra enemies spawn. Spread out during the explosion. Stack up during the healing phase. Each mechanic is a rule. Break a rule and the group takes damage. Break enough rules and the group wipes.

Complex bugs have mechanics too.

The race condition only triggers under concurrent load. The memory leak only appears after 48 hours of uptime. The null pointer only occurs when the user has an empty cart and clicks checkout twice. Each condition is a rule. Satisfy the right combination and the bug reproduces.

WoW teaches a specific approach to boss mechanics: learn the fight, don’t brute-force it.

I don’t defeat a boss by throwing myself at it repeatedly, hoping for better luck. I study the mechanics, adjust my strategy, and execute precisely. A boss that takes 50 wipes to learn might die in a single attempt the next week with the right approach.

Debugging complex bugs is the same.

I don’t fix a bug by randomly changing code until it works. I read the logs, reproduce the issue, identify the conditions, and fix the root cause. A bug that takes a week to diagnose might be fixed in one line once I understand the mechanic.

The raid strategy for new bosses: watch a guide, learn the phases, practice the execution. The debugging strategy for new bugs: read the stack trace, identify the phase, fix the condition.

Wipe Recovery: Incident Response
#

In WoW, a wipe means everyone dies.

The boss resets. The group runs back. The resurrection timer ticks. I repair my damaged gear, rebuff, and try again.

What separates good raid groups from bad ones isn’t whether they wipe; everyone wipes. What separates them is how they recover.

Bad groups rage in voice chat. They blame the healer, the tank, the damage dealers. They argue about whose fault it was while the respawn timer counts down. They waste five minutes on blame before trying again. And they wipe again, because they didn’t learn anything.

Good groups skip the blame. Someone calls out what went wrong (“the healer got silenced during the area-of-effect phase”) and the group adjusts. They try again in thirty seconds. They might wipe again, but they wipe to a different mechanic, which means they’re learning.

Incident response is wipe recovery.

A production outage is a wipe. Something broke. Users are affected. The system needs to recover.

Bad incident responses are blame-heavy. “Who deployed this?” “Why wasn’t this tested?” “Who approved this change?” The questions are valid but the timing is wrong. The team is still in combat. Fix the issue first. Do the post-mortem later.

Good incident responses are diagnostic. “What changed?” “What’s the error rate?” “When did it start?” The group focuses on understanding and fixing, not assigning fault. The post-mortem comes after the system is healthy (in WoW terms, after the boss is dead).

The WoW lesson: wipe, learn, adjust, try again. The speed of iteration determines the speed of progression.

Guilds: Engineering Organizations
#

In WoW, guilds are persistent groups of players who raid together, share resources, and build social bonds.

A good guild has clear leadership, a shared culture, and mutual respect. Players show up on time, prepared, and committed to the group’s success. They help each other gear up. They share strategies. They celebrate kills together.

A bad guild has drama. Loot disputes. Attendance problems. Players who show up unprepared, demand carries, and leave when they get what they want.

Engineering organizations are guilds.

The good ones have clear technical direction, a culture of code review, and mutual respect between teams. Engineers share knowledge, mentor juniors, and celebrate launches. They invest in shared infrastructure that benefits everyone.

The bad ones have politics. Turf wars over services. Engineers who hoard knowledge and resist review. Teams that optimize for their own metrics at the expense of the product.

WoW players know: the guild determines the experience more than the game.

A great guild makes mediocre content fun. A bad guild makes great content miserable. The same is true in software. A great team makes a boring product interesting. A toxic team makes an exciting product unbearable.

Choose the guild carefully. Or in hiring terms: choose the team carefully.

The Auction House: Package Registries
#

The Auction House is WoW’s economy. Players buy and sell items (crafting materials, gear, consumables) in an open market. Prices fluctuate based on supply and demand. Some players spend more time on the Auction House than in raids.

Package registries are the Auction House.

npm, PyPI, Maven Central, RubyGems: open markets where developers distribute code. Most of it is free, but the economics are the same. Supply and demand determine which packages thrive. Quality varies wildly.

WoW teaches caution with the Auction House. That cheap flask might be underpriced for a reason. That epic bind-on-equip item might be a scam.

npm teaches the same caution. That package with 10,000 weekly downloads might have a security vulnerability. That library with the slick README might be abandonware. The left-pad incident was an Auction House crash: a critical commodity disappeared and the market panicked.

The WoW player’s defense: know the market, check prices, don’t buy suspicious deals. The developer’s defense: audit dependencies, check maintenance history, don’t install packages with three stars and no recent commits.

Addons: Developer Tooling
#

WoW’s addon system lets players customize their UI and extend their gameplay. Damage meters, boss mod warnings, raid frames, loot council tools: the default UI works, but serious players run dozens of addons.

Developer tooling is the addon ecosystem.

Linter, formatter, pre-commit hooks, custom IDE snippets, shell aliases, tmux configurations: the default development environment works, but serious developers customize extensively.

In WoW, the player who refuses to install boss mods dies to mechanics they could have seen coming. In software, the developer who refuses to use a debugger steps through logs they could have inspected visually.

But WoW also teaches addon discipline.

Too many addons cause conflicts, crashes, and performance problems. Players who install every addon they find spend more time configuring their UI than playing the game. The best players use a focused set of addons that solve specific problems.

Developer tooling needs the same discipline. A developer who spends more time configuring tools than writing code has lost the plot. The best toolchains are minimal, focused, and reliable.

Professions: Side Projects and Tooling
#

In WoW, characters can learn professions: blacksmithing, enchanting, engineering, alchemy. These secondary skills let players craft items, enhance gear, and create consumables.

Professions don’t advance the main quest. They don’t give experience. But they make the main quest easier.

Internal tooling is professions.

CLI tools, build scripts, code generators, monitoring dashboards: they don’t ship features, but they make shipping features faster. A team that invests in professions (that builds internal tools) levels faster than one that doesn’t.

The WoW lesson: max professions early.

A blacksmith who starts crafting at level 1 has far better gear than one who starts at max level. A team that builds tooling from day one has far better productivity than one that starts tooling after the crunch.

Threat and Aggro: On-Call and Incident Management
#

In WoW, every NPC enemy has a threat table. Whoever generates the most threat gets attacked. Tanks generate threat intentionally. Damage dealers generate threat as a side effect of dealing damage. Healers generate threat by healing.

If a damage dealer generates too much threat, the boss turns and kills them. This is called pulling aggro. It’s almost always fatal.

Production incidents have threat tables.

The on-call engineer is the tank. They absorb the pressure, pages, alerts, user complaints, Slack messages. They hold threat so the rest of the team can work without distraction.

But just like in WoW, if someone pulls aggro (if a non-on-call engineer starts making changes in production, or a manager starts demanding real-time updates every thirty seconds) the incident gets worse. The wrong person has the boss’s attention.

The WoW solution: let the tank hold threat. The incident solution: let the on-call engineer own the response. Everyone else supports (provides context, runs commands when asked, stays available) but doesn’t grab aggro.

A damage dealer who pulls aggro doesn’t just kill themselves. The boss might cleave and kill the healer too. A developer who pushes an untested fix during an incident doesn’t just fail to resolve the issue: they might make it worse and take down another system.

Let the tank tank.

Enrage Timers: Deadlines
#

Many raid bosses have an enrage timer. After a fixed duration, the boss enters an enraged state: damage increases dramatically, new mechanics activate, and the raid will wipe within seconds.

The message is simple: be good enough, fast enough.

Software deadlines are enrage timers.

The quarterly OKR deadline. The conference demo. The enterprise client’s contract renewal date. These are fixed points in time after which the consequences escalate sharply.

WoW teaches that enrage timers create two strategies: out-gear the fight or out-skill the fight.

Out-gearing means coming back with better stats and burning the boss down before the timer. In software, out-gearing means adding more engineers, more resources, more hours, throwing bodies at the deadline.

Out-skilling means executing perfectly, minimizing wasted time, and maximizing output with the resources at hand. In software, out-skilling means good architecture, clean code, and efficient processes.

The WoW meta has swung between both strategies across expansions. In software, the meta swings between hiring blitzes and efficiency drives. The answer, as always, is both: enough gear to survive, enough skill to execute.

Grinding: Maintenance Work
#

In WoW, some activities are just grinding.

Reputation grinds. Daily quests. Material farming. Running the same dungeon for the thirty-seventh time because the trinket won’t drop. Nobody enjoys grinding. But grinding is how players progress.

Software maintenance is grinding.

Updating dependencies. Fixing flaky tests. Rotating credentials. Cleaning up log files. Refactoring code that works but is hard to read. Nobody launches a software career to update dependency versions. But the grind is how the factory keeps running.

WoW players who skip the grinding find themselves under-geared when new content drops. They can’t participate in the new raid because they didn’t do the preparatory work.

Teams that skip maintenance find themselves unable to ship when new features are needed. The dependency tree is two years out of date. The test suite takes forty minutes. The deployment process is manual and error-prone. They can’t ship because they didn’t do the preparatory work.

The grind isn’t glamorous. But it’s what separates the prepared from the unprepared.

Expansions: Major Rewrites
#

Every few years, WoW releases an expansion.

A new continent. New systems. New mechanics. Sometimes, old systems are completely rebuilt. Stats are squished. Abilities are pruned. The talent tree is redesigned. The game I knew is fundamentally changed.

Some changes are loved. Some are hated. Every expansion has players who threaten to quit and players who return after years away.

Major platform rewrites are expansions.

A migration from monolith to microservices. A transition from on-premise to cloud. A framework upgrade from v2 to v3. The system I knew is fundamentally changed.

Like WoW expansions, major rewrites are risky. They take enormous investment. They disrupt existing workflows. They might attract new users or they might alienate existing ones.

WoW’s approach to expansions is instructive: the core identity stays the same. Despite every expansion’s changes, WoW is still about questing, dungeons, raids, and gear. The systems change. The core doesn’t.

Successful rewrites do the same. The core business logic is preserved. The deployment infrastructure might change, the data store might change, the frontend framework might change, but the product’s purpose stays the same.

Don’t change what the game is about. Change how the game plays.

Heirloom Gear: Reusable Components
#

In WoW, heirloom items are special pieces of gear that scale with a character’s level.

I earn them on my max-level character and mail them to my alts, my alternate characters. A level 1 alt wearing heirloom gear is dramatically stronger than a level 1 character in normal gear. The investment I made on my main character pays dividends on every alt.

Design systems and shared libraries are heirloom gear.

A component library built by one team makes every subsequent team faster. A shared authentication module, a common logging framework, a standardized deployment pipeline: these are investments that pay dividends across the entire organization.

The WoW lesson: invest in heirlooms early.

Players who acquire full heirloom sets for their alts level twice as fast. Organizations that invest in shared infrastructure ship twice as fast. The upfront cost is real (farming the currency to buy heirlooms, or building a design system instead of shipping features) but the compound return is enormous.

The Late Game: Software Factories
#

In WoW’s late game, the most efficient guilds stop running content manually.

They sell raid carries, experienced groups that carry less-skilled players through content for gold. They run GDKP splits, systematic distribution of loot based on a bidding system. They have addon rotations that automate cooldown tracking, buff management, and consumable usage.

The game transitions from playing to orchestrating.

Software factories are the late game of development.

I stop writing code manually. I write specifications that AI agents implement. I stop running tests manually. I design verification systems that run automatically. I stop deploying manually. I build pipelines that ship code continuously.

Like WoW’s late game, this requires an enormous investment in infrastructure.

A guild can’t sell raid carries without first clearing the raid dozens of times. A team can’t run a software factory without first building the CI/CD, the testing infrastructure, the monitoring, and the AI tooling.

Guilds that try to skip to carry runs without learning the mechanics get exposed when the buyer notices they’re failing. Teams that try to skip to software factories without the infrastructure get exposed when the AI-generated code doesn’t work, doesn’t test, and doesn’t deploy.

Clear the raid first. Then sell the carry.

The Lesson
#

World of Warcraft is a game about progression through coordination.

I start alone, killing boars in a starting zone. I end in a raid of twenty-five, executing a complex dance of mechanics that requires every player to perform their role flawlessly. The satisfaction isn’t in the gear: it’s in the coordination.

Software development is the same game.

We start alone, fixing bugs in a codebase we don’t understand. We end in organizations of hundreds, shipping systems that require every team to perform their role flawlessly. The satisfaction isn’t in the code: it’s in the coordination.

In WoW, every expansion resets the gear but not the skill. The players who clear content first aren’t the ones with the best loot: they’re the ones who’ve been playing longest, who understand the mechanics deepest, who coordinate most tightly.

In software, every project is different but the fundamentals are the same. The teams that ship fastest aren’t the ones with the most tools: they’re the ones who’ve been building longest, who understand the trade-offs deepest, who coordinate most tightly.

If I’m still solo questing, it’s time to join a guild. If I’m still running dungeons, it’s time to raid. If I’m still equipping greens, it’s time to earn my epics.

For the Horde. Or the Alliance. Just pick a side.

See also
#


Code Factories: Or How I Learned to Stop Worrying and Build the Belt

I land on an alien planet with nothing but a pickaxe and a furnace.

That’s Factorio. It’s also my first day as a software developer.

In Factorio, I crash-land and must build a rocket to escape. I start by hand-mining iron ore, smelting it in a stone furnace, and crafting simple items. Within hours, I’ve built conveyor belts that carry ore automatically, assemblers that craft without me, and trains that shuttle materials across the map. The factory grows. I go from doing everything myself to watching machines do everything for me.

Software development is following the same trajectory. The question is whether I’m still hand-mining iron ore.

The Belt: The CI/CD Pipeline
#

In Factorio, the conveyor belt is the first automation I build. Instead of walking back and forth carrying ore, I lay down a belt and let it move resources while I do something else.

The CI/CD pipeline is the belt. Every time I push code, tests run, builds compile, deployments ship. I don’t walk the ore to the furnace anymore. The belt carries it.

Teams without CI/CD are the players who never unlock belts. They’re still carrying ore by hand, one commit at a time, manually deploying to servers, manually running tests. It works when the team is small. It doesn’t scale.

Assemblers: The Build System
#

After belts come assembling machines. I feed them ingredients and they output a product. I don’t craft gears by hand anymore (the assembler does it, faster and without mistakes).

Compilers, bundlers, transpilers: these are the assemblers. I feed them source code and they output runnable software. I used to manage dependencies by hand, include scripts individually, and pray the versions matched. Now the assembler handles it.

The parallel goes deeper. In Factorio, I quickly learn that one assembler isn’t enough. I need a chain: iron ore becomes iron plates, iron plates become gears, gears become transport belts. Each step is its own assembler, fed by belts from the previous one.

The build pipeline works the same way. Source code becomes transpiled code, transpiled code becomes bundled assets, bundled assets become container images, container images become deployed services. Each stage is an assembler in a chain. If one assembler is slow, the whole chain backs up. If one assembler breaks, nothing after it gets built.

Inserters: The Integration Points
#

Inserters are the quiet heroes of Factorio. They take items from belts and put them into assemblers, furnaces, and chests. They’re the glue between every machine.

Integration points in software are the inserters. APIs, webhooks, message queues, event streams: they move data between services. Nobody talks about them at conferences. But when an inserter stops working in Factorio, the assembler starves. When an integration point breaks in production, the service starves.

Most production outages aren’t caused by a broken assembler. They’re caused by a broken inserter, a misconfigured webhook, a timed-out API call, a corrupted message in a queue. The machines were fine. The connection between them failed.

The Main Bus: The Monorepo
#

As my Factorio factory grows, I face a critical design decision: how to organize my belts. Most experienced players converge on the same solution, the main bus.

A main bus is a wide highway of parallel belts carrying every resource I need, running in a straight line across my factory. I branch off production lines from the bus, pull what I need, and return byproducts. It’s not the most space-efficient design. It’s not the fastest. But it’s the most understandable, and in a game where my own factory can become incomprehensible, understandability is survival.

A monorepo is the main bus. All the code, all the services, all the shared libraries in one place, organized in a predictable structure. Teams branch off to build their services, pull shared dependencies from the bus, and contribute back. Like Factorio, the monorepo isn’t optimal in every dimension. But when a new developer joins and needs to understand how everything connects, they follow the bus. No archaeology required.

Teams that reject the main bus in Factorio end up with spaghetti, belts crisscrossing everywhere, impossible to trace, impossible to modify without breaking something. Teams that reject the monorepo end up the same way: dozens of microservices with undocumented dependencies, where nobody knows which service calls which, and changing one API breaks three things nobody knew existed.

Logistics Bots: The AI Agents
#

At some point in Factorio, I unlock logistic robots. Flying drones that carry items anywhere in my network. They don’t need belts. They don’t follow paths. I request an item, and a bot brings it.

AI coding agents are the logistics bots. I ask for a function, and the agent writes it. I ask for tests, and the agent generates them. I ask for a bug investigation, and the agent traces the stack. They don’t need me to lay down a belt first. They go directly to the source and bring back what I need.

But here’s what Factorio teaches about bots: they don’t replace belts. Players who try to run everything on bots discover that bots have a capacity limit. When the network gets busy, bots queue up, delivery times spike, and the factory starves. The best factories use bots for the weird, one-off requests and keep belts for the high-throughput, predictable flows.

The best engineering teams do the same. AI agents handle the ad-hoc tasks, the one-off scripts, the bug investigations, the documentation updates. But the core pipeline (the build system, the CI/CD, the deployment process) runs on belts. Predictable. Reliable. Fast.

The Ratios: The System Architecture
#

In Factorio, every recipe has precise ratios. To produce one science pack per second, I need exactly 1.25 assemblers making gears and 0.8 assemblers making copper cable. The math is deterministic. If I get the ratios wrong, I get bottlenecks. One belt backs up while another starves. Resources pile up where they’re not needed and run dry where they are.

System architecture has the same dynamics, just less precise. Every service has throughput limits. Every database has connection pool limits. Every queue has a maximum depth. If the authentication service can handle 100 requests per second but the API gateway is sending 200, there’s a bottleneck. The requests pile up. Timeouts cascade. Users see errors.

Factorio players solve ratio problems with calculators and spreadsheets. They plan their factory before they build it. Software engineers solve the same problems with load testing and capacity planning, or they should. Too many teams build first and measure later, then wonder why production is slow.

Biters: The Production Incidents
#

The alien natives in Factorio are called biters. They attack the factory in increasing waves, drawn by the pollution the machines produce. The more I build, the more they attack. I can ignore them for a while, but eventually they’ll overwhelm my defenses.

Production incidents are the biters. They come in waves, drawn by the complexity of the system. The more services I deploy, the more dependencies I add, the more incidents I attract. I can ignore them for a while, patch the symptom, restart the service, move on. But eventually they’ll overwhelm me.

In Factorio, the solution isn’t to stop building. It’s to build defenses: walls, turrets, artillery. In software, the solution isn’t to stop deploying. It’s to build defenses: monitoring, alerting, automatic rollback, chaos engineering.

The best Factorio players don’t just react to biter attacks. They proactively clear nests before they evolve. The best engineering teams don’t just react to incidents. They proactively eliminate failure modes before they cause outages.

Throughput vs Latency: The Eternal Trade-off
#

Factorio players eventually discover that throughput and latency are different things. A belt with 100 items per minute has high throughput but items take time to travel from one end to the other. A bot delivery is low throughput (one item at a time) but low latency (it goes straight there).

Microservices vs monoliths is the same trade-off. A monolith has high throughput; everything runs in the same process, no network calls. But change latency is high; I deploy the whole thing even if I changed one function. Microservices have low change latency; I deploy one service independently. But throughput suffers from network overhead, serialization, and distributed coordination.

Factorio doesn’t judge me for choosing bots over belts or belts over bots. It just shows me the consequences. Software architecture should work the same way. I choose my trade-offs, but I stay realistic about what I’m trading.

The Rocket: Shipping
#

The goal of Factorio is to launch a rocket. Everything I build (every belt, every assembler, every defense) exists to launch that rocket. The goal is easy to forget. Players spend hundreds of hours optimizing a single belt intersection, perfecting a circuit network, or making their factory look pretty. Meanwhile, the rocket sits unbuilt.

Software teams do the same thing. They refactor code that works fine. They migrate to the latest framework. They rebuild systems that don’t need rebuilding. Meanwhile, the product sits unshipped. The users sit unserved. The business sits unimproved.

Factorio teaches a simple lesson: the factory exists to launch the rocket, not the other way around. The code exists to ship the product. Every optimization that doesn’t serve the product is a belt to nowhere.

The Map: The Unknown Unknowns
#

When I start Factorio, the map is covered in fog. I don’t know where the iron is, where the oil is, or where the biters are nesting. I explore by walking into the fog, revealing terrain piece by piece. Sometimes I find a massive ore patch right next to my base. Sometimes I walk into a biter nest and die.

Software development is exploring a fog of war. I don’t know what the users want until I ship. I don’t know what the legacy system does until I try to change it. I don’t know what the dependency actually does until it breaks in production.

The Factorio solution to the fog of war is radar. I build radar stations that slowly reveal the map around them. Not all at once, but gradually, giving me visibility without requiring me to walk everywhere.

Observability is the radar. Logging, metrics, tracing, dashboards: they don’t eliminate the unknown, but they reveal it gradually. I can’t see everything. But I can see enough to make good decisions.

Pollution: Technical Debt
#

Every machine in Factorio produces pollution. Pollution spreads across the map and triggers biter attacks. More machines, more pollution, more attacks. Pollution is the cost of growth.

Technical debt is pollution. Every shortcut, every hack, every “we’ll fix it later” generates debt. Debt spreads through the codebase, making changes harder, triggering bugs, slowing development. More code, more debt, more incidents.

I can’t eliminate pollution in Factorio without eliminating production. I can’t eliminate technical debt without eliminating software. The key is management: build efficiently, clean up regularly, and invest in infrastructure that reduces the debt per feature shipped. Electric furnaces produce less pollution than steel furnaces. Good abstractions produce less technical debt than bad ones.

The Late Game: Software Factories
#

In the late game of Factorio, something interesting happens. I stop building things myself entirely. Instead, I design blueprints, templates for entire sections of factory. I place a blueprint and construction bots build the whole thing automatically. I’m no longer an assembler. I’m an architect.

Software factories are the late game of software development. I don’t write code. I write specifications. I don’t review code. I design verification systems. I don’t debug. I design healing systems.

Like Factorio’s late game, the software factory requires an enormous upfront investment. I need to have built the belts, the assemblers, the bots, the logistics network before I can stamp down blueprints. Software factories require CI/CD, testing infrastructure, monitoring, and AI agents before they can operate autonomously.

Players who try to skip to blueprints in Factorio without building the infrastructure first find that their construction bots can’t reach the build site, don’t have materials, or build the wrong thing. Teams that try to skip to software factories without the infrastructure find that their AI agents produce broken code, can’t deploy, and create more problems than they solve.

The Spidertron: Autonomous Agents
#

The Spidertron is Factorio’s ultimate vehicle. A walking base that I can remote-control, equip with rockets, and send into dangerous territory. It’s the end result of everything I’ve built: it uses the tech I researched, the weapons I crafted, the logistics network I established.

Autonomous AI coding agents are the Spidertron of software development. They roam the codebase, make changes, run tests, deploy code, all while I watch from the map. But like the Spidertron, they’re only as good as the infrastructure behind them. A Spidertron without researched weapons is a walking target. An AI agent without a testing infrastructure is a liability.

The Lesson
#

Factorio is a game about building something that builds itself. I start by doing everything manually. I end by watching machines do everything for me. The satisfaction isn’t in the automation itself: it’s in designing a system that works, that’s elegant, that grows.

Software development is the same game. I start by writing code manually. I end by designing systems that write, test, and deploy code without me. The satisfaction isn’t in the code: it’s in the factory.

If I’m still hand-crafting every iron gear, it’s time to build my first assembler. If I’m still carrying ore by hand, it’s time to lay down a belt. If I’m still reviewing every line of code myself, it’s time to build a verification system.

The factory must grow.

See also
#


Code Factories: The StarCraft Perspective

You start with four workers, a command center, and fog of war in every direction.

That’s StarCraft. It’s also your first day at a startup.

In StarCraft, you command one of three races (Terran, Protoss, or Zerg), each with radically different economies, armies, and strategies. You gather minerals and vespene gas, build structures, research upgrades, and produce units. You scout the opponent, react to their strategy, and try to win through superior economy, tactics, or both. The clock never stops. The other player never waits.

Building a software organization is the same game with different units. The question is which race you’re playing and whether you know it.

APM: Developer Productivity
#

In StarCraft, APM (actions per minute) is the raw measure of how fast a player can issue commands. Pros sustain 300+ APM over games that last 20 to 40 minutes. Beginners hover around 30.

But high APM doesn’t win games. Efficient APM does. A pro spends most of those actions on macro (building workers, expanding, producing units) and only the necessary actions on micro, controlling individual units in combat. A beginner wastes APM clicking the same unit six times or panicking during a fight.

Lines of code per day is the APM of software development. It measures activity, not impact. A developer who writes 500 lines in a day isn’t necessarily more productive than one who writes 50. The 50-line developer might have deleted 200 lines, simplified an abstraction, or prevented a week of debugging.

The StarCraft lesson: optimize for effective actions, not total actions. In code, optimize for value shipped, not code written.

Worker Production: Hiring
#

In StarCraft, the single most important thing a new player can learn is to never stop making workers. Workers gather resources. Resources fund everything else: units, buildings, upgrades. A player who stops producing workers at the five-minute mark will be economically crushed by one who didn’t, regardless of army composition or tactical skill.

Hiring is your worker production. Every engineer you add increases your resource gathering rate, the rate at which your team can design, build, and ship software. A team that stops hiring after its founding engineers will be outpaced by a team that kept recruiting, even if the founding team was brilliant.

But StarCraft also teaches that worker production has a ceiling. You can only send so many workers to a mineral patch before they queue up and waste time. In software, the ceiling is communication overhead. Add too many engineers to a project and they spend more time coordinating than building. Brooks said it decades ago in The Mythical Man-Month: adding people to a late project makes it later. StarCraft players learn it every game: there’s an optimal number of workers per base, and exceeding it wastes resources.

Expanding: New Teams and Services
#

In StarCraft, one base isn’t enough. The mineral patches deplete. Gas geysers run dry. To keep growing, you must expand, build a new command center, nexus, or hatchery at a new resource location.

Each expansion is a bet. It costs resources to build. It takes time to become profitable. And the expansion is vulnerable: spread across the map, harder to defend, exposed to attack.

Starting a new team or service is expanding. You invest resources (hiring, onboarding, infrastructure) in exchange for future throughput. The first team’s codebase, like a mineral patch, eventually becomes congested. Too many engineers working on the same service creates merge conflicts, deployment bottlenecks, and architectural compromises. A new team with its own service spreads the load.

But like StarCraft expansions, new teams are vulnerable. They don’t yet know the codebase, the domain, or the culture. They’ll make mistakes the first team already learned from. They’ll build things that duplicate or conflict with existing systems. And they require protection (mentoring, clear interfaces, architectural guidance) or they’ll be overrun by the complexity the first team already tamed.

StarCraft players know: expand when your main base is saturated, not when you’re under attack. Software leaders should know: create new teams when the current team is at capacity, not when the project is already late.

The Supply Cap: Organizational Scaling
#

In StarCraft, you can’t just build an infinite army. Every unit costs supply. Terran supply depots, Protoss pylons, Zerg overlords: each race has its own mechanism for increasing the supply cap. If you hit the cap, production halts. Your factories, barracks, and starports sit idle until you build more supply.

Organizational scaling has supply caps too. They just aren’t as explicit.

The first cap is communication. A team of 5 people has 10 communication channels. A team of 15 has 105. At some point, people spend more time talking than building, and adding another engineer actually decreases output.

The second cap is architecture. A monolith can support a certain number of contributors before merge conflicts, test suite times, and deployment coordination become unbearable. You need to split the monolith (build a pylon, if you will) to increase the cap.

The third cap is process. A small team doesn’t need sprint planning, architecture review boards, or release managers. A large team does. Each process is a supply depot: it costs resources to build but increases the number of people who can work together productively.

Teams that ignore the supply cap wonder why their army is small despite having plenty of factories. The factories are there. The supply isn’t.

Build Orders: Project Plans
#

Every StarCraft game begins with a build order, a planned sequence of actions for the first few minutes. Build a supply depot at 10 supply. A barracks at 12. A refinery at 13. Expand at the natural at 20.

Build orders aren’t rigid scripts. They’re opening principles, a sequence that has been proven to lead to a strong mid-game position. Players deviate when they scout something unexpected, but they always have a plan to return to.

Project plans are build orders. You don’t start building features randomly. You have a sequence: set up the repository, configure CI/CD, build the core domain model, add the API layer, implement authentication, deploy to staging. The order matters because each step depends on the previous one.

But just like in StarCraft, the build order only covers the opening. After the first few minutes, the game becomes dynamic. You react to what you see. You adapt to the opponent’s strategy. The build order gave you a strong position: it didn’t win the game.

Agile methodology is the StarCraft mid-game. You’ve executed your build order; the project is set up, the architecture is sound. Now you play reactively, adjusting to user feedback, market changes, and technical surprises. The build order got you here. Reaction wins the game.

Scouting: User Research
#

In StarCraft, if you don’t scout, you die. Period. A player who builds the wrong units because they didn’t know the opponent was going air gets crushed. A player who expands into a choke point the opponent already controls loses the expansion. Information is more valuable than any unit.

User research is scouting. If you don’t talk to users, watch them use your product, read their support tickets, and analyze their behavior, you’re building blind. You might be building the perfect counter to a strategy the opponent isn’t using. You might be expanding into territory nobody wants.

StarCraft players send a worker to scout at supply 13. They sacrifice a unit to gain information. Good software teams do the same: they sacrifice development time to talk to users, run usability tests, and analyze metrics. The cost of scouting is always less than the cost of building the wrong thing.

Tech Trees: Technology Choices
#

Every StarCraft race has a technology tree. You can’t build battlecruisers without a starport, a fusion core, and an armory. You can’t research stimpack without a tech lab on your barracks. Each technology unlocks new capabilities but requires investment in the prerequisite technologies.

Technology stacks are tech trees. You can’t deploy containers without a container runtime. You can’t run Kubernetes without understanding networking, DNS, and certificate management. You can’t implement real-time features without WebSockets, which requires understanding persistent connections, which requires understanding your load balancer’s timeout settings.

The StarCraft lesson about tech trees is simple: don’t tech too fast and don’t tech too wide.

Teching too fast means skipping army production to rush advanced technology. In StarCraft, this loses to an early attack. In software, this means spending months building infrastructure while shipping nothing. The business can’t wait for your perfect Kubernetes setup. Ship something with simpler tech and upgrade later.

Teching too wide means researching every upgrade simultaneously. In StarCraft, this spreads resources thin and leaves you weak everywhere. In software, this means adopting every new framework, database, and tooling option. Your team can’t be experts in everything. Pick a path through the tech tree and commit to it.

Unit Composition: Team Composition
#

In StarCraft, army composition matters more than army size. A player with 50 marines loses to a player with 10 banelings and 20 zerglings. A player with 20 stalkers loses to a player with 10 immortals. Each unit has strengths and weaknesses, and the right combination is stronger than any individual unit.

Team composition works the same way. Ten frontend developers can’t build a backend service. Ten senior engineers can’t ship quickly without junior engineers handling the simpler tasks. Ten generalists can’t match a team with specialized expertise in security, performance, and DevOps.

The ideal StarCraft army mixes unit types that cover each other’s weaknesses. Marines deal high damage but are fragile; medivacs keep them alive. Zealots are strong in close combat but slow; sentries create force fields to trap enemies.

The ideal software team mixes skills the same way. Backend engineers build the services. Frontend engineers build the interfaces. DevOps engineers build the infrastructure. Security engineers build the defenses. No single role can win the game alone.

Multitasking: Context Switching
#

StarCraft demands multitasking. While your army fights at the front, your economy must keep producing at home. While you scout the enemy, your upgrades must keep researching. Drop one ball and the whole performance suffers.

Software development demands the same. While you write code, production issues arise. While you debug a problem, meetings are scheduled. While you plan the next sprint, the current sprint falls behind.

StarCraft players learn to use control groups, binding units and buildings to hotkeys so they can jump between tasks instantly. Press 1, manage the army. Press 2, build workers. Press 3, research upgrades. The hotkeys don’t reduce the number of tasks, but they reduce the cost of switching between them.

In software, your control groups are your tools and workflows. A good IDE setup lets you switch between files instantly. A good terminal setup lets you switch between environments instantly. A good project management tool lets you switch between tasks instantly.

But StarCraft also teaches that there’s a hard limit to multitasking. Even pros can’t manage five simultaneous drops, a base race, and an upgrade timing all at once. They prioritize. They let minor fights play out automatically while they manage the critical ones.

Software developers need to learn the same lesson. You can’t context-switch between five tasks and do any of them well. Prioritize the critical path. Let minor tasks wait. Not everything is a drop in your mineral line.

Creep Spread: Codebase Quality
#

The Zerg provide the clearest metaphor for codebase quality. Creep is the organic substance that Zerg structures generate, spreading across the ground like a living carpet. Zerg units move faster on creep. Zerg structures can only be built on creep. Creep tumors extend the network, and a well-spread creep carpet gives the Zerg player vision, mobility, and territorial control.

Codebase quality is creep spread. Good test coverage, clear documentation, consistent naming conventions, and well-defined interfaces: these are your creep tumors. Each one extends the area where future development moves faster. New engineers onboard more quickly on a well-documented codebase. Refactoring is safer with comprehensive tests. Features ship faster when the interfaces are clean.

Terran and Protoss players hate creep. It gives the Zerg vision and speed in territory that should be neutral. Technical debt is the reverse: it gives bugs and confusion territory that should be clean. Every hardcoded value, every undocumented assumption, every god class is an area where development moves slower and bugs move faster.

The Zerg lesson: invest in creep spread early and often. A Zerg player who tumors aggressively in the first five minutes controls the map in the tenth. A team that invests in code quality early ships faster in the long run. Not because quality is its own reward, but because quality compounds.

Ladder Anxiety: Imposter Syndrome
#

Every StarCraft player knows ladder anxiety. That feeling before clicking the “Find Match” button, the fear of losing, of being exposed as a fraud, of dropping a league and having everyone see.

The anxiety is universal. Grandmasters feel it. Day9 famously talked about how terrified he was to play his placement matches, and he was one of the best players in the world.

Imposter syndrome in software is ladder anxiety. The fear of submitting a pull request because your code might be wrong. The fear of speaking up in an architecture meeting because your idea might be bad. The fear of applying for a senior role because you might not be good enough.

StarCraft players overcome ladder anxiety the same way every time: by playing. Not by studying build orders. Not by watching replays. By clicking the button and playing the game. Losses stop hurting after the hundredth one. Wins start feeling earned.

Software developers overcome imposter syndrome the same way. Submit the pull request. Speak up in the meeting. Apply for the role. The fear doesn’t go away. You just learn that it’s not predictive of outcome.

Cheese: Shortcuts and Hacks
#

Every StarCraft player has been cheesed. A cannon rush in your mineral line. A proxy barracks outside your base. A six-pool of zerglings that arrives before you have any defense.

Cheese strategies are high-risk, high-reward. They win quickly against unprepared opponents and lose decisively against prepared ones. Nobody wins a tournament with cheese alone. But everyone encounters it, and everyone has to learn to defend against it.

Technical shortcuts are cheese. Copy-pasting code from Stack Overflow without understanding it. Deploying directly to production without tests. Hardcoding a configuration value because you’re in a hurry.

Like StarCraft cheese, technical shortcuts work in the short term. The code runs. The feature ships. The deadline is met. But the opponent (in this case, future you or your teammate) is unprepared for the consequences. The hardcoded value becomes a production incident. The untested code breaks in an edge case. The copy-pasted solution has a security vulnerability.

StarCraft players learn to scout for cheese early and defend against it. Software developers need to do the same. Code review catches shortcuts before they merge. Linting and static analysis catch them before they deploy. The defense doesn’t have to be elaborate, just present.

The Late Game: Software Factories
#

In the late game of StarCraft, something shifts. Individual battles matter less than economy and production. The player with more bases, more production facilities, and better upgrades wins through attrition. They replace losses faster. They tech-switch faster. They recover from setbacks faster.

Software factories are the late game of software development. Individual code contributions matter less than the systems that produce them. The team with better CI/CD, better testing infrastructure, better monitoring, and better AI tooling ships faster. They recover from incidents faster. They adapt to changing requirements faster. They replace departing engineers faster.

In StarCraft, the late game rewards the player who invested in economy during the early and mid game. The player who cut workers to build a bigger army might win a battle, but they lose the war. In software, the late game rewards the team that invested in infrastructure when it would have been faster to just ship features. The team that skipped tests to hit a deadline might ship faster this quarter, but they slow down every quarter after.

Playing the Race: Choosing Your Stack
#

In StarCraft, race selection defines everything. Terran is positional and mechanical (siege tanks, bunkers, planetary fortresses). Protoss is elegant and powerful (expensive units, warp-in mechanics, force fields). Zerg is swarm-like and reactive (expendable units, rapid reinforcement, creep spread).

Each race rewards a different mindset. A player who tries to play Terran like Zerg (aggressive, expendable, swarm-like) loses. A player who tries to play Protoss like Terran (defensive, positional, slow) loses. You have to play your race’s strengths.

Technology stacks are races. A Python/Django stack rewards rapid development and convention-over-configuration (Protoss-like elegance). A Java/Spring stack rewards enterprise robustness and type safety (Terran-like positional strength). A Go microservices stack rewards simplicity, concurrency, and operational efficiency (Zerg-like speed and resilience).

Teams that try to fight their stack’s nature lose. Using Python for high-performance computing. Using Java for rapid prototyping. Using Go for enterprise business logic. Each can work, but each is fighting the race’s design.

Play your race. Or in StarCraft terms: pick Random, learn all three, and choose the one that fits the game you’re playing.

The GG: Knowing When to Refactor
#

In StarCraft, there’s a moment every player must learn to recognize: the game is lost. Your economy is destroyed. Your army is gone. Your opponent has three bases to your one. Fighting on is admirable but wasteful.

Good players type “gg” (good game) and leave. Not because they’re quitters. Because the time spent losing a doomed game is better spent starting a new one where they can apply what they learned.

The software equivalent is knowing when to rewrite. Not every codebase can be saved. Sometimes the technical debt is so deep, the architecture so convoluted, the assumptions so wrong, that incremental improvement is slower than starting fresh.

But here’s where the StarCraft analogy gets tricky. In StarCraft, a new game starts clean. In software, a rewrite inherits the constraints of the existing system: the users, the data, the integrations. The “gg” in software isn’t abandoning the project. It’s recognizing that the current implementation has reached the point of diminishing returns and a new approach will serve everyone better.

StarCraft players learn to recognize the threshold through experience. They don’t quit at the first setback. They quit when recovery becomes impossible. Software teams need the same judgment. Don’t rewrite at the first sign of technical debt. Rewrite when the debt makes every change slower than a fresh start would be.

The Lesson
#

StarCraft is a game of simultaneous decisions under time pressure. You manage economy, technology, army composition, map control, and reconnaissance all at once, while an opponent does the same and tries to disrupt you. The best players aren’t the ones with the fastest hands: they’re the ones who make better decisions about where to invest their attention.

Software development is the same game. You manage features, infrastructure, team composition, code quality, and user feedback all at once, while the market changes and competitors advance. The best teams aren’t the ones who write the most code: they’re the ones who make better decisions about where to invest their resources.

In StarCraft, every game is different. The map changes, the opponent changes, the meta shifts. But the fundamentals remain: workers gather resources, buildings unlock technology, scouting reveals information, and good decisions win games.

In software, every project is different. The domain changes, the team changes, the technology shifts. But the fundamentals remain: engineers build features, infrastructure enables scale, user research reveals needs, and good decisions ship products.

If you’re still playing single-player, it’s time to scout the map. If you’re still on one base, it’s time to expand. If you’re still manually producing every unit, it’s time to set a rally point.

GL HF.

See also
#