Value from software

A deeper look at Competence debt

When I introduced the concept of competence debt I assumed it was an intuitive idea. The discussion since then has proved me wrong. This post is an attempt to explain competence debt more clearly and show how it mirrors technical debt.

Many have observed that source code is a way of communicating what a system is able to do to other people. All communication is susceptible to problems with the way the message is formulated and to interpretation problems at the receiver. Technical debt is about the quality of the message; the understandability of the code if you like. Competence debt is about how well the developers “know” the system. You can be a world class C++ developer, but the first day with a very large codebase will not be very productive. If you succeed in adding a new capability to the system, chances are that you add technical debt at the same time. In many mature systems there is often only one person that can change parts of the system. Sometimes no one dares change a core component. This is when people start talking about the system as unmaintainable.

The downward spiral

Technical debt and competence debt feed each other. As tech debt grows, developers tend to become less motivated in learning how the system works. It is simply too frustrating. When developers have a poor knowledge of a system they will be more likely to add tech debt when changing it. I´m not aware of empirical evidence but I suspect that an organization that is struggling with high tech debt will have a higher employee turnover which leads to more competence debt.

When software development is rushed, both types of debt will grow. Technical debt grows when things like refactoring get scoped out. Competence debt grows since you will tend to let the developer that knows an area best make all the changes to it.

Fighting debt

It turns out that many of the strategies that are used to reduce technical debt also have a positive effect on competence debt.

Organize around teams
Every time a team is broken up at the end of a project, competence debt grows. Strive to keep teams intact.

Focus on the system/product
You are not producing features, you are evolving a system.

Pair program
By pairing you actively spread understanding of the system.

Keep your codebase as smallas possible
Avoid adding features of dubious utility. Strive to remove dead features and redundant code.

Write unit tests
Developers use unit tests to understand what the system is supposed to be able to do.

Documentation that isn’t worthless

Systems tend to be documented in two ways, not at all or with lots of useless and outdated information. This has led some people to argue that it is better to write self-documenting code. The problem with this approach is that it does not scale well. A large system with self-documenting code will still be very hard for a new developer to grasp without some kind of guide to the big picture. There are two types of documentation that you should always create:

Architecture stories

When a new system is created the architecture tends to be pretty simple. Only the most important domain objects and features are in place. Over time things get more and more complicated. The developers evolve their understanding from the small model to a large complex one. So why are new developers typically given static documents that describe everything in the system? What they need is to be able to take a similar journey from the simple model with the core domain objects and follow how it evolved to the present one. This is the way many developers intuitively explain a system on a white-board. They start with the core components and add more as they trace the evolution of the system.

There are many ways an architecture story can be documented depending on how ambitious you are. Why not just make a video of a developer explaining the architecture on a white board?

Document the things not done

Have you ever had the following conversation:

“I see that our system can only handle images up to 3Mb. Why did we set the limit at 3Mb?”

“I think that was decided at a meeting last year but I cant remember what the reasoning was”

Self documenting code will not tell you why you chose not to do something. In every project I have ever been involved with, we have made many assumptions about what the system should be able to handle and what it should not. Documenting these assumptions makes it much easier to understand the reasoning that led to the current system.