The self-study video course “Surviving Legacy Code” was retired on December 19, 2025. That course has been replaced with this one, but there is no plan for a self-study version of this course. Individuals looking for training should consider joining the waiting list for the Evolutionary Design Studio.

Dealing With Regret in Software Design

Designing software is difficult, unpredictable, and emotionally charged. Even seasoned developers face uncertainty, pressure, and the ever-present risk of looking back at a codebase and thinking, “I wish we had done this differently.” Most of us aren’t taught what to do with that regret, so we ignore it, rationalize it, or let it quietly accumulate.

This course takes a different approach. Instead of trying to eliminate regret, we’ll learn how to work with it. We explore software design regret as a natural consequence of learning in complex environments and help participants develop strategies to respond constructively, confidently, and collaboratively. The focus isn’t on getting things right the first time, but on becoming more aware of our blind spots, building systems that are resilient to change, and sharpening the judgment needed to improve designs under real-world conditions.

Through hands-on coding exercises, personal reflection, and structured group discussions, participants will practise concrete techniques for managing the costs of design mistakes and recovering from them. We’ll work with a curated, intentionally flawed codebase that’s complex enough to challenge, but small enough not to intimidate. And if you’d like to practise applying these techniques to your own codebase, you’ll have the opportunity to do just that.

This course is also grounded in practical realism. We understand that participants will return to environments with inertia, time pressure, and varying levels of team support. Rather than promise transformation through idealized practices, we focus on skills and strategies that work within your constraints, helping individuals and teams pursue meaningful progress without disillusionment or burnout.

Throughout, participants are invited to engage with skepticism and even cynicism, not as obstacles, but as honest signals of past frustration. This is a psychologically safe environment where people can discuss failure, frustration, or fear of judgment without being told to “just do it better.” Whether you’re burned out from past efforts to improve things, or you simply want to make thoughtful design improvements with less risk and conflict, this workshop is designed to meet you where you are.

Audience

This course is for anyone who writes code and has ever felt regret about a software design decision—whether because of a missed opportunity, a rushed compromise, or something that just didn’t turn out the way they hoped. Participants will benefit if they want:

All levels of experience are welcome. It will help if you already feel comfortable using at least one unit testing library and adding it to an existing project. If you don’t currently write code as a significant part of your job, you are still welcome to join, because during hands-on segments, you’ll have the opportunity to engage in reflection, planning, or guided observation instead.

This course is designed to support a variety of technical contexts, including remote/distributed work, regulated environments, and legacy-heavy systems. Instead of endorsing a particular methodology or process framework (such as Scrum, Agile, DevOps), we’ll explore how to adapt core design practices within the organizational and technical constraints you already face.

Typical Course Contents

Every course is different, depending on the participants and their needs, but this is an inventory of a typical course, based on decades of workshops with clients struggling with their software designs.

Understanding Regret in Software Design

  • Why we feel regret in our work and why we rarely talk about it
  • Design decisions under pressure: tradeoffs, uncertainty, and irreversibility
  • How design regret affects individuals, teams, and systems

The Various Costs of “Not Knowing Yet”

  • Understanding the U-curve of effort: design up-front vs. design later
  • The hidden toll of overconfidence, underplanning, and learned helplessness
  • Design uncertainty as a source of both cost and opportunity

Practising Where It’s Just Difficult Enough

  • Hands-on exercises with a curated, imperfect codebase
  • Exploring design flaws with just enough mess to be instructive
  • Option to bring your own codebase or use freely available open-source examples

Making Changes Safely Uses Techniques That Go Beyond Writing Unit Tests First

  • Balancing test-first and test-after workflows
  • Understanding how safety arises from habits, constraints, and skill, not merely “discipline”
  • Common traps when trying to “test your way to safety”

Refactoring for Discovery and Direction

  • Purposeful refactoring: heading toward a known, intentional structure
  • Speculative refactoring: uncovering improvements without a fixed goal
  • When and how to stop refactoring

Practising Foundational Design Moves

  • Revealing intention: naming and organizing to expose design clarity
  • Isolating calculation from action: making logic reusable and testable
  • Removing duplication to discover missing abstractions and relationships

Collaborating Through Design Tension

  • Navigating disagreements about “what good design looks like”
  • Differentiating between design risks and personal preferences
  • Reducing unproductive conflict by surfacing assumptions

Building Design Confidence and Communicating Clearly

  • Turning hindsight into insight without spiraling into blame
  • Strategies for tracking and reflecting on design changes
  • Communicating regret constructively with peers and decision-makers
  • Planning future discussions and code work that apply these techniques at your job

Live/Remote Private Course

The standard course runs as 4 sessions of 1/2 day each scheduled within a 2-week period. The course is suitable for groups up to 20 people. Larger groups should run the course multiple times so that the participants can get the dedicated help they need.

Add team working sessions to your course in order to better support teams working together during the course. During the 1/2-day team working sessions, we practise the techniques of the course using ensemble programming as well as guided exercises. In these sessions, teams have the opportunity to rescue their legacy code with my guidance and support.

It is also recommended to add follow-up working sessions to be scheduled 1 month, 3 months, and 6-12 months after the course ends, as a way to support the group as they apply what they’ve learned to their daily work.

Start the booking process for your live/remote course.