# sebald.me - Content Archive

<article id="/notes/where-the-map-ends">
Title: "Where the Map Ends"
Date: 2026-05-17
URL: https://sebald.me/notes/where-the-map-ends
Topics: design-systems

When you integrate a design system into a legacy product, you learn to be patient. The codebase we were working in had been growing for over two decades. Inline CSS next to string-concatenated templates next to JavaScript tangled up in business logic. Nobody could tell where one ended and the other began. You don't fix that in a quarter. You don't fix it in a year.

So we took a different approach. We built a modern frontend layer underneath the existing UI and styled it to look identical to what was already there. Same colors, same spacing, same components. Product teams could use our design system without fighting the old infrastructure. Customers never noticed anything had changed. That was the point. Early on, the work was about earning a foothold within the software, without triggering resistance.

It worked. Slowly, then all at once, teams started building with the new tools. It turned out the disguise was the perfect cover. Nobody questioned the work because nothing on the surface seemed to be changing. Behind that surface, we had quietly replaced most of the frontend stack: the components teams reached for, the styling that held them together, the JavaScript underneath, the build pipeline that shipped it all. The foundation was solid.

And then we started running into the limits of our own disguise.

The design system could do more than the old interface allowed, but nobody could see or use that, because the disguise required everything we shipped to look and behave like what came before. The gap kept growing. Meanwhile, signals were accumulating that the dated UI was costing us. Conversations with potential customers. Feedback from sales. The occasional lost deal where the product could do the job, but the way it looked made customers doubt its capabilities.

Nobody had touched the visual design in over a decade. Not because nobody cared. Because nobody wanted to be the ones to try.

Not laziness, not indifference. It's organizational inertia, the tendency of systems and the people inside them to stay exactly where they are, or to keep moving in the direction they've always moved, not through active resistance but through the sheer accumulated weight of everything that came before. The longer a system has been running, the harder it is to change course. Ours had been running for over two decades.

## The hidden preparation [#the-hidden-preparation]

At some point we realized the invisible approach had taken us as far as it could. As long as we kept the design system hidden, its potential stayed locked. Inside the team, we had a new visual direction ready: modern, simple, unobtrusive. A safe bet. Something that could earn trust before asking for anything. But it was sitting in a drawer. The disguise had served its purpose. It had let us build without triggering the inertia that would have stopped us earlier. Now it was in the way.

We mapped out which conversations needed to happen, and in what order. We did a pre-mortem on everything that could go wrong. If this fails six months from now, what was the reason? The list was long. A codebase with unknown traps around every corner. No established way to communicate changes to sales. No infrastructure to collect real feedback from users. We were confident we could navigate it, but humble enough to know there were things we couldn't see yet.

None of this was visible to the rest of the organization. But it meant that when the moment came, we weren't starting from zero. We had a direction, a sequence, and an honest picture of the risks.

Then leadership started asking the same questions we had been quietly sitting on. The product was costing deals. The dated UI was no longer something the company could keep absorbing. They had arrived at the same place we had, just from a different direction. That kind of alignment doesn't happen often. When it does, you act.

Aligning with leadership meant agreeing on a direction. The word we landed on was beauty. The immediate work was narrower than the word suggests. The product would stop working against itself. Cluttered surfaces would clear. Dated metaphors would go. Real beauty was a longer arc.

What we didn't have was a picture of what that beauty would actually look like. That question came up constantly once we started. We never fully answered it, because we genuinely didn't know yet. We wanted to react to feedback rather than defend a fixed plan. That turned out to be the right call and also the hardest part to hold. People don't love "we'll know when we get there" as an answer. But it was the honest one.

## Starting without a net [#starting-without-a-net]

We started with things that were easy to reverse.

Change the background color from a muddy beige to a clean neutral. Update the font from Arial to Inter, like every other product on the internet. We picked the simplest, safest changes we could. Not because we lacked ambition, but because we knew that every change was a step into territory we hadn't fully mapped. Anything else risked triggering the inertia.

There was another reason to be careful. The codebase had its own logic. Over a decade of features had been added without anyone stepping back to look at the whole. Workflows that made sense if you had used the product for years were invisible traps to anyone new. Some things that looked like bugs were actually decisions. Edge cases someone had handled years ago for a specific customer, never documented, never explained. You don't learn that from reading code. You learn it from breaking things and dealing with the fallout.

So we kept each change small enough that if something went wrong, we could pull it back within hours. It was the only responsible way to move inside a system this size without a complete map of what everything touched.

Every break taught us something the code wouldn't. Some of it was technical, like styles bleeding into unexpected corners of the product. But the most important ones were human. Every change that shipped was a test of how much the organization could absorb without losing confidence in us. We were learning the tolerance of the system, not just the code.

## Problems you manage, not fix [#problems-you-manage-not-fix]

Technical problems are solvable. You break something, find the cause, fix it, move on. Social, political and organizational problems work differently. You don't fix them and move on. You manage them, and they keep demanding attention. There is no definitive solution, only the next version of the problem.

Take sales, for example. We had been communicating changes, but not every detail, not weeks in advance, not in the level of granularity that would have let people lock in opinions before anything had shipped. That was a deliberate choice. The inertia in a system this old is immense. Give people too much time to anticipate a change and they will find a hundred reasons to stop it before it even starts. We used velocity as a form of protection. Slowness gives the inertia time to work.

We knew that the people who pushed back hardest were also the people who cared most. Sales had been demoing the same screens for years. They knew every flow, every quirk, every odd corner of the old interface. When we changed things, we changed their pitches. Their resistance wasn't irrational. It was information. These were exactly the people we needed to be talking to.

So we brought them in earlier. Still on our terms, but early enough that their objections could shape the work. This slowed us down slightly, the very thing we had been guarding against. We took the trade on purpose. People who help shape a change start moving with it. Bringing sales in didn't just get us better feedback. It turned them from drivers of inertia into drivers of the work.

They caught things we had missed, like features that were technically still present but harder to find, or flows that made sense when you knew the product but were disorienting to someone seeing it for the first time. Their feedback was occasionally delivered with more heat than was strictly necessary. We answered every question anyway. That's where the trust came from: not from having the right answers, but from not flinching when the questions were hard.

That seemed to settle it. It didn't. People would skim through testing and sign off, then come back with serious objections after something went live. We had solved the communication problem and inherited a new one. Inertia doesn't surface when you ask people what they think. It surfaces when they have to live with the answer.

Other times, we'd ship a change that worked well for the majority of users, only to find out that a small group, often top-tier customers with the most at stake and the least patience, used the product in a way nobody had accounted for. We had improved things for most people and made them worse for exactly the people we couldn't afford to disappoint.

Learning to live with that, to keep moving anyway, takes a certain kind of stubbornness. At some point you stop trying to make the discomfort go away and start treating it as part of the job. Because the alternative was to wait for certainty that was never coming.

We learned that the hard way when we set out to make the app layout more responsive. After a while we'd developed a feel for which changes would cause friction and which wouldn't. At least we thought we had. The responsive layout felt safe. It wasn't fixing anything visible. It was just bringing the product in line with what people expect on smaller devices. We didn't expect a reaction.

It came anyway. And fast. Which was jarring, because the change had a legitimate purpose. Large tables had been breaking the layout for years. The product had never been truly usable on mobile, and making it responsive was supposed to be the first step toward changing that. What we hadn't accounted for was how people were actually navigating around that brokenness. They had turned a limitation into a feature, and in doing so, made it theirs.

Nobody knew, including the users themselves, how much the product's daily use had been shaped by its own limitations. The interface had never been built for mobile. On phones and tablets it was technically broken: tables overflowing, elements colliding. But users had found a way. They zoomed out to see the whole table at once, then panned across to read what they needed. The data was tiny at full zoom and barely readable, but they could take in the whole picture. They had been doing it for years. It was awkward, but it worked and they relied on it. When we made the layout responsive, we took that away. The zooming behavior changed. The tables they had been zooming and panning across were now locked inside a responsive container. They had to scroll horizontally instead, and the container clipped the data they needed to see.

We reverted the change immediately.

This was the sharpest lesson of the whole year. The broken thing was the workflow. A decade of workarounds had quietly become the product. Users hadn't asked for it to be fixed because to them it wasn't broken. It was just how the software worked. We thought we were reading the territory. We were still reading the map.

## Moving through it [#moving-through-it]

You only learn things like that by moving. Even when it feels like motion for its own sake. The workflows users build inside the broken parts of a system are easy to miss in research or in conversations. They surface when you take them away.

You can't think your way past inertia. You have to move through it. Every small change we shipped was a conscious act against it, and a source of information we couldn't have gotten any other way. In a system this old, you don't know what it will tolerate until you touch it. You don't know what users actually need until something breaks.

After a year, the visible signs were strong. The codebase had stopped resisting change. Features that used to take months took weeks. A small customer survey on the visual refresh came back strongly positive. But none of that came from a plan we could defend in advance. It came from calls with executives, sessions with sales teams whose demos kept changing under them, conversations with colleagues about decisions that lived nowhere in the documentation. Edge cases added years ago for a specific customer. Behaviors that looked like bugs but were actually decisions. Treating this as a pure technical migration would have lost all of it.

Small reversible steps. The discomfort of shipping something you might have to take back. That was the price of moving.
</article>

<article id="/notes/failing-forward-at-design-systems">
Title: "Failing Forward at Design Systems"
Date: 2026-02-16
URL: https://sebald.me/notes/failing-forward-at-design-systems
Topics: design-systems

When you set out to build a design system, your head is full of components, tokens, and documentation. That's what a design system is, right?

It's tangible work. You can shape it exactly how you want, and it feels like real progress. Then you meet the reality of how your colleagues actually work, and you find out the hard part was never the building.

We learned that the hard way. My team spent four years building a design system for a product with over 20 years of history and all the legacy that comes with it. Most of our assumptions turned out to be wrong, but each time one broke, it pushed us somewhere better than where we'd planned.

## The territory we inherited [#the-territory-we-inherited]

The product was capable. Really capable. But you wouldn't know it by looking at it. The UI felt dated. If you judged the product by its interface, as people usually do, you would severely underestimate what it could do.

This wasn't for lack of effort. Teams were working hard, but they spent most of their energy extinguishing fires caused by decisions made years ago.

Technical debt had compounded to the point where even small UI changes felt risky. "We can't build that" became a reflex, not because the developers lacked skill, but because the codebase had made ambition expensive.

So the plan became to split the monolithic software into multiple standalone products. The hope was that this would bring technical and organizational benefits. Smaller codebases, independent teams, modern stacks. If the products were going to live apart, they'd need something to keep them speaking the same language. A design system seemed like the natural fit: shared components and a shared language across products.

## Building the map [#building-the-map]

We put together a small team, bootstrapped a component library with a modern tech stack, and paired it with an updated visual design that had been approved long ago but never made it into production.

Around the same time, one of the product teams was about to rebuild their product from the ground up. We jumped on the opportunity. A greenfield environment. The perfect test case.

And it actually worked. The pilot team delivered something we were proud of. Components that used to take days to build from scratch were available out of the box. We ran into growing pains, but that was expected. The proof was there.

## Crickets [#crickets]

We now had a real product to point at. Unfortunately, nobody cared. The rest of the company was still fully invested in the legacy system, and the plan to split the monolith never gained traction. We had built for a future the organization wasn't moving toward.

When we showed up with our shiny new tools, our colleagues looked at their workload and said "I don't have time to learn this." They weren't being difficult. They were being rational. Learning something new feels like too much of a gamble when you're already struggling to keep up.

## Meeting them where they were [#meeting-them-where-they-were]

The approach wasn't working. Our assumption had been that teams were just waiting for us to hand them something better. They weren't. We met with them to understand their perspective.

The answer might seem counterintuitive: we disguised our new design system to look exactly like the legacy app. We matched every visual detail so that anything built with the new components was indistinguishable from the old code. Under the hood, developers were working with modern tools. On the surface, nothing changed.

Pulling this off was possible because we'd made a bet early on and kept the visual layer of our components separate so they could adapt to different brands across the company. We didn't expect that to matter so soon. The old codebase had no tokens, no shared variables, just scattered CSS files that styled raw `input` and `table` elements directly. So we rebuilt the whole look from scratch with our own tokens and ended up normalizing a lot of the visual inconsistencies along the way.

Then we focused on making the transition painless. We wrote guides. We gave training sessions. We improved the dev environment.

But what actually mattered was showing up. We sat with colleagues during their first steps with the design system. We helped with the first app, stayed for the first obstacle, debugged alongside them. We weren't a library they could install. We were a team they could call.

## The trap [#the-trap]

Slowly, it started working. The narrative shifted from "we can't build that" to "we can build that... most likely." One team after another started using the design system without us having to ask. In product demos, more and more features were built with our tools. The numbers looked great.

So yay! We did it! ...right?

Not quite. Adoption was up, but teams were still building inconsistent interfaces. Same buttons, same inputs, same building blocks. The pages looked consistent at first glance, but the way they worked and felt told a different story.

Our colleagues knew how to use the components. They were productive. But knowing how to use a component is not the same as knowing when to use it or how to combine them. The system had little opinion about how things should come together. Teams approached the same user flows differently and arrived at results that were close enough to look right, but different enough for users to notice.

The moment it became obvious was a quarterly product demo. Several teams had shipped new features with our components, and instead of looking cohesive, the results were all over the place. A parking policy configurator had become needlessly complex. An access management flow had been crammed into a dialog when it needed a proper page, making the experience frustrating to use. Teams had reached for every component they could just because it was available. The implicit rules of the legacy system, the ones nobody had written down but everyone followed, were suddenly gone. Components gave teams vocabulary, but nobody had agreed on the grammar.

So we pivoted again.

The patterns we ended up writing didn't come from an audit or a workshop. They came from conversations. When we asked teams what support they were missing, nobody said "we need documented patterns." But what they described pointed us there: teams were solving the same problems differently and didn't always know which approach to pick. So we started writing down what we'd already been figuring out together in pairing sessions. Less "here's a button," more "here's how to load data and keep people in the loop."

## Failing forward [#failing-forward]

For most of the journey, it felt like we kept getting it wrong. But looking back, the pattern is clear: we kept confusing the map for the territory.

Our documentation, our component library, our adoption metrics: that was the map. Organized, clean and controlled. The territory is what we kept crashing into. Layers of workarounds in a codebase that never stopped growing. Tight deadlines forcing teams to take the same shortcuts they'd been taking for a decade.

Every time we treated the map as truth, the territory corrected us. Being ignored pushed us to invest in developer experience and hands-on support. Inconsistent interfaces showed us how much teams needed clear recommendations.

Each obstacle forced us closer to the people using our system, and that is where things actually got better.

We are still failing forward. The territory keeps changing. But we've stopped treating the obstacles as setbacks. Because what got us here wasn't sticking to a plan. It was the willingness to throw it out.

<Callout variant="info" title="This started as a talk">
  I gave this as a talk in December 2024. If you prefer slides (or Friends
  references), check out the [original
  presentation](https://sebald.github.io/failing-forward-at-design-systems/).
</Callout>
</article>