Pythonium

Python, What else ?

Signs that a project is becoming difficult to maintain

At the beginning of a project, everything seems simple. The code is recent, the features are still limited and well organized, and each change seems quick to implement.

Then, over the months or years, things gradually change. A simple change can take several hours, bugs appear in unexpected places, and every deployment becomes a source of stress. I have already worked on a project without unit tests where every modification caused side effects and new regressions. We often spent more time fixing bugs than developing the feature itself.

A project does not become difficult to maintain overnight. There are usually warning signs that are better detected as early as possible. Let's look at them together.

Nobody dares to modify certain parts of the code

Sometimes, there are files that everyone avoids. Every developer knows that modifying this area could break something, but nobody really understands why. We then start writing workarounds instead of fixing the actual problem. And this is where the snowball effect begins...

If part of the project becomes a "black box", it is rarely a good sign. Or if only one developer feels confident enough to modify the code, this is already a warning sign.

A small change requires modifications everywhere

Adding a simple field to a form requires modifying several controllers, services, SQL queries, tests...

A simple feature should not require changing ten different files. Otherwise, it probably means the code is not properly separated, and this will likely get worse over time.

When everything is strongly coupled, every change becomes expensive because you have to think about and search for all the dependencies throughout the codebase.

Names no longer make sense

Over the years, you start seeing classes like:

UserManager
Helper
Utils
Common
DataService
GlobalFunctions

These names are often a sign that the responsibility of the code has gradually grown. A class that does "a bit of everything" almost always ends up becoming impossible to properly understand and maintain.

Methods become endless

Functions containing several hundred lines...

In this kind of function, you will probably find validation, SQL queries, business logic, and many other things.

When touching this kind of function, we will probably make the problem even worse by adding a few dozen more lines.

The larger a method becomes, the harder it is to test and evolve.

Comments replace explicit names

Comments are useful to explain a technical choice or a particular behavior. However, when they are only used to explain what the code does, it often hides a problem.

On a certain project, I remember documenting the business logic we were implementing just below the code, with several dozen lines of explanations. But if the code had been clear, it should not have required that much detail.

In my case, it was with a proprietary language that was difficult to read, which did not help.

Tests become complicated to write

A method requires a database, several mocks, an HTTP server, ...

Before even writing the first test, several dozen lines are needed to prepare the environment.

Highly coupled code is generally difficult to test.

As a side effect, this discourages developers from writing new tests...

Every new feature creates regressions

You add an unrelated feature, and a completely different part of the application stops working.

This usually reveals:

  • strong coupling between components;
  • a lack of automated tests;
  • side effects that are difficult to anticipate.

The more frequent the regressions become, the higher the cost of changes gets.

I remember periods where I spent more than 80% of my time fixing bugs, for almost a year. It was clearly a sign that the project had become impossible to maintain.

Conclusion

A project that is difficult to maintain is usually not the result of a single bad decision, but rather the accumulation of many small compromises: a method that becomes too long, a temporary duplication that becomes permanent, an unclear class name, or a dependency that is never updated.

The good news is that these signs can be detected early enough. Regular refactoring, code reviews, a consistent architecture, and appropriate tests are often enough to prevent technical debt from building up.

However, if we wait too long, we eventually reach a tipping point. Every change becomes slow and risky, regressions multiply, and a large part of the time is spent fixing bugs rather than developing new features. At that stage, small improvements are no longer enough: a major refactoring, or even a rewrite of some parts of the project, often becomes unavoidable.




Laisser un commentaire