My developer manifesto

As a developer I commit to do everything I can to

Understand

As a team, we don’t produce features, let alone lines of code. We produce understanding. Of the domain and constraints, flowing between our brains and our creature. Our goal is to understand:

  • problems to solve, for all stakeholders: users, decision makers, payers, sales, buyers, developers, people keeping the system alive, etc
  • constraints
  • options in our reach to lubricate how we share understanding
  • options kept in the past
  • tensions
  • our creature
  • how this understanding is perceived by all stakeholders

I prefer a solution helping me understand, rather than a solution allowing me not to require understanding

I commit to taking the time to understand context, continuously, and making sure that what needs to flow between our brains, and between our brains and our creature, flows.

Improve the environment

Upgrading the environment by 1% each of the 218 days we’re supposed to work annually in France, stacks up to a 875% increase at the end of the year.

On the other hand, letting the environment deteriorate by 1%, each of the 218 days, adds up to a total 89% decrease at the end of the year.

And the system naturally decays.

Imagine comparing those 2 teams at the end of the year. Between them, you get an 80 fold ratio. Hard to justify, right? Continuous improvement is a mandate, it needs to be a part of every task the team does, every day.

I commit to taking the time to identify, priorise, and fix issues, every day, whatever the priorities.

Verify hypotheses

The difference between theory and practice is practice.

Unless you already did the same task several times in the same context, you can hardly predict its outcome precisely. When the task and the context get more complex, there is no chance your oracle comes true.

When we prepare a release, or a piece of code, we often face the unknown, somewhere between cynefin’s chaotic and complicated domains. And it’s a good thing. If this was false, we would be doing the same thing all over again. And when humans do repetitive things, computers come together and make fun of us.

So we make hypotheses a lot, all the time. Wise people take time and attention to spot and verify them. This is how they capture comprehension in an iterative and incremental way. Others watch the ground fall under their feet, when what they thought of as foundations was actually quicksand.

I commit to interrupting discussions to challenge hypotheses, asking for facts that increase confidence in hypotheses and options, and taking the time to gather facts. I commit to doubting and making people doubt.

Stay away from solutions

History repeats itself

Nothing is more dangerous than an idea when you have only one idea (Emile-Auguste Chartier)

Nothing is more dangerous than a road when you have only one road on your roadmap

Nothing is more dangerous than an option when you have only one option

Nothing is more dangerous than a solution when you have only one solution

Jeff Patton tells us the 3 issues with ideas:

  • everyone has some
  • most of them are lame
  • expect mine

Virginia Satir tells us that having one choice is not a choice, having two choices is a dilemma, and having 3 choices offers new possibilities

Chris Matts talked relentlessly to us about real options. And in particular:

  • options have a value
  • options expire
  • never commit to an option until you know why

As long as options are open, the greatest value you can bring to the table is adding new options.

I commit to focusing on problems, and leaving options open as much as I can.

Learn and share my knowledge

Dev requires dozens of practices.

Mental models like cynefin or wardley mapping

DDs, like DDD, BDD, and TDD

Patterns and design smells

Refactoring techniques, from shortcuts to nanosteps.

Activities for retrospective, event storming, example mapping, tres amigos.

Postures, like ego-less programming.

Mobbing and pairing.

Patterns for evolving designs.

These are just examples.

Everyday, all of us need to improve our knowledge, and our muscle memory for our tools. We must repeat and multiply katas.

Improving is part of our job. We must improve, for our collective mission and our employer, on our working time.

I commit to taking the time to discover and share, and showing a good example in a way everyone can see.

Share my understanding of systems

We build a system, for a system, within a system, from a system.

Systems are made of constraints, nodes, queues, mathematics.

They’re made of granularity levels. None of them has the properties of its components. Most of them can’t be understood by decomposing them.

Because I’m interested in these subjects, I see issues that nobody hoping for the system to be predictable can understand. I see bottlenecks and bad optimizations before the red from watermelon indicators reaches their skin. I see illusions, sometimes self-realizing, but rarely close to an optimal.

OK, a common example: a well utilized highway is a parking lot. Optimizing a system for resource utilization makes it grinds to a halt. That’s Little’s law. Mathematics.

I commit to sharing the knowledge that all current problems come from the system that is perfectly optimized for them to occur.

Learn to appreciate uncertainty

Cognitive biases pull us towards a predictable future, certainty. To the extent that, like the 3 monkeys, we make it predictable, at all cost. Until reality breaks through our idealized harness.

If only we knew. In an uncertain world, risks are higher, but so are opportunities. If we act as passive agents, it’s just more amplitude in highs and lows, and the average is the same. But we are not passive. We can sense, choose, and sort options. And thus orient highs and lows in a direction that fits us better. Therefore, the higher the amplitude the quicker we can get to our goals.

Our interest is to live in an uncertain world. We must learn to fight our biases to appreciate uncertainty, and adapt our practices to be more comfortable in such an environment.

In addition, when we don’t know, we learn things. It’s great.

I commit to promoting joy in uncertainty.

Maximize frugality

The easiest code to modify (secure/test/APIfy/document/support) is no code. It is an ideal, and I try to tend towards it. It is also true for features, system complexity, things, and people.

John Cutler promotes Remove a feature day.

Never add things “just in case”. Even less because it’s easy to add them. When Sir Tony Hoare, inventor of null, is asked why he did that, he answers he did it because it was easy to do. He calls it his Billion dollar mistake.

Complexity increases, not with the number of things, but with the number of relations between things, and between things and the environment. And relations increase exponentially with the number of things.

I learn to adapt to my microscopic cognitive capacity. I move in baby-steps, then micro-steps, then nano-steps. It helps me keep fewer hypotheses dangling.

I commit to producing as few sub-products of understanding as possible, like code or features.

Do nothing when it’s time

Every time a task is blocked, we stop… and in general, we move to another task. Our biases make us scared of the void. We need to feel useful, by taking tickets on the board, by doing something. Every time we do so, we violate a more or less explicit agreement we have in the team: we agreed that the blocked task was a priority, so our duty is to concentrate our time and effort on unblocking it.

When we move tasks with less priority while higher-priority tasks still ask for moving forward, we don’t only take capacity from high-priority tasks. We also add noise to the system, further reducing our capacity in general.

When downstream capacity is full, we can do more than our basic job, and help unlocking the task. If we can’t, we can prepare future tasks. Which means, from the backlog’s point of view, do nothing.

Oh by the way. In lean, when the WIP limit does not block tasks anymore, we decrease it on purpose, in order to expose the next problem to solve, and thus understand and improve.

I commit to leaving room for high priorities, by doing nothing when they already take the capacity of a constraint.

Become useless

I will never be essential. Whether you say bus factor or lottery factor, nevermind. I won’t be responsible for a value of 1.

Necessary heroes are bottleneck. They are a source of stress for themselves and their environment. They decrease everybody’s engagement. And yet, everyone does fine when they leave.

We must share our practices and know-how, but also our comprehension of the domain, the environment, and our creature.

I commit to making sure nobody sees the difference when I’m not here.

Promote testing

Professional testers make a difference between tests and checks.

Checking is confirming the software gives the expected results in a given example. To avoid computers making fun of us, we automate checks as much as we can. It is a tiny part of testing.

Testing is a journalist’s job. Testers gather, compile, and render information that is relevant to someone. It can be checking expected behaviors, but also giving information about unpredictable things, like performance, ergonomic, security, limits of the system, instabilities… Tons of things we can’t really check.

Testing is as manual as developing with an IDE and a computer, continuous integration and deployment with analysis tools, etc. You can automate testing as much as development, management, or proof-reading this article.

Testing is central to all problems of all stakeholders, all constraints of the environment, details and generalities. In my opinion, it is the most difficult job in software.

I commit to promoting the job of testing, promoting the need for testers that are professional, competent, influent, and well payed.

Leave a test campaign that accelerates refactoring

I don’t try to increase code or branch coverage. I don’t try to balance the test pyramid. I try to have a harness that allows me to modify code with more confidence more quickly.

I consider a modification as done when it brought its value without increasing risks. When it passed all stages to get to the hands of users. The quicker I can detect risks increasing, the cheaper I make modifications.

The harness is the main tool helping me accelerate problem detection. The harness goes from compiler indication to team understanding, and includes code analysis tools, linters, all types of automatic checking, and testing.

The big topic we always wonder about in writing automated checks is granularity.

A test that only embeds an isolated class runs quickly. But when I need to update the code, if I also need to modify tons of test stubs, I waste time.

On the other hand, I recently experienced a very smooth refactoring, with confidence, because I had written tests at a higher granularity level than the team was used to.

I only know one heuristic to choose the right granularity level, and I only learned it in 2022: test interfaces you are ready to commit to (talk in French sorry).

Note that you have less problems choosing the right granularity in a functional core corresponding to the right aggregate of the right bounded context: there is only one, side-effect free, functionally relevant, autonomous, quick to run, level of granularity. That looks like an ideal, right?

One last thing. Feedback speed is the whole test campaign’s job. The team must maintain a consistent campaign, testing each aspect of the code in a necessary and sufficient way.

I commit to adapting each test to the level of granularity that looks the most stable to me, and to maintaining a consistent and frugal campaign.

Leave plastic or disposable code

“When you don’t have the time to do things right, you have the time to do them twice”

Code can be in 2 states:

  • plastic enough, scannable, you get intentions, it has a sufficient harness to detect regressions quickly, contracts are clear and maintained. All these properties are subjective. Anyway, I trust this code enough to evolve and adapt to requirements to come. I can commit to maintaining it.
  • immutable, read only. When its requirements evolve, we throw it away and rewrite it. Writing disposable code is a totally valid option, and I use it on a regular basis. To make sure the option works, the organization of the code must allow it. The contract linking this code to the rest of our creature must be clear and stable.

Like the diesel gate showed us by sending engineers to jail, we are responsible for the quality of our creature. The level of quality we adopt in our code base and practices is nobody’s business but ours. Like washing their hands for surgeons, quality is not negotiable.

I commit to writing code that I’m confident to maintain, or to organizing it such that I can easily delete it, without blinking.

Ignore estimates

Estimates are not commitments.

Estimating can help understanding the problem to solve, and the constraints we will live in to solve it.

Once we committed, knowing we don’t progress at a rate that would allow meeting our commitment is useful. It is a signal for the need to discuss or renegotiate commitments. And estimates are far from being the only way to see that.

But estimates, once done, are useless. Knowing we are tripling estimates while developing is useless. Doing better than estimates is useless.

I commit to ignoring estimates once they are communicated and digested.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s