Que faites-vous si vous atteignez une impasse de conception dans des méthodes évolutives comme Agile ou XP?

11

Alors que je lisais le célèbre article de blog de Martin Fowler, Is Design Dead? , l'une des impressions frappantes que j'ai eues est que, étant donné que dans la méthodologie agile et la programmation extrême, la conception ainsi que la programmation sont évolutives, il y a toujours des points où les choses doivent être refactorisées.

Il est possible que lorsque le niveau d'un programmeur est bon et qu'il comprenne les implications de la conception et ne fasse pas d'erreurs critiques, le code continue d'évoluer. Cependant, dans un contexte normal, quelle est la réalité du terrain dans ce contexte?

Dans une journée normale, étant donné qu'un certain développement important se produit dans le produit, et lorsqu'un changement critique se produit dans les exigences, n'est-ce pas une contrainte que nous souhaitons autant que nous le souhaitons, les aspects fondamentaux de la conception ne peuvent pas être modifiés? (sans jeter la majeure partie du code). N'est-il pas tout à fait probable que l'on aboutisse à une impasse sur toute autre amélioration possible de la conception et des exigences?

Je ne préconise aucune pratique non agile ici, mais je veux savoir des gens qui pratiquent des méthodes de développement agiles ou itératives ou évolutives, quant à leurs expériences réelles.

Avez-vous déjà atteint de telles impasses ? Comment avez-vous réussi à l'éviter ou à y échapper? Ou existe-t-il des mesures pour garantir que la conception reste propre et flexible à mesure qu'elle évolue?

Dipan Mehta
la source

Réponses:

17

Je viens de lire le lien de l'article que vous avez publié, je dois dire que Fowler a fait de très bons points et beaucoup de choses qu'il a dit, je plaide avec notre équipe depuis des années.

OMI, si vous faites une conception décente, vous ne devriez pas entrer dans ce qui serait considéré comme une situation sans issue. J'ai toujours considéré les logiciels comme des éléments constitutifs . Je crois toujours en une conception initiale, mais l'objectif principal n'est pas de concevoir le produit dans son ensemble, mais de fournir une architecture / direction globale afin que votre équipe puisse visualiser une image commune vers laquelle nous travaillons tous. Si vous avez un tas de morceaux de cube et de triangle, il est utile d'esquisser la façon dont un château serait assemblé avant de commencer à gifler les morceaux ensemble.

Puisque je viens de la terre OO, pour moi chaque bloc est une classe et la surface de ce bloc est l'interface publique (ce qui est visible par les classes externes ou dérivantes). Si vous suivez les bons principes SOLID, vous vous assurerez que chaque bloc est extrêmement simple et dispose d'une interface publique intuitive. Pour en revenir à mon analogie, vous voulez vous assurer que le code ne crée que des formes simples. Chaque fois que vous créez des classes trop complexes (beaucoup de fonctions, beaucoup de variables), vous créez des formes qui sont difficiles à réutiliser quand les exigences changent.

Je suis d'accord avec Fowler en ce que le plus grand risque / défi pour la conception évolutive est que vous laissez les décisions de conception au temps de codage, et vous vous attendez à ce que chaque développeur individuel prenne ces décisions. C'est là que le système peut tomber en panne si vous n'avez pas de mécanismes de rétroaction appropriés en place. Chaque fois qu'une nouvelle fonctionnalité est demandée, il est extrêmement tentant de simplement trouver la fonction qui doit être étendue, de mettre une sorte de condition à l'intérieur et d'ajouter simplement un tas de code à l'intérieur de cette fonction. Et parfois, c'est peut-être tout ce dont vous avez besoin, mais c'est aussi (IMO) la pratique la plus courante qui conduit à des composants sans issue. Cela n'a rien à voir avec la conception évolutive. C'est ce qu'on appelle "pas de conception".

Tant que vous prenez le temps de prendre du recul et de dire, attendez une minute, cette classe a déjà 15 variables membres, laissez-moi en extraire 6 et les mettre dans leur propre classe autonome, votre logiciel sera composé de très léger -blocs de construction légers, flexibles et réutilisables. Bien sûr, si les PM arrivent et modifient la moitié des exigences de produits pour vous, vous devrez peut-être retirer certains de vos blocs, les remettre sur l'étagère et en dessiner de nouveaux (tout comme lors de la construction d'un château, vous ne pouvez pas utiliser tous vos cylindres). Mais à ce stade, cela ne fait que faire partie des affaires. Les exigences ont changé et en gardant votre code flexible et modulaire, vous devriez pouvoir changer votre produit pour l'aligner avec votre nouvelle direction commerciale.

Je crois que cette approche évolutive de la conception fonctionne avec tous les niveaux de compétence de l'ingénieur. Personnellement, je fais du logiciel depuis très longtemps et avant que notre équipe ne passe à une méthodologie agile, j'étais responsable de l'expédition de plusieurs composants majeurs de mon PC de développement presque directement au client avec pratiquement aucun contrôle qualité. En même temps, ces composants sont toujours restés flexibles et maintenables.

J'essaie seulement de dire que je me considérerais relativement décent dans la conception de logiciels. En même temps, si vous me demandiez de rédiger un document de conception de 100 pages, de le donner à un codeur et de s'attendre à ce qu'il fonctionne, je ne pourrais probablement pas me concevoir à partir d'un sac en papier. Au début du travail, je dessinais parfois quelques diagrammes de type UML (très simplifié, pas en langage complet), mais lorsque je commence à coder, je refactoriserais selon les besoins et mon code final ne ressemblerait jamais à ce que j'avais dessiné à l'origine. Même si je passe un mois ou deux à penser à chaque petit détail, je ne peux pas imaginer que quelqu'un d'autre puisse prendre mes diagrammes et proposer un logiciel solide sans modifier la conception pendant le codage.

À l'autre bout du spectre, actuellement dans mon équipe (maintenant agile et je soutiens pleinement cela), nous avons quelques gars qui nous ont rejoints depuis un terrain intégré où ils n'ont fait que du C pendant les 15 dernières années. J'ai évidemment aidé à la planification initiale et à l'organisation des cours, mais je me suis également assuré de faire un suivi avec des révisions de code régulières et des séances de remue-méninges où nous discutons des applications de SOLID et des principes de conception. Ils ont produit du code de spaghetti qui m'a fait un peu grincer des dents, mais avec juste un petit coup de pouce de ma part, ils ont commencé à refactoriser ce qui était déjà produit et la partie drôle est que l'un d'eux est revenu quelques jours plus tard et dit, je déteste pour le dire, mais après avoir déplacé ce code, cela semble beaucoup plus lisible et compréhensible. Impasse évitée. Point I ' Ce que j'essaie de faire, c'est que même quelqu'un qui est complètement nouveau à OO peut produire du code quelque peu décent, tant qu'il a un mentor avec plus d'expérience, pour lui rappeler que «conception évolutive» n'est pas la même chose que «pas de conception». Et même certaines de ses classes "plus complexes" ne sont pas si effrayantes parce que chaque classe n'a pas beaucoup de responsabilité (c'est-à-dire pas beaucoup de code), donc le pire devient pire, si cette classe "cul-de-sac", nous jetez-le et écrivez une classe de remplacement qui a la même interface publique (jusqu'à présent, je n'ai jamais vu un besoin de cette contingence dans tout ce que nous avons écrit et j'ai fait des révisions de code deux fois par semaine).

Pour terminer, je suis également un fervent partisan des documents de conception (au moins pour les conditions commerciales de mon équipe actuelle), mais l'objectif principal de nos documents de conception est la mémoire organisationnelle , de sorte que les documents réels sont écrits après la production du code et refactorisé. Avant le codage, nous avons généralement une phase de conception rapide (parfois moins rapide) où nous esquissons des cours sur des serviettes / mspaint / visio et je rappelle toujours aux gens que cette phase produit un chemin à suivre, pas un plan directeur et lorsqu'ils commencent à coder, tout ce qui n'a pas de sens devrait être changé. Même avec ces rappels, les nouveaux gars ont tendance à essayer de remettre le code en forme dans le design original, même si cela ne leur semble pas naturel. Cela apparaît généralement dans les revues de code.

Dang, j'ai beaucoup écrit. Désolé pour ça.

DXM
la source
1
+1 Ça valait le coup pour chaque mot. Je rencontre ces situations comme vous l'avez décrit et une fois la date limite respectée, demandez-leur de nettoyer (lire la refactorisation) davantage de ce que je pense être un bon sens du design. Mais souvent, les gens trouvent la même question répétée - Pourquoi est-ce que je refais la même chose? Je suppose que j'ai maintenant la réponse - si vous avez besoin d'un délai de mise sur le marché plus rapide et que le design évolue, la refactorisation n'est pas une compensation à vos anciens péchés mais en fait une chose légitime à faire.
Dipan Mehta
Oui, vous avez beaucoup écrit, mais c'était une bonne chose. Vraiment apprécié de le lire :).
Radu Murzea
11

Je dirais que le phénomène "impasse de conception" est orthogonal aux méthodes agiles. Ce que je veux dire, c'est qu'il est possible de faire de la cascade, de passer beaucoup de temps à l'avance sur un (mauvais) design. Ensuite, passez beaucoup de temps à le mettre en œuvre pour vous retrouver dans une impasse.

Si quoi que ce soit, les méthodes agiles devraient vous aider à découvrir plus tôt que vous avez fait de mauvais choix de conception. La raison en est que votre carnet de commandes doit avoir les éléments de valeur client les plus élevés en premier et que vous devez vous concentrer sur la fourniture d'incréments utiles du logiciel. Si votre conception vous permet de fournir une valeur et une utilité élevées, c'est déjà bon pour quelque chose :-) En revanche, vous pourriez avoir une mauvaise conception dans une situation de cascade où vous ne découvrirez peut-être pas pendant de nombreuses années que cette conception ne peut pas fournir toute valeur et toute utilité - tout ce que vous avez, c'est l'illusion qu'il s'agit d'un bon design. Comme on dit, la preuve est dans le pudding.

Le revers de la médaille est que même dans les méthodes agiles, il est important d'avoir une vision viable de la conception du système qui guide les décisions d'itération en itération. Je pense que Ken Schwabber a dit quelque chose comme si vous avez une équipe de développeurs terribles, ils produiront les mauvais logiciels de manière cohérente itération par itération. Agile signifie simplement que vous ne passez pas beaucoup de temps à l'avance car vous êtes limité dans ce que vous pouvez apprendre ou imaginer avant de commencer à mettre en œuvre ( et les exigences changent également). Cependant, il y a des situations où vous devez faire un travail initial (par exemple la recherche) et ensuite vous devez le faire.

Comment éviter les impasses?

Je dirais surtout en anticipant les besoins futurs. C'est quelque chose que vous obtenez avec l'expérience et la familiarité avec des projets / produits similaires. Cette anticipation est en partie ce qui vous aide à mettre en place une bonne conception, car vous vous posez beaucoup de questions «et si» sur votre système actuel. Pour moi, c'est l'élément essentiel. Des techniques comme OO vous aident simplement lorsque vous savez déjà ce que vous faites.

Que faites-vous si vous avez une impasse?

Une « impasse » est pas différent de tout autre bloc technique , vous serez frappé pendant le développement de tout ce qui est nouveau. La première chose à réaliser est qu'il n'y a vraiment pas de véritables "impasses" qui vous obligent à revenir en arrière complètement. À tout le moins, c'est votre apprentissage jusqu'à ce point qui vous permet d'avancer afin que l'effort ne soit pas gaspillé. Lorsque vous frappez une impasse, vous avez un problème . Le problème est de savoir ce qui doit changer pour répondre à une nouvelle (ou ancienne) exigence et comment optimiser ce changement. Il ne vous reste plus qu'à résoudre ce problème. Soyez reconnaissant qu'il s'agit d'un logiciel et non, par exemple d'une conception d'avion, car le changement est beaucoup plus facile. Identifiez les problèmes, corrigez-les == refactor == génie logiciel. Parfois, beaucoup de travail est impliqué ...

Si vous utilisez Scrum, ce changement doit naturellement être basé sur les user stories (que retire l'utilisateur de ce changement?). Le processus commencerait à partir d'une histoire qui ne peut pas être facilement adaptée à la conception actuelle (oups) et une discussion aurait lieu avec le propriétaire du produit sur la façon de décomposer cette histoire. Vous continuez d'appliquer des principes agiles grâce à ce changement.

Quelques grands changements d'exigences célèbres du monde du système d'exploitation qui me viennent à l'esprit:

Quelle que soit la façon dont vous les voyez, cela représente beaucoup de travail. La conception originale n'a presque certainement pas pris en compte la possibilité que cela se produise (c'est-à-dire que la portailité n'était pas une grande exigence). Que la conception soit OO ou non n'est probablement pas un facteur énorme non plus. Dans une bonne conception, les parties spécifiques de la plate-forme seraient quelque peu isolées et le travail serait plus facile.

Guy Sirton
la source
En fait, les premières versions de Windows NT implémentaient une "couche d'extraction de matériel" et prenaient en charge DEC Apha ainsi que x86. Comme personne n'a jamais acheté de machines DEC alpha, cela a été discrètement abandonné. J'imagine que cette "indépendance de la machine" existe toujours dans un format résiduel dans la version actuelle, donc un port ARM n'est peut-être pas si difficile.
James Anderson
3

Je refaçonne mes projets en permanence et j'utilise également des diagrammes de classes UML. Je veux dire que je crée un ou plusieurs diagrammes de classes par packages. Chaque diagramme est enregistré à la racine du package. Chaque classificateur UML possède un propre ID qui est mappé à l'ID Java associé. Cela signifie que lorsque j'ouvre mon diagramme, il est automatiquement mis à jour avec les dernières modifications de refactorisation de code. Je peux également modifier directement mes diagrammes de classe au niveau graphique et tout mon projet est immédiatement refactorisé. Cela fonctionne plutôt bien mais ne remplacera jamais l'homme. Mon diagramme de classe UML n'est également qu'une vue graphique de mon code. Il est très important de ne pas mélanger le code et le modèle comme le fait l'éclipse EMF car dès que le refactoring est effectué, les informations du modèle sont également perdues. Je n'utilise jamais de générateur de code Model Driven Development car cela est inutile. Je ne '

Cela dit, avoir plus de 100 diagrammes de classe représentant tous les détails de la structure de mon projet et plein de notes partout est vraiment utile. Je crée uniquement des diagrammes de classes pour les projets, car les développeurs n'ont généralement pas le temps d'apprendre ou d'utiliser d'autres diagrammes. Les diagrammes de classes sont également très bons car mis à jour automatiquement. Les diagrammes de classes peuvent être créés après le code en inversant simplement un package et en ajoutant des notes. Il est rapide et toujours précis et 100% itératif.

Veuillez ne pas confondre le développement piloté par modèle qui est un code générateur de modèle et généralement en utilisant UML comme présentation graphique avec des diagrammes de classes UML mis à jour à partir du code. Seul le code synchronisé UML a une valeur réelle pour moi si plusieurs itérations.

Désolé d'être si long mais je pense que nous devrions donner une seconde chance aux diagrammes de classes UML s'ils ne sont utilisés que comme une vue graphique de notre projet. Cela signifie que UML couvre le projet complet et a un modèle unique composé de grands diagrammes de classe représentant le projet complet. Il serait ridicule d'avoir des centaines de petites vues et un modèle pour chaque vue d'un projet ayant des centaines de vues :-)

UML_GURU
la source
1
+1 pour montrer l'idée du code postal UML! Chose intéressante, nous ne revenons jamais aux documents de diagrammes après le code!
Dipan Mehta
Oui, c'est exactement le problème du développement piloté par modèle associé à UML. Vous générez de la documentation et ne l'utilisez jamais en cas de modification de projet. La fusion du modèle et du code nous permet d'utiliser UML et de le changer autant de fois que nécessaire.
UML_GURU
3

J'ai atteint l'impasse de mon code et d'autres codes en raison d'une mauvaise conception, d'un changement de direction, etc. J'ai également vu beaucoup d'autres rencontrer ce problème. La grosse erreur (au moins cela me semble être une erreur) est le désir immédiat de jeter le code de travail et de tout réimplémenter de fond en comble.

J'ai abordé chaque cas de la même manière qui semblait bien fonctionner:

  • identifier pourquoi la conception actuelle ne fonctionne pas
  • proposer un nouveau design et un plan de transition
  • baliser le code qui ne sera pas utilisé comme obsolète
  • mettre en œuvre uniquement ce dont j'ai besoin pour la nouvelle conception afin de répondre au besoin immédiat
  • supprimer le code que le nouveau code rend obsolète

Frais:

  • plus de complexité grâce à 2 implémentations dans la base de code en même temps
  • Coût total par fonctionnalité / correction de bogue plus élevé que la refonte / réimplémentation complète en supposant de bons cas d'utilisation et des tests

Avantages:

  • au moins un ordre de grandeur moins de risque parce que vous avez toujours l'ancien design / code de travail
  • plus rapide à commercialiser pour toutes les fonctionnalités 1 à n-1 qui ne nécessitent pas une refonte complète
  • si le produit / code finit par mourir avant d'avoir terminé la refonte complète, vous aurez économisé la différence de temps de développement
  • approche itérative et tous ses avantages
Dietbuddha
la source
2

Il y a environ un mois ou deux, notre projet actuel est resté un peu bloqué en raison de mauvaises décisions de conception (et du manque de conception en un seul endroit), avec le style de développement SCRUM.

Notre solution (et ce que je crois être la norme pour SCRUM) était de consacrer un sprint entier (~ 2 semaines) à rien d'autre qu'au refactoring. Aucune nouvelle fonctionnalité n'a été ajoutée pendant cette période, mais nous avons pu penser à la base de code actuelle et concevoir un système bien meilleur pour ce que nous faisions.

Nous avons maintenant dépassé cet obstacle et avons ajouté de nouvelles fonctionnalités.

Izkata
la source
C'est une autre grosse friction à trouver. Avoir à dire au client - que nous construisons maintenant la même chose - de fonctionnalités qui n'ont rien de nouveau, après la livraison de la première version! À quelle fréquence et si souvent (si jamais) pouvez-vous vous permettre de le dire au client? ou comment expliquez-vous même?
Dipan Mehta
Vous avez deux options de base, soit d'abord vous dites simplement la vérité simple - que bien que ce que vous avez fonctionne, c'est un gâchis et qu'il doit être rangé pour aller de l'avant ou deuxièmement, vous dites que vous construisez une infrastructure pour soutenir le développement en cours ( ce qui n'est pas moins vrai mais qui est tourné pour être un peu plus positif). Vous pouvez conclure ces deux éléments en disant que pour offrir la fonctionnalité, nous avons contracté une dette technique qui doit maintenant être remboursée.
Murph
@Dipan Mehta: Eh bien, supposons qu'un client veuille une maison à deux étages. Vous le concevez et le livrez. Ensuite, ils veulent avoir quatre étages supplémentaires. Vous dites, eh bien, je dois passer ce temps juste pour rendre le bâtiment actuel plus robuste afin qu'il contienne quatre étages supplémentaires. Je ne pense donc pas que cela devrait être un problème pour le client si le plan d'origine ne comprenait que deux étages. Si six étages étaient prévus dès le début, oui, cela pourrait être un problème à en informer le client.
Giorgio
@DipanMehta Nous sommes également un peu chanceux car les clients ne connaissent pas nécessairement ce projet. Il s'agit d'une mise à niveau d'un produit qu'ils utilisent actuellement, avec une date d'achèvement semi-vague vers la fin de cette année. Donc, ils n'ont même pas besoin de connaître un délai pour le refactoring;) (Le gestionnaire qui gère la plupart des décisions de conception est en interne)
Izkata
2

La clé pour limiter le coût des modifications de conception est de garder le code aussi SEC que possible. Cela conduira la plupart du code d'application à un niveau très élevé, où la plupart du code exprime directement l'intention et spécifie relativement peu de mécanisme. Si vous procédez ainsi, les décisions de conception auront la plus petite expression possible dans le code et les modifications de conception auront le coût le plus faible possible.

Kevin Cline
la source
2

La clé pour éviter les impasses de conception est de reconnaître le plus tôt possible quand votre conception doit changer, et de la modifier ensuite. Les plus gros problèmes ne viennent pas en faisant évoluer continuellement votre conception, mais en refusant de faire évoluer votre conception jusqu'à ce que ce soit un énorme problème.

Par exemple, Netflix a une fonction de profil, où différents membres de la famille peuvent facturer au même plan, mais ont des files d'attente distinctes. Il y a quelques années, ils ont annoncé qu'ils devraient annuler cette fonctionnalité, car seulement 10% de leurs utilisateurs l'utilisaient, mais en raison du piratage de la mise en œuvre, elle consommait une quantité excessive de travaux de maintenance. Après un tollé, ils ont mordu la balle et ont fait une refonte coûteuse afin de garder ces clients.

Je suis sûr que certains ingénieurs ont reconnu une conception sous-optimale lorsqu'ils ont ajouté cette fonctionnalité pour la première fois. S'ils l'avaient changé à l'époque, cela n'aurait pas été aussi grave.

Karl Bielefeldt
la source
1

N'est-ce pas Fred Brooks qui a dit quelque chose comme "Prévoyez de jeter le premier"? Ne vous sentez pas trop sombre à ce sujet, les conceptions sans issue apparaissent également dans des projets qui essaient de faire tout le design à l'avance également. Les remaniements se produisent dans tous les types de développement, que ce soit parce que c'était une conception inapplicable dès le départ (les 20% restants qui sont passés sous silence - "le diable est dans les détails") ou parce qu'un client change d'orientation. Il n'y a pas vraiment besoin de sonnettes d'alarme, ne vous inquiétez pas trop.

anon
la source