Values, culture and the software we make

Returning from last week’s Mozilla all hands in Berlin, I ended up spending a good chunk of time on my (long) flight home thinking about values, how they guide a product, and how they guide a software engineering culture. I recently started taking on management of accessibility engineering for Firefox, so given these recent changes to my role at Mozilla, I suppose my wayward pondering on this topic was inevitable. For accessibility to thrive — to be more than just an afterthought in feature development — it needs to be a core part of engineering culture, something everyone thinks about not at the end, but at the beginning of an engineering process.

Back when I was a graphics engineer at Adobe, working on the pre-1.0 versions of XD, I spent a lot of time thinking about performance. In fact, nearly everyone on the team spent a lot of time thinking about performance. It was part of the product mantra that users should be able to use our tool to “design at the speed of thought.” Performance was paramount to achieving this goal, and our product managers were not shy about reminding us of this fact.

As such, a good chunk of my tenure on the Adobe XD graphics team was spent speeding up our core renderer — implementing things like eagerly decoding bitmaps on file open to speed up time to first paint, or better parallelizing access to our bitmap cache to reduce jankiness during pan and zoom. We were constantly stress testing our renderer, checking for performance regressions, thinking about ways we could eliminate dropped frames and pump more pixels to the screen faster. There was a trade-off to all this time spent focusing on performance, of course, and that trade-off meant less time spent building new features. Nevertheless, it paid off — when XD 1.0 launched it was a far cry from the competition in terms of overall feature parity, but it was arguably the fastest-performing design tool on the market. I would like to think that performance was our best-selling feature.

One of the primary lessons I took away from my time on that team was that the values that guide your product decisions must also be the values that guide your engineering culture. They need to be constantly reinforced, cared for, nurtured, repeated. If performance is important to your product then every engineer on the team must care and think about performance. If accessibility is important then every engineer must care and think about accessibility. If stability is important then every engineer must care and think about stability. It really does help to have a mantra for this type of thing. But, as a corollary, not everything can have a mantra. You can’t possibly care about it all; you can’t “boil the ocean.” Prioritize, prioritize, prioritize.

Prioritizing one value over another requires a trade-off. Everything you choose to value also has a cost. Performance and abstraction, for instance, are typically at odds. So the cost of caring deeply about performance typically manifests in technology and architectural choices that impede cross-platform compatibility. You tend to write more native code, “closer to the metal,” that is difficult to abstract in a performant way and has to be re-written for each platform. It takes a lot more work to maintain Windows and Mac, or iOS and Android versions of software written this way. Even a something that feels like table-stakes — security, for instance — has a cost. The cost of security typically manifests in complexity. Strategies like sandboxing, multiple access levels, encryption, whitelisting, etc. all add complexity. Of course, the cost of ignoring security is much higher than the investment needed to implement it.

As for accessibility? It too has a cost, which is the time commitment necessary to do it well. This cost is lower if valued and considered at the beginnings of a project, when architectural and technology decisions are being made. But, more importantly, like security the cost of not making software accessible typically far outweighs the investment needed to make it accessible. Ignore it at your peril, because you ignore a sizable chunk of your potential user population, and your competitors likely won’t make the same mistake.

The timing of these decisions matters. The values that guide your culture also guide your architecture, and architecture is not something you easily change. The architectural and technology decisions you make early in a product’s lifetime can often determine the space of possibility for how well you can stay true to your values well into the future. Unlike the typical user-facing feature, you can’t build a product and then later “bolt on” better performance, or “bolt on” stronger security. Yes, you can always improve these things, but only within the space of possibility that the architecture allows.

It’s an extraordinary amount of work to make a team suddenly care about a value that was not core to the culture from the beginning. Cultural norms and habits form quickly, but they evolve slowly. Partially this is human nature; it’s just hard to change well-established habits. And partially our development environments tend to reinforce a certain inertia; if the architecture and processes and tools and testing infrastructure make it easy to tune performance because it was valued from the beginning, then performance tuning is much more likely to happen. But if they don’t … well … barring a major initiative to enforce a change and lots of hard work to build the necessary testing and tooling, engineers are more likely to follow the path of least resistance. Better to do the hard work early to make the path of least resistance lead where you want it to go.