(A post in my “Role Models” series…)
In late 2000, I joined a small team tasked with rewriting the core technology at PowerQuest. The old codebase–despite embodying a number of patent-pending concepts, and serving as the foundation for all our revenue–was fragile, rife with technical debt, and unfriendly to localization, new platforms, and other roadmap priorities.
This rewrite had been attempted before–more than once, by some of the brightest engineers I’ve ever worked with. Each time, the press of looming releases, and the lack of obvious progress, culminated in a “we’ll have to come back to this later” decision.
Our little team was confident that This Would Not Happen To Us. We were going to build an engine that was cross-platform from the ground up. No weird dependencies, no assumptions about compiler quirks or endianness, would permeate the code. Internationalization (i18n) and localization (l10n) support would be baked in. Errors would be clearer. Modules would be small, beautiful, and loosely coupled. Gotos would disappear. Vestiges of C dialect would be replaced by best-practice STL, boost, metaprogramming, and other cutting-edge C++ ideas.
Experience Versus Enthusiasm
Before I tell the rest of the story, make a prediction. Do you think we crashed and burned, muddled through, or succeeded wildly?
How you answer will say a lot about you.
If you’re young and optimistic, you may expect me to tell a story with a happy ending. But if you’re an industry veteran, you probably expect I’m going to tell a cautionary tale framed by failure. You know that rewriting a core technology from scratch almost never succeeds, and you can give a dozen excellent reasons why that’s the case.
If you’ve got Roland Whatcott’s genius, you can imagine either outcome — and more importantly, you know how you can choose the future you want.
Fast forward a few months. A couple senior programmers had been pulled onto other assignments. They’d been back-filled, sort of, although replacements were part-time loaners, with competing priorities elsewhere. We had the working skeleton of an engine, and it could do some cool things. We could compile it for different processor architectures–or so we claimed. It had so far avoided a lot of the warts that made the old engine ugly. We had automated builds and a working unit test framework. We’d written tests for many aspects of the system. When management asked us for a demo, we’d launch our testrunner and show how everything turned green.
Most importantly, the new engine had its first “customer” — an internal team was planning to build a new product on top of our codebase/API.
At this point, I was functioning as a technical team lead as well as an ad hoc manager. I remember attending iteration meetings for the product team that was our customer, listening to their requirements, and going back to my own team with long lists of tasks, interdependencies, and action items.
When I heard that a newly hired manager named Roland Whatcott would soon take over the management side of my responsibilities, I was elated. Now I could get back to my major interest, which was writing code. He’d take care of all the “other stuff.”
Roland saw our demos, reviewed the codebase, got to know the team, went to meetings… And he became concerned. Yes, our team was making steady progress. Yes, we had been productive, by many measures. But our customer team was not happy. We were delivering what we planned in our iterations, largely on time and on target; yet the set of features ready for prime time was not yet broad enough for a complex layer of business logic, let alone a UI, to build upon. Many of the features we delivered would “work” in some sense, but with so many caveats that they didn’t yet have a lot of practical value. Our “demos” were actually de-motivating to many, since they ran in debuggers or shells, quite divorced from any useful product context. And most troubling, upper management was strained to keep funding the new engine instead of building revenue-producing features on top of what already worked.
Roland told me he was worried. I could understand some of what bothered him, but I didn’t have a lot of problem-solving vision. The smartest course seemed to be to double down and get through faster.
Roland believed in stretch goals, but he didn’t think heroism alone would see us through. He saw clearly that our momentum was faltering toward zero.
This, he knew, was a serious problem.
Roland’s response to this quandry was both astute and creative.
He went looking for momentum.
He’d heard talk about HP’s need for a disk imaging product that would support its new itanium server line. Itanium was a totally unfamiliar processor architecture, with crude compiler support. The old engine didn’t have a snowball’s chance in Phoenix of supporting Itanium. But the new engine did. We were endian- and bitness-agnostic, right?
In fairly short order, we were signed up to ship a product to HP. The timetable was whirlwind short. Our mainstream product team customers were 9 months away from shipping; the HP product needed to be in customer hands in a couple months.
I remember complaining to Roland about the ridiculousness of this release. We’d have to hurry the development of some features that we’d been planning to mature over a much longer timeframe, and neglect capabilities that were already halfway implemented. How were we supposed to do continuous integration, if we didn’t have any 64-bit itaniums to run our unit tests, and the compiler barely worked? Our automated build system would lose most of its value. And we didn’t even know that the itanium release would make money; it was barely on product management’s radar.
All of my objections were reasonable, I think. But they were irrelevant. Roland knew that without a momentum boost, our initiative would be scrapped, and we’d be right back in the old engine quagmire all over again.
Long Story Short
We pulled it off. We shipped the world’s first disk imaging product for itanium, on a schedule so aggressive it even made the customer’s head spin. It was not easy. There was pain–for those on our team, and for the product team that was waiting for more mainstream features to mature. Kudos to lots of smart engineers, to Roland’s savvy management, and to the courage and vision of upper management, who let us try.
We emerged with momentum. Those unit tests we’d worked so hard to create now had a track record of stabilizing the code on the shifting sand of alpha-generation compilers and alpha-generation c runtimes–to the point where the new engine was demonstrably more stable than the code it proposed to supersede. Managers talked about it. The decoupling we created with abstract factories and dependency injection had clearly kept the worst of platform differences at bay; nobody wondered anymore if we could do a Linux port. Teams wondering if they could depend on the new engine folks to come through in the clutch no longer woke up sweating in the middle of the night.
A few months later, the product team that had been our original internal customer shipped. Disk-based backup entered the imaging age, and “the new engine” turned into “the engine” to folks in our department.
Just because momentum is a state of mind doesn’t mean it lacks real-world consequences. Make sure that ambitious undertakings have plenty of momentum all along the way. Win early and often, not just in a big bang at the end; if you wait too long, the big bang might never materialize.
Like all principles, this one can be misapplied. You can hype to get temporary momentum spikes; you can make too many short-term compromises for the sake of brownie points, and sabotage your future.
But if you do it right, momentum will carry you through some incredibly difficult challenges with flying colors.
Thanks for the lesson, Roland.
Analyze the momentum for a recent or current project. What challenges to momentum do you have? How can you overcome them.