<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://roll.bybacon.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://roll.bybacon.com/" rel="alternate" type="text/html" /><updated>2026-10-21T18:30:52+00:00</updated><id>https://roll.bybacon.com/feed.xml</id><title type="html">bacon roll</title><subtitle>Software, teams, and the craft of building things that work.</subtitle><author><name>alex berger</name></author><entry><title type="html">Who’s Actually Out of a Job?</title><link href="https://roll.bybacon.com/2026/10/21/whos-actually-out-of-a-job.html" rel="alternate" type="text/html" title="Who’s Actually Out of a Job?" /><published>2026-10-21T18:30:00+00:00</published><updated>2026-10-21T18:30:00+00:00</updated><id>https://roll.bybacon.com/2026/10/21/whos-actually-out-of-a-job</id><content type="html" xml:base="https://roll.bybacon.com/2026/10/21/whos-actually-out-of-a-job.html"><![CDATA[<p>I ended the <a href="https://roll.bybacon.com/2026/10/14/vibes-dont-maintain.html">last post</a> with a question: if the tool can do my job, what was I still for?</p>

<p>The people asking were mostly managers. It’s worth looking at what they thought my job was - and what they thought theirs was - because I think they had both backwards.</p>

<hr />

<p>Start with the claim itself: a new tool will let people build software without understanding software. It’s not new. No-code wasn’t tried only once. It has been tried in every decade since computers got a mouse, and it died every time.</p>

<p>Microsoft FrontPage, 1996. Drag a box, type some text, click publish. Nobody would ever have to code a website again. That’s why web development as a profession ended in 1997.</p>

<p>What actually happened is that FrontPage produced websites that looked like websites and behaved like a stack of pictures. The moment someone wanted a contact form that did something, or a page that changed based on who was looking at it, a developer got called. The tool collapsed the easy part to zero and left the hard part exactly where it was. Dreamweaver - FrontPage for people with taste - did the same thing with nicer defaults. Flash let you draw your way to a website that moved, right up until the platform itself was switched off and every one of those sites went dark on the same day.</p>

<p>PowerPoint was never sold as a way to build software, and it never became one. What it became was the tool for click-dummies. Screen, arrow, screen, arrow, and you had an app you could click through in a meeting. Click-through prototypes - Balsamiq, InVision, later Figma - were the same idea with better fidelity. Or again, for the people with taste. The deck was never wrong, just incomplete. It just described a surface of the happy flow, and every arrow hid a hundred decisions about what happens when the thing on the other side of it fails. To be fair, nobody ever cared about the error messages anyways.</p>

<p>Then Stack Overflow Driven Development. Search the error, paste the top answer, move on. It freed us from writing the code and, more importantly, from the guilt of not understanding it. If the internet hadn’t said it was wrong, it was good enough. The rest was up to the compiler. Those codebases worked right up until they didn’t, and then nobody could (or wanted to) say why any given block was there.</p>

<p>Each of these had its moment, its conference talks, and its “developers are over” headlines. Each one quietly ended up back in the hands of the developers it was meant to replace - or ended, full stop.</p>

<hr />

<p>Agents like Claude Code, Codex, or Copilot are the same thing with the delay removed.</p>

<p>FrontPage needed you to lay out the page. PowerPoint needed you to draw the arrows. Stack Overflow needed you to find the right answer and glue it in. An agent takes a sentence and does all three, in minutes, and the result runs.</p>

<p>That’s the real change. Not what’s possible - how fast and how cheaply you reach the point where it <em>looks</em> done. That point used to be weeks away. Now it’s an afternoon. The distance between “looks done” and “is done” hasn’t moved. It just shows up sooner and more convincingly, and the bill for crossing it arrives later and bigger.</p>

<p>An agent can produce far more than FrontPage or PowerPoint ever could. But it shares one trait with the managers: it knows a nice-looking UI sells better than an hour-long monologue about the state machine behind an error case. Sex sells. Ask for an app and you get the parts that demo well.</p>

<p>So someone has to tell it to build that state machine, its states how they transition. Then someone has to check that it’s correct. That’s just one example out of hundreds. A human developer built those things for two reasons: they knew they had to be built, and they knew it would come back to them if they didn’t. It was part of the job. The agent doesn’t care. It will tell you it built what you told it to, and it did. Thinking outside the box is your job.</p>

<hr />

<p>Now the part the managers got backwards.</p>

<p>What did they think they brought to the table? The idea. The business case. The pitch. The deck with the arrows. What did they think we developers brought? Typing. The slow, expensive conversion of their vision into something that runs.</p>

<p>If that were true, they’d be right to worry about us. The typing is what got cheap.</p>

<p>But look at what my restaurant friend produced with an agent in an afternoon: a deck with arrows that runs. That is the manager’s deliverable, delivered by the tool. Idea to surface, the first-meeting demo - the thing that used to justify a role - now costs nothing and requires no one.</p>

<p>What it didn’t produce is everything underneath. The seatbelts. The understanding of why it was built the way it was. The ability to open the hood when it breaks. That part didn’t get cheaper. It got rarer, because fewer people on the way to the demo had to touch it. It’s what we developers brought to the table all along, and we’re still here, still bringing it.</p>

<p>Here’s my hypothesis, then: AI makes the manager more redundant than the engineer.</p>

<p>Engineers can come up with ideas too. We always could but we were busy. If we really don’t write the code anymore, that’s a lot of afternoons freed up to notice what’s missing, sketch it, and put it in front of someone. We can sell them - a working thing is the most persuasive pitch there is, and we can produce one as fast as anyone now. And when it goes wrong, we can fix it. That last one is the whole difference. The manager with an agent gets a click-dummy. The engineer with an agent gets a product, and keeps it running.</p>

<hr />

<p>So what does the engineer actually bring, if not the typing?</p>

<p>A stack they know deeply. Not because Rails is better than Spring Boot or Laravel in the abstract, but because when something breaks at eleven at night you have to know where to look, and that knowledge doesn’t come out of a prompt.</p>

<p>Behavior written down before the code, as scenarios that run. If the <em>what</em> is unambiguous, the <em>how</em> is easier to read, easier to hand to an agent, and easier to verify when it comes back. The right architecture does the same for structure: the moving parts have names and places.</p>

<p>And a record. Our stories, specs, and decisions are markdown files in git, kept with <a href="https://github.com/bybacon/bacon-tracker">bacon-tracker</a>. Markdown is human-readable and trivially safe to keep - and a folder of well-written markdown is enough to rebuild the whole thing from scratch, by a person or by whatever agent is current in three years. The code is disposable. The intent isn’t.</p>

<p>None of that is new either. It’s what engineers did when the typing was the slow part, too. The tools just stripped away enough of the typing that you can finally see it was never the job.</p>

<hr />

<p><em>bacon-tracker is open source: <a href="https://github.com/bybacon/bacon-tracker">github.com/bybacon/bacon-tracker</a>.</em></p>]]></content><author><name>Alex</name></author><category term="xp" /><category term="ai" /><category term="teams" /><summary type="html"><![CDATA[Every decade has had a tool that promised software without developers. The hard part never moved. What AI actually makes cheap is the part managers thought was theirs - and engineers can do that part too.]]></summary></entry><entry><title type="html">Vibes Don’t Maintain</title><link href="https://roll.bybacon.com/2026/10/14/vibes-dont-maintain.html" rel="alternate" type="text/html" title="Vibes Don’t Maintain" /><published>2026-10-14T19:00:00+00:00</published><updated>2026-10-14T19:00:00+00:00</updated><id>https://roll.bybacon.com/2026/10/14/vibes-dont-maintain</id><content type="html" xml:base="https://roll.bybacon.com/2026/10/14/vibes-dont-maintain.html"><![CDATA[<p>Since ChatGPT took off, people have been coming up to me to say some version of “you people will be out of a job soon.”</p>

<p>Most of them were managers. They knew it was provocative, and they wanted to see how I’d react - partly to test the waters on whether this was a real scenario. What they had in common was that none of them had a clear idea of what software development actually is. Not what it looks like from the outside. What it is.</p>

<p>Last week I got the best version of that conversation I’ve had so far.</p>

<hr />

<p>A friend of mine owns a restaurant. He told me he’d built an app for it with Claude Code - a web app to manage tasks and processes for his staff. He was proud of it, and he had every right to be. He had never written a line of code and he had a thing on a screen that did what he described.</p>

<p>I had a look. It was nice. Clean layout, sensible flow, data that persisted between page loads so it felt like a working system.</p>

<p>Then I started poking. No responsive layout - it broke on the phones his staff would actually use. No dark mode 🏴‍☠️. No login, so no notion of who did what. No settings. No translations, in a kitchen where half the team doesn’t speak the language the app was written in. No error states. No handling of the empty case, the duplicate case, the two-people-edit-the-same-thing case. The data “persisted” in a way that would survive a refresh and not much else.</p>

<p>It was a click-dummy. A prototype. A perfectly good proof of concept for a first round of conversations about whether the idea holds up - which is a real and valuable thing to have.</p>

<p>Then he asked me if I could host it for him and do ops.</p>

<hr />

<p>This is the biggest misunderstanding people have about software, and it has nothing to do with AI.</p>

<p>People see the surface. They see the parts that work. They don’t see the parts that run when something goes wrong, the parts that exist to stop things going wrong, or the parts that have never once executed in production because they’re there for a worst case someone sat down and imagined.</p>

<p>The seatbelt and the airbag in your car have, with luck, never done anything. That doesn’t make them useless. You don’t buckle up because the law says so or because the car beeps at you. You buckle up because you understand that one day you might need it. Software is mostly seatbelts. The happy path - the thing the demo shows - is the smallest part of the codebase.</p>

<p>My friend, understandably, didn’t see that. His read was that the app works 100% as intended, so 90% of the work is done. The rest is hosting. And I shouldn’t overcomplicate it.</p>

<hr />

<p>Here’s how that version plays out.</p>

<p>The prototype came almost free and almost instantly. He decides the product is done. He might even get it in front of users - his staff start using it for real shifts, real tasks, real schedules.</p>

<p>Then something goes wrong. The database file corrupts. A dependency update breaks something. Someone finds the app on the open internet and has a look around. An edge case fires that nobody wrote down. Or my personal favorite: daylight saving time, and every shift in the schedule is off by an hour.</p>

<p>Everything goes boom.</p>

<p>He doesn’t know what he built. He doesn’t know why it was built the way it was - the reasoning lived in a chat session that’s gone. He doesn’t know what to look for or where to start looking. There is no spec, no test, no document, no commit message that explains the intent of anything.</p>

<p>At that point he has two options. Find someone to fix it and prepare to hand them all his money, because the first week of that engagement is pure archaeology. Or flee the country.</p>

<p>That is what “vibes don’t maintain” means in practice. The vibe got him to the demo. Nothing carried forward from there.</p>

<hr />

<p>None of this is “don’t use AI.” We use it every day. But two things are true at the same time.</p>

<p>First: AI does not make you a software engineer if your background is baking bread, any more than your oven at home makes you a chef. It makes execution cheap. It does nothing about knowing what to execute, or what to do when the execution fails.</p>

<p>Second: shit in, shit out. If the input is a loose description of what the happy path looks like, the output is a happy path. The AI will not invent the seatbelts for you. It doesn’t know you’ll need them, because you didn’t.</p>

<p>What survives a boom is not the code. It’s the record of what the code was supposed to do - the stories, the specs, the decisions - written down somewhere a human or an agent can read them back. Ours are markdown files in git, kept with <a href="https://github.com/bybacon/bacon-tracker">bacon-tracker</a>. My friend has a chat history he can’t find anymore.</p>

<p>That record is what you’re paying for. Not the click-dummy.</p>

<p>There’s a second question hiding in his request, and in all those “you’ll be out of a job” conversations: if the tool really can do my job, what exactly was I still for? But that’s for another day.</p>

<hr />

<p>I called him the next day. I told him I got myself a Thermomix - the one with AI - and was planning to open a restaurant the week after.</p>

<p>He laughed. Then he went quiet for a second.</p>

<p>I hope he got it. But knowing him I think he did not.</p>]]></content><author><name>Alex</name></author><category term="xp" /><category term="ai" /><summary type="html"><![CDATA[A friend built an app for his restaurant with Claude Code and asked me to host it. What he had was a click-dummy. The parts of software you can see are the cheap part. The parts you can't are the product.]]></summary></entry><entry><title type="html">XP Is More Important Now Than It Was Before AI</title><link href="https://roll.bybacon.com/2026/10/07/xp-with-ai.html" rel="alternate" type="text/html" title="XP Is More Important Now Than It Was Before AI" /><published>2026-10-07T17:00:00+00:00</published><updated>2026-10-07T17:00:00+00:00</updated><id>https://roll.bybacon.com/2026/10/07/xp-with-ai</id><content type="html" xml:base="https://roll.bybacon.com/2026/10/07/xp-with-ai.html"><![CDATA[<p>There’s a common assumption floating around that AI coding tools make software engineering practices like BDD, pairing, and XP less necessary. The machine writes the code, so the ceremony around how humans collaborate to produce code matters less.</p>

<p>This assumption is backwards.</p>

<p>AI makes execution cheap. It makes the wrong thing fast to build. And it makes the cost of unclear requirements higher than it has ever been.</p>

<p>The practices that XP gave us - writing behavior first, pairing to share understanding, framing stories before starting work - exist precisely to produce clarity before execution. When execution was slow and expensive, fuzzy requirements were tolerable because you had time to correct course. Now execution is fast and cheap, and fuzzy requirements produce wrong software at previously impossible speed.</p>

<p>XP is the meta-skill for the AI age.</p>

<hr />

<p>Let me be specific about what I mean.</p>

<p><strong>BDD when an AI is writing your code</strong></p>

<p>Behavior-driven development always had two jobs. The obvious one: produce test coverage. The less obvious one: force a conversation about what the software should actually do before anyone writes any code.</p>

<p>The second job is now more important than the first.</p>

<p>When you write a Gherkin scenario - <code class="language-plaintext highlighter-rouge">Given a user has an empty cart, When they add an item, Then the cart total reflects the item price</code> - you are not primarily writing a test. You are making the expected behavior concrete enough that anyone, human or machine, can implement it unambiguously.</p>

<p>An AI given a good set of BDD scenarios will implement them correctly. An AI given a vague story (“add cart functionality”) will implement something that seems plausible, tests green, ships to staging, and fails the demo because nobody specified what happens to the cart total when a coupon code is applied, or when the same item is added twice, or when the item goes out of stock between add and checkout.</p>

<p>This was always the failure mode. AI just accelerates it.</p>

<p>The teams I’ve seen do this well treat their BDD scenarios as the authoritative source of truth for what they’re building, not as an afterthought that follows implementation. They write the scenarios in the discovery session, before any code exists, with the product owner in the room. Then they hand those scenarios to the AI.</p>

<p><strong>Pairing when one pair is an AI</strong></p>

<p>Pairing changed when AI became a capable programming partner. You can now pair with something that knows every library, never needs to look up syntax, is available at 2am, and doesn’t get frustrated with your keyboard shortcuts.</p>

<p>What it doesn’t do: push back on your approach. Ask if you’ve considered the edge case. Notice that you’ve been working toward the wrong abstraction for the last hour. Say “wait, what are we actually trying to accomplish here?”</p>

<p>Human pairing at its best is a conversation about intent. Two developers at a keyboard are not just two people writing code - they’re two people keeping each other honest about what the code is for and whether the current approach is going to get there. The navigator isn’t just watching. They’re maintaining the map.</p>

<p>AI pair programming is more like autocomplete with opinions. It’s extremely good at the local, immediate task. It has no view of the larger goal unless you give it one. It will helpfully implement a design you described poorly and produce something that technically works and conceptually misses.</p>

<p>This is why I still pair with humans. Not because the AI isn’t useful - it’s indispensable - but because my human pair provides something the AI can’t: they remember what we were trying to do, they notice when I drift, and they’ll say “I don’t think we need this” in a way that I’ll actually hear.</p>

<p>The pairing practice that works in 2026 looks like this: human pair sets the direction and holds the intent, AI handles the implementation details, human pair reviews what came out. The roles shifted. The practice didn’t.</p>

<p><strong>Discovery and framing when AI can generate stories</strong></p>

<p>The hardest lesson from working with AI on story writing is that it can generate plausible-looking user stories very quickly and they’re often subtly wrong.</p>

<p>The output looks right. The format is correct. The acceptance criteria seem complete. And then you get to refinement and realize the story assumes a user flow that doesn’t match how the feature was actually designed, or bring together two different types of users, or skips an entire edge case that your domain expert would have caught in the first five minutes.</p>

<p>Discovery and framing exists because the gap between what stakeholders want and what developers build is a communication problem, not a technology problem. AI doesn’t close that gap. It papers over it faster.</p>

<p>The D&amp;F sessions I’ve been part of that work well use AI for synthesis - pulling together notes, drafting story text after the conversation, generating scenario outlines - but keep the conversation itself human. The stakeholder explaining why this feature matters. The developer asking “what happens if the user doesn’t have this permission.” The product manager reconciling two contradictory requirements from two different teams.</p>

<p>That conversation is the product. The story document is just the record of it.</p>

<hr />

<p>What I’m not saying: that you need to follow the full XP playbook to ship software with AI tools. You don’t. Plenty of teams are shipping without written BDD scenarios or pairing sessions, and some of them are fine.</p>

<p>What I am saying: the failure modes are more severe now. If your requirements are vague, AI builds the vague thing with confidence. If nobody holds the intent, the AI follows the path of least resistance and you end up with a technically functional system that doesn’t actually solve the problem.</p>

<p>The practices XP named - write the behavior first, keep two people watching the same screen, do the clarity work before the execution work - are responses to a enduring problem in software: that building the wrong thing is easier than building the right thing.</p>

<p>AI made execution dramatically cheaper. It did nothing about the problem of knowing what to build.</p>

<p>The clarity work is still yours.</p>]]></content><author><name>Alex</name></author><category term="xp" /><category term="ai" /><summary type="html"><![CDATA[AI coding tools make Extreme Programming practices more important, not less. When the machine writes the code, human judgment about what to build becomes the scarce resource.]]></summary></entry><entry><title type="html">The Spec That Runs</title><link href="https://roll.bybacon.com/2026/09/30/the-spec-that-runs.html" rel="alternate" type="text/html" title="The Spec That Runs" /><published>2026-09-30T19:00:00+00:00</published><updated>2026-09-30T19:00:00+00:00</updated><id>https://roll.bybacon.com/2026/09/30/the-spec-that-runs</id><content type="html" xml:base="https://roll.bybacon.com/2026/09/30/the-spec-that-runs.html"><![CDATA[<p>Every team has two representations of what their software should do. The first lives in the project management tool - Jira tickets, Notion pages, PRDs, whatever they’re using. The second lives in the test suite. Both are supposed to describe the same behavior. They rarely do.</p>

<p>The ticket says “Users can filter search results by category.” The test says <code class="language-plaintext highlighter-rouge">expect(response.body).to include('Electronics')</code>. These are not the same specification. One is a product intention. The other is an implementation artifact. As the product evolves, tickets stay frozen, tests get updated, and the two drift apart.</p>

<p>This is the default state. Most teams live with it.</p>

<p>Spec-driven development is the refusal to accept that drift as inevitable.</p>

<hr />

<p>The core idea is simple: the spec and the test should be the same document. Not two documents that describe the same behavior. One document, in a form that is both human-readable and machine-executable.</p>

<p>This is what Gherkin gives you. A feature file is a requirements document that runs. It describes what the system should do, who benefits, and what specific behaviors constitute done - in language a product manager can read and a test runner can execute.</p>

<p>For a booking management feature start like this:</p>

<div class="language-gherkin highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">Feature</span><span class="p">:</span> Booking Manager

As Molly
I want to manage Bookings for my Events
So that I can track who is attending, who is waitlisted, and who canceled

<span class="kn">Scenario</span><span class="p">:</span> Arthur books a spot for an available Event
  <span class="nf">Given </span>Molly has an available Event with open capacity
  <span class="nf">When </span>Arthur visits the new booking page for the Event
  <span class="nf">And </span>Arthur fills in his name and email address
  <span class="nf">And </span>Arthur submits the booking
  <span class="nf">And </span>Arthur confirms the booking via the email link he got
  <span class="nf">Then </span>Arthur should see the booking on the Event bookings list
  <span class="nf">And </span>The booking should be confirmed
</code></pre></div></div>

<p>That file is the spec. It describes behavior that matters to actual users in a form that survives a demo, a PM review, and a CI pipeline. The same document does all three jobs.</p>

<hr />

<p>There’s a second part of spec-driven development that doesn’t get enough attention: the order.</p>

<p>The spec runs first. Before any implementation exists.</p>

<p>You write the feature file. You write the step definitions. You run the suite. It fails. That failure - the red - is the most important moment in the process. It proves the spec was written correctly, that the test infrastructure is wired up, and that when you write code to make it pass, the green result actually means something.</p>

<p>This sounds obvious. Teams skip it constantly.</p>

<p>The way it usually gets skipped: someone implements a feature, then writes the spec to document what they built. The spec runs green on the first try. Everyone feels good. The problem is you have no idea if that test would catch a broken implementation. You only know it doesn’t catch the current one. You wrote a test that proves the present state, not one that will catch the future regression.</p>

<p>The red proves the spec was real. Without it, you just have green.</p>

<hr />

<p>Where the spec lives matters as much as what it says.</p>

<p>Most teams keep specs in the test directory of the codebase, isolated from wherever product requirements live. This creates the same split in a different location: requirements in one system, tests in another.</p>

<p>The pattern that works is keeping specs in version control alongside everything else - treating them as the primary product artifact, not a byproduct of implementation.</p>

<p>For us, feature files live in a <code class="language-plaintext highlighter-rouge">docs/</code> directory with sequential IDs: <code class="language-plaintext highlighter-rouge">BCN-001-booking-manager.feature</code>, <code class="language-plaintext highlighter-rouge">BCN-002-authentication-manager.feature</code>. Each file has frontmatter tracking its status. Features move through four stages: <code class="language-plaintext highlighter-rouge">1_icebox</code> → <code class="language-plaintext highlighter-rouge">2_backlog</code> → <code class="language-plaintext highlighter-rouge">3_started</code> -&gt; <code class="language-plaintext highlighter-rouge">4_done</code>. The stack-ranked backlog is a text file, also in git.</p>

<p>There is no Jira. No Linear. The spec is the story is the ticket is the test.</p>

<p>(bacon-tracker)[https://github.com/bybacon/bacon-tracker] is the tooling that makes this concrete:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rake story:feature['Booking Manager']  → features/1_icebox/BCN-001-booking-manager.feature
rake story:commit[BCN-001]             → moves to 2_backlog, adds to backlog.md
rake story:start[BCN-001]              → moves to 3_started
rake story:done[BCN-001]               → moves to 4_done
</code></pre></div></div>

<p>Git becomes the audit trail. The story file is the commit. The test run is the verification. Nothing external can drift from what the code actually does, because there is no external system.</p>

<hr />

<p>The caveat: good Gherkin is harder to write than it looks.</p>

<p>Bad Gherkin is a Jira ticket in a different format. It’s either vague (“When the user does something / Then it works”), or over-specified (“Given the database has a User record with id=4 and email=’test@example.com’”), or it describes implementation instead of behavior.</p>

<p>Good Gherkin describes behavior at the level of abstraction where the test catches regressions that actually matter. “When Arthur submits the booking / Then the booking should be confirmed” is a behavior. “When <code class="language-plaintext highlighter-rouge">POST /bookings</code> is called with valid params / Then <code class="language-plaintext highlighter-rouge">response[:status]</code> is <code class="language-plaintext highlighter-rouge">confirmed</code>” is an implementation test wearing a Gherkin costume. The first survives refactoring. The second breaks every time you touch the internals.</p>

<p>The tooling creates the structure. The thinking that goes into the scenarios is still yours.</p>

<hr />

<p>The deeper value of spec-driven development is not test coverage. It’s clarity.</p>

<p>When the spec runs, you know exactly where you stand. Green scenarios are done. Red scenarios are not. There is no ambiguity about what done means, because done is defined in executable form.</p>

<p>That’s rare in software. Most teams operate with done as a matter of interpretation - does it match the ticket? Does it match what the PM remembers from the meeting? Does it pass QA’s judgment call? Each layer of interpretation is a place where the thing you built can drift from the thing that was needed.</p>

<p>A spec that runs eliminates most of that drift. Not by adding rigor, but by collapsing two separate representations of truth into one.</p>]]></content><author><name>Alex</name></author><category term="xp" /><summary type="html"><![CDATA[Every team has two descriptions of what their software should do: the tickets and the code. Neither is authoritative. The spec that runs is - and most teams don't have one.]]></summary></entry><entry><title type="html">Stories Scale</title><link href="https://roll.bybacon.com/2026/09/23/stories-scale.html" rel="alternate" type="text/html" title="Stories Scale" /><published>2026-09-23T18:00:00+00:00</published><updated>2026-09-23T18:00:00+00:00</updated><id>https://roll.bybacon.com/2026/09/23/stories-scale</id><content type="html" xml:base="https://roll.bybacon.com/2026/09/23/stories-scale.html"><![CDATA[<p>When a team is small enough, you don’t need stories.</p>

<p>Two or three people, shared context, constant communication - you can carry the product in your heads. You have the same Slack conversation, you attended the same meeting with the customer, you know what you’re building and why. You write code, you show each other, you ship.</p>

<p>Stories feel like overhead at this stage. Filling out templates, writing acceptance criteria, running refinement sessions - it all seems like process for the sake of process. Why write down what everyone already knows?</p>

<p>This feeling is accurate. At that scale, stories are overhead.</p>

<p>The problem is that teams don’t stay small. And when they grow, the thing that worked before stops working, and nobody is quite sure why.</p>

<hr />

<p>What happens when teams grow is not complicated: people stop knowing what everyone else knows.</p>

<p>A second team gets formed to work on a different part of the product. Developers join who weren’t in the original customer conversations. A product manager is hired specifically because the founding engineers don’t have time to talk to customers anymore. The CEO is no longer in the room when features get scoped.</p>

<p>The shared context that made informal communication work evaporates, incrementally, over months. Nobody notices it happening until the demo where two teams show features that contradict each other. Or the release where a feature shipped without the edge case that the customer specifically asked for. Or the planning meeting where nobody can remember why a particular decision was made.</p>

<p>These failures are not failures of intelligence or effort. They’re failures of information distribution. The people who knew, couldn’t tell everyone who needed to know, fast enough, clearly enough, durably enough.</p>

<p>Stories are the solution to this problem.</p>

<hr />

<p>A user story, written well, is a portable unit of shared understanding.</p>

<p>It carries what the feature is, who it’s for, why they need it, and what “done” looks like. It can be read by a developer who wasn’t in the planning session. It can be referenced by a QA engineer testing six weeks later. It can be used by a product manager explaining scope to a stakeholder who asks why a feature works the way it does.</p>

<p>None of this requires a sophisticated project management tool. It requires that someone, before work starts, wrote down: who needs this, what they need, and how we’ll know when we’ve delivered it.</p>

<p>The format that makes stories most durable is the BDD scenario - not because it produces better test coverage, but because it forces the story to be concrete. “As a user, I want to filter search results” is not a story. It’s a wish. “Given I have searched for a product, When I apply a category filter, Then only results in that category are shown” is a story. It’s testable, unambiguous, and reviewable by anyone who needs to understand what was built and why.</p>

<p>Concrete stories survive the conversation they came from. Vague ones don’t.</p>

<hr />

<p>The word I keep coming back to is <em>durable</em>.</p>

<p>Informal communication is fast and cheap but perishable. The conversation in Slack about what the feature should do is gone in a week. The decision made in the hallway doesn’t exist unless someone wrote it down. The context the founding engineer has in their head leaves when they leave.</p>

<p>Stories are durable by design. They’re a record of what was decided and why, in a form that can be shared, searched, and referenced later. They’re the mechanism by which knowledge about what you’re building survives beyond the moment it was created.</p>

<p>This matters more as the team grows because the distance between “person who decided” and “person who implements” increases. At two people that distance is zero. At twenty people, it can be significant. At fifty, the person implementing something may have never spoken to the person who requested it.</p>

<p>Stories are how information crosses that distance without degrading.</p>

<hr />

<p>There’s a consequence to all of this that’s worth saying directly: the discipline of writing stories pays dividends before the team is big enough to obviously need them.</p>

<p>Teams that practice writing concrete acceptance criteria get better at understanding what they’re building before they build it. The act of writing “Given… When… Then…” exposes ambiguity in requirements that would otherwise surface during implementation, during QA, or during the demo. Catching it earlier is cheaper.</p>

<p>Teams that wait until they’re large enough to need stories are already behind. The habit of clear communication has to be built at small scale, or it won’t be there when the team grows.</p>

<p>The time to start writing good stories is when you don’t think you need them. By the time you obviously need them, you needed them three months ago.</p>

<hr />

<p>Stories don’t scale your team for you. Nothing does that. But they do make it possible for a growing team to maintain alignment without requiring that everyone be in every room for every decision.</p>

<p>That’s not a small thing. Most of what slows down large engineering teams is not technical - it’s the cost of getting everyone pointed at the same goal, working from the same understanding, measuring against the same definition of done.</p>

<p>Stories are infrastructure for shared understanding. Like other infrastructure, they feel like overhead until you don’t have them.</p>

<p>Then they feel like something you can’t do without.</p>]]></content><author><name>Alex</name></author><category term="xp" /><category term="teams" /><summary type="html"><![CDATA[When the team is small, user stories are overhead. When it grows, they become the only reliable way to coordinate work without everyone stepping on each other.]]></summary></entry><entry><title type="html">Always Be Knolling</title><link href="https://roll.bybacon.com/2026/09/16/always-be-knolling.html" rel="alternate" type="text/html" title="Always Be Knolling" /><published>2026-09-16T18:00:00+00:00</published><updated>2026-09-16T18:00:00+00:00</updated><id>https://roll.bybacon.com/2026/09/16/always-be-knolling</id><content type="html" xml:base="https://roll.bybacon.com/2026/09/16/always-be-knolling.html"><![CDATA[<p>Tom Sachs has a rule in his studio: always be knolling. Knolling is the practice of arranging all objects at right angles to each other or parallel to the edges of the surface they’re on. Everything in use is out. Everything not in use is put away. Like things are grouped. All things are aligned.</p>

<p>It sounds like tidiness for its own sake. It isn’t. It’s a working method. When your tools are arranged, you can see what you have. When you can see what you have, you can find what you need. When you can find what you need, you can work without interruption. The environment supports the work instead of fighting it.</p>

<p>The principle maps directly to software. Most codebases are not knolled. Most backlogs are not knolled. Most development environments are not knolled. And the cost of this disorder is paid in attention, every day, by everyone who works in them.</p>

<hr />

<p>The four steps of knolling are a useful frame.</p>

<p>The first is to scan your environment for things not in use. In a codebase this is dead code, stale branches, unused dependencies, config keys that reference services no longer running, commented-out blocks that haven’t been touched in two years, feature flags whose features shipped in 2023. These things are not harmless. They occupy cognitive space. Every developer who opens a file with dead code has to spend a moment deciding whether it’s dead or whether it’s doing something they don’t understand. That moment, multiplied by every file and every developer and every week, is a real cost.</p>

<p>The second is to put away everything not in use. Delete the dead code. Delete the stale branches. Remove the unused dependencies. If it’s not in active use, it shouldn’t be in the working environment. The objection is always “what if we need it later” - the answer is version control. It existed. It can be recovered. The cost of deleting something you later want back is retrieving it from git. The cost of keeping everything you might want someday is a workspace that nobody can navigate without a map.</p>

<p>The third is to group all like things. Routes with routes, models with models, specs with specs, utilities with utilities. Conventions that everyone follows consistently. Not because the grouping is the only correct grouping, but because a consistent grouping is one that anyone can navigate without asking. Surprise is the enemy of legibility. When things are where they’re expected to be, the structure disappears and the work comes forward.</p>

<p>The fourth is to align all things. Consistent naming, consistent formatting, consistent structure across files that do the same kind of thing. The codebase that reads like one person wrote it, even though ten people did. When code is aligned, you read the content, not the style. When it isn’t, your eye keeps catching on variations - a differently named test helper, a file that organizes its methods in the opposite order from everything else.</p>

<hr />

<p>The real practice is leaving things more knolled than you found them.</p>

<p>Not in a single heroic cleanup sprint that produces a massive PR nobody wants to review and touches every file in the project. That’s not knolling. That’s rearranging furniture in a way that makes the house temporarily unrecognizable.</p>

<p>The practice is: every time you open a file, scan for one thing that’s out of place. A dead method. An unused require. An import that’s listed twice. Remove it. Commit it. Move on. Over weeks, the codebase gets cleaner in proportion to how often people touch it - which is exactly the right distribution. The files you’re actively working in become progressively more organized. The files you don’t touch sit undisturbed.</p>

<p>This is the principle Sachs calls leaving no trace: when you’re done with the space, it should be in better condition than when you arrived. Not perfect. Just better.</p>

<hr />

<p>Backlogs need knolling too.</p>

<p>A backlog that hasn’t been knolled is a graveyard of good intentions. Tickets opened six months ago for features that were later descoped. Bugs that reproduced on a version three releases behind. Ideas that felt important at the time but were quietly superseded by different decisions. These are not open work items. They are noise. Every planning session that involves scrolling past them is time spent on things that don’t matter at the expense of things that do.</p>

<p>Knoll the backlog on a regular basis. Close tickets that are no longer relevant. Group related items. Archive anything that’s been sitting untouched for more than a quarter. If it matters, it will surface again - and when it does, you can open a new, clearer ticket with current context. If it doesn’t surface again, it didn’t matter.</p>

<hr />

<p>The underlying principle is that disorder has a cost, and that cost is usually invisible until it becomes significant.</p>

<p>No single dead method makes a codebase hard to work in. No single stale ticket makes a backlog unusable. No single misaligned file makes a codebase illegible. The accumulation does. Disorder compounds slowly and then suddenly. At some point the codebase is the thing everyone complains about, the backlog is the thing nobody trusts, and the working environment is the thing that slows everything down.</p>

<p>The antidote is not periodic cleanup. It is continuous, small, habitual knolling. Scan. Put away. Group. Align. Leave the space better than you found it. Do it every time you’re in a file, every sprint review, every time you’re setting up your environment.</p>

<p>The environment is not separate from the work. It is the condition of the work. Knoll it accordingly.</p>]]></content><author><name>Alex</name></author><category term="culture" /><category term="simplicity" /><summary type="html"><![CDATA[Tom Sachs' knolling principle applied to software: scan for what's not in use, put it away, group like things, align everything. The discipline of leaving a codebase more organized than you found it.]]></summary></entry><entry><title type="html">Sacred Space</title><link href="https://roll.bybacon.com/2026/09/09/sacred-space.html" rel="alternate" type="text/html" title="Sacred Space" /><published>2026-09-09T17:00:00+00:00</published><updated>2026-09-09T17:00:00+00:00</updated><id>https://roll.bybacon.com/2026/09/09/sacred-space</id><content type="html" xml:base="https://roll.bybacon.com/2026/09/09/sacred-space.html"><![CDATA[<p>The way a team treats its environment is a signal.</p>

<p>Not a metaphorical signal - an actual one. A codebase full of dead files and commented-out blocks and TODO comments from three years ago tells you something about the standards the team holds itself to. A backlog with hundreds of tickets nobody is going to do tells you something about the relationship the team has with its own commitments. A dev environment that takes a day to set up and breaks twice a week tells you something about how much the team values each other’s time.</p>

<p>None of these things announce themselves as problems. They accumulate quietly, and by the time they’re visible they’ve already shaped the culture. Once it becomes normal to leave a mess, it becomes the standard.</p>

<hr />

<p>The principle is simple: respect for space and tools is essential.</p>

<p>This sounds obvious. It mostly goes unpracticed.</p>

<p>Respecting the space means leaving things in good condition when you’re done with them. Merging or deleting the branch. Closing the ticket. Cleaning up the test data you generated while debugging. Not leaving a half-finished refactor in main because you got pulled onto something else. Not merging a PR with a console.log you forgot to remove. Not shipping a feature with dead code from the previous version still sitting next to it.</p>

<p>Respecting the tools means keeping them working. If the build is broken, fix it before you move on. If a test is flaky, fix it or delete it - a flaky test is worse than no test because it erodes trust in the entire suite. If the local dev setup has a step that doesn’t work anymore, update the documentation or fix the step. Don’t silently work around it and leave the next person to discover it the same way you did.</p>

<hr />

<p>The problem with mess is that messes normalize.</p>

<p>The first dead file someone leaves in the codebase is slightly awkward. The second is less so. By the tenth, nobody thinks about it. The standard has shifted. What was a lapse is now just how things are here.</p>

<p>This is the mechanism by which a codebase that was clean becomes a codebase that everyone complains about. Not one bad decision. Not a single catastrophic shortcut. A thousand small lapses, each of which was low-stakes at the time, compounding until the accumulated disorder is the dominant feature of the environment.</p>

<p>The same mechanism runs in reverse. Every time someone cleans up a thing they didn’t make a mess of - removes the dead code they found while working on something else, fixes the flaky test that was bothering everyone, updates the outdated doc - they push the standard slightly upward. The team notices, even if they don’t say anything. It becomes slightly more normal to leave things clean. That also compounds.</p>

<hr />

<p>The practical test is: when you’re done with something, would the next person encounter the environment in better shape than you found it?</p>

<p>Not perfect. Not comprehensively refactored. Just better. A little cleaner, a little more organized, a little closer to the state it would be in if everyone had always cared about it.</p>

<p>That’s not a high bar. It’s a consistent one. And consistency, over time, is what determines whether the environment supports the work or fights it.</p>

<p>The codebase is shared space. Treat it accordingly.</p>]]></content><author><name>Alex</name></author><category term="culture" /><summary type="html"><![CDATA[Respect for space and tools is essential. Don't leave a mess. The way a team treats its codebase, its backlog, and its environment is the clearest signal of how seriously they take the work.]]></summary></entry><entry><title type="html">The Curse of the Clever Solution</title><link href="https://roll.bybacon.com/2026/09/03/the-curse-of-the-clever-solution.html" rel="alternate" type="text/html" title="The Curse of the Clever Solution" /><published>2026-09-03T16:00:00+00:00</published><updated>2026-09-03T16:00:00+00:00</updated><id>https://roll.bybacon.com/2026/09/03/the-curse-of-the-clever-solution</id><content type="html" xml:base="https://roll.bybacon.com/2026/09/03/the-curse-of-the-clever-solution.html"><![CDATA[<p>There is a specific kind of dread that comes from opening a file and finding something ingenious.</p>

<p>Not clever in the “oh, that’s tidy” way. Clever in the “I have to read this four times before I understand what it does, and even then I’m not sure I understand why” way. Metaprogramming that generates methods at load time. A chain of functional transforms that reduces fifty lines to three but requires deep familiarity with the paradigm to follow. A macro that behaves differently depending on context you have to trace three files to discover.</p>

<p>The author of this code was clearly smart. And they’re probably gone.</p>

<hr />

<p>The problem with clever code is not that it’s wrong. Usually it works. The problem is the asymmetry it creates between writing and reading.</p>

<p>Writing a clever solution is satisfying. You’ve found the elegant path through a complex space. The code does something non-trivial and it does it briefly. It feels like mastery of the problem, of the language, of the particular trick being applied.</p>

<p>Reading someone else’s clever solution is different. You don’t have the context they had when they wrote it. You don’t know which alternatives they considered and rejected. You don’t know the constraint that made brevity important. You have the code and the behavior and nothing else. And the code is the most compressed possible representation of the decision, which makes it the hardest possible thing to understand.</p>

<p>The author spent an hour finding the clever path. Every reader spends an hour per encounter trying to reconstruct it.</p>

<hr />

<p>This shows up in predictable forms.</p>

<p>In dynamic languages, it’s the method that generates other methods - ten lines of metaprogramming replacing three hundred lines of repetition. The author was right that the repetition was bad. The metaprogramming is, technically, less code. But now every developer who works in this area needs to understand the generation mechanism before they can understand any of the generated methods. The cognitive cost is front-loaded, mandatory, and invisible until someone tries to debug something that doesn’t behave the way the template says it should.</p>

<p>In type systems, it’s the constraint that encodes a business rule as a compile-time invariant. Theoretically elegant. In practice, you spend twenty minutes reading error messages that describe structural problems in the type machinery rather than the actual mistake you made.</p>

<p>In algorithms, it’s the O(n log n) solution to a problem that only ever runs on twenty items. The O(n²) version would have been slower by microseconds and readable by everyone. Instead someone reached for the sophisticated approach, and now the obvious fix - adding a special case for empty input - requires understanding the entire algorithm before you can safely insert it.</p>

<p>The common thread: the cleverness solves a real problem, but the complexity it introduces doesn’t pay for itself.</p>

<hr />

<p>There are situations where cleverness is the right call. A parser, a serialization library, a compiler - these are systems where sophistication is the product. The whole point is to do something non-trivial, and the code reflects that. In these cases, complexity is justified and the audience expects it.</p>

<p>Similarly: performance-critical paths where the clever solution is measurably better and the alternatives are genuinely unacceptable. If you’ve benchmarked the naive approach and it can’t meet the requirement, the sophisticated one is not an indulgence - it’s a constraint. Document the benchmark. Leave a breadcrumb for the reader who comes after you.</p>

<p>Sometimes the smart solution is the right one. But “right” should mean <em>necessary</em>, not <em>preferred</em>. You chose it over simpler alternatives for a reason you can explain, not because it was more interesting to write.</p>

<hr />

<p>The test I’ve started applying: if I had to hand this code to a developer who is competent but unfamiliar with this part of the system, how long before they understand it well enough to change it safely?</p>

<p>For most business logic, the answer should be minutes. A few hours if the domain is genuinely complex. If the answer is “days” or “only after reading the design document from 2019,” you’ve built a trap.</p>

<p>Code outlives its authors. The developer who writes something clever and moves on has made a decision that every future reader will pay for. That’s not craftsmanship. It’s debt with no due date - it just sits there, compounding as slower changes, more bugs, and more time spent reading before anyone can write.</p>

<hr />

<p>Write the boring version first. If it’s too slow, measure. If it’s too long, find the repetition and extract it cleanly. If it still can’t be simple, make it as clear as possible and leave a note explaining why.</p>

<p>The reader who comes after you is often you, six months later. They deserve better than a puzzle.</p>]]></content><author><name>Alex</name></author><category term="simplicity" /><category term="culture" /><summary type="html"><![CDATA[Clever code is satisfying to write and painful to read. The author spent an hour finding the elegant path. Every future reader spends an hour reconstructing it. Write for the reader.]]></summary></entry><entry><title type="html">Work to Code</title><link href="https://roll.bybacon.com/2026/08/26/work-to-code.html" rel="alternate" type="text/html" title="Work to Code" /><published>2026-08-26T17:00:00+00:00</published><updated>2026-08-26T17:00:00+00:00</updated><id>https://roll.bybacon.com/2026/08/26/work-to-code</id><content type="html" xml:base="https://roll.bybacon.com/2026/08/26/work-to-code.html"><![CDATA[<p>Creativity is the enemy of execution.</p>

<p>That sentence makes people uncomfortable. Creativity is supposed to be good. It’s how problems get solved, how products improve, how teams grow. Nobody wants to work somewhere that suppresses creative thinking.</p>

<p>But there is a specific kind of creativity that consistently makes teams slower, codebases worse, and work harder to hand off. It is the creativity that invents new ways of doing things when a way of doing things already exists.</p>

<hr />

<p>Every team that has been together for more than a few months has developed a way of working. How tests are structured. How code is organized. How tasks are described and tracked. How deployments happen. How decisions get made. These conventions exist because someone made a choice at some point, and the team aligned around it, and over time it became the thing that makes the codebase navigable and the work predictable.</p>

<p>The conventions are not perfect. They are good enough, and they are shared. That second part is the one that matters.</p>

<p>When a developer decides their personal approach to structuring services is better than the one the team uses, and implements it in a new service, the codebase now contains two conventions. The next developer who touches that service has to figure out which one they’re looking at before they can understand the code. The developer after them might not even notice there are two, and produce a third. Six months later someone opens a PR review and spends twenty minutes on a discussion about which pattern to follow that would never have happened if the first person had just used the established convention.</p>

<p>The creative decision cost more than it added.</p>

<hr />

<p>The principle is not “never change how you work.” It is “change how you work deliberately, collectively, and for reasons you can state clearly.”</p>

<p>If the current convention is causing real problems - friction, bugs, things that consistently go wrong - then changing it is worth the disruption. Propose the change. Talk about it. Align the team. Update the standard. Then everyone follows the new thing.</p>

<p>What doesn’t work is individuals making local decisions that diverge from the shared convention because they prefer a different approach, or because they want to try something they read about, or because they weren’t aware the convention existed. The divergence accumulate, and the shared codebase becomes a patchwork of individual preferences that nobody fully understands.</p>

<hr />

<p>This applies to tools as well as patterns.</p>

<p>There is an endless supply of new libraries, frameworks, and approaches in software. Most of them are improvements over what came before in some dimension. Some of them will become the standard in a few years. This does not mean you should adopt them now.</p>

<p>Every new dependency is a surface you have to understand, maintain, and explain to other developers. Every new tool you introduce is a thing someone else has to learn before they can be productive in the part of the codebase where you used it. The cost is not just your time. It’s the team’s time, now and in the future.</p>

<p>Inventions should come from necessity, not preference. When the thing you have genuinely cannot solve the problem in front of you, reach for something new. When it can solve the problem - even if imperfectly, even if another tool would solve it more elegantly - use the thing you have. The cost of consistency is lower than the cost of fragmentation.</p>

<hr />

<p>This is what “work to code” means. There is a way of working. Follow it. Make it better when it needs to be better - but make it better for everyone, through the team, not just for yourself.</p>

<p>The code that looks like one person wrote it, the codebase that a new developer can navigate in a day, the system where you can read any file and immediately understand what it’s doing and why - this is not the product of constraint. It is the product of discipline. Everyone following the same patterns, in the same direction, over time.</p>

<p>Consistency is not boring. Consistency is what makes everything else possible.</p>]]></content><author><name>Alex</name></author><category term="culture" /><category term="simplicity" /><summary type="html"><![CDATA[Creativity is the enemy of execution. You have a way of working already in place. New inventions should come from necessity, not from what interests individuals. Consistency compounds.]]></summary></entry><entry><title type="html">Cut Every Task in Three</title><link href="https://roll.bybacon.com/2026/08/19/cut-every-task-in-three.html" rel="alternate" type="text/html" title="Cut Every Task in Three" /><published>2026-08-19T18:00:00+00:00</published><updated>2026-08-19T18:00:00+00:00</updated><id>https://roll.bybacon.com/2026/08/19/cut-every-task-in-three</id><content type="html" xml:base="https://roll.bybacon.com/2026/08/19/cut-every-task-in-three.html"><![CDATA[<p>Most people do the middle part of a task. They start when the work is already in front of them and stop when the visible work is done. The preparation that would have made it easier never happened. The cleanup that would have left no trace gets skipped because it feels optional.</p>

<p>It isn’t optional. It’s two-thirds of the job.</p>

<hr />

<p>Every task has three parts. Prepare it. Complete it. Leave no trace.</p>

<p><strong>Prepare the task.</strong> Before you write a line of code, before you send the message, before you start the meeting - do you actually understand what you’re doing? Have you read the spec or the ticket? Do you know what done looks like? Do you have what you need to start, or are you going to discover a blocking dependency thirty minutes in and have to context-switch out to resolve it? Preparation is the work that makes the work go smoothly. Skip it and you pay for it in interruptions, wrong turns, and rework.</p>

<p>In practice this looks like: read the ticket fully before opening a file. Write the test before writing the implementation. Confirm the acceptance criteria with whoever wrote the spec before building. Spend ten minutes at the start of a task asking what could go wrong, so you’re not surprised by it halfway through.</p>

<p><strong>Complete the task.</strong> This is the part everyone does. Or mostly does. The actual execution - the code written, the message sent, the feature shipped. The catch here is finishing. A task that is 90% done is not done. It is a context-switch waiting to happen, a liability that will surface at the worst possible moment, a thing that costs future-you more than it would have cost present-you to simply close it. Finish things. If a task is too large to finish in one session, break it into smaller tasks that can each be fully completed. Half-done work is debt.</p>

<p><strong>Leave no trace.</strong> This is the part that separates good work from work that makes a mess. When the task is done: close the ticket, merge and delete the branch, update the spec if reality diverged from it, pass along relevant information to whoever needs it, clean up the files you made changes on, remove any temporary scaffolding you put in place to make the work possible. The task is not complete when the feature works. It is complete when the environment is in the same state it would have been in if the task had always existed - plus the improvement the task was meant to make.</p>

<hr />

<p>The reason most people skip prepare and leave-no-trace is that neither one produces visible output. Nobody sees the preparation you did before writing the code. Nobody thanks you for the branch you deleted or the ticket you closed. The reward structure points at the middle part, so the middle part is what people optimize for.</p>

<p>But teams that optimize for the middle part produce codebases full of half-finished work, backlogs full of stale tickets, and a constant low-level friction where the environment is always slightly worse than it should be. The shortcuts accumulate. Eventually the environment is the main obstacle to doing work, and a cleanup project appears on the roadmap as if the disorder arrived by itself.</p>

<p>It didn’t arrive by itself. It was left, incrementally, by everyone who stopped at “complete”.</p>

<hr />

<p>Apply it as a habit. Before starting a task, spend a moment on preparation - even if it’s just two minutes of reading to confirm you understand the goal. After finishing, spend another moment on cleanup - close the loop, leave no trace. Build both ends into your definition of done.</p>

<p>The work is not over when the feature ships. It is over when there is nothing left behind.</p>]]></content><author><name>Alex</name></author><category term="culture" /><category term="xp" /><summary type="html"><![CDATA[Prepare the task. Complete the task. Leave no trace. Most people only do the middle one. The other two are what separate good work from work that makes a mess.]]></summary></entry></feed>