Aller au contenu

Méthodes de travail

Make it work, make it right, make it fast.

Ken Beck

En fonction de vos connaissances et compétences, la création d’une nouvelle application est une étape relativement facile à mettre en place. Le code qui permet de faire tourner cette application peut ne pas être élégant, voire buggé jusqu’à la moëlle, il pourra fonctionner et faire ”preuve de concept”.

Les problèmes arriveront lorsqu’une nouvelle fonctionnalité vous sera demandée, lorsqu’un bug sera découvert et devra être corrigé ou lorsqu’une dépendance cessera de fonctionner ou d’être disponible. Comme une application qui n’évolue pas finira inlassablement par mourir, toute application est destinée :

  • Soit à être modifiée, corrigée et suivie
  • Soit à déperrir et à être délaissée par ses utilisateurs.

C’est cette maintenance qui est difficile : selon certaines études académiques et industrielles, 60 à 80% du coût associé à n’importe quelle ligne de code correspond à de la maintenance de la ligne initialement écrite. Ceci est dû à des bogues, à des modifications de fonctionnalités, à des dépendances qui évoluent, qui ne sont plus maintenues ou qui doivent être remplacées.

L’application des principes présentés et agrégés ci-dessous permet surtout de préparer correctement tout ce qui pourra arriver, sans aller jusqu’à surcharger tout développement par des fonctionnalités non demandées, juste “au cas ou”, aussi connu sous l’acronym YAGNI ou “You ain’t gonna need it”.

Pour paraphraser une partie de l’introduction du livre Clean Architecture:

Getting software right is hard : it takes knowledge and skills that most young programmers don’t take the time to develop. It requires a level of discipline and dedication that most programmers never dreamed they’d need. Mostly, it takes a passion for the craft and the desire to be a professional.

Robert C. Martin

Le développement d’un logiciel nécessite une rigueur d’exécution et des connaissances précises dans des domaines extrêmement variés. Il nécessite également des intentions, des prises de décisions et énormément d’attention. Indépendamment de l’architecture que vous aurez choisie et des technologies que vous aurez patiemment évaluées, une architecture et une solution peuvent être cassées en un instant, en même temps que tout ce que vous aurez construit, dès que vous en aurez détourné le regard.

Un des objectifs ici est de placer les barrières et les gardes-fous, afin de péréniser au maximum les acquis, stabiliser les bases de tous les environnements (du développement à la production) qui accueilliront notre application, et ainsi fiabiliser chaque étape de la communication.

Dans cette partie-ci, nous parlerons de méthodes de travail, avec comme objectif d’éviter que l’application ne tourne que sur notre machine et que chaque déploiement ne soit une plaie à gérer. Chaque mise à jour doit être réalisable de la manière la plus simple possible, et chaque étape doit être le plus possible automatisée.

Dans son plus simple élément, la mise à disposition d’une nouvelle version d’une application pourrait se résumer à ces trois étapes :

Dans une version plus automatisée, une application pourrait être mise à jour simplement en envoyant son code sur un dépôt centralisé : ce déclencheur a la responsabilité de démarrer une chaı̂ne de vérification d’utilisabilité, de bon fonctionnement et de sécurité, pour immédiatement la mettre à disposition de nouveaux utilisateurs si chaque acteur de cette chaı̂ne indique que tout est OK.

D’autres mécanismes fonctionnent également, mais au plus les actions nécessitent d’étapes ou d’intervenants humains, au plus la probabilité qu’un problème survienne est grande, même dans le cas de processus de routine. Sans aller jusqu’à demander de développer vos algorithmes sur douze pieds, la programmation reste un art régit par un ensemble de bonnes pratiques, par des règles à respecter et par la nécessité de travailler avec d’autres personnes qui ont souvent une expérience, des compétences ou une approche différente.

Conclusions

La perfection est atteinte, non pas lorsqu’il n’y a plus rien à ajouter, mais lorsqu’il n’y a plus rien à retirer.

Antoine de Saint-Exupéry

Il est impossible de se projeter dans le futur d’une application: il est impossible d’imaginer les modifications qui seront demandées par les utilisateurs, de se projeter dans l’évolution d’un langage, dans les nécessités d’intégration de certaines librairies ou dans le support-même de certaines fonctionnalités par les navigateurs Web. Ce sont des choses qui viennent avec l’expérience (ou avec une certaine torture d’esprit). Cela rejoint le fameux “YAGNI” ((YAGNI, You Ain’t Gonna Need It)) dont nous parlions plus tôt : il est inutile de vouloir développer absolument toutes les fonctionnalités qui pourraient un jour pouvoir être utilisées ou souhaitées, car cela complexifiera autant le code, que les déploiement, l’utilisabilité ou la compréhension que les utilisateurs pourront avoir de votre application. Tout ceci a un impact sur la dette technique, dont nous parlions plus tôt, où sur la manière dont vous vous sentirez lorsque vous devrez modifier une partie déjà fonctionnelle, pour en modifier son comportement général.

Il est impossible d’imaginer ou de se projeter dans tous les éléments qui pourraient devoir être modifiés après que votre développement ait été livrée. En ayant connaissance de toutes les choses qui pourraient être modifiées par la suite, l’idée est de pousser le développement jusqu’au point où une décision pourrait devoir être faite. A ce stade, l’architecture nécessitera des modifications, mais aura déjà intégré le fait que cette possibilité existe. Nous n’allons donc pas jusqu’au point où le service doit être créé (même s’il peut ne pas être nécessaire), ni à l’extrême au fait d’ignorer qu’un service pourrait être nécessaire, mais nous aboutissons à une forme de compromis. Une forme d’application de la philosophie de René Descartes, où le fait de seulement envisager une possibilité ouvre un maximum de portes.

Avec cette approche, les composants seront déjà découplés au mieux.

Les composants peuvent être découpés au niveau:

  • Du code source, via des modules, paquets, dépendances, …
  • Du déploiement ou de l’exécution, au travers de dll, jar, linked libraries, …, voire au travers de threads ou de processus locaux.
  • Via la mise à disposition de nouveaux services, lorsqu’il est plus intuitif de contacter un nouveau point de terminaison que d’intégrer de force de nouveaux concepts dans une base de code existante.

Cette section se base sur deux ressources principales , qui répartissent un ensemble de conseils parmi quatre niveaux de composants:

  • Les méthodes et fonctions
  • Les classes
  • Les composants
  • Et des conseils plus généraux.

Certaines des valeurs ci-dessous sont totalement arbitraires (voire empiriques) ; une autre manière de prendre du recul consiste à suivre les règles proposées par Jeff Bay cite:[thoughtworks_anthology] cite:[dogmatism] :

  • One level of indentation per method
  • Don’t use the ELSE keyword
  • Wrap all primitives and Strings
  • First class collections
  • One dot per line
  • Don’t abbreviate
  • Keep all entities small
  • No classes with more than two instance variables
  • No getters/setters/properties.