How will you collaborate?

When there are decisions to be made, people have feelings about it. Some people want to make the decisions, others to influence it, others to hear about it.

Where does everyone in your group stand? Are you set up for conflict or for smooth collaboration?

For instance, say there’s a new product to start. We will need to decide how to market it, how to price it, and how to build it. Within building it, there will be all kinds of smaller decisions, from platform to architecture to every tiny piece of code.

Collaboration Contracts let us get explicit about how we will make decisions.

Doc Norton suggests: everyone pick your place in each decisionmaking. There are 6 options.

the six options as expressed by different colors of tooth people
which one are you?

Are you making the decision?

  1. Explainexplain person is orange“I will make this decision, and explain it to others.” No obligation to accept input.
  2. Consult: consult person is red“I will make this decision after consulting with others.” You can influence me, but I will decide.
  3. Agree: agree person is purple “We will make this decision by coming to agreement somehow.” Method of agreement to be determined later. You can influence us.

Otherwise, are you involved at all?

  1. Advise: advise person is green “You make the decision after I advise you.” I have thoughts; hear them and then I’ll respect the decision you make.
  2. Accept:accept person is blue“You make the decision. I’ll accept it.” Whatever it is, I’m in.
  3. Abstain:abstain person is grey “You do what you want. I abstain from this whole activity.” Why am I even in this meeting?

This lets us identify baked-in conflicts.

After everyone declares the role they expect to play in a decision, you can notice conflicts.

"explain" and "consult" and "agree" roles conflict with each other
“explain” and “consult” and “agree” conflict with each other.

If more than one person thinks they are making the decision, and they’re not all in the “agree” category, you have a problem.

"explain" and "advise" roles conflict with each other too

If someone thinks they’re making the decision unilaterally (the “explain” category), plus at least one person sees themself as “advise,” you have a problem.

Once you identify conflict, you can renegotiate. The person who thought they could make the decision without input can agree to ask others. The person who thought they would consult can seek agreement instead, or the people who wanted to agree can delegate the decision.

This model is useful at all levels of decisions. I find it especially interesting to apply it to low-level code decisions.

We can apply this model to collaboration on code.

Down at the nitty-gritty implementation level, someone is at the keyboard. Maybe its me. If I’m working alone, then I’m making the decisions. I am in the “explain” role.

After the code change is ready, what happens?

It’s OK to make unilateral decisions.

Maybe I push it to master, with an explanation of my decisions in a commit message. No conflict there.

Maybe I create a pull request, including an explanation of what I did and why. Then what?

If my colleage glances at it, sees that the build passed, and hits “merge,” maybe they’re taking the “accept” role and we’re fine.

There is conflict when we expect our decision to fly but it doesn’t.

But what if the reviewer has suggestions? Then they’re taking the “advise” role, and that is in conflict with my “explain” role. Looks like I actually have the “consult” role, except that I don’t get to consult until after I make the decision once and then I have to go make it again.

Pull request fight. Me: "Let's do this!" Them: "But what about..." Me: "Fine, they we'll..." Them: "That's not OK" Me (very sad): "Work with me here!"
the pull request slide, from decisionmaking to placation

And what if those comments aren’t suggestions, but blockers? Then we are both in the “agree” role. I thought it was my decision but it wasn’t; only I had to make the decision first and then someone else pops in and now we have to agree.

These are not smooth. I do not enjoy this.

We have ways of collaborating smoothly.

two "agree" people at one computer

If we were aiming for the “agree” role all along, why not start there? In pair programming, one of us is typing, but we make decisions together.

Or even better, mob programming: the person at the keyboard (the driver) is not allowed to make decisions, so every decision is spoken aloud. The driver is in the “accept” role.

mob programming with a navigator: an "accept" person with the keyboard; one "consult" person; several "advise" people

If your mob has a navigator, then each person takes a turn in “consult” and the rest are “advise.” This works.

mob programming: one "accept" person has the keyboard. Everyone else is "agree"

Without a navigator, everyone is “agree.” This works too.

Consider the design of your collaboration.

This model illuminates why pull requests hurt so much. They have conflict built in to their structure.

To make pull requests work, I have to lower my expectations.

I’ve learned to consider my pull requests to be suggestions. I’m proactively taking an “advise” role in a decision I hope some project committer will make. Success can look like: they implement the same functionality in a manner of their choosing. My PR functions as a very specific feature request. It doesn’t matter that my code didn’t make it into production, if my idea did.

The only exception to this is when I know the project maintainer (or am the project maintainer), and I come to agreement with them before submitting the PR. Then I expect it to be accepted, after some minor comments and changes are exchanged.

When you see conflict, consider your collective expectations.

Next time you feel resentment at someone else’s intrusion, or frustration at decisions made without you, try to picture the roles everyone thought they were playing. Are they compatible? Was conflict endemic to the structure of this interaction?

If so, don’t blame yourself, nor the other person.

Ask, can we be clear about our decisionmaking intentions? and then adjust them to remove conflict before it starts?

Be specific about your expectations. Set yourself up for smooth collaboration.

Definition of DevOps

Step 1: On one team, put the people with the knowledge and control necessary to change the software, see the results, change it, see the results.

Step 2: Use automation to take extrinsic cognitive load off this team, so that it needs fewer people.

That’s it, that’s DevOps.

Step 1 describes the cultural change that leads to flow. Delivering change requires no handoffs or approvals from outside the team; the impact of change flows back to the team. Act and learn.

Step 2 is where tools come in. If all you do is improve your tooling, well, that helps a little, but it doesn’t get you the qualitative change in flow. That comes from Step 1. The serious value of automation is that it enables Step 1, a single team with all the relevant knowledge.

Our job as developers is making decisions. DevOps gets us the knowledge we need to make good decisions, the authority to implement them, and the feedback to make better ones in the future.

I don’t want the best

“Which database is the best?”

Superlatives are dangerous. They pressure you to line up the alternatives in a row, judge them all, make the perfect decision.

This implies that databases can be compared based on internal qualities. Performance, reliability, scalability, integrity, what else is there?

We know better than that. We recognize that relational databases, graph databases, document stores etc serve different use cases.

“What are you going to do with it?”

This is progress; we are now considering the larger problem. Can we define the best database per use case?

In 7 Rules of Effective Change, Esther Derby recommends balance among (1) inner needs and capabilities, (2) the needs and capabilities of those near you, and (3) the larger context and problem. (This is called “congruence.”)

“What is the best?” considers only (1) internal qualities. Asking “What are you doing with it?” adds (3) the problem we’re solving. What about (2) the people and systems nearby?

Maybe you want to store JSON blobs and the high-scale solution is Mongo. But is that the “best” for your situation?


  • does anyone on the team know how to use and administer it?
  • are there good drivers and client libraries for your language?
  • does it run well in the production environment you already run?
  • do the frameworks you use integrate with it?
  • do you have diagnostic tools and utilities for it?

Maybe you’ve never used Mongo before. Maybe you already know PostgreSQL, and it already runs at your company. Can you store your JSON blobs there instead? Maybe we don’t need anything “better.”

The people we are and systems we have matter. If a component works smoothly with them, and is good enough to do the task at hand, great. What works for you is better than anyone else’s “best.”

Rules are not easy

Sometimes in software design we get this idea, “We’ll make this a rule engine. Then the business can write the rules, and they’ll be able to change them without changing the code. That’ll make it more flexible.”


The rules are code; they change the behavior of the system. Rules interact in ways that are hard to anticipate. It’s harder to write rules than to write code.

It seems like we make business decisions in terms of rules, because we talk about them that way.

People make uncomplicated decisions by rule. We make complicated decisions by aesthetic (from expertise), and these are difficult or impossible to express in rules.

Real-life rules often contradict each other. A human with a feeling for the situation can prioritize among them.

For instance, “How do you position a picture in a column of text?” Back in the day, people laid out the newspaper pages, and they positioned them using some rules and also their eyes. How does a browser do it? Careful people have created nine precise rules for positioning float elements. Excerpt:

4. A floating box’s outer top may not be higher than the top of its containing block. When the float occurs between two collapsing margins, the float is positioned as if it had an otherwise empty anonymous block parent taking part in the flow. The position of such a parent is defined by the rules in the section on margin collapsing.

you don’t need to actually read this

If you think “Rules are declarative, they’re easier to reason about than imperative code” then go format a complicated web site with CSS. Make changes in the hundreds of lines of CSS, and see if you can predict the results. Now see if you can predict the results of changing someone else’s CSS.

Writing rules is hard. Designing a syntax and semantics that let people write rules to cover all the cases in the world, even harder. Do you really want to embark on that? Is it really more effective than changing some code when the business wants change?

As humans, we make aesthetic judgements for complicated decisions. This is one of our superpowers. Putting those judgements into rules is never easy; don’t pretend it is. And no, you don’t need to implement a rule engine.

Thanks to @nokusu for teaching me about floats and margins and other layout fun.


How important is correctness?

This is a raging debate in our industry today. I think the answer depends strongly on the kind of problem a developer is trying to solve: is the problem contracting or expanding? A contracting problem is well-defined, or has the potential to be well-defined with enough rigorous thought. An expanding problem cannot; as soon as you’ve defined “correct,” you’re wrong, because the context has changed.

A contracting problem: the more you think about it, the clearer it becomes. This includes anything you can define with math, or a stable specification: image conversion, what do you call it when you make files smaller for storage. There are others: ones we’ve solved so many times or used so many ways that they stabilize: web servers, grep. The problem space is inherently specified, or it has become well-defined over time.
Correctness is possible here, because there is such a thing as “correct.” Programs are useful to many people, so correctness is worth effort. Use of such a program or library is freeing, it scales up the capacity of the industry as a whole, as this becomes something we don’t have to think about.

An expanding problem: the more you think about it, the more ways it can go. This includes pretty much all business software; we want our businesses to grow, so we want our software to do more and different things with time. It includes almost all software that interacts directly with humans. People change, culture changes, expectations get higher. I want my software to drive change in people, so it will need to change with us.
There is no complete specification here. No amount of thought and care can get this software perfect. It needs to be good enough, it needs to be safe enough, and it needs to be amenable to change. It needs to give us the chance to learn what the next definition of “good” might be.

I propose we change our aim for correctness to an aim for safety. Safety means, nothing terrible happens (for your business’s definition of terrible). Correctness is an extreme form of safety. Performance is a component of safety. Security is part of safety.

Tests don’t provide correctness, yet they do provide safety. They tell us that certain things aren’t broken yet. Process boundaries provide safety. Error handling, monitoring, everything we do to compensate for the inherent uncertainty of running software in production, all of these help enforce safety constraints.

In an expanding software system, business matters (like profit) determine what is “good enough” in an expanding system. Risk tolerance goes into what is “safe enough.” Optimizing for the future means optimizing our ability to change.

In a contracting solution, we can progress through degrees of safety toward correctness, optimal performance. Break out the formal specification, write great documentation.

Any piece of our expanding system that we can break out into a contracting problem space, win. We can solve it with rigor, even make it eligible for reuse.

For the rest of it – embrace uncertainty, keep the important parts working, and make the code readable so we can change it. In an expanding system, where tests are limited and limiting, documentation becomes more wrong every day, the code is the specification. Aim for change.

Areas of responsibility

“And the Delivery team is in charge of puppet….” said our new manager.

“Wait we’re in charge of WHAT?” – me

“Well I thought that it fits in with your other responsibilities.”

“That’s true. But we’re not working on it, we’re working on these other things. You can put whatever you want in our yellow circle, but that’s it.”

“The yellow circle?”

See, I model our team’s areas of responsibility as three circles. The yellow system is everything we’re responsible for — all the legacy systems and infrastructure have to belong to some team, and these are carved out for us. Some we know little about.
Inside the yellow circle is an orange circle: the systems we plan to improve. These appear on our backlog in JIRA epics. We talk about them sometimes.
Inside the orange circle, a red circle: active work. These systems are currently under development by our team. We talk about them every day, we add features and tests, we garden them.

That yellow circle holds a lot of risks: when something there breaks we’ll stop our active work and learn until we can stand it back up. Management may add items here, as they recognize the schedule risk. We sometimes spend bits of time researching these, to reduce our fear of pager duty.

The orange circle holds a lot of hope, our ambitions for the year and the quarter. We choose these in negotiation with management.

The red circle is ours. We decide what to work on each day, based on plans, problems, and pain. Pushing anything directly into active work is super rude and disruptive.

“OK, it’s in the yellow circle, cool. I’ll work on hiring more people, so we can expand the orange and red circles too.”

Stacking responsibilities

TL;DR – Support decisions with automation and information; give people breadth of responsibility; let them learn from the results of their choices.
When I started writing software in 1999, The software development cycle was divided into stages, ruled over by project management.

Business people decided what to build to support the customers. Developers coded it. Testers tested it. System Administrators deployed and monitored it. Eventually the customer got it, and then, did anyone check whether the features did any good?

These days Agile has shortened the cycle, and put business, development, and QA in the same room. Meanwhile, with all the tools and libraries and higher-level languages, feature development is a lot quicker, so development broadens into automating the verification step and the deployment. Shorter cycles mean we ask the customer for feedback regularly.

Now developers are implementing, verifying, deploying, monitoring. The number of tools and environments we use for all these tasks becomes staggering. Prioritization – when the only externally-visible deliverable is features, who will improve tests, deployment, and monitoring? We automate the customer’s work; when do we automate ours?

The next trend in development process helps with these: it divides responsibilities without splitting goals. Business works with customers, developers automate for business, and a slice of developers automate our work. Netflix calls this team Engineering Tools; at Outpace we call it Platform. Instead of handoffs, we have frequent delivery of complete products from each team.

Meanwhile, when developers own the features past production, another task emerges: evaluation of results. Automate that too! What is success for a feature? It isn’t deployment: it’s whether our customers find value in it. Gleaning that means building affordances into the feature implementation, making information easy to see, and then checking it out. We’re responsible for a feature until its retirement. Combine authority with information, and people rise to the occasion.[1]

Learning happens when one person sees the full cycle and its effects, and that person influences the next cycle. Experiments happen, our capabilities grow.

In this division of responsibilities, no one delegates decisions. Everyone shares a goal, and supports the rest of the organization in reaching that goal. The platform team doesn’t do deployments. It creates tools that abstract away the dirty details, supplying all information needed for developers to make decisions and evaluate the results. At Outpace, the Platform team is composed of people from the other development teams, so they share background and know each others’ pain. The difference is: the platform team has a mandate to go meta, to improve developer productivity. Someone is automating the automation, and every developer doesn’t have to be an expert in every layer.

The old way was like a framework: project managers take the requirements from the business, then the code from the developers, and pass them into the next step in the process. The new way is like libraries: the platform team provides what the developers need, who provide what the business needs, who provide what the customer needs. Details are abstracted away, and decisions are not.

When a developer’s responsibilities end with code that conforms to a document, it’s super hard to get incentives aligned to the larger needs. Once everyone is responsible for the whole cycle, we don’t need to align incentives. Goals align, and that’s more powerful. Remove misaligned incentives, give us a shared goal to work for, and people achieve. Give us some slack to experiment and improve, and we’ll also innovate.

[1] via David Marquet