On Development

Start failing.

Always (this means every single time) start development with error handling and failing conditions.
Errors will always happen and can’t be avoided. So, it’s better to have an error-handling strategy in place.
This way, failure will always be graceful.
Nothing reflects worse on you than an unhandled error response. Or worse, multiple ones.

Special cases kill. And, specially, they kill projects.

Special cases increase complexity to the point where failures and bugs become unpredictable. Avoid them whenever possible.

One is a special case of many.

Single returns should be treated as multiple ones.

Shit happens. Be prepared.

“If something can go wrong, it will.” — Sod’s law

“Anything that can go wrong will go wrong.” — Murphy’s law

Most people misuse these laws. They think it’s just a pessimistic outlook on life, but it’s actually an approach to engineering. An engineer should assume that anything that can go wrong will eventually go wrong, and should plan for that eventuality.

Adding manpower to a late software project makes it later.

What a developer does in one month, two developers do in two months.
Brook’s law

One ticket, one thing

Tickets/tasks are the smallest units of work in a project management system. Everything else builds up from here. A single ticket represents an indivisible issue.

“Nonessential elements of a story must be removed.” — Chekhov’s gun

One ticket, one instance.

Each ticket requires its own development instance. Keep the development of issues separated from other tasks or long-running development branches. With today’s local development tools, there’s no excuse not to do this. Say goodbye to foreign and unexpected code appearing in your commits.

Single responsibility principle.

Take it seriously. It’s harder than you think. Try not to lose detail or significance in the pursuit of simplicity. This principle sets a clear boundary for where to stop.

“Everything should be made as simple as possible, but not simpler.” — Albert Einstein

“If I had more time, I would have written a shorter letter.” — Blaise Pascal

“Simple can be harder than complex: You have to work hard to get your thinking clean to make it simple. But it’s worth it in the end because once you get there, you can move mountains.” — Steve Jobs

“Good design is as little design as possible.” — Dieter Rams

“Simplicity –the art of maximizing the amount of work not done– is essential.” — Principles behind the Agile Manifesto

“Nothing is as easy as it looks”

Murphy’s Second Law

Don’t track bugs, fix them.

Allen Holub

Bugs are first and foremost. They should be a priority in the sprint planning. When you find a bug, fix it. Now, convince your PM.

“Always live the camp better than when you found it.” — Boy Scout rule

“Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.” — Kernighan’s Law

“Every method you use to prevent or find bugs leaves a residue of subtler bugs against which those methods are ineffectual.” — Beizer’s Law

“Change introduces new forms of failure.” Know how complex systems fail

Never start everything at the same time!

I’ve seen development teams coding frantically, directed by the PM, before an architect or tech lead joins the project. Someone hired them early and insists they work (i.e., write code) just to fill seats, even when no one knows the direction. This is a gross misunderstanding of Agile and any sane development approach. Avoid this at all costs, or you’ll end up with a train wreck.

Don’t do anything else until you have the results of what you did before.

In iterations and feedback loops change just one thing at a time and observe its consequences before making any further changes. This is the foundation of cybernetics and scientific thinking.

First, solve the problem. Then, write the code.

John Johnson

“Successful problem solving requires finding the right solution to the right problem. We fail more often because we solve the wrong problem than because we get the wrong solution to the right problem.” — Russell Ackoff

Problems are universal.

Every problem is universal (it doesn’t exist in isolation) and can be approached in many ways. We box problems by applying our limited knowledge to them, restricting the range of potential solutions. Think out of the box (it is easier said than done).

Advances to any discipline often come from non-experts of such discipline. The “I did it because I didn’t know it couldn’t be done” effect. Therefore, teams must be heterogeneous (A wise team is a good team).

“When a distinguished but elderly scientist states that something is possible, he is almost certainly right. When he states that something is impossible, he is very probably wrong.” — Clarke’s first law

“The only way of discovering the limits of the possible is to venture a little way past them into the impossible.” — Clarke’s second law

Sometimes problems are not what they appear to be. Our biases and prior knowledge prevent us from seeing the whole picture, or even the right picture.
“You cannot apply a technological solution to a sociological problem.” — Edwards’ Law

Any piece of software reflects the organizational structure that produced it.

Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations.
The systems we design always reflect the organizational structure of the community that designed them. Our software and automated systems end up “shaped like” the teams and companies that created them. Melvin Conway Conway’s law

Have development guidelines.

Development guidelines are documents that inform the team about policies, technologies, and technical approaches to use during the project. They are based on previous experience and define the working baseline for the current project, helping to eliminate common friction points and misunderstandings.

These guidelines won’t constrain the team’s creativity, but they set the framework to innovate productively.

Some things to include:

  • Code formatting rules.
  • Development workflow, including CVS, testing and deployment.
  • Local development tools (no more “it works in my machine”).
  • Protocols to introduce new libraries and to manage dependencies.
  • Minimum testing requirements.
  • Code checking standards.
  • Etc.

From craftsmen to engineers.

Good developers are true craftsmen, brilliant artisans. That is excellent. But team developers must become engineers: less magic, more process. In a team environment, collaboration is more important than individual mastery.

I am an engineer who became a developer. An average developer with good principles. This is more scalable and yields better team results than personal mastery.

Document what you do and how to use it.

It is difficult to achieve a balance here, because documentation competes with “work”. But it pays off in the long run. It is a matter of practice.

Using a good tool to organise your thoughts is key. For example xxx

Don’t set up rules that can’t be enforced.

Keep your guidelines and criteria as simple as possible. Anything too complicated will not be followed and will be difficult to enforce.

A common example here are the definitions of “ready” and “done”; in many cases they are too complicated to be used.

As far as the customer is concerned, the interface is the product.

Jef Raskin

“In many cases the user interface to a program is the most important part for a commercial company: whether the programs works correctly or not seems to be secondary.” — Linus Torvalds

This may seem like an ode to the frontend victory in development, but AI is becoming the new interface. And it seems to be more permissive with choppy backends.

The user will never know what they want until after the system is in production (and maybe not even then).

Humphrey’s law

For any system there is a certain amount of complexity which cannot be reduced.

“Every application has an inherent amount of complexity that cannot be removed or hidden. Instead, it must be dealt with, either in product development or in user interaction.” — Tesler’s law

Premature optimization is the root of all evil.

Knuth’s optimization principle

A subset of Convenience is the root of all evil.

Any code of your own that you haven’t looked at for six or more months might as well have been written by someone else.

Eagleson’s Law

The first 90% of the code accounts for the first 90% of the development time. The remaining 10% of the code accounts for the other 90% of the development time.

Ninety-Ninety Rule by Tom Cargill

If it works it’s obsolete.

McLuhan’s Law

Obsolete software tends to work very well as it is tried and tested. Choose boring technology to avoid uncertainties associated to the latest and flashiest technology stacks.

Start simple. Think simple. Build simple. Then grow from there.

“A complex system that works is invariably found to have evolved from a simple system that worked. A complex system designed from scratch never works and cannot be patched up to make it work. You have to start over with a working simple system.” — Gall’s law

In a way this is what we observe in nature. It makes sense in development. A simple system that is the wrong solution will fail earlier and cheaper. A simple system can be addressed by a small team at a small cost. It is a very good strategy to find the right solution fast. Once identified, grow from there.
Consider the children’s behaviour in the marshmallow challenge.

Commitment is sacred. Own your work.

I have witnessed many Agile pretends in my career, where the essence of Agile (responsibility and commitment) was discarded. This is a grave mistake, probably the biggest mistake a PM can make.

Commitment is sacred, no matter what. The delivery commitment of a developer can’t be broken. It is essential for personal growth and team dynamics. If developers decide what they work on, they must deliver what they promised. It is only fair. Sometimes it wil be painful, but that is a lesson. In the future it will be better. PMs need certain certainty for their projections and predictions. The least developer can be is truthful to their part on that equation.

Only interfaces matter. Define them, respect them, abode them. Anything else is easily fixable.

Software architecture can be understood around the interfaces it defines between the systems and components, much like real-world engineering. As long as interfaces are correctly defined, it doesn’t matter how components are implemented as they will be swappable. So, bad code in components can be fixed with minimum fuss. This is how I learn’t to love bad code.

Know your technical debt. Prefer it soft and cheap.

Types of technical debt:

  • Hard: related to infrastructure and technical stack. Always expensive.
  • Soft: related to software.
    • Expensive: related to architecture and interfaces.
    • Cheap: related to software implementation.

The goal is to keep technical debt soft and cheap, as it’s easier to address and has a smaller impact on the application. Expensive technical debt will significantly damage the viability of the application due to high maintenance costs.

Software systems are complex systems.

Systems are not the sum of their parts but the product of their interactions. Systems have emergent properties and complex failure modes.

Maintainability is the most important thing.

Prioritise maintainability. It is the most important factor for complex and lasting systems.

The only valid development QA measurements are maintainability and reliability. No one will care about feature X if the application keeps crashing.

Coding for maintainability will make you code correct, clean, beautiful.

“The central enemy of reliability is complexity.” — Geer et al.

“Simplicity is prerequisite for reliability.” — Edsger W. Dijkstr

“Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.” — Rick Osborne

A spaceship is aas good as the engineers in charge of it.

Scotty (Start Trek)


Last updated: 20 February 2025