By Darryl Brown
For most of our history, quality was something we checked for at the end.
We had skilled people doing that checking, and they were good at it — which is a significant part of why our production bug rate was so low. Customers almost never found bugs. That was a genuine point of pride.
However, checking for quality at the end of a process is the most expensive place to find it. We started asking whether we could move that discovery earlier. Much earlier.
In Post 2 of this series I wrote about QA being our bottleneck by design. Leadership had recognized that the constraint had to live somewhere in the process, and had made a deliberate decision that QA was the right place for it — a safety net the organization treated as a feature, not a flaw. It produced a near-zero production bug rate. But it came with a cost to throughput that we eventually decided to address differently.
The deeper question, once we’d addressed the throughput problem, was: why were work items arriving at QA with problems in the first place?
When we traced our quality issues upstream, we found that many of them started long before a developer wrote a line of code. Work items that lacked clarity, specificity, or a clear definition of success were entering our process and generating churn — features that didn’t match what customers actually needed, rework, rejected work items cycling back through the system. The problem wasn’t in QA. It was in requirements.
The further a problem travels through the process before it’s caught, the more expensive it becomes to fix. A requirements misunderstanding that reaches QA means rebuilding work already done. One that reaches production means all of that, plus the cost of a live issue. The goal of shifting left is to catch problems as early as possible — before significant work has been built on top of a flawed foundation.
This realization led to a shift in how we think about work items, and it connects directly to the “Ask why: discipline that runs throughout this series.
Before a work item describes a solution, it needs to answer a more fundamental question: what problem are we actually solving, and for whom? We moved away from work items that prescribed how something should be built toward ones that defined the problem clearly and stated the result required. That shift gave developers the freedom to figure out the best path, while ensuring everyone agreed on the destination before work began.
The difference in practice is easier to show than to describe. Here is a real work item that recently failed our Definition of Ready check:
Title: Research: Can the iPad block file uploads that are encrypted or not PDFs
Description: Steps to test:
- In the customer environment, in the Examples cabinet, add a Test Form.
- In the Media Viewer section, try to upload a locked PDF and a PDF that isn’t really a PDF (e.g. a renamed JPEG). Try them individually and try them both at the same time.
- Observe that the problem is correctly reported and the file(s) is/are not uploaded.
- In the Library, try to upload a locked PDF and a PDF that isn’t really a PDF.
- Observe that the problem is correctly reported and the file is not uploaded.
Implement blocking users from uploading encrypted/protected PDFs via the iPad, similar to what was done for web.
When our automated Definition of Ready check evaluated this work item, it flagged it as not ready and added the following comment directly on it:
“This ticket lacks the critical elements required for a Feature ticket’s Definition of Ready:
1. Context is missing: Why are we investigating blocking file uploads on the iPad? What specific problem are we solving? Who requested this research/feature?
2. Requirements need clarification: Define what constitutes an ‘encrypted’ PDF. Specify what makes a PDF ‘not real’. Describe the exact criteria for blocking file uploads.
3. Acceptance Criteria are not defined: What are the specific, measurable outcomes? How will we verify the implementation?
Consider restructuring this as a Research ticket to first explore the technical feasibility and requirements before converting it to a Feature ticket.”
The work item was revised. Here is what it looked like after passing the check:
Title: Research: Can the iPad block file uploads that are encrypted or not PDFs
Research Question: Can we block encrypted/protected PDFs and non-PDF files from being uploaded via iPad, similar to the web implementation?
Scope:
- In Scope: Testing file upload restrictions for encrypted/protected PDFs and non-PDF files in both Media Viewer and Library upload flows. Comparison with existing web implementation. Timebox: 1 day.
- Out of Scope: Implementing the actual blocking feature. File types other than PDFs and JPEGs. Platforms other than iPad.
Expected Deliverable: Written summary of findings: Can the iPad reliably detect and block encrypted/protected PDFs and renamed files? What technical approaches are available? Any platform limitations or user experience considerations. Recommendation on next steps. List of open questions or risks.
Context: Customers have reported multiple issues per week related to problematic file uploads on iPad. The web app already blocks these uploads; parity is needed on iPad. The goal is to reduce support burden and improve reliability for all customers.
The difference is not subtle. The first work item tells a developer what steps to follow without explaining why any of it matters. The second defines the problem, the scope, the expected output, and the context that makes the work meaningful. A developer picking up the second work item knows exactly what success looks like before they write a single line of code. And critically — that evaluation was done by an automated AI check, not a human reviewer. As described in Post 4, one of our quality engineers built that workflow in a single day. It runs on every work item. It either clears it as ready or comments directly with a specific explanation of what needs to be addressed — and references the creator so the right person knows to act. No human has to triage, interpret, or forward anything.
To codify this thinking across the process, we introduced two concepts: a Definition of Ready and a Definition of Done.
The Definition of Ready is the set of criteria a work item must satisfy before it can be assigned to a developer for the week. It covers clarity of the problem, the customer it affects, the acceptance criteria, and any identified risk. No work item gets assigned until it passes. The automated check is the first line of enforcement.
The Definition of Done works at the other end — a set of quality gates a solution must pass before it advances to the next stage of the process. This is where our automated code reviews live, including an automated pass that runs on every set of proposed changes before any human reviews them. We are actively adding additional AI expert reviewers — for security, performance, and best practices — as part of this same gate. The goal in either case is the same: quality criteria built into the process rather than applied at the end of it.
Together these two definitions create quality gates at the beginning and end of each work item’s journey. The work between them has guardrails it didn’t have before.
The name for this shift is Quality Engineering — as distinct from Quality Assurance. The difference is more than semantic. Assurance is reactive: it checks whether something meets a standard after the fact. Engineering is proactive: it designs the standard into the process so that fewer things fail to meet it in the first place.
Simon Sinek tells a story in Start with Why about Japanese engineers who designed quality so thoroughly into their manufacturing process that they could eliminate the need to test at the end. They knew it was right before it was finished. That story became a touchstone for our Director of Quality Engineering as he shaped this work — and it’s the right frame for what we’re building. We are not trying to catch more bugs at the end. We are trying to engineer a process where fewer bugs reach the end at all.
My Director of Quality Engineering is writing his own more detailed account of this transformation in his own blog. I’d encourage you to follow that work if this topic interests you — he is closer to it than I am and has more to say about the specifics.
This work is recent. We began in earnest in Q4 2025 and we are still measuring results. The early signal is encouraging — fewer work items bouncing back late in the process, and when they do bounce, they don’t travel as far to be fixed. But we haven’t declared victory. We’re watching the data and adjusting as we go, which is consistent with how we’ve approached everything else in this series.
That is the right note to close on.
Every post in this series has described something we tried, measured, learned from, and adjusted. Nothing arrived fully formed.
It might sound, reading these posts in order, as if we had a plan from the beginning — as if each change followed logically from the last. That’s not quite right. There are really two layers to what’s described here. The first is the foundation: the culture of safety, the habit of asking why, the willingness to try things and occasionally get them wrong. That foundation didn’t come from any single decision. It grew slowly, through trust built over time. The second layer is everything built on top of it — the pipeline changes, the automations, the sprint structure, the quality engineering work. Those experiments were only possible because the foundation was there. If you’re reading this series looking for somewhere to start, start there. The experiments will follow.
The pipeline simplification surprised us with how fast it moved. The sprint structure worked better than expected once we committed to defining it honestly. The AI adoption was harder than anticipated and easier than feared. The quality engineering work is the newest and least proven of everything described here.
What has been consistent throughout is the practice: step back, ask why, design an experiment, measure what happens, and keep going. Not because we had a master plan, but because we had a team willing to try things and a culture where trying things — and occasionally getting them wrong — was safe.
That culture didn’t come from a process or a tool. It came from the people on this team. I’ve tried to create the conditions for it. They did the rest.
If you’re checking for quality at the end, you’re already too late.
Thank you for reading this series. I hope something in it was useful, whether you’re building a development team, leading one, or just trying to figure out what the job actually is.
By Darryl Brown
Getting our team to adopt AI turned out to be more complex than I expected for reasons that were both practical and deeply human.
On the practical side, these tools are difficult to use well. The quality of what you get out is directly tied to the skill and effort you put in. Learning to work effectively with AI requires real investment — in understanding how to frame problems, how to evaluate output critically, and how to redirect when the tool goes off course. That learning curve is real.
But underneath the practical challenge was something deeper: the change asked people to revalue expertise they’d spent years accumulating. Some tasks that used to take a day now take minutes. That’s genuinely exciting — and it’s also genuinely disorienting if your sense of professional value is tied to the expertise that made the day-long task hard. Those are not small things to ask someone to reconcile simultaneously.
Let me explain why this mattered so much to us specifically.
We are a small team. We don’t have the budget to simply add resources whenever demand increases. What we have is a group of skilled people, a set of problems to solve, and a need to do more with the same — or fewer — resources over time. One of our developers put it plainly: we have deadlines to meet and products to build to stay relevant and win new work. If we don’t innovate, we won’t succeed.
AI is not optional for a team in that position. It’s the difference between a team that can punch above its weight and one that can’t.
I began introducing the topic in late 2024 in our weekly team meeting that has evolved well beyond its original purpose into a space where anyone can bring technical challenges, frustrations, new ideas, or demos. It’s not a top-down meeting. I use it occasionally to float ideas, and AI became a frequent topic. The timing felt right. By late 2024, the tools had crossed a threshold — the return on using them had become obvious enough that the conversation had shifted from “Should we?” to “How do we?”
My view, which I shared with the team directly, was that the direction of travel wasn’t really optional, not because I said so, but because the world outside our company was moving this way regardless. What I could offer them was a chance to get ahead of it. I wanted everyone on this team to be employable in five years, whether that was here or somewhere else. Framing it that way perhaps landed differently than “Here is a new tool, please use it.”
How we landed on our specific tools reflects the same principle of trusting the team.
I had a conversation with a CEO at another company who was ahead of us in AI adoption. He generously shared their experience and mentioned they were experimenting with Devin. Some of our engineers had already been trying Cursor on their own. We discovered the two tools had different strengths, so we’ve continued using both for different purposes rather than forcing a single choice. GitHub Copilot was a natural addition given that we already use GitHub for our codebases. Any tool that integrated cleanly with existing infrastructure had a lower barrier to adoption.
Copilot has its annoyances, but it also consistently catches real bugs and gives genuinely useful advice on best practices. On balance, it has proven its usefulness.
Adoption wasn’t uniform or frictionless. The developers who adopted early became internal champions, and social proof did work that no mandate could have done. We started sharing AI experiences in our weekly team meeting — the good, the bad, and the ugly. There were enough genuinely remarkable experiences that the case for AI made itself more effectively than any directive from me.
The shift in how developers work is real. They’re not writing the majority of the code. They plan a solution with AI, direct it toward an implementation, evaluate the output, and validate that it isn’t doing anything unexpected. The role changed. It didn’t disappear.
AI is not a replacement for engineering judgment. Someone still has to evaluate whether the output makes sense, whether it’s introducing subtle problems that look fine on the surface, whether the approach is sound. The developer became the director rather than the implementer — which requires a different and in some ways more demanding set of skills than pure coding. AI is most valuable as a partner throughout the work — helping plan a solution, generating an implementation, reviewing that implementation from multiple angles, and iterating when something isn’t right. The developer directs that partnership at every stage.
We’ve also begun building AI expert reviewers into our code review process. Our code review tool currently reviews every set of proposed changes before any human sees them, catching real bugs and flagging best practice violations. We are actively adding additional automated passes — for security, performance, and other specialized concerns — that will run as part of the same gate. The goal is that issues are caught by an automated expert before a human ever looks at the code, making them cheaper to fix and faster to resolve. That work is in progress and the early results are encouraging.
One thing we’ve been deliberate about is separating how we prompt AI from which tool we’re using — and treating prompting as its own discipline entirely. Within each of our codebases, we maintain a set of context files that describe the codebase for an AI reader: best practices, architectural decisions, coding standards, and baseline instructions. When a developer engages an AI tool on a work item, the first instruction is always to read those files before attempting to solve anything.
The result is that the AI operates with the same foundational knowledge any experienced member of our team would bring to the work. The context travels with the code, not with the person. It’s tool-agnostic by design — when we switch platforms, the accumulated knowledge of how to get useful output from our codebase doesn’t disappear with the old tool. The recipe travels with us.
This matters more than it might seem. The quality of what you get from AI is largely determined by the quality of what you put in. Investing time in how you interact with these tools, not just which tools you use, is where the real leverage is. The context files are our answer to that challenge, and they’ve made a meaningful difference in the consistency and quality of AI-generated output across the team.
The mindset shift we’ve worked toward is this: AI augments the team. It lets us remain small and still meet the demands of a growing business. The developer’s job is to direct that augmentation at every stage: framing the problem clearly, evaluating the output critically, redirecting when the AI goes off course, and applying judgment the tool doesn’t have.
Stepping back from our own experience, I think the AI moment we’re in has surfaced something important about organizational readiness that goes beyond tools and workflows.
Many of the principles that drove our transformation — small batch sizes, eliminating waste, continuous improvement, creating safety to experiment and fail — are core tenets of LEAN manufacturing, applied to software. What I’ve learned is that these principles aren’t just useful for building better software. They are the prerequisite for implementing any significant change at all. Without a culture where people can ask why, experiment, and occasionally fail without consequence, an organization cannot iterate its way toward a better state. It will announce changes rather than grow them. And announced changes, in my experience, rarely stick.
This matters urgently right now. The companies that will successfully adapt to AI are not necessarily the ones with the biggest budgets or the most sophisticated tools. They are the ones with the cultural foundation to absorb change iteratively — to try something, measure it, adjust, and keep going. The technology is, in many ways, the easier part. The culture is the hard part. And it cannot be installed overnight.
There is one broader implication of this shift that the industry hasn’t fully answered yet.
As AI has taken over the tasks that used to define junior engineering work — the straightforward implementations, the repetitive foundational code, the well-defined work items — I’ve found that I no longer need junior engineers in the way I once did. The work that remains requires seniors: people who can architect solutions, evaluate AI output critically, redirect the tools when they go wrong, and write complex code themselves when the problem demands it. Those are not skills a junior engineer walks in the door with. They’re skills developed over years of doing exactly the kind of work AI is now doing.
Which raises a question I don’t think the industry has answered yet: where are tomorrow’s senior engineers going to come from, if we are no longer hiring juniors to develop them? I don’t know. But it’s worth asking — and worth watching carefully as this unfolds.
The tools are changing quickly. The responsibility to think clearly isn’t going anywhere.
The final post in this series is about a shift in how we think about quality, not as something we check at the end, but as something we build in from the start.
By Darryl Brown
One of the harder lessons of the last two years was realizing that my value wasn’t in solving problems. It was in making sure problems got solved.
Those sound similar. They are not. The first makes you a bottleneck. The second, if you get it right, makes your team stronger every time something goes wrong.
I learned the early version of this lesson before I became CTO, back when I was promoted to Director of Software. I’ve always had strong opinions, and as a senior developer on the team, I was used to voicing them freely and with conviction. When I stepped into that director role, I became aware and concerned that colleagues who were often my equal or superior in pure engineering terms might worry I’d use the position to enforce my views. So I made a conscious decision to take a backseat in technical discussions. To listen before speaking. To let others go first.
What I found surprised me. Most of the time, someone else would voice the opinion I was holding. My input wasn’t necessary. On the occasions when it was, it was usually to break a tie or to bring in context the team wasn’t privy to — the broader company picture, a strategic constraint, something that required the view from my seat rather than just a technical opinion.
There was another benefit I hadn’t anticipated. When I wasn’t the one introducing an idea, I could evaluate it more clearly. If I walked into a discussion with a formed opinion, that opinion carried its own momentum — a subtle pressure to see it validated. When someone else voiced the same thought, I had no stake in defending it. I could weigh it honestly against other ideas. Listening first increased my objectivity and made space for others.
That experience taught me something I wish I’d learned earlier: my voice and opinion were not nearly as important as I thought they were. I had smart people. The answers were already in the room. My job was to create the conditions for them to surface, not to be the one who provided them. Letting go of the need to control outcomes and trusting the team was a challenging lesson, but I’ve come to believe it’s one of the most critical to me in leadership.
That lesson didn’t stay in the Director role. I carried it directly into the CTO seat. The mechanism is the same: in meetings, I listen more than I speak. I try not to voice strong opinions or direct outcomes unless I genuinely believe my perspective is critical and wouldn’t otherwise surface. I respect what others bring to the table, and I’ve found that when I hold back, the table usually has what it needs.
What changed as CTO was the degree of trust. I’m not part of the daily work at this point. Problems get solved without me, not because I removed myself from the process reluctantly, but because the team is capable of solving them. My involvement tends to come when something requires an enterprise perspective: helping frame a situation for a customer, facilitating communication between departments, or bringing strategic context that the team doesn’t have visibility into. Those are the moments where my voice adds something. The rest of the time, the best thing I can do is stay out of the way and let smart people do their jobs.
That said, staying quiet is not the same as being passive. There are ideas I believe in strongly enough to champion — to introduce, repeat, and advocate for until they take hold. AI adoption is a good example. I’ve been pushing for our team to embrace AI tools for over a year, because I believe it’s strategically critical for us to stay competitive. I now have many champions on the team and we’ve adopted it wholeheartedly. That’s a different kind of leadership than solving a daily problem It’s about pointing at something on the horizon and saying, “We need to go there.” Once the team sees it too, they take it from there. I’ll write more about that in the next post.
A developer on our team described this dynamic better than I could when I asked what had driven our transformation:
“Identifying an area where we need improvement and giving team members the space to figure out the ‘how’ around that improvement helps us own the process and desire to optimize it.”
That’s exactly it. My job is to point at the thing that matters. The how belongs to the team. When they figure out the how, they own it. When they own it, they care about whether it works. When they care about whether it works, the quality of what gets built is different than it would have been if I’d handed them a solution.
The behaviors that make this possible are small. I ask more than I answer. When someone proposes a solution, I ask what problem it’s solving before evaluating whether it’s a good solution. When we debrief after an incident, we treat it as useful data and an opportunity to improve, not a mistake to explain away. None of those things require a process or a framework. They require consistent practice over time, and occasional awareness of when I’m defaulting back to the old pattern because the pull toward inserting myself is always there.
When I asked my team what they thought had driven our transformation over the last two years, none of them described a decision I made or a solution I provided. They talked about culture, safety, trust, and experimentation. They described an environment, not a leader with answers, but a set of conditions in which the team could find answers itself.
Some of those answers were generous in ways I won’t pretend not to appreciate. “Change starts at the top” — that’s me, and I’m comfortable owning that. But the more important validation was broader than any comment about my leadership. The culture and safety this team described are a group effort. I’ve played a significant part in building them. So has everyone else on this team. I’m comfortable taking some of the credit and leaving plenty on the table for the team.
Simon Sinek argues in “Leaders Eat Last” that the most effective leaders are not the ones with the best answers but the ones who create environments where people feel safe enough to bring their best thinking, take risks, and solve problems collectively. The title itself captures the principle: a leader’s job is to put the needs of the team first, to absorb uncertainty and pressure so that the people doing the work don’t have to. That framing resonated deeply with me. It’s a human-centric view of leadership that has nothing to do with authority and everything to do with conditions. A leader’s job in that model is not to be the answer. It’s to protect the conditions that allow the group to find the answer itself. That’s the job I’ve been trying to do. I don’t always get it right. But I think it is the right job.
Every problem you solve yourself is one your team doesn’t get to learn from.
The final two posts are about the two biggest bets we’re making on the future — the role AI is beginning to play in how we build software, and engineering quality earlier in the process.
By Darryl Brown
When I moved from Director of Software to CTO, two things changed that fundamentally shaped how I operated.
The first was accountability. For the first time, there was no one above me in the technical organization to escalate to, defer to, or share the weight with. My peer executives provided much needed guidance on people issues, budgets, and other enterprise-wide topics, but when it came to technical challenges, I owned them. That was a clarifying and somewhat uncomfortable realization.
The second was how I spent my time. I stopped doing the work and started thinking about it instead. About the team. About what we were trying to accomplish. About what should matter to us and why. I was no longer expected to write code regularly, and that freed up space to think strategically in a way I had never done before.
I did actually receive an instruction book of sorts — about twenty pages describing the recurring tasks, daily rhythms, and monthly activities of my predecessor. But alongside it came something as valuable: the explicit direction that I should make the role my own. The basics needed to get done, but how I did them was up to me.
What I inherited was a description of activities. What I had to figure out for myself was the purpose behind them. This was the early days of asking “Why?” — a habit that, as you’ll see throughout this series, turned out to shape almost everything we did.
Before this role, I’d been CTO at smaller companies — teams of ten or fewer — where the job looked a lot like my directors’ jobs do now: part strategy, part getting the work done. I know what it feels like to be pulled in both directions simultaneously, to have a meeting about team structure immediately followed by a problem that needs fixing. That experience gave me empathy for what I was asking of them.
That transition, for me, happened because I embraced it. My directors didn’t have the same choice — and in my view, they have the harder job.
They manage their disciplines, contribute to the daily work, and were now being asked to think strategically about their domains at the same time. The immediate, visible work never stops demanding their attention. Strategic thinking, by contrast, doesn’t produce immediate, visible results. It’s exactly the kind of important-but-not-urgent work that gets crowded out — and without a conscious effort to protect time for it, it will always lose to the urgency of the day.
Some of my directors were already in their roles before I became CTO, and their expectations had been shaped around tactical execution: doing the work, managing the daily flow, keeping things moving. When I began asking them to step back and think strategically about their domains, I was effectively changing their job description on them. I’m certain that was uncomfortable.
We set strategic goals together in our one on ones. But in some cases those goals weren’t getting the time they needed — the daily work kept winning. In one case I eventually had a more direct conversation. I suggested to this director that perhaps they were not in the right role. I said it without accusation and with genuine openness — they did excellent work in what they were accomplishing, but it wasn’t strategic. I was open, but I also said it plainly: their first priority was being a director, not doing the work. If that meant some tasks took longer and some schedules slipped, that was a consequence I was willing to accept. What I was not willing to accept was that strategic thinking kept getting crowded out by tactical urgency.
That was a tricky conversation for me. In the past, I’ve had a hard time saying things that could be construed as negative to people who work for me. Over time, and in this role in particular, I’ve come to see that impulse as ultimately unkind. The people who work with me deserve my honest viewpoint. That is the most compassionate and fair thing I can offer them, even when it’s awkward or causes discomfort in the moment. Saying “we might have you in the wrong role” is not the same as saying “you are doing terribly.” It’s an honest assessment that gives someone the information they need to make a real choice.
This person wanted to give the strategic work a serious try. And something shifted around this time.
They began making time for strategic goals. Our one on ones became regular reviews of those goals rather than status updates on daily work. They started keeping a running list of ideas — smaller items that could be worked on independently, and larger ones that fed into their annual goals. That list became the actual fodder for their strategic projects, not an aspirational document that sat untouched.
But the biggest change was harder to measure and more important than any list. They started asking why.
Why are we doing weekly status reports for this customer by hand? Why are we collecting detailed time tracking data for every minute of everyone’s day? Those questions , asked genuinely, about things that had always just been done, are exactly what a director should be asking. They are also, not coincidentally, the same questions that drove most of the transformation described throughout this series. The “ask why” discipline doesn’t just apply to software pipelines and process automation. It applies to every layer of how an organization operates. When a director starts asking it about their own domain, the leverage is significant.
Each director began spending time asking a different category of question than they had before. Not “What needs to be done today” but “What is causing stress on my team?” Not “How do I move this task forward” but “What friction keeps this task from moving forward on its own?” Not “Did we ship this week?” but “Are we doing better than last week?”
Those questions sound simple. They’re not easy to make time for, and they don’t get rewarded in the short term. But they are where the real leverage lives. The changes described in most of the other posts in this series — the process redesign, the automation work, the sprint structure, the shift to quality engineering — all of them started with someone stepping back and asking one of those questions seriously.
In Post 4 I wrote about the practice of asking “why” five times to reach the root cause of a problem rather than treating the symptom. A director asking “Why are we doing weekly status reports for this customer?” is making exactly the same intellectual move as an engineer asking “Why does this step exist in our process?” The question is the same. The leverage is just different. When that habit takes hold at the leadership level, it doesn’t just improve a workflow. It changes how an entire domain is managed.
Patrick Lencioni’s “Five Dysfunctions of a Team” identifies absence of accountability and lack of commitment as two of the five ways teams fail. Looking back at that director conversation, I can see both at play. and in a specific sequence. The absence of accountability was on me. I hadn’t held my director to the strategic expectations of the role clearly enough until that conversation. The lack of commitment was on him — he hadn’t fully committed to the director role while the pull of the daily work remained so strong. What Lencioni’s model makes clear, and what that conversation confirmed, is that the two are connected. Commitment rarely precedes accountability. Once I held the expectation plainly, the commitment followed.
This is one of the areas where we are still actively working. The tension between doing and leading is real and ongoing. What I’m most proud of is that the strategic questions now have a permanent place on our agenda. We’ve created enough space to think about the organization deliberately, rather than letting it simply happen while we’re busy doing everything else.
If your team rarely feels done, it’s worth asking how work is being structured.
Up next I will talk about one of the harder lessons of the last two years. I was realizing that my value as a leader wasn’t in solving problems. It was in making sure problems got solved. The next post is about what that distinction looks like in practice.
By Darryl Brown
In the last post I wrote about removing repetitive manual work from our process. In the post before that, about reducing the friction in how information moved through our team. And in Post 2, about shortening the release cycle so that work reached production in days rather than months. All of those changes had a secondary effect we didn’t fully anticipate: they made the experience of doing the job fundamentally different. This post is about that effect and about two additional changes we made specifically to address it.
I always knew that job satisfaction depended on the conditions around the work — culture, flexibility, recognition. Those things are real and they matter. What I didn’t fully appreciate until recently was how much the shape of the work itself contributes. Specifically: how long, how onerous, and how disconnected the journey from “I understand what needs to be done” to “it’s live in production” actually feels.
That journey has many steps. Understanding the task clearly enough to estimate it. Planning the implementation. Writing the code. Getting it reviewed. Getting it tested. Watching it release. Each of those steps, in our old process, was a source of friction, and the whole journey took months. By the time a developer’s work reached production, they had long since moved on to something else. They might have had to re-acquaint themselves with code they’d written weeks or months earlier just to answer a question about it. And the release itself, the moment the work actually shipped, happened at some distant point, executed by someone else on the team. The satisfaction of completion was diluted by time and distance until there was very little of it left.
That’s what we changed. Not just the speed, though speed matters. What we changed was the experience of completing something.
Today, a developer works on a task and sees it through to production while it is still fresh in their mind. The review happens within a day of the changes being made. Testing follows quickly. When the work ships — released by the reviewer or a quality engineer who has been closely involved — the developer receives a notification. That notification arrives while the work is still alive in their memory. The satisfaction of completion is immediate rather than deferred. The journey from start to finish is something they can hold in their head as a single experience rather than a series of disconnected episodes spread over months.
Several things contributed to improving job satisfaction over the last two years — the compressed journey from start to production, the culture of safety and experimentation, the removal of process friction from the work itself. But two of the more concrete and immediate interventions are worth describing in detail, because the mechanism behind each is instructive.
The first was moving to weekly sprints.
This was important in part because of a new challenge in our development context. Over the last two years our development work has grown significantly, and the markets we’ve begun serving changed the time horizon of that work. Tasks that previously unfolded over months were now expected in weeks or days. For a team whose processes were built around longer cycles, it created real stress, not because the work itself was harder, but because the rhythm of the work had changed and our systems hadn’t changed with it.
One of the things that amplified that stress was the backlog.
Every development team has more work than time. That’s normal and healthy. It means there’s always something worth doing next. But there’s a meaningful difference between an infinite pile of shifting priorities and a finite, agreed set of commitments for the current week. We had the former. People were staring at an enormous list of tasks whose priorities changed weekly, with no clear signal of what mattered most right now. The pile felt overwhelming not because it was larger than usual, but because it was unbounded and unstable.
The stress wasn’t really about the volume of work. It was about the absence of clarity. Sprints were how we chose to address this. Not a new idea, I considered it a good thing we were not inventing a solution from scratch.
A sprint is essentially a commitment: here is what we are certain about for this week, here is the work we are agreeing to do, and everything else can wait. The pile doesn’t get smaller. It never does. But it becomes legible. Instead of an undifferentiated mass of tasks, you have this week’s work and everything else. That distinction, it turns out, does a significant amount of the work that “motivation” usually gets credit for.
We started this process by looking at our metrics, specifically the average number of points estimated on work items we were completing each week, and used that as our sprint goal. It didn’t take long to notice a problem with that approach: average means you don’t hit the target half the time. It also didn’t account for unplanned work coming in from support. A sprint you regularly fail to complete is not a sprint that makes people feel like they’re winning. So we adjusted. We now define sprints with a lower total than the average — sprints that are genuinely achievable rather than theoretically possible. The goal is a sprint you can finish, not one that proves how much you can take on.
Once defined, the sprint lives on its own Kanban board with all work prioritized from top to bottom. A developer doesn’t need to ask what to work on next. The board answers that question. They can see exactly where the finish line is.
There’s a subtlety here worth naming. Priorities did still shift. That’s the reality of any software business, and we weren’t going to pretend otherwise. But the sprint created a protected window. Whatever was happening to next week’s priorities was not relevant — no developer was watching next week. Their current week was static. The work was agreed, the order was clear, and nothing was going to change it mid-stride. That stability, even just for five days, turned out to matter enormously. It’s the difference between running a race where someone continuously moves the finish line and running one where you can see exactly where it is.
The second intervention addressed the daily clarity problem.
Each morning, every developer receives an automated Slack message — built with n8n, drawing from both our project management tool and our code repository — that summarizes exactly what tasks are on their plate for that day.
Here’s what one of those messages looked like for a developer on our team this week:
The odds of hitting your target go up dramatically when you aim at it.— Mal Pancoast
In Review
- TVC – Pipes welded too many times… 1
In Progress
- API 751 Create the Failure Reason chart… 2
Blocked
- Update permission on dashboards and tvc so all use… No estimate.
- Create a project progress chart… 3
- Audit Trail is not recording values populated duri… 3
- Traceability – Convert JS files to TS and add unit… 2
All tasks assigned to them, in priority order. All code reviews waiting for their attention. Everything in one place, at the start of the day, without anyone having to compile it or send it manually. And, because a little humanity goes a long way, a daily quote to start things off.
It sounds like a small thing. In practice it changed the experience of starting the workday. Instead of opening multiple tools and trying to reconstruct a picture of what needed attention, the picture was already there. One message. Clear priorities. No ambiguity about where to start.
It also removed a category of interruption we’d normalized without realizing it — the mid-morning ping asking whether someone had seen a review request, or the end-of-day message checking in on a task. When everyone already knows what’s in their queue, those conversations become unnecessary.
Underlying both of these changes is the same principle from the earlier posts in this series: don’t ask people to do things that the system can do for them. Sprints removed the need to make daily priority decisions. The morning summary removed the need to reconstruct your own to-do list. What remained was the work itself, which is what people came to do.
Shawn Achor’s research in “The Happiness Advantage” inverts the assumption most of us carry into work: that success produces happiness. His finding is that it works the other way. Positive emotion, a sense of progress, and small wins prime the brain for higher performance. We weren’t trying to make the team happier as a side benefit of moving faster — but Achor would predict exactly what happened: the happiness and the higher performance came together, both the result of designing a process where people could complete their work, see it ship, and feel the satisfaction of that — quickly and regularly.
Any developer will tell you: they want to build things and ship them. They want to hold a complete piece of work in their mind from start to finish and feel the satisfaction of seeing it land. The longer and more fragmented that journey, the harder it is to stay connected to why the work matters. We compressed that journey as much as we could. In LEAN terms, we were reducing cycle time, or the elapsed time between starting a piece of work and delivering value from it. Shorter cycle times don’t just improve efficiency. They improve the human experience of doing the work.
There’s a line I wrote in an earlier post in this series that I want to return to here:
Momentum creates pride. Pride creates ownership. Ownership creates quality.
I believe that. And I’ve watched it play out. When developers could hold their work in their heads from start to finish — when completion was days away rather than months — the experience of the job changed. They spent less time navigating process and more time solving problems. Which is what they came to do.
Job satisfaction, in the end, wasn’t something we designed directly. It was a byproduct of designing everything else well. Get the process right, shorten the journey, make the work winnable — and the satisfaction follows.
If a metric doesn’t change what your team does, it’s just something you’re tracking.
Next: as the work itself changed, so did the demands on the people leading it. The next post is about what happened when our directors had to shift from doing the work to thinking strategically about it.
By Darryl Brown
Every change we made over the last two years was an experiment. We had a hypothesis that simplifying our pipeline would increase throughput, that weekly sprints would reduce stress, and that automated code reviews would catch issues earlier. But a hypothesis without measurement is just an opinion. To know whether our experiments were working, we needed to establish what we were measuring before we changed anything, make the change, and then watch what happened. That discipline — measure, change, observe — is what turned our instincts into evidence. Metrics were how we replaced hope with information.
The framework we’ve been developing to structure that discipline looks like this:
Define the problem clearly:
- What is the problem or behavior we are trying to address?
- Why does it matter?
- What is the measurable current state/the baseline we can track against?
Design the experiment:
- What is our theory on why the problem is occurring?
- What solution or change do we want to try?
- What does success look like, and by when?
That structure forces two things we used to skip: defining the metric before the experiment begins, and separating the problem from the solution. It’s easy to correctly execute an experiment and still have a negative impact on the thing you actually care about because you were measuring the implementation rather than the outcome. Defining the metric first removes that trap.
This framework is still a work in progress. Not all of our experiments have been this well-structured. We’ve tried things with less rigor, measured the wrong things, or defined success too loosely. But it’s the standard we’re working toward, and when we get it right, the difference is clear.
Here’s what it looks like when it’s done well. Our Director of Quality Engineering recently defined this goal:
Goal: Reduce late requirement clarification.
Problem: Developer time is lost to requirement clarification after implementation has already started — a costly and disruptive pattern.
Outcome: By year-end, decrease late requirement clarification by 75%, without increasing the time spent refining requirements upfront or reducing overall throughput.
Measures: Late Clarification Rate as the primary metric; a diagnostic metric we call the Definition of Ready False Confidence Rate — which tracks cases where a work item passed our readiness check but still generated clarification requests later.
Hypotheses: Readiness criteria for work items can be implicit or inconsistent; requirements are validated too late in the process; developers compensate for unclear work items during implementation rather than flagging them earlier.
Experiments: Introduce structured readiness criteria by work item type; implement and refine Definition of Ready enforcement mechanisms, including the AI-powered automation described in Post 4.
The problem is specific. The outcome is measurable and time-bound. The hypotheses are honest about uncertainty. The experiments are designed to test those hypotheses — not just to implement a solution and hope it works.
Getting to that kind of clarity required some hard lessons about metrics themselves.
Early in this journey we made a serious attempt at building a proper data infrastructure. We set up a data warehouse and used automated connectors to pipe data in from our various tools: time tracking, project management, development workflow. The goal was a single place where we could see everything, compute trends, and make informed decisions about the team.
It was a good instinct. For a larger organization with dedicated analytics capacity, I still think that’s a great architecture. But for a twenty-person team, the cost-to-benefit didn’t hold up. Maintaining the connectors was more overhead than we could absorb, and when they broke — which happened with enough regularity to be a problem — the data became unreliable. We’d look at a metric, trust it, and make a decision based on it, only to discover later that the underlying data had been wrong for weeks.
Inaccurate metrics are more dangerous than no metrics. At least with no data we knew we were operating on instinct. With bad data we were operating on incorrect evidence.
So we pivoted. We moved our time tracking into our project management tool, which already held our workflow data, and leaned on what it provided out of the box. We traded sophistication for reliability. For our team at our size, it was the right call. A simple metric we trusted was worth more than a sophisticated one we didn’t.
We also learned that a metric isn’t a thing you add to a dashboard because it seems interesting. It’s a specific answer to a specific question: is this experiment working? For that, three things matter: the metric has to be easy to collect, it has to be accurate, and it has to reach the person whose behavior we want to influence. If any one of those is missing, we don’t have a metric. We have noise. And noise is worse than nothing.
We track throughput — the total number of completed tasks and their estimated points per month — as a trend line. When we add AI to our development process, the throughput trend tells us whether it’s moving the needle. We track production bug rates when we experiment with new quality engineering approaches. These are straightforward signals, not sophisticated dashboards. But they’re accurate, they’re current, and we trust them.
A number on a dashboard that nobody acts on is decorative. A piece of information that lands with the right person at the right time and changes what they do on a Tuesday afternoon — that’s a metric earning its keep.
The broader principle here connects to something Gene Kim illustrates throughout “The Phoenix Project.” In a factory, you can walk the floor and see exactly where work is piling up, where machines are idle, and where the bottlenecks are. In a software organization, that visibility doesn’t exist by default. You have to build it. That’s what our metrics are trying to do. Throughput trends, bug rates, clarification rates, these are our factory floor. They make the state of our process visible so we can see what’s actually happening, not just what we assume is happening. Without them, we’re managing blind.
We are still building this out deliberately, adding metrics where we can answer the “what decision will this change” question clearly, and resisting the temptation to add them where we can’t. The principle we’re holding onto: every metric we add should either tell us something we’ll act on, or tell someone else something they’ll act on. If neither is true, we probably don’t need it.
Before you automate anything, make sure it’s worth doing in the first place.
Next up we will look at what happened once we had a way to measure our experiments and what made developers genuinely want to show up.
By Darryl Brown
The mantra that shaped a lot of our thinking over the last two years was simple: eliminate, automate, or delegate. In that order.
That order matters. Automating something you don’t need to do is just efficient waste. So before we reached for a tool or built a workflow, we asked why the step existed. What problem was it solving? Was that still the right problem? Was there a simpler version of the solution we hadn’t considered? LEAN manufacturing calls this muda — the elimination of waste before optimizing what remains. We didn’t start with that vocabulary, but we arrived at the same principle.
At some point in the last two years, something shifted in how our team instinctively responds to a repetitive task.
The first question stopped being “who does this?” and became “why are we doing this?”
That’s not a rhetorical question. We ask it genuinely, and we keep asking it, working back through the layers until we reach the root of what a given step is actually trying to accomplish. Sometimes that process reveals something useful: the step exists to solve a problem that no longer exists, or that could be solved more simply, or that we’d assumed needed solving but actually doesn’t. When that happens, the best outcome is that the step disappears entirely. Problem gone. No solution required.
This isn’t a new idea. Sakichi Toyoda built it into the Toyota Production System decades ago — the practice of asking “why” five times to reach the root cause of a problem rather than treating the symptom. We didn’t invent it. We just found that it applied as naturally to software process as it did to a factory floor.
That’s the first move: eliminate. We try to hold every step in our process to a simple test: Does this add value to the outcome, or does it just exist because it always has? Only once we’re satisfied a step genuinely earns its place do we ask the next question: Does a person need to be the one doing it?
For a lot of what we looked at, that questioning process didn’t eliminate the step, but it changed our understanding of it. And that understanding shaped what we built. If you know precisely why something needs to happen, you can design an automation that actually serves that purpose rather than one that mechanizes the existing habit without questioning it.
In the last post I wrote about redesigning our process so that messages and manual handoffs weren’t required to move work forward. Automation was the backbone of those changes. Once you’ve redesigned the process, you start asking: of the steps that remain, which ones actually require a human? The honest answer, more often than I expected, was: not many.
Let me give some concrete examples of what this looks like in practice.
When a developer starts work on a task, their set of changes should be automatically linked to the relevant work item in our project board. When those changes are submitted for peer review, same thing. When the review is approved and the changes are merged into the shared codebase, the work item status should update without anyone deciding to update it. When code reaches production, the board should reflect that immediately.
None of those steps require human judgement. They require information to move from one place to another at the right moment. So we automated them, using a combination of our project management tool, our code repository, and n8n, a workflow automation platform that connects systems together without requiring traditional software development skills to use.
he result is a board that reflects reality. When a developer looks at the board, they’re seeing an accurate picture of where everything stands, because the system is maintaining it.
That matters more than it sounds. A board that’s occasionally out of date is one you stop trusting. And a board you don’t trust is worse than no board at all. The deeper principle I kept coming back to was this: every unnecessary decision point in a process is a tax on attention.
One of the things that made this possible at our scale was n8n. It lowered the cost of building automations considerably — to the point where the people closest to a problem could often build the solution themselves, without needing to queue it as engineering work. That last part is important, and worth a concrete example.
As part of a broader initiative to catch quality issues earlier in our process — something I’ll write about in a later post — we defined a Definition of Ready: a set of criteria every work item must satisfy before it can be assigned to a developer. The question then became how to check work items against that definition without creating a manual review burden. One of our quality engineers took that problem on herself and built an n8n workflow to solve it. The workflow evaluates work items against our Definition of Ready using an AI agent. If a work item passes, it gets tagged “ready.” If it doesn’t pass, it gets tagged “not-ready” and receives an automated comment describing exactly what the AI found missing, with a reference to the person who created it. The entire workflow — including the AI integration — took her approximately one day to build.
The code review notification described in the previous post is another good example of the same principle: the right information reaching the right person automatically, with no human intervention required. Two very different problems, the same underlying approach.
The best automations tend to come from the people who feel the friction most acutely. If building an automation requires submitting a request and waiting for it to be prioritized, most of the smaller but genuinely valuable ones never get built. n8n removed that barrier — anyone on our team can build one, not just engineers. The result was an automation that doesn’t just identify a problem — it closes the loop entirely. No human has to triage, interpret, or forward anything. The right information reaches the right person with the context they need to act. The deeper principle was this: every unnecessary decision point in a process is a tax on attention.
Not every step that looked like a decision actually required one. Is this set of changes linked to the right work item? Has the status been updated since the code was merged? These aren’t interesting problems that deserve a developer’s focus. They’re administrative overhead dressed up as tasks. Add them up across a team of twenty people over the course of a day, and the attention cost is real, not because any single one is significant, but because the cumulative interruption to focused work is.
Our goal was never to automate people out of the process. It was to make sure that when a person’s judgement was genuinely required, they had the headspace to apply it. Skilled engineers should be solving hard problems. Not checking whether a card got moved.
Over time, the list of automated workflows grew, not because we sat down and planned an automation strategy, but because the habit developed. Someone noticed a repetitive manual step, asked whether it needed to be manual, and more often than not, it didn’t. Each automation that worked made the next one easier to justify.
In “The Phoenix Project,” one of the core ideas Gene Kim returns to repeatedly is the cost of unplanned work, or the small interruptions and manual tasks that don’t show up on any plan but quietly consume a significant portion of a team’s capacity. Repetitive manual steps are exactly that. They seem trivial individually. Collectively, they’re a meaningful drag on what a team can accomplish.
Automating is a decision about where skilled people’s attention actually belongs.
As with many of these changes, there is a more subtle positive result that is harder to measure, but real and maybe more important. People get to spend more of their time doing what they want to do instead of managing process. I discuss this in the next post.
There’s a version of this principle that goes further than workflow automation — further than anything a project management integration or an n8n flow can handle. I’ll get to that in a later post about AI. But the foundation is the same idea: if a step in a process is repetitive and predictable enough to automate, take the time to do it.
If work only moves when someone follows up, the system isn’t doing its job.
You can’t design something deliberately without being able to measure it. The next post is about how we approached metrics — what worked, what didn’t, and what we learned about the difference between measuring things and actually changing them.
By Darryl Brown
Our communication problem wasn’t too many meetings. It was Slack, our internal messaging platform.
More precisely, it was the fact that our process required Slack interactions to function. For many common stages in our process — a priority shift, a handoff, a release request — someone had to message someone else. The work couldn’t progress until a person intervened. And so people intervened, constantly, because that’s what the process asked of them. Nobody was doing anything wrong. The system just ran on human nudges, and Slack was where those nudges lived.
The specific friction points were familiar to anyone who has managed a software team. A project manager needed to communicate a priority change and that meant finding the right developer and messaging them. QA finishing a piece of work didn’t automatically signal anyone; someone had to notice and act. Releasing a feature required requesting it of the team member who held that responsibility, which cycled between team members. Every one of those moments was an interruption for both the sender and the recipient. Multiply that across a team of twenty people and dozens of active work items, and the noise adds up quickly.
The deeper issue was that each of those interruptions represented a gap in the process — a place where the system couldn’t carry information from one stage to the next on its own, so a person had to carry it instead.
We moved from Pivotal to ClickUp, but the tool change was almost beside the point. What mattered was how carefully we defined the process inside it. We built a Kanban board where all active work lived, prioritized and visible to everyone. But the more important work was defining the states a piece of work could be in at any given moment. We spent real time thinking through what each state meant, what triggered a transition, and critically: who needed to know when that transition happened.
Let me give a concrete example of what that thinking produced.
One of the most important states we introduced was “Merged.” When a developer merges code to the main codebase, the work is in a vulnerable position. It exists in between intention and reality. The code is committed but not yet in production. That moment deserved its own state, its own visibility, and its own automated response.
In the new process, the developer follows four steps:
- Merge changes to the main codebase.
- Test, if needed.
- Mark the work item to “Pending Deployment” in our board.
- Release the code by typing /release into Slack.
Within those steps, a lot of automation occurs in the background, giving the developer all the information they need to move through each step and release to production confidently. Notably, there is no communication with anyone else required. The developer does not need to reach out to a single person. The result was that everyone on the team received both the power and the responsibility to release code.
To appreciate why that matters, it helps to know what we replaced.
Previously, releases were a significant event. Over the course of a month, and sometimes up to three months, developers would merge work into a shared codebase. When the team decided enough work was ready, QA would test the entire batch together. Spreadsheets tracked names and versions by hand. A person was specifically assigned to each release, responsible for preparing and executing a lengthy set of release instructions. As often as not, something would go wrong mid-release, pulling in various people to troubleshoot. The release was a staged production itself.Now a developer types /release in Slack. That’s it.
Early on, there was hesitation about whether something that simple could really be trusted. I answered that question one afternoon when I took some time off to go mountain biking. In the middle of my ride, I pulled out my phone, typed into the Production Launch channel that I was doing the next release, tested the new command via Slack, and sent an irrelevant selfie from the trail. The release went fine. If the CTO can release code from atop a mountain bike, the process has genuinely changed.
The wider goal of reducing communication was simple in principle and harder in practice: a developer should be able to look at the board and know exactly what to work on next without anyone messaging them. QA should know when something is ready to test without being pinged. A priority shift should be visible to everyone the moment it happens, without a broadcast message.The process should carry the information, not people.
Another change I’m pleased with is one we built with n8n to address the code review problem.
Anyone who has worked on a software team knows the notification problem. The volume is extraordinary — review requests, comments, approvals, automated assignments. It becomes a firehose of information. I turned off all GitHub email notifications some time ago. They stopped being useful precisely because there were so many of them.
A little context for non-technical readers: when a developer completes a set of changes, those changes must be peer reviewed before they can be tested or released. A second set of eyes catches problems before they reach customers. Those review requests get assigned to another developer — and developers, reasonably given the noise, weren’t always responding quickly. Work sat waiting. There was no clear picture of where things stood.
Rather than creating a new reminder process or a policy about review turnaround times, we built an automation. At the start of each day, it looks at all open review requests, checks their status, and sends a single targeted Slack message to each developer summarizing everything pending — both requests waiting for their review and their own changes waiting on others. It also shows how long each has been waiting.
Here’s what that message looks like in practice:
Aldo Rojas — Outstanding code reviews
0 days old — reviews to complete:
- Fix form search field bug — IN REVIEW
- Add ability to restrict assets via cabinet menu — IN REVIEW
Reviews needing attention:
- Adding quarantined assets to quality checks — CHANGES REQUESTED
Your changes in review by others:
- Removing Missing Image / kept Missing Stencil Image — waiting 10 days
- Applying changes to traceability dashboard — waiting 11 days
We have a one business day expectation on review responses. The automation didn’t enforce that rule. It just made the current situation visible to the person who could act on it — specifically, clearly, and at the right moment.
That’s the principle I keep returning to, and it connects to something Rory Sutherland explores in his book “Alchemy,” which I’d recommend to anyone who thinks seriously about how behavior actually changes. Sutherland’s core argument is that humans are not rational optimizers. We respond to context, framing, and environment far more than we respond to incentives or explicit instructions. Small changes to what people see and when they see it often shift behavior more reliably than rules or consequences ever could. We didn’t tell developers to review faster. We just made it impossible not to notice when they hadn’t. The behavior changed because the visibility changed. Sutherland would not be surprised.
There’s a pattern in all of this worth naming.
Every place in our process where someone had to send a Slack message to make something move forward was a gap. Sometimes those gaps required human judgement to fill — context, relationship, nuance. More often, they just required the right information to arrive at the right place at the right time.
If your pipeline feels heavier than it should, it probably is. Start asking what actually needs to be there.
We didn’t try to reduce communication. We tried to make communication less necessary and less driven by people. When someone did reach out, it was because something genuinely required a person, not because the process had failed to carry information on its own.
Next: we took this further. Once we’d reduced the communication our process required, we turned to automating the repetitive tasks that were left. That’s what the next post is about.
By Darryl Brown
In my last post, I described my first step as CTO — holding a retreat to consider our current state and imagine a future one. This post is about what that retreat yielded, and what implementing those commitments unlocked.
When I stepped into the CTO role, one of the first things I wanted to understand was how we shipped software. Not just the mechanics, but the feel of it. How long did it take? What did it cost in effort and attention? What did it feel like to the people doing it? This wasn’t by chance. I had worked in that system, and felt it was ripe for improvement.
At the retreat, we started by discussing our current state honestly.
In the best scenario, we had a three-month cycle from the moment a piece of work became actionable to the moment it reached our customers in production. Work moved through multiple testing and validation stages, each supported by a complex infrastructure of custom-built tools and processes. Over the years we’d built hundreds of purpose-driven solutions to support that pipeline.
It wasn’t all bad. The defining principle of our process was quality. Our production error rate was near zero. That level of reliability wasn’t an accident. But there was a cost.
Because we shipped in large batches and staged work through long cycles, it was challenging and time-consuming to get a meaningful set of improvements out in a single release. We averaged one release per month.
The longer a piece of work lingered, the harder it became to ship cleanly. By the time changes entered their third month, they had to survive inevitable churn: other work moving, assumptions or requirements changing, dependencies shifting.
Then there was QA. By design, QA was our bottleneck. They couldn’t keep pace with the volume of work being completed. We had changes that were years old, not because they were bad ideas, but because we never had the bandwidth to test and release everything we’d built. In one memorable example, a developer left the company for three and a half years and returned shortly after I became CTO. He ended up shipping his own work four years after he’d originally written it.
This ponderous process carried its own risk. When you can’t ship quickly, you can’t respond quickly to bugs, to customer requests, to anything.
For my part, I was willing to accept some risk in exchange for speed. Ship faster, and perhaps we introduce more issues but we can respond faster too.
Prior to the retreat, I challenged the team to come up with proposals for how to make our process simpler. I’d used Vercel previously for small projects — a platform that makes deploying software effortless. Make a change, and it’s live. That simplicity creates a default expectation: shipping is easy, so you ship more often. I didn’t know if we could replicate that experience with a legacy product and real customers. But I was asking: could we get close? Could releasing software become something we did continuously, rather than something we prepared for over weeks?
At the retreat we talked openly about how painful the current process was, defining what those pain points were, then turning to imagining an improved future state. There were three days of discussion, iteration, and ideation. Presenting it here makes it sound straightforward. In practice, we had many false starts and tangents. Those were as important as the ideas we kept. All ideas were met with openness by the team. One key ingredient to these discussions was research done beforehand by key developers. They looked at how the best software teams in the world were solving these problems, and that guided much of our vision.
In the end, the team envisioned a future state built on two commitments:
- We would practice continuous development — shipping small, reliable improvements to customers on an ongoing basis rather than in large, infrequent batches.
- We would drastically simplify our delivery pipeline — challenging everything we’d built and keeping only what we could genuinely justify as adding value.
To implement continuous delivery, we adopted a workflow where every developer integrates small, frequent changes into a single shared version of the codebase, relying on automated checks to keep it always ready to ship. This has an important implication — there’s no room for a long testing cycle where work piles up and ships together. The size of each change must shrink. Testing must become continuous. Releasing must become easy and frequent.
To understand what this actually changed, it helps to know what we replaced. Previously, a developer would work on a set of changes for a minimum of three months. Those changes moved through multiple separate stages, each with their own infrastructure, before reaching customers.
Under the new approach, a developer completes a set of changes and submits them for review. Once approved, those changes are marked ready for testing. QA picks them up, merges them into the shared codebase, which triggers an automated build, and starts testing immediately. When tests succeed, the changes are released straight to customers. The typical cycle is a few days to a few weeks, not months.
The reaction from the team as we started implementing these changes was telling. The team was enthusiastic, but we also felt uncomfortable with the speed. It felt almost like we were doing something we shouldn’t be. Work was reaching customers so quickly that people kept waiting for someone to say it wasn’t allowed. I was the only one who could have said that, and I didn’t want to.
It is worth naming again that these ideas came from the engineers who had built the original pipeline. The same people who had designed and maintained that complex system were the ones who proposed replacing it. I think that happened because the retreat created two conditions that had been missing. First, genuine space to say “we could do this differently.” Second, a belief that the team had the support and the will to actually make the changes. Once those conditions were met, they didn’t need me to tell them how. They knew better than anyone where the pain lived.
We started the transition in late January. The technical lift was not trivial, but it was accomplished in weeks. And much of the effort was less about building something new and more about removing what we no longer needed. Simplifying. Deleting. Unwinding complexity that had accumulated over years.
That was a lesson I’ve carried since: unwinding complexity is much faster than building it.
Once the streamlined pipeline was in place, the workflow changed. When any pending work was tested, we would release it immediately. I’ll write separately about the process and communication changes that made this flow smoothly — that’s its own post.
The results were immediate and significant.
Within about a month, we went from one release per month to several releases per day.
These changes had a cumulative and dramatic impact on productivity. Over the first quarter of 2024, the number of completed work items reaching production nearly doubled. And, it kept going up. By the end of 2024, we had a sustained throughput gain of roughly 4 times compared to our previous baseline.

Here’s the part that surprised me most: our bug rate didn’t go up. It effectively went down. We had roughly the same number of bugs per month as before, but we were shipping four times the work. The same absolute number of issues across four times the output is a dramatically better ratio. That wasn’t luck, but we had not predicted it.
I can’t say for certain why this occurred. I postulate that when you ship in smaller pieces, faster, you reduce the surface area of potential failure. You find issues earlier, while context is fresh. And you avoid the hidden complexity that comes from batching changes together for weeks. Shipping faster didn’t make us sloppy. It made us sharper. LEAN manufacturing has known this for decades — small batch sizes and reduced work in progress are foundational principles for a reason. We just applied them to software.
Harder to measure — but just as real — was what happened to the team.
Developers were seeing their work reach customers quickly. The feedback loop tightened. The reward came faster. They spent less time navigating process and more time solving problems.
Any developer will tell you: they want to spend their time solving problems — not fighting the pipeline or the process, not watching their work sit untouched for months.
Momentum creates pride. Pride creates ownership. Ownership creates quality.
We didn’t do this because we wanted to go faster. We did it because we wanted a healthier system that we enjoyed working in. The consequence was a system where progress was visible, learning happened quickly, and we didn’t have to choose between reliability and delivery.
We still care deeply about quality. That didn’t change. What changed is how we achieve it.
In “The Phoenix Project,” Gene Kim describes how work piling up at a single constraint compounds across the entire system. QA was our bottleneck by design — a safety net the organization treated as a feature, not a flaw. That wasn’t wrong. It produced a near-zero production bug rate. But it came with a cost to our team enjoyment and throughput that we eventually decided to address differently. Relieving that constraint didn’t lower our standards. It let us meet them more consistently.
Sometimes the safest thing you can do isn’t to slow down. It’s to shorten the distance between start and finish – in our case – building, shipping, and learning.
If progress only shows up in big moments, it’s going to feel slow. Make it visible more often.
In my next post I will share how we redesigned our process to reduce the human communication our workflow required, and what happened when we did.
By Darryl Brown
I became CTO in January 2024. My first major act was to call a team retreat and spend most of it listening. It was the only honest option I had.
I’d been with the team for seven years, first as a developer, then as Director of Software. I knew the people, the product, the technical debt. What I didn’t know yet was what the view looked like from the CTO seat. And I’d learned enough in my first month to know: I didn’t have the information yet to lead with answers.
So I came in with a strong sense of trust in my team, and I listened with an open mind.
I didn’t conjure that approach from thin air. My CEO and the executive team gave me genuine latitude to figure out what needed doing and do it. The trust I was trying to extend to my team started with them.
The retreat happened at the end of my first thirty days. I asked the team to come with open minds and honest assessments of our process, our pipeline, our ways of working. I also conveyed that I was willing to allocate team resources to process and infrastructure improvement. This is not easy as we all know. We, like all teams everywhere, have an unending amount of work on our docket. The team needed to believe that I was willing to commit resources to making these improvements.
That commitment is harder than it sounds. Resources take away from customer deliverables, which drive revenue, which keeps us in business. Stephen Covey writes in “First Things First” about the difference between what is urgent and what is important — and the tendency of urgent work to crowd out important work indefinitely. Process improvement is almost never urgent. There is always a customer deliverable that feels more pressing. And so process improvement gets shunted, year after year, until the cost of not improving becomes impossible to ignore. We had done that. I felt the payoff potential was worth the investment, and it was the kind of team I wanted to be a part of — experimental, improving, dynamic.
The good stuff started to happen after I stopped talking. They had ideas. Not mild suggestions but real, considered, sometimes radical ideas about how things could be different. They’d been thinking about this for a while. What they hadn’t had was a chance to believe these ideas might come to fruition.
Organizations develop rhythms over time. Ways of working become familiar, and familiar things become hard to question, not because anyone decides they’re untouchable, but because that’s just how systems tend to calcify. The team wasn’t stuck because they lacked answers. They were waiting for the conditions to share them — to believe change was possible. I think about Simon Sinek’s concept of the Circle of Safety here — the idea that people will only take creative risks when they are in a trusting environment.
One way we incorporate this trust is in how we frame management decisions. We first present them as proposals to our team and ask for feedback. Occasionally someone raises a concern, and in our experience, those concerns are typically valid. When that happens, we try to iterate in the moment. If a clear path forward doesn’t emerge right there, we form a working group to explore options — a diverse group with the most useful perspective on the problem. The idea comes back revised.
We extended this same approach beyond the development team. Our development organization had fallen into a habit of making decisions and announcing them — decisions that affect other departments: operations, sales, customer success. There were probably good reasons that pattern existed before I arrived, but it wasn’t serving the company well anymore. So we tried to apply the same principle outward: treat cross-departmental changes as proposals too, invite the people affected to weigh in, and iterate when useful. It made for slower decisions occasionally. It made for much better ones, and facilitated buy-in from others since they had participated. LEAN practitioners call this respect for people — the principle that the people closest to a process have the most valuable insight into how it should change. We just extended that respect beyond our own team.
That process — propose, invite objection, iterate — isn’t a formal policy. It’s a habit of framing. It changed the dynamic from a “here is what we are doing” to “what do you think of this?” That shift in framing changed what our meetings felt like. People who had been recipients of decisions became participants in them, and the quality of what we built together reflects that.
I’ll write more about what the retreat’s commitments looked like in practice in my next post.
Spoiler alert: the ideas for specific transformations were not mine. They came from the engineers who had built and been living inside the system. My job was to create the right conditions for the team to generate the answers.
The results were extremely positive. The increase in productivity was something I and our board members appreciated. But at a more fundamental level, the changes affected the team itself. A senior developer put it best: “Once we realized we could change and be successful, it spawned a culture of experimentation that’s now embedded.” There is a palpable momentum that started after we implemented the changes from that retreat, and it is still here today.
I believe a critical part of being a leader is making it easy for the people around you to do what they’re capable of. Sometimes that means having the right answer. More often, it means getting out of the way.
If your team already has the answers, your job might be to make it safe enough for them to say them.
This is a series of what I’ve learned, and what my team taught me, over the last two years.
By Darryl Brown
In 1993, I graduated with a Master’s degree in Artificial Intelligence. At the time, that was a great way to confuse people at parties. AI was an academic curiosity, not an industry. Nobody was hiring for it. I pivoted into traditional software development. I spent the next two decades working through many startups, including running my own web design and development company. I eventually landed at TRU Solutions ten years ago as a developer. I became Director of Software, and two years ago I became CTO.
I’m writing this series for two reasons.
The first is to learn from what we have done. Reflecting on what our team has accomplished over the last two years — writing it down, putting it in order — is how I hope to not lose sight of how we did it. The practices that changed everything could quietly become the new normal, and the thinking behind them fades. I don’t want that to happen. So I’m writing it down.
The second is a small act of gratitude. This industry has given me an extraordinary career over thirty-five years. Hopefully, something in these posts will prove useful to someone in that journey — a developer who wants to lead, a new CTO figuring out the role, someone trying to understand why their team isn’t moving the way they want it to.
Ten posts. Ten lessons. Each one is about something specific: how we simplified our release pipeline, how we redesigned our process to reduce friction, how we approached automation, AI adoption, quality engineering, and more. As I’ve reflected on all of it, I’ve come to think there’s a single thread running through every one of those changes.
We started asking why.
I should mention that I had an unfair advantage in recognizing that thread. My partner (and fiancée) works as an operations improvement consultant and is a LEAN manufacturing expert. As I described changes we were making, she would help me understand how they connected to LEAN principles — small batch sizes, eliminating waste, continuous improvement, creating safety to experiment and fail. What I was doing intuitively, she could validate and name. I got regular free consulting from someone with deep expertise in the subject, and the combination of her knowledge and my instincts turned out to be a great combination. The LEAN principles didn’t drive our transformation from the top down — but looking back, they were present in almost every decision we made. I’ll point to those connections throughout the series.
The other significant influence on my thinking was Simon Sinek. I’ve read several of his books, but Leaders Eat Last struck the deepest chord. His human-centric approach to leadership — the idea that a leader’s primary job is to create an environment where people feel safe, valued, and able to do their best work — helped me find my own why as a CTO. And my why turns out to have little to do with technology. It is about my people and my company. It is about following the principles I have come to believe in deeply — protecting and lifting up the people I work with, excelling together as a team, and serving one another in this shared endeavor – capitalism as a force for good. The technology is the vehicle. The people are the point. You’ll see Sinek’s influence throughout this series, particularly in the posts about culture, safety, and leadership.
And it turns out that leading with people in mind and leading with curiosity are not separate things. The same orientation that asks ‘what does my team need?’ also asks ‘why are we doing it this way?’ Both questions start from the same place — a refusal to accept the status quo without understanding it.
Why are we walking code through five separate environments before it reaches production? Why does this ticket prescribe how something should be built before we’ve understood what problem we’re actually solving? Why can’t releasing software be as simple as merging to a branch? These questions, asked genuinely, repeatedly, at every level of the team, turn out to be a powerful tool. It surfaces assumptions. It exposes complexity that exists out of habit rather than necessity. It creates the conditions for people to propose better answers.
I don’t think I would have named “ask why” as our guiding philosophy while we were in the middle of it. I was applying it deliberately in specific moments without recognizing it as the theme. It took stepping back to write this series to see it clearly. Which is, I suppose, its own small argument for reflection
If any of this feels familiar, I’ll walk through exactly how we applied it in the posts that follow.
The posts that follow are about what we did and, more importantly, how we did it. The what is interesting. The how is what’s actually useful. I hope something here earns its place in your thinking.
