The language frames the story

Suppose you’ve said to me that “the falling maple leaves whirl in a delicate dance with the gentle breeze.” It’s late fall, so it feels like a reasonable thing to say. The trouble is, my language only has words like “eat, fight, run, here, that, there, now, later.” I might be fascinated by what you’ve said, but get very little out of it — and even less to pass on to others. At best, I will point at the sky and say “that!” and bulge my eyes meaningfully.

This might seem like one of those — duh! — obvious observations. Of course the language frames the story. However, I am finding that I easily forget this in the contexts of teams and how they are organized. To communicate with each other, teams establish a common language, a set of semantic shortcuts that allow them to work together effectively. This is where the non-obvious bits hide. This common language also frames what is being communicated.

For example, let’s imagine a hypothetical organization where communicating strategy across teams is done through a list of annual objectives and key results (OKRs). There is a process to assemble them into a coherent whole. When it’s all said and done, the story written in the language of OKRs tells where we will go next year.

However, some of our desired destinations take longer than a year to reach. To communicate these destinations, we need a language that can describe ideas that last longer than a year. Can you guess what happens when we try to express them in the language that only speaks in year-long sentences? Sure, within teams there might be long-term thinking and sound strategic artifacts. However, given the pidgin of annual OKRs that prevails outside, it is unlikely that these artifacts survive cross-team communication. The multi-year ideas will be neatly chopped or scrunched into the one-year box — rendering them as useful as my eye-bulging-while-pointing.

If I am lucky enough to work in an organization full of brilliant individuals, I will also start seeing these folks adapt to the common language. More and more, I will see how they pick out ideas that fit within the language to reduce the friction, making sure that only year-long journeys are those that count, whether in impact or attention of leads. Sure, there will still be the linguistic idealists who rail helplessly trying to overcome the limits of the OKR pidgin, but those will eventually give up and leave.

While the organization wonders why it struggles to think strategically, it might be worth it to examine the language it uses to organize itself. Is the language flexible enough to accommodate both short-term and long-term destinations? Are all ideas that matter expressible in the semantic shorthand that everyone is expected to speak?

Developer surface

I mentioned this concept before, and I feel like it’s worth expanding on a little bit. If we are in the business of making a product that developers rely on to create user experiences, the developer surface of this product is the union of all means through which developers create these experiences. 

Let’s unpack this, starting with a simple case. Suppose you and I decided to ship a library that has one function. Applying the definition, that library is the product and its developer surface is the function. Easy, right? As our product becomes popular, we start noticing something weird. Remember that one-line file where we track the version of the library, just for ourselves? Well, turns out some developers started using its contents in their build. So when we thought — “oh hey, let’s just delete that file, we don’t need it anymore” — all hell broke loose? That file became developer surface, too!

In mature developer-facing products, the developer surface becomes far more than just the API. Shipping samples along with the library? Yep, these are part of the developer surface, too. Got some clever heuristics deep in your code? Or maybe just bugsHyrum’s Law captures beautifully the spirit of this phenomenon: 

With a sufficient number of users of an API,
it does not matter what you promise in the contract:
all observable behaviors of your system
will be depended on by somebody.

This sufficiently high number of API users can truly mess with what is or is not a developer surface. While we imagine the contract with developers as a crisp document of high transparency and clarity, we are usually mesmerized by the messy innards that are the outcome of developers just trying to get things to work. Even messier in comparison will be our attempts to convince developers to use the APIs the way we intended.

When we embark on a project that intends to ship a developer-facing product, it’s worth planning the work and structuring the team in a way that anticipates this messiness. We are not writing the developer contract. Developers write the contract with us, and frequently, their contributions carry more weight. Walking this line of carrying our original intention while having awareness of where the developers want to take is not something that comes intuitively or easily.

The story of belonging

Next in my adventure across the coherence narrative realm is the story of belonging. It sort of maps into one of the fundamental needs from the Four Needs Framework, but plays a subtly different role here.

The story of belonging is also something that is easy to spot as a felt experience. Someone wise suggested that humans are wired for connection, and the web of these connections is what creates the gravitational pull in the story of belonging. There’s something about being together with others, being part of the group, next to those who consider you kin, being loved, included, and understood.

When I try to examine stories of belonging, I notice something interesting. They usually contain the words “we,” “community,” “together,” “teamwork,” “alignment,” “unity,” and so on, but structurally, it’s almost always not a standalone story. Instead, the story of belonging acts as a powerful catalyst, laced into the story of a threat or the story of an opportunity. Just milling around together is one thing, but something magical happens when the “we are”  is combined with “under attack” or “the future”: the capacity for coherence shoots up like a rocket. No matter what kind of compounding loop we might face, it seems that doing it as a tightly knit group feels natural and right to us humans. 

To add to the weirdness, the loss of belonging is a common story of a threat — and finding it a common story of an opportunity. In our interconnected world, this kind of ouroboros is in itself an abundant source of compounding loops. It’s one reason why teams tend to form boundaries and organizations grow silos. It is also the undercurrent behind the craving to gain more likes or followers and many similar societal dynamics. 

Considering the story of belonging as means to improve organizational coherence, a couple of thoughts come to mind. First, the stories of belonging are quite inert by themselves. The need to combine with compounding-loop stories to get traction. Second, we live and tell multiple stories of belonging simultaneously. Navigating all these stories is tricky, and growing new stories of belonging (“we are a team!”) is a careful, finicky process that often bumps against all the participants’ stories, taking patience and time to develop. Maybe this is why we use the word “culture” to describe a mature organization’s story of belonging?

Veering toward first-order effects

Have you ever driven a car that pulls to one side? It’s often subtle, but after a while, the counter-steering effort becomes impossible to ignore. This metaphor comes to my mind whenever I encounter a common developer experience pattern: the veering toward first-order effects.

To set the context a bit more, let’s arrange the effects of producing developer surfaces in two orders. The first-order effects relate to producing the developer surface. When we ship an API, we want it to be adopted, to be used broadly. Thus, when we measure first-order effects of our efforts, we look at the API adoption rate, developer satisfaction, etc.

The second-order effects relate to developers producing user experiences using our developer surface. At the end of the day, an organization that invests into shipping APIs does so — intentionally or not — to influence the overall state of user experience in some way. When we measure second-order effects, our metrics will likely track changes in the user experience. Does using our APIs result in products that are more secure, performant, accessible, etc. for the user?

Based on what I’ve seen working with developer experience teams throughout my career, there’s a pronounced pull toward first-order effects. They are easier to measure, have a shorter feedback loop, and are more familiar to folks accustomed to shipping consumer products. Even if a team sets out to influence the state of user experience at the beginning of their journey, the appeal of relative immediacy of first-order effects is so strong that the original intention often gets left behind.

A common symptom of forgetting to counter-steer toward second-order effects is the loss of strategic flexibility within a larger organization. When the first-order effects become the means onto themselves, they tend to get entrenched in a local maxima of developer expectations, stuck in an optimizing loop. An organization that contains teams stuck in that particular way feels like it is unable to do anything about it: everyone is seemingly doing “the right thing,” and prioritization exercises quickly devolve into peanut buttering. When something like this is happening, it’s a good hint that the concept of second-order effects got rolled into a dusty corner of the team’s shared mental models space, or ejected altogether. 

To counter-steer, organizations must exert conscious effort to keep second-order effects in the shared mental model space. Whether it’s constantly pointing at them during the all-hands, setting up the metrics structure to reflect user experience shifts, or even just reminding about the unyielding force that — like that darned car — never quits pulling, it’s an investment that’s well-worth the price.

Cutting or highlighting?

Talking with one of my wise colleagues, we arrived at this neat framing around making decisions. “Decision” is a weird word. My friend Neel tells me that its Latin root is literally “to cut away,” and that recognition that a decision is always about narrowing the list of available options can be both liberating and anxiety-inducing. The interesting bit is that sometimes, decisions aren’t meant to cut away.

As it often happens in larger organizations, we tend to live in the swirl of the short-term and long-term objectives. And it is definitely a swirl: the art of leadership is picking out the right mix. Blend in too much short-term, and we’ll find the team stuck in the corner of a local maxima, overconstrained by its previous choices. Blend in too much long-term, and the team fails to make progress that’s necessary to keep that motor running.

To adjust the mix, leaders decide. A common mechanism here is prioritization: picking a shorter list of things that the team needs to focus on. One approach to prioritization is to apply the cutting mindset, as in cutting the list in half: keep what’s above the line and discard the rest. For example, let’s suppose I want to build an app that is available on both Android and iOS phones, but I want to prioritize iOS users. Applying this cutting mindset, I just forget about Android for a while, break out my XCode and start typing some Swift. Only after the iOS version is shipping do I start looking at the rest of the list. Given how many unexpected turns a typical software project takes, will I ever get to do that? Maybe. Will this approach result in a painful migration or two — or worse yet, the “release polka” where my app always looks out-of-date on one platform compared to the other? Probably.  

The cutting mindset is straightforward and clarifying. Yet, in situations where the rest of the list is still a thing we want to do later, it often leads to inferior choices. In these situations, we need something different. Instead of cutting the list, we want to highlight the items on which we want to focus — while still keeping the rest of the list in mind. With this highlighting mindset, the choices we make take on a different spin. Instead of asking “what’s the next step to deliver <prioritized item>?” we ask “how can we take a step toward delivering <prioritized item> that also takes us closer to completing the whole list?” The thing is, the items on our lists are rarely orthogonal and live in clean separate boxes. More often than not, considering them as a whole reveals opportunities for advancing toward completion of multiple items simultaneously. In my app example, while still focused on the iOS release first, I might consider picking a UI framework that also runs on Android, or at least build my middleware in a way that is portable.

When making prioritization decisions, it’s worth being explicit about the mindset with which you’re approaching, discussing with the team the reason you chose one over the other. Otherwise, despite your desire to highlight, an eager PM might swiftly cut your long-term objectives out of the mix. Or conversely, the team will continue to swirl aimlessly in the ideals you have already forgotten about, from back when you thought you cut them away.

Making cross-cutting investments

Over the last few weeks, I’ve been thinking about approaches to influencing projects and teams across a large organization. I framed the exercise like this: suppose I have some organizational currency (headcount!) to invest. How do I nudge project trajectories in the most effective way?

Then, I talked to a bunch of peeps, looking for forces present in this problem space. There are probably many more, but these two piqued my attention. The first one has to do with the term of the investment: do I want to invest in several different things over time or do I mostly want to keep investing into the same thing? The second one has to do with how much control I want to have over the structure of investment: how much steering do I want to do with my investment? Mapping these two forces into thinking space, a few recognizable clusters emerge. 

A good example of low-control, permanent investment is donation. I find a team, recognize that it is doing important work and decide to help them by adding to their capacity to hire new folks. Based on my experience, this is more or less a permanent investment. Withdrawing donated headcount tends to be painful for all parties involved. Nevertheless, if the team’s goals are largely aligned with mine over the long term, and I have no qualms with their strategy, it’s a pretty good fit.

If I want a more temporary engagement, I need a different approach. One is to temporarily augment a team with a group of folks to accelerate a particular aspect of work. It’s exciting to imagine that such a team will drop in and race forth with uncanny precision. However, in orgs that have strong engineering practices and structures, augmentation is first and foremost a matter of learning to follow those practices and fitting into existing structures. “Who will review your CLs?” is the question to contemplate when considering the augmentation setup. They work well in homogenous organizations, when the members know the engineering practices well and are the people who can review CLs. Otherwise, this investment tends to offer less control than anticipated.

To gain a bit more control without permanence, I will likely try to incubate a team: seed it with good peeps, set up a resilient structure to help it stay on course, get it past the early growing pains, and let it go. Variants of this approach are found in research organizations and idea incubators, and I’ve seen it work. In the couple of times that I participated in the process, the biggest challenge was finding the right fit for the graduating team and then shepherding the team through often painful reintegration. At least to me, incubation felt more like an art rather than a repeatable process, but that just might be the lack of experience.

Finally, if I am seeking to invest in the long term while retaining high control, I am probably productizing, or reframing my desire to help in terms of a developer-facing product: a tool, a library/framework, an SDK, etc. This product must be good enough for the teams to want to rely on — and to get results that I want them to get. Note that this end result is a second-order effect (first, they want to use it, second, they produce desired outcomes), which is what makes this approach so challenging. On the other hand, precisely because of the indirection, this approach has something that no other approaches offer: the ability to influence multiple teams. Productizing is typically more demanding compared to others. It takes more effort and capacity to build an effective team that reliably ships a successful developer product and have the resilience to keep an eye on the outcomes I need. That last one is important. It takes just a little bit of stress and firefighting to fall back into the “let’s make developers happy” mode and forget the whole point of the exercise.

Hosting and hosted API design perspectives

When discussing API design strategies, I keep running into this distinction. It seems like a developer experience pattern that’s worth writing down.

Consider these two perspectives from which API designers might approach the environment. The first perspective presumes that the API implementation is hosting the developer’s code, and the second that the API implementation is being hosted by the developers’ code.

From the first perspective, the API designer sees their work as making a runtime/platform of some sort. The developer’s code needs to somehow enter a properly prepared environment, execute within that environment, consuming the designed APIs, and then exit the environment. A familiar example of designing from this perspective is the Web browser. When the user types the URL, a new environment is created, then the developer’s code enters the environment through the process of loading, and so on. Every app (or extension) platform tends to be designed from this perspective. Here, the developer’s code is something that is surrounded by the warm (and sometimes not very warm) embrace of the APIs that represent the hosting environment.

When I design APIs from the second perspective, the developer’s code is something that hosts my code. I am still offering an API that is consumed by someone else, but I don’t set the rules or have opinions on how the surrounding environment should work. I just offer the APIs that might be useful. Typically, this perspective results in designing libraries and frameworks. For example, I might write a set of helper functions that provide a better handling of date math in Javascript. This tiny library can run in any Javascript environment, be that server or client. It can be hosted by any app or site that needs date math. This “run wherever, whatever” is a common attribute of this API design perspective.

There is the growth/control tension that seems to map into these two perspectives. Hosting perspective exhibits the attitude of control, while hosted perspective favors the force of growth. As with any tension, complexity arises along the spectrum between the two.

A Javascript framework (a hosted API) that has strong opinions about its environment (wanting to be a hosting API) will have challenges maintaining this environment, since it is ultimately incapable of creating it. Back in the day when I still worked in the Web Platform, I’ve had many discussions with framework authors who wanted us Web Platform folks to give them the option to create clean environments. This desire to shift from hosted to hosting was not something I recognized back then and now wish this article existed to help me reason through the struggle.

Similarly, a hosting API that wants to grow will be pressed to make the environment more flexible and accommodating. Going back to the example above, we Web Platform folks were experiencing that pressure, the force that was pulling us away from hosting and toward a hosted API design perspective. After that shift, the code that renders Web pages — the fundamental building block of the Web Platform environment — would become just one of the libraries to pick and choose from.

It is also important to note that, using Hamilton Helmer’s classification, the existence of a hosting environment is a form of cornered resource. It’s something that only becomes possible to have when the API designer has the luxury of a significant quantity of willing hosted participants. In the absence of eager hordes of developers knocking on your door, taking a hosting API design perspective is a high miracle count affair. When thinking about this, I am reminded of several ambitious yet ultimately unsuccessful efforts to “create developer ecosystems.” There are ways to get there, but starting out with the hosting API design perspective is rarely one of them.

The fractal dragon

I’ve already shared this piece elsewhere, but might as well post it here. This story is almost like a piece of fantasy fiction that’s waiting to be written — and a metaphor to which I keep coming back to describe flux.

Imagine a warrior who sets out to slay the dragon. The warrior has the sharpest sword, the best armor, and is in the top physical shape. The dragon is looming large, and the warrior bravely rushes forth. What the warrior doesn’t know is that this is a fractal dragon. You can’t defeat a fractal dragon with a sword. So our courageous, yet unwitting warrior lands mighty blows on the dragon. The warrior moving in perfect form, one with the sword. You might look at this feat of precision and go: wow, this warrior is so amazing at crushing the dragon into a million bits! Look at them go! Except… each bit is a tiny dragon-fractal. A few hundred more valiant slashes and the warrior will be facing a new kind of opponent: the hive of the dragon sand. The warrior’s blade will woosh harmlessly through the sand and all we can hope is that the warrior has dragon-sandblast-proof defenses (hint: nope).

This weird effect of flux is something that we engineering souls need to be keenly aware of. When we find ourselves in that confident, exhilarating problem-solving mindset, it is on us to pause and reflect: are we perchance facing the fractal dragon? Will each “solution” create an army of different kinds of problems, each more and more immune to the tools we applied to the original problem? And if/when we recognize the fractal dragon, do we have the access tools that aren’t our mighty sword we’re so fond of?

Causal chains

My experience is that most folks around me (myself included) enjoy employing the power of causality to understand various phenomena. There’s something incredibly satisfying about establishing a sound causal chain. Once the last piece of the puzzle clicks in place, there’s nothing like it. Back when I still worked directly in code, some of my fondest memories were tracking down the causes of bugs. I remember once, we shipped a version of Chrome and suddenly, people started having the freakiest of crashes. Like, I spent a few days just staring at traces trying to comprehend how that might even be possible. However, as more information (and frustrated users) piled up, the long causal chain slowly coalesced. This happens, then this, then that, and — bam! — you get a sad tab. I still remember the high of writing the patch that fixed the crash. The grittiest of bugs have the longest causal chains, which always made them so much fun to figure out.

At the same time, there are causal chains that we perceive as incredibly short. Reach for a cup – get a drink. Press a key to type a letter in a doc. They might not actually be short (by golly, I know enough about HTML Editing and how Google Docs work to know otherwise) — but to us, they are simple action-reaction chainlinks. We see them as atomic and compose the causal chains of our life stories out of them.

We engineers love collapsing long causal chains into these simple chainlinks: turning a daunting process into a single action. My parents reminded me recently of how much harder it used to be to send emails before the Internet. I had forgotten the hours I spent traversing FIDO maps, crafting the right UUCP addresses, and teaching my Mom how to communicate with her colleagues — in another city! Electronically! Nowadays, the Wizardry of Email-sending has faded away into the background, replaced with agonizing over the right emoji or turn of the phrase. And yes, adding (and encoding) emojis also used to be a whole thing. A poetic way to describe engineering could be as the craft of seeking out and collapsing long causal chains into simple chainlinks, crystallizing them into everyday products.

Based on my understanding of the human brain, this is not too dissimilar from how it works. I am not a neuroscientist myself. My guides here are books by Lisa Feldman Barrett and Jeff Hawkins, as well as Daniel Kahneman’s seminal “Thinking, Fast and Slow”. It does look like the two processes: the discovery of causal chains (Dr. Barrett calls the process “novelty search”) and then collapsing them into chainlinks (“categorization/compression” or “reference framing”) are something that our brains are constantly engaged in.  And once collapsed and turned into simple chainlinks, our brains are incredibly efficient at reaching for them to — you guessed it — seek out novel causal chains, continuing the infinite recursion of making sense of the world.

This seems like a perfect system. Except for one tiny problem: our discovered causal chains often contain mistakes. If this then that might omit an important variable or two. Remember those freaky crashes? Those were manifestations of engineers’ mistakes in their process of collapsing the massive causal chains that comprise a modern browser into the simple “go to URL.” In software, engineers spend a lot of time finding and fixing these bugs — and so do our brains. Still, both our software and our brains are teeming with chainlinks that hide mistakes (yes, I’ve said it — we’re full of bugs!) Worse yet, the recursive nature of our sense-making tends to amplify these mistakes, while  still concealing their origin. While software just stops working, we tend to experience the amplified, distorted mistakes as suffering: anxiety, depression, burnout, anger, stress, etc. It takes intentional spelunking to discern these mistakes and not get further overwhelmed in the process. Like most astonishing things, our capacity for discovering and collapsing causal chains is both a gift and a curse. Or so the causal chain of this story says.

Ecosystems from product and user perspective

In a couple of conversations this week, the word “ecosystem” came up, and I realized that there were two different ways in which we employed that word.

The first one I heard was using “ecosystem” to describe a collection of products with which users come in contact. Let’s call it the product ecosystem perspective. This perspective puts software and/or hardware at the center of the ecosystem universe. Users enter and exit the ecosystem, and changing the ecosystem means making updates to products, discontinuing them, and shipping new products. It’s a fairly clean view of an ecosystem.

The other way I’d heard the word “ecosystem” being used was to describe the users that interact with the product, or the user ecosystem perspective. Here, the user is at the center of the ecosystem universe. It is products that move. Users pick them up or drop them, according to interests, desires, comfort, or needs. Users are humans. They talk with each other, giving out their own and following others’ advice, giving rise to waves and wanes in product popularity. This view of an ecosystem is messy, annoyingly unpredictable, and beautifully real.

It feels intuitive to me that both of these perspectives are worth keeping in mind. The empowering feel of the product ecosystem perspective is comforting for us technologically-inclined folk. It’s easy to measure and prioritize. Diving into the complexity of user ecosystem perspective provides deeper insights into what’s really important.