A couple of months ago, I started work on a new project – it’s big and complex, with a lot of smart and opinionated people involved, an enormous amount of “legacy” code (mostly C++), and tools and systems that are sorely in need of an update.
In situations like this it’s always really tempting to start over with a completely clean slate, using modern tools and programming techniques. In truth there’s still enormous value in all that legacy code, and throwing it out would be a terrible idea. This is almost always the case in situations like this. Instead the trick is to figure out how to preserve as much of that legacy value as possible, while also unburdening the team and the product from the worst parts of the legacy tool-chain. Evolution, not revolution.
User data needs to be preserved, as does the way it’s used by the system. Systems built on that data need to continue to function. Performance characteristics need to improve, or at least not degrade. A space needs to be carved out where we can safely build new features. But we don’t have to build any new features using those legacy tools – new stuff can exist in parallel or “on top of” the old. We might need to create new interfaces in old code so that the new system can leverage existing functionality, and we might even need to refactor some old code to make that possible. What we shouldn’t do is boil the ocean.
The transition ahead isn’t dissimilar to some of the transitions Apple has made over the last couple of decades, the most significant being the shift from the old “Classic” MacOS to the current POSIX system which came from the Unix/Linux universe, and the Cocoa UI framework which came from NeXT. It took careful management and an iterative approach over more than a decade, but Apple was able to (nearly) completely replace their base OS, UI framework/runtime, and primary programming languages on way to transitioning to the universe we now live in with billions of people using iPhones and iPads every day, running the same base system that Apple’s desktop machines use. They were able to do this while bringing the most important developers along into the new universe (though not without casualties), for the very reason that they chose to iterate in a long-term way instead of starting again from scratch.
While I was working at Microsoft, the company tried to make a similar transition from the legacy OS and programming model, to a new one that was centered the then new WinRT API and the Metro design language. They thought they had to do this in order for their ARM-based Surface devices to successfully compete against iPad. The shift to relatively inexpensive tablets and mobile devices was perceived by some as an existential threat, and the response was partly reactionary. Microsoft failed badly, at least initially, to drive the transition it intended, in no small part because they couldn’t bring their developer community along. Too much changed too fast, and a clear path to the new ecosystem wasn’t communicated clearly enough. The new APIs weren’t compatible, and yet at least on some devices, the old APIs were no longer alowed. By playing catch-up instead of playing their own version of the iteration game, Microsoft alienated many developers who quickly jumped-ship to the Web and to the iOS and Android ecosystems.
Steven Sinofsky was the head of Windows during the second half of my time at Microsoft, and is now at Andreessen Horowitz. Last week he posted a long thread on Twitter about some of the changes Apple is now considering, and naïve criticism of their approach in recent years.
That’s what got me thinking about this post, and I think it’s well-worth a read:
1/ Apple has a software problem. Here's how it plans to fix it. https://t.co/dJaikfRhs7 via @markgurman // Let’s take a step back and talk about the broader context and product development at scale. Lots follows…
— 🧘🏻♂️Steven Sinofsky ॐ (@stevesi) February 12, 2018