Ryan Singer

When engineers say "that'll take months!"

In a comment on my appearance on the Lenny podcast, Igor writes:

Our product is 15 years old, with a lot of legacy code and outdated technologies. We also have four platforms, and every new feature needs to be implemented across all of them. Our engineers say that the minimum time they need to ship anything of real value (not just small things) is about three months — which is much longer than the six-week cycle in Shape Up.

How can we apply the Shape Up approach in a situation like this?

Yes, legacy code adds friction and makes things take longer. And yes, supporting multiple platforms adds complexity. But there’s something tricky going on here. Those words “anything of value” are extremely broad. They imply there is some general pushback from engineering to product. Usually, when that is happening, it’s because there isn’t enough sharpness in the shaping. There isn’t enough back-and-forth between product and engineering about the exact itch we’re trying to scratch and what trade-offs we’re willing to make.

Narrowing down the problem

I worked on a team that was asked by leadership to build “notifications” for their web-based intranet. The intranet was a kind of custom CMS that sprawled out over time. In response to the request for “notifications”, engineers sketched out a big project: it had different notification types for each content area, native apps for iPhone and Android, and what seemed like unavoidable settings and administrative screens. The concept covered everything you could reasonably expect “notifications” to mean.

But because the concept was so big, it sat for over a year with no movement. There was never enough capacity to take it on.  Leadership kept bringing it up with escalating urgency, but it was always too big for the small team to tackle. Eventually, they pulled me in to unstick the project.

The first thing I did was question leadership about the framing. Why were they so urgently in need of “notifications”? What were they doing without notifications today, and what was going wrong with that? It turned out the real issue was they had an ancient but critical mailing list that wasn’t integrated with the SSO. To leadership, “notifications” meant being able to send messages through their intranet to verified identifies instead of using the old mailing list.

This reframing enable us to shape a tight project under six weeks. We built a “newsfeed” feature on the intranet that surfaced updates according to the existing permission system and sent email notifications for each update. It wasn’t necessary to build other notification types, native apps, or complex settings. When we launched and shut down the old mailing list, it was a big victory.

Narrowing down the problem isn’t an either/or proposition — it’s not that you either get all the behavior you want, or just one small piece. Finding a foothold can solve a real problem, produce a meaningful win, and pave the way for more. In this case, narrowing down to the mailing list problem and building the newsfeed gave us a lightbulb for the native apps. After the newsfeed shipped, we shaped and built an iOS app that surfaced the newsfeed, sent push notifications instead of emails, and offered webviews to the rest of the intranet. This was another big win. The other notification types and settings that were speculated about in that first big concept haven’t been needed yet.

Slicing the segments

Another cause of monster scope is trying to address every customer segment at once. Is it really true that the solution must solve every case for every customer in order to be valuable? Often not.

A fintech I worked with wanted to improve conversion in their onboarding by eliminating a long form of financial questions. They discovered it was possible to pull data from their bank integrations instead of asking for it again. But each bank integration provided different data under different agreements. If they framed the project as “eliminate this onboarding step for all customers”, it would take too long to cover every case. So they sliced customers into segments by bank, and looked at the relative sizes. They discovered they could hit a meaningful target for the quarter by focusing on just two of the five banks.

Negotiating the rewrite

There will be times when legacy code and complexity in the stack are creating so much friction that all development slows down. I’ve seen cases where teams at small companies adopted tech created for large enterprises (eg. Kubernetes or GraphQL), only to find out later that it was always in their way.

Refactorings, infrastructure changes, and rewrites do earn their bad reputation. They easily get out of hand and block customer-facing progress. But they can be necessary.

If something really needs to get ripped out or redone, the key point is to negotiate it as a business decision. Rewrites go wrong when they are treated as something unique to the engineering department, exempt from normal business scrutiny. Engineering and product should come together, frame the problem, and weigh the investment against all the other opportunities on the table.

One under appreciated approach is to leave the existing system in place and build a new version on a new chassis with an upgrade path. If the entire old system has to move over, there isn’t room for trade-offs — anything that breaks will upset someone. But when you’re building a new alternative, you can do what is described above and be selective about the most valuable cases.

When the monster is worth it

Sometimes a project is a monster and that’s okay. When I was at 37signals, we did a giant rewrite of our user authentication system across multiple apps that combined different databases into a central SSO with unified billing. That was a giant effort that took months, and everyone felt satisifed with the time we spent.

If the thing can’t be done in under six weeks, but it’s still worth doing, then the approach is to slice the monster into head, tail, legs, etc. Frame and shape each piece as a separate effort to build in under six weeks. Slice vertically — into things you can try and demo separately. Don’t break the work into logical parts that are supposed to all come together at the last moment — they never do. 

Sequence is important. Tackle the most unknown slices first. It’s tempting to do the “knowns” first, to show momentum. But this is an illusion. You don’t want a smooth-looking project that blows up at the last minute when a critical piece doesn’t work the way we expected. Better to surface those unknowns as early as possible, when we still have time to change the approach.

Lastly, every slice doesn’t call for the same level of finish. Sometimes a stub is enough, in order get something routine in place (like auth) and move on to a more critical slice. Very often, it’s enough to wire the code with some raw UI to demonstrate the functionality works. Finishing all the way to pixel-perfect makes sense when we’re confident that the mechanics are correct and we won’t have to rip it up and redo it.

Question everything

If there’s a take-away here, it’s to never take scope at face value. Engineers are being completely rational when they respond to fuzziness with more time and scope to cover all possible interpretations. Nailing down exactly what is needed, what is possible, and negotiating to find the biggest win is possible. The more challenging the engineering constraints are, the more we need to shape. And the more we take the shaping as a collaborative challenge, the more energizing it is when we find a solution together.

© 2025 Ryan Singer