Coder vs Développeur : Configuration partie 2, le retour
Générée par Microsoft Designer sans serre-tête cette fois, sniff

Coder vs Développeur : Configuration partie 2, le retour

Autre aspect de l'épineuse question de la configuration, j'ai bien parlé de comment faire de la bonne config dans mon post précédent sur le sujet, là on va aborder le sujet sous un autre angle. J'ai une application, on a certaines exigences concernant la configuration, qui commence à avoir une taille méritant réorganisation, quelle(s) stratégie(s) adopter pour faire cette réorganisation. Et on va le voir ensembles, ce n'est pas exactement une mince affaire.

Je précise aussi que je ne rentrerai pas dans le détail de ce que fait exactement cette application, c'est 100% hors sujet.

Ce qui nous intéresse dans cet exemple c'est comment réfléchir autour de ce problème, comment raisonner pour rationnaliser l'usage de la configuration dans ce projet, comment ne pas produire un foutoir et tenter de garantir un résultat exploitable à terme. En gros, c'est la logique et la discussion qui sont intéressants ici, l'exemple de l'application, ce n'est qu'un exemple qui sert à illustrer la manière de réfléchir, rien de plus.

Rentrons dans le vif du sujet. Voici les informations utiles concernant l'application qui vont permettre de comprendre la réflexion :

  • L'application est actuellement un client lourd (oui je sais, c'est un truc de dinosaure, il y a des raisons à ça), est installée sur chaque poste utilisateur, et doit pouvoir avoir des variations de configuration d'un utilisateur à l'autre (légères quand les utilisateurs travaillent au même endroit, fortes sinon)
  • L'application orchestre des appels à différents composants. Il ne s'agit pas d'un archi microservices mais bien d'un bloc (pour l'instant) monolithique qui sous traite à différents composants, certains étant des exécutables appelés à la demande, d'autres étant des bibliothèques embarquées, etc. et toutes les configurations de chaque composant sont centralisées en un seul et unique endroit. Les accès à tous ces composants sont également stockés en configuration.
  • Les composants sont susceptibles de servir pour une des étapes clés du gros traitement fait dans l'orchestrateur. Ce gros traitement a plusieurs étapes bien distinguées, et la plupart des composants et des configurations ne servent que pour une étape, même s'il existe des exceptions.
  • Nous savons déjà que de nombreux composants seront encore ajoutés et supprimés au cours des évolutions de ce programme. Nous savons aussi qu'il est possible que certains composants soient désactivés pour certains clients ou utilisateurs.
  • Nous envisageons qu'il soit possible qu'on dépende d'autres types de composants. Pour l'instant les services web sont off limit mais il se pourrait qu'on ait besoin d'url ou d'autres types de ressources à l'avenir.
  • L'orchestrateur a aussi ses propres éléments de paramétrage nécessitant de la configuration.
  • L'application doit pouvoir évoluer vers une application de type client web pour certains clients
  • Il y a également de gros blocs de données de type référentiel qui, pour diverses raisons, sont stockés en tant que configuration (un des arguments étant permettre aux différents utilisateur de se les transmettre très facilement, ce choix nous épargne donc la tâche devoir faire un export et un import de ces éléments, pour la petite note)

Du coup, assez vite on se retrouve avec une config qui contient :

  • De gros blocs de paramétrage client
  • Des éléments de paramétrage relatifs au fonctionnement de l'application
  • Des chemins vers les binaires d'autres programmes et composants
  • Des chemins vers des dossiers de travail utilisés par ces composants
  • Des éléments de paramétrage relatifs au fonctionnement des composants

Et bien sûr on a appliqué autant que possible les réflexions de l'autre post sur le fait d'en rentre le moins possible explosifs (allez lire l'autre post si vous ne voyez pas de quoi je parle 😉), de mettre des valeurs par défaut, etc.

Et nous avons atteint la fameuse étape du "Vite, il faut faire du rangement tant que c'est pas trop cher, ça devient un sacré bazar !"

Du coup, que fait-on ? Comment on découpe pour mieux ranger ?

Premier sujet absolument non négociable, le gros bloc de données de références suit son propre chemin à part du reste pour coller au besoin métier qui le concerne. Ça fait un gros paquet en moins, mais pour le reste, que fait-on ? Le dev en charge a fait un exemple et m'a appelé pour qu'on en parle à partir d'un cas concret.

Son idée : faire un découpage technique. En gros, la config centrale d'un côté, les configs de chaque composant d'un autre, les chemins vers les binaires ailleurs, les chemins vers les dossiers de travail ailleurs, etc.

Ma réaction : "c'était pas ça que j'avais en tête que on a parlé de faire du découpage et des regroupements, mais si ça se trouve c'est mieux que ce à quoi je pensais, on pose tout à plat sur un tableau et on en parle"

On a d'abord listé les principales stratégies sur ce type de problème (tout en gardant nos contraintes bien sûr, comment par exemple de garder une configuration centralisée pour n'avoir à la mettre à jour qu'à un seul emplacement), en voici un résumé :

Découpage technique

  • Paramètres de l'application
  • Paramètres des composants
  • Chemins des binaires
  • Chemins des dossiers de travail
  • Ressources
  • Urls
  • Etc.

Découpage par composant

  • Un bloc pour chaque composant avec tout ce dont il a besoin, en fonction des besoins de chaque composant
  • L'application principale est considérée ici comme étant un composant parmi les autres

Découpage par étape

  • Un bloc pour chaque étape de traitement du point de vue de l'orchestrateur
  • Un bloc pour l'orchestrateur en lui-même, dont 100% de l'activité n'est pas exclusivement sur ces étapes principales

Le découpage technique a l'avantage de ne presque jamais bouger, structurellement parlant. On va assez rarement avoir besoin de rajouter de nouveaux classes de sérialisation de configuration, et tout ce qu'on doit ranger est simple et rentre dans peu de catégories. Il a le défaut qu'un même composant va être présent dans plusieurs catégories de découpe, rendant le nettoyage compliqué et l'ajout de nouveaux composants peut-être "à risque" (un jour quelqu'un risque de se dire "je range tout là, c'est plus simple").

Le découpage par composant a l'avantage qu'au moins tout est simple et bien regroupé, sauf qu'il faut créer une nouvelle classe de sérialisation pour chaque nouveau composant à intégrer. La suppression d'un composant est simple comme bonjour, la maintenance en général est simple, c'est juste la solution qui implique le plus de travail à chaque nouveau composant.

Le découpage par étape a l'avantage de bouger relativement peu lui aussi, mais pose le même soucis de redondance que le découpage technique mais uniquement pour le cas des rares composants qui interviennent sur plusieurs étapes. Le vrai risque est si on doit changer la manière dont les étapes sont organisées, car on couple la structure de la configuration avec le détail des étapes dans le process. Tant qu'on ne fait qu'en rajouter ça ne pose pas de soucis mais le jour où une étape est supprimée ou découpée en plusieurs par exemple, on va se retrouver avec une charge de travail assez forte "pour rien".

On a donc plusieurs coûts et gains à chaque fois : combien ça me coûte d'ajouter un nouveau composant, d'ajouter juste un nouveau paramètre de configuration (est-ce que je trouve facilement où il va et est-ce que j'ai des chances raisonnables d'appeler son objet de configuration dans le code, en gros), de supprimer un composant et sa configuration associée, est-ce que je peux retrouver facilement tout la configuration associée à un composant si celui-ci doit bouger ou être remplacé ou complété par un autre, ce genre de choses.

Pour tenter de gagner le meilleur des mondes, on a finit par estimer une solution alternative, connue comme étant très bancale, que voici :

Découpage par unicité

  • Au lieu de définir la stratégie avec une règle cohérente et facile à reproduire, on va se focaliser sur l'unicité de chaque item. Les découpages technique et par étape impliquent d'avoir peut-être des éléments répétés pour un même composant là où le découpage par composant implique de coder de nouvelles sections de configuration à chaque nouveau composant. Dans les deux cas il y a un risque (assumé dans le cas du découpage par composant) de redite, de rajouts de code un peu lourdingue, de surcoût de maintenance soit lors de l'ajout de nouvelles lignes de configuration, soit lors de leur retrait.
  • De ce fait, la stratégie va être de proposer un découpage par étape (ou technique, en fait cela change peu de choses dans la réflexion) sauf pour les composants qui pourraient être présents sur plusieurs étapes, qui auront droit à leur configuration à part, peut-être plus adaptée. Tout doit être fait non pas pour que ce soit simple à retrouver à partir de l'existant mais pour que chaque configuration soit unique.

Très vite la conclusion est tombée sur cette dernière option : trop de risque qu'elle ne supporte pas la durée et aggrave le foutoir à partir du moment où quelqu'un devra ajouter quelque chose sans trop comprendre le pourquoi du comment.

Du coup, que fait-on ? Reste-t-on sur le découpage technique qui va répandre chaque composant dans toutes les catégories mais est très simple à mettre en place et à comprendre, va-t-on sur un découpage par étape de traitement qui a des avantages similaires mais un risque accru en cas d'évolution de l'algo central ou encore un découpage par composant qui implique un coup plus élevé à chaque nouveau composant mais une encapsulation maximale et une simplicité aussi élevée qu'avec les autres ?

Et bien le choix a été tourné vers le découpage par composant. Parce que le surcoût de développement (comparé aux autres solutions s'entend) n'est pas si énorme, parce que le gain en maintenance est important (ex : si on désactive un composant on sait qu'on peut retirer tout son bloc de configuration ou au moins le commenter pour les frileux côté exploitation), parce que ça permet d'agir en toute confiance.

J'insiste sur une chose : ce choix n'est rien de plus qu'une prise de décision avec un objectif et l'espoir que ça se passe comme on l'imagine. Je ne prétends ni que ce choix est le bon, ni que quelqu'un de compétent aurait fait le même.

Simplement maintenant, il y a un exemple qui illustre comment on fait pour organiser sa configuration. Et c'est ce genre de réflexion qui fait la différence entre des gens qui savent "juste" coder et d'autres qui savent faire plus. Non pas que certains seraient moins légitimes pour coder que d'autres, simplement qu'à différence de profil il peut y avoir différence de poste, tout simplement, comme toujours dans cette série de billets.

Et ensuite la question qui fâche : là on a eu la chance de voir ce besoin tôt dans le cycle de vie du produit. Qu'en est-il quand il a de nombreuses années d'existence et quelques dizaines ou centaines de paires de mains et de cerveaux qui lui sont passés dessus, générant des cohortes de lignes de configuration dont on ignore si ça sert encore à quelque chose ? Vous pensez que ça pourrait faire l'objet d'un troisième billet, la Vengeance de la Configuration ? J'ai quelques notes à ce sujet, si jamais ça tente certains...

Identifiez-vous pour afficher ou ajouter un commentaire

Autres pages consultées

Explorer les sujets