Recently, I finished reading "A Philosophy of Software Design" and in the second chapter, it explores the topic of Software Complexity.
The book "A Philosophy of Software Design" defines complexity practically:
"Complexity is anything related to the structure of a software system that makes it hard to understand and modify."
In other words, complexity can take many forms, and doesn't necessary has anything to do with performance, your code can be performant and still be complex
I'd like to share some key definitions and insights from the book in this article. But first, let's imagine a common situation that probably you’ve already been to…
Let's dive into a horror story many of you have probably experienced or will experience.
It started with a simple CRUD task management app. The code was clean, modular, and easy to maintain. The development team was happy, and the system worked perfectly for initial clients.
Problems began when the sales team sold the system to a large company, claiming it had calendar integration, email notifications, and an amazing report generator. With the sale finalized, these features had to be implemented quickly.
Calendar Integration: The team had to integrate with Google Calendar and Outlook. Different developers implemented the solutions, resulting in inconsistent approaches.
Email Notifications: Email notifications were added next. One developer used a specific library, while another created a custom solution. The mixed approaches made the code confusing.
Report Generator: For the report generator, developers used various technologies: PDFs, Excel exports, and interactive dashboards. The lack of a unified approach made maintenance a nightmare.
Growing Complexity: Each feature was developed in isolation and quickly, leading to dependencies between features. Developers started creating "quick fixes" to make everything work, increasing the system's complexity and coupling.
Software development doesn't happen in a vacuum; various internal and external factors influence it. We've all been, or will be, in a situation like this.
Then the problems began:
It's clear we now have a complex system.
Now let's "dissect" this complexity to make it easier to identify and mitigate it.
Well, "mitigate" means:
"To make less severe, serious, or painful; to alleviate."
I believe complexity is often inherent in code. Some things are complex by nature. Your role as a developer isn't just to create code that the computer can execute efficiently but also to create code that future developers (including your future self) can work with.
“Controlling complexity is the essence of computer programming.”
— Brian Kernighan
The author of the mentioned book states that complexity typically manifests in three ways, which we will explore here.
Change amplification occurs when a seemingly simple change requires modifications in many different places.
For example, if the Product Owner requests a "priority" or "completion date" field and your entities are tightly coupled, how many changes would you need to make?
Cognitive load refers to the amount of knowledge and time a developer needs to complete a task.
So imagine this scenario: A new developer joined the team, he was assigned to fix a bug in the report generator. To complete this task, the dev needed to:
Il s'agit du scénario classique « impossible à estimer », dans lequel la tâche pourrait prendre un ou huit points : mieux vaut lancer un D20 et répondre en conséquence.
Les inconnus inconnus, c'est quand vous ne savez pas ce que vous ne savez pas.
C'est la pire manifestation de la complexité, car vous pourriez modifier des choses que vous ne devriez pas, ce qui provoquerait la rupture de tout.
Exemple : Un développeur a modifié le code d'envoi d'e-mails pour ajouter une nouvelle notification, ignorant que cela affecterait le générateur de rapports, qui dépendait de cette fonction. Cela a causé des problèmes importants aux clients, illustrant la pire forme de complexité émergente.
Après avoir vu l'histoire d'horreur et les trois principaux symptômes, regardons ce qui cause la complexité.
Les dépendances sont essentielles dans les logiciels et ne peuvent pas être complètement éliminées. Ils permettent aux différentes parties du système d’interagir et de fonctionner ensemble. Cependant, les dépendances, lorsqu’elles ne sont pas gérées correctement, peuvent augmenter considérablement la complexité.
Une dépendance existe lorsque le code ne peut pas être compris ou modifié de manière isolée, nécessitant la prise en compte ou la modification du code associé.
L'obscurité se produit lorsque des informations importantes ne sont pas évidentes. Cela peut rendre la base de code difficile à comprendre, entraînant une charge cognitive accrue et le risque d'inconnues.
L'obscurité se produit lorsque des informations importantes ne sont pas évidentes.
Parce que c'est progressif, il est facile de penser : « juste pour une fois, ça n'aura pas d'importance ». Mais une fois accumulées, réparer une ou deux dépendances à elle seule ne fera pas beaucoup de différence.
« Tout est un compromis en génie logiciel. »
— Je ne me souviens pas de l'auteur
Je pourrais écrire beaucoup de règles, de stratégies et de cadres que vous avez probablement déjà vus sur Internet pour éviter la complexité : SOLID, Design Patterns, YAGNI, KISS, etc.
Cependant, vous pouvez les unifier tous en un seul principe directeur (comme mentionné dans « Le programmeur pragmatique. ») : « Ce que j'implémente est-il facile à changer ? » Si la réponse est non, alors vous augmentez probablement la complexité.
S'assurer que votre code est facile à modifier simplifie la maintenance, réduit la charge cognitive des développeurs et rend le système plus adaptable et moins sujet aux erreurs.
Merci !
The above is the detailed content of The Never Ending Battle Against Software Complexity. For more information, please follow other related articles on the PHP Chinese website!