Increasing potential as a specific output of flow

In Projects to Products, Mik Kersten divides flow items in software products in four: features, defects, risks, and debt.

If you only count features added and bugs fixed – changes visible externally – then you neglect the other outcome of our work: the next version of the team+software.

I prefer to think of “technical debt” work as groundwork for future changes. I like Kersten’s suggestion to do more of this at the beginning or a release cycle, while preparing to add a lot of features.

Pretending that software is “done” at the end of a project is dangerous. Naming risks and technical debt as part of the output of flow makes caring for our future explicit.

Closed games vs Open Games

From The Grasshopper, by Bernard Suits:

When you play a board game, or a game of baseball, you’re playing a closed game. There is a defined end, and a defined set of means to reach it.

When you play pretend, or when you build a career in baseball, you’re playing an open game. The objective is to keep playing, to make it more interesting. While some means are proscribed (don’t deny what the other player added, no steroids), it helps to bring in new people or tools.

Software projects are run as closed games. The objective is to end on time and on budget, using business-approved resources.

Software products are open games. The objective is to keep being useful in a changing world. We can bring in new tools, and new people, and there is no “done.”

When we play open games, we play for the future. Outcomes. We care about the people who come after us. Closed games (such as annual performance goals) lead to crunch time, when all we care about is checking boxes whether it does any real good or not.

Closed games can be zero-sum. You win, I lose. In an open game, for me to win, you have to win too.

Every business is an open game. Life is an open game. Can we keep the closed games to the dining room table and sports, please?

Closing the feedback loop from the customer

Feedback loops are essential to learning. In business, they’re essential to getting the product right. We need to know what the customers think, what they’re struggling with, what they value.

There’s one department that has a lot of contact with customers. Whole conversations, where we can learn a lot about what frustrates people. Yet, customer service is generally operated as a cost center, optimized for low pay instead of high knowledge acquisition.

business experts talk to developers, who create an app, which is used by a whole slew of customers, who then call customer service. Does customer service get to send that feedback to the business experts?

Is the business getting feedback from this rich source of customer contact? or are we too busy coping with a quantity of calls? So many different people using the app. Each call represents only a tiny piece of customer experience.

In software-as-a-service, where the customers are developers, each of them is responsible for millions of uses of the app. Developers are high-leverage this way. What they struggle with, what stops them from using the product more, stops their applications from using the product LOTS more. The impact of each developer-customer is orders of magnitude larger than that of a single customer of a consumer product.

For this reason, in place of (or in addition to) customer service, we have Developer Advocates. A developer advocate answers questions, gathers experiences, and interacts with developer-customers at high bandwidth. Developer advocates are hired for impact, not for low pay.

replace the slew of customers with a few developers controlling their software which uses our app; these devs talk to a developer advocate, who talks to developers, business experts, and influences our app directly.

Developer advocates share feedback with developers of the product. They can impact the customer’s experience with the product directly: by changing it, and by adding plugins, tutorials, documentation, etc.

Feedback loops are short and thick compared to traditional customer service. It makes sense that this is possible in software, because the quantity of humans we need to interact with is much lower, and the impact of each is higher.

This seems like a win. I 💓 software-as-a-service.


Generativity is about caring about what comes after you.

In a social context, it’s when old people care about subsequent generations, instead of maximizing their own happiness for the last few years.

In business, it’s when executives care about the health and outcomes of the whole executive team, instead of their own career after this job.

Generativity is building the next version of yourself, your team, and your organization. This includes current work and all the work you’ll be capable of in the future.

For software development teams (among many others), companies care about the work they’re capable of doing. They care about productivity — the outward-facing work of the team.

productivity is externally visible; generativity improves the team

If we look at productivity as a property of individuals, if we measure and reward “how many tickets did you personally close?” then we give people reasons to work alone, to rush, to keep information to themselves. This cuts away at the potential of the team.

If we care about the team as a whole, both now and in the future, then we encourage generativity. Teach each other, communicate, craft software so that people can understand and work with it.

Generativity is hard to measure, but not so hard to detect. Ask, who helped you today? Who answered your questions and taught you something useful? What scripts or documentation or comments or variable naming made your work smoother?

long-term productivity comes from a healthy team

If productivity is the externally visible work that is attributed to you, then I define:

Generativity – the difference between your team’s outcomes with you, vs without you.

It is not about me, and it is not about right now. I want to make my team and my company better for the future. I want to be generative.

Every action has two results (Erlang edition)

Every action has two results: a set of side effects on the world, and the next version of ourselves.

I learned this from Erlang, a purely functional yet stateful programming language. Erlang uses actor-based concurrency. The language is fully immutable, yet the programs are not: every time an actor receives a message, it can send messages to other actors, and then return a different version of itself, instantiated with different state.

Here’s an example from the tutorial in the Erlang docs:

%%% This is the server process for the "messenger"
%%% the user list has the format [{ClientPid1, Name1},{ClientPid22, Name2},...]
server(User_List) ->
        {From, logon, Name} ->
            New_User_List = server_logon(From, Name, User_List),
%%% ...

This defines a server process (that is, an actor) which receives a logon message. When it does that, it builds a new list of users including the one it just received and all the ones it knew about before. Then it constructs a new version of itself with the new list! (That’s implicitly returned from receive.) The next message will be received by the new server.

It’s like that with us, too. Today I made coffee, with a side effect of some dirty cups and fewer coffee beans, and a next version of me that was more alert. Today I checked twitter, with a side effect of nothing observable, and a next version of me ready to write this post. Now I’m writing this post, which will have side effects with unknown consequences, depending on what y’all do with it.

This works in our teams, too. Every task we complete changes the world, and it changes us. Maybe we add tests or implement a feature. In the process, we learn about the software system we participate in. Did we do this as a team, or will we catch each other up later? Is changing the software more safe or harder than before?

When “productivity” measures focus on externally-visible outcomes, sometimes the internal system is left in a terrible state. Burnout in people, “technical debt” in code, and a degeneration of the mental models that connect us with the code we care for.

The consequences of our work matter now. The next version of us matters for the whole future, for everything after now.

Victory at life

In most (modern) board games, there’s a phase where you build an engine, and a phase where you use that engine to achieve victory. This is not explicit, it’s just that in the first part of the game you choose things that give you more power, while in the last few rounds you maximize victory points. And then you win!

For instance, in San Juan, you win with victory points. The core mechanic is: pay cards to build buildings. Some of the buildings give you lots of victory points, while others give you powers that help you get more cards.

At the start of the game, build only buildings that help you get more cards. Points don’t matter. Near the end of the game, build whatever gets you the most points. Cards are about to be useless. Only points matter.

In life, there are activities that build our engines, that grow ourselves or improve our circumstances. Some other activities are just winning.

Winning is looking at beautiful things, art or the faces of people. Winning is laughing while my children goof around together. It is playing music, dancing all-out, soaking up the sun.

Winning is also taking action to move the larger system, the country or the world, in a better direction. Donating money helps, but if we participate in a campaign, we get to experience the winning.

What gives you victory points at life? Those activities that give you the feeling, “Yeah. This is what we are here for.” For me, looking out a plane window during takeoff. Eating great food. Cuddling with my partner. Playing Beat Saber with great ardor.

We never know when our game will end. Cards will become useless. Victory is never useless, so collect some points every day.

An old idea in a new context is new.

“Ideas don’t spring fully formed from the mind of an individual. Ideas emerge between people.”

Avdi Grimm, in his closing keynote at Southeast Ruby, told how when he sets out to write a talk, he wants to go out on his deck and walk back and forth until he squeezes the ideas out of his brain. “That works a little, but it’s a slow trickle. Then I phone a friend, and the ideas gush out.”

People think together. Through direct conversations, and through what we write and what we make.

Also at Southeast Ruby, Brandon Weaver talked about how programming languages like Ruby evolve by incorporating ideas from other languages (with a magic book! and 62 original drawings! of lemurs!). When people write horrifying gems to make Ruby to look like Scala, that’s a step in the evolution. Why do it? because we can. To let people see something new. That’s art, man.

And in the opening keynote, I talked about how ideas don’t belong to one canonical source. If some idea has been around (published) since the 70s, and someone recently made it useful in a new library, that is new work! If you find an idea in an article and apply it in your context, that is new work! If you explain a concept to someone who didn’t understand it before, new work! Heck, if you send a link to someone that gives them the explanation that they needed in this situation, that contributes to the idea. It draws a line between the idea and a person, in a context where it is useful.

But what about attribution, about credit?

If you find use in work published by someone in academia, please go to lengths to give them credit, and link to their work publicly. Attribution is currency in academia; it’s scarce and necessary to careers.

My favorite part about naming people who carried an idea to me is that it shows that nothing springs fully formed out of my brain. Everything is a synthesis, a reapplication in a new situation, a restatement — all these are new work.

For me personally, attribution is not scarce. Spreading ideas has intrinsic value. That value also appears between people, in conversation. The reward is who I get to talk with.

In his keynote, Avdi quoted Abeba Birhane‘s work, on “A person is a person through other persons.” None of this is worth anything, alone.

Give me feedback that is qualitative, broad, and random

Today in standup, a colleague reported that a GitHub isn’t sending the hooks it did last week, after we wrote code to handle it, and it’s a problem for us.

“Did you contact GitHub?”

“I asked around, and I heard they’re very unhelpful.”

So no, he didn’t contact GitHub. The people writing that hook will not hear from us about how it makes their integrations less useful to everyone. Customer service, people. It’s so important!

Today T-mobile did something very wrong with my very straightforward order. I’m gonna have to call customer service and be like, “Hey, when I order a new phone and add a new line, I want the new phone connected to the new line.” Will this request ever make it back to the people who specify their software? If I had confidence it would, I would feel good about making the call. But I’ve worked at a telecom before, so I expect that data to stay with the rep, with no power to change the system.

You know what we need in order to make great software? Great feedback.

Feedback loops are the soul of any ongoing system. What is fed back, gets sustained, it gets built into the very structure of the system, that this is perpetuated. Only what is fed back.

So we need more metrics, right? Ha ha ha, no

Metrics sustain numbers. Not whatever you thought you were measuring.

We need broad feedback loops. We need information that we didn’t know we needed. We need to know what our customers experienced, what they expected and didn’t get, what surprised them, what pieces of our software make the larger system better. We need all the information we can get.

Except! all the information is the same as no information. We could look at log dumps that show all the usage. But we’d never see any of it, because it’s too much. Our attention is precious.

What we need is some of the information, and a different “some” each day. Little enough that we can listen, random enough that we sometimes encounter that precious bit that provides insight.

Breadth and surprises come from talking to people. So talk to people! Different people each day, and get their stories about today and whatever sticks in their heads.

metrics are tiny thin paths of feedback. Conversation is a big thick broad feedback path.

This is qualitative data. For real feedback about the real systems we contribute to, this should be most of what we look for.

Quantitative data, metrics, should be the exception. Every metric has its dark side. Use them with caution, because they distract us from everything else that we aren’t measuring.

All kinds of harm, all kinds of opportunities are obscured by a few shining metrics.

Seek out feedback loops that are incomplete and random and broad. Cherish the ones that bring you unexpected information. And please, please, meet your company’s customer service people and beg them for their stories.

hat tip to John Ohno for inspiring this post with a tweet thread.

Let’s reason about behavior

When we learn math, geometry, and logic in school, we’re always talking about things that are holding still. The element is in the set or it isn’t. The angle is acute or obtuse or right or we can’t know. Things are related or not. A thing has a property, or doesn’t.

Code can have properties. A function has side effects, or doesn’t. Data is mutated, or never. An API call can be idempotent. Whole programs can have properties and we like to reason about them.

Yesterday talking with Will Larson on >Code (episode 142), he pointed out that once we move beyond a single process, especially when we go to microservices and have oodles of processes running around, we don’t get to talk about properties anymore. Instead, we have behaviors. He said:

Properties, you can statically analyze.
Behaviors, you can verify they happen.

A call to one program, or even a series of calls, can be transactional. Once you’re in a distributed system, not a thing. You can talk about how the system behaves.

Rein pointed out that in distributed systems, properties are incredibly expensive. Guarantees like all-or-nothing transactions, exactly-once delivery, consistency are never perfect in the real world, and the closer you choose to be, the more you pay in money and latency. Coordination is expensive.

In addition, can we get better at verifying and reasoning about behaviors?

Will pointed out that fault injection is a way to verify behaviors. That makes sense: psychologists learn a lot about the way we think from a few people with localized brain injuries. Emitting and querying events is another way.

Then how do we reason about behaviors? Systems thinking helps. Will recommends Donella Meadows’s Primer as a start. (I loved that book too.) Also, the social sciences have been studying behaviors forever. Maybe their methods, like Grounded Theory, can help us.

We’re people, right? We have behaviors. If we can get better at naming and reasoning about them, maybe we can get better at being people. It could happen.

Other people’s messes

There’s a funny thing, that when I walk into the kitchen and there’s sunscreen on the counter that I left there before yesterday’s bike ride, there’s a plate that I put to soak on the counter and there’s a book about Klimt that I had hoped to read with my coffee, this is fine.

It doesn’t feel messy. I almost feel a comforting sense of continuity with my past self.

But when other people leave crab rangoons and cups and bowls and mail and washcloths lying around, ugh! mess!

It’s somehow different when I have the story behind it.

Code is like this too. If I remember writing it, then I know this nutty interface name was a placeholder. This ratty console.log helped me debug a tricky crash. I’m in the process of refactoring to use the new functions, but the old ones are still around some places.

When that’s anyone else’s code, it looks like trash.

This tells me: if the code is my own toy, and I’m likely to be back to it before I forget who I was when I wrote it, then all those intermediate states are fine. They might help me get back into this groove, even.

But if the code is shared, or if I won’t be back in it later this week, make small changes completely. One at a time, in series, so that each commit leaves the code clean. Put the sunscreen on and put it away. Wash the plate and put it in the dishwasher immediately. Take my coffee upstairs to drink with the book.

Sometimes I wish I lived alone, so I’d only have my own mess to deal with. I don’t want to code alone, though, except on toy projects. I do wish I lived with people who cleaned up after themselves. I resolve to make smaller messes in our shared code, one at a time.