Quand on a demandé à Murray Gell-Mann comment Richard Feynman avait réussi à résoudre tant de problèmes difficiles, Gell-Mann avait répondu que Feynman avait un algorithme:
- Notez le problème.
- Pense vraiment fort.
- Notez la solution.
Gell-Mann essayait d'expliquer que Feynman était un autre type de solutionneur de problèmes et qu'il n'y avait aucune idée à tirer de l'étude de ses méthodes. Je ressens un peu la même chose à propos de la gestion de la complexité dans les projets logiciels de moyenne / grande taille. Les personnes qui sont bonnes sont fondamentalement douées pour le faire et parviennent en quelque sorte à superposer et à empiler diverses abstractions afin de rendre le tout gérable sans créer de cruauté supplémentaire.
Ainsi, l’algorithme Feynman est-il le seul moyen de gérer la complexité accidentelle ou existe-t-il des méthodes que les ingénieurs en logiciel peuvent systématiquement appliquer pour maîtriser la complexité accidentelle?
la source
Réponses:
D'après mon expérience, le principal facteur de complexité accidentelle réside dans le fait que les programmeurs s'en tiennent au premier projet, simplement parce que cela fonctionne. C'est quelque chose que nous pouvons apprendre de nos cours de composition en anglais. Ils prennent le temps de passer en revue plusieurs brouillons dans leurs travaux, en intégrant les commentaires des enseignants. Les cours de programmation, pour une raison quelconque, ne le font pas.
Il existe des livres remplis de moyens concrets et objectifs pour reconnaître, articuler et corriger un code sous-optimal: code propre , travailler efficacement avec un code hérité , et bien d'autres. Beaucoup de programmeurs connaissent ces techniques, mais ne prennent pas toujours le temps de les appliquer. Ils sont parfaitement capables de réduire la complexité accidentelle, ils n'ont tout simplement pas pris l'habitude d' essayer .
Une partie du problème réside dans le fait que nous ne voyons pas souvent la complexité intermédiaire du code des autres utilisateurs, à moins que celui-ci ait été examiné par des pairs à un stade précoce. Le code propre semble facile à écrire, alors qu’il implique en général plusieurs brouillons. Vous écrivez au début le meilleur moyen qui vous passe par la tête, notez les complexités inutiles qu’il introduit, puis "cherchez un meilleur coup" et refactorisez-le pour éliminer ces complexités. Ensuite, vous continuez à "chercher un meilleur coup" jusqu'à ce que vous ne puissiez pas en trouver un.
Cependant, vous ne publiez pas le code avant d'avoir terminé tout ce processus, de sorte que, de l'extérieur, il semble qu'il s'agisse d'un processus semblable à celui de Feynman. Vous avez tendance à penser que vous ne pouvez pas tout faire d'un seul morceau comme ça, alors vous ne vous fatiguez pas à essayer, mais la vérité est que l'auteur de ce code magnifiquement simple que vous venez de lire ne peut généralement pas tout écrire en un seul morceau comme cela non plus, ou s’ils le peuvent, c’est uniquement parce qu’ils ont déjà écrit plusieurs fois auparavant un code similaire et qu’ils peuvent maintenant voir le modèle sans les étapes intermédiaires. De toute façon, vous ne pouvez pas éviter les courants d'air.
la source
"Les compétences en architecture logicielle ne peuvent être enseignées" est une erreur répandue.
Il est facile de comprendre pourquoi beaucoup de gens le croient (ceux qui sont doués en la matière veulent croire qu’ils sont mystiquement spéciaux, et ceux qui ne veulent pas croire que ce n’est pas de leur faute s’ils ne le sont pas). est néanmoins faux; la compétence est juste un peu plus intensive en pratique que d'autres compétences logicielles (par exemple, comprendre les boucles, gérer les pointeurs, etc.)
Je suis fermement convaincu que la construction de grands systèmes est susceptible d’être répétée et de tirer les enseignements de l’expérience de la même manière que devenir un grand musicien ou un orateur public: un minimum de talent est une condition préalable, mais ce n’est pas un minimum démesurément élevé portée de la plupart des pratiquants.
La gestion de la complexité est une compétence que vous acquérez en grande partie en essayant et en échouant plusieurs fois. C’est juste que les nombreuses directives générales que la communauté a découvertes pour programmer dans le grand (utiliser les calques, lutter contre la duplication où qu’elle se lève, adhérer religieusement à 0/1 / infini ...) ne sont pas aussi manifestement correctes et nécessaires débutant jusqu’à ce qu’ils fassent réellement quelque chose de grand. Jusqu'à ce que vous ayez été mordu par la duplication ayant causé des problèmes seulement des mois plus tard, vous ne pouvez tout simplement pas comprendre l'importance de tels principes.
la source
La pensée pragmatique d’Andy Hunt aborde ce problème. Il fait référence au modèle Dreyfus, selon lequel il existe 5 étapes de maîtrise de différentes compétences. Les novices (étape 1) ont besoin d'instructions précises pour pouvoir faire quelque chose correctement. Les experts (étape 5), au contraire, peuvent appliquer des schémas généraux à un problème donné. Citant le livre,
Cette règle générale consistant à voir (et par conséquent à éviter) différents problèmes peut être appliquée spécifiquement au problème de la complexité accidentelle. Avoir un ensemble de règles donné n'est pas suffisant pour éviter ce problème. Il y aura toujours une situation qui n'est pas couverte par ces règles. Nous devons acquérir de l'expérience pour pouvoir prévoir les problèmes ou trouver des solutions. L'expérience est quelque chose qui ne peut pas être enseigné, on ne peut l'obtenir qu'en essayant, en échouant ou en réussissant constamment et en apprenant de ses erreurs.
Cette question de Workplace est pertinente et IMHO serait intéressant à lire dans ce contexte.
la source
Vous ne le précisez pas, mais la «complexité accidentelle» est définie comme une complexité qui n'est pas inhérente au problème, par rapport à la complexité «essentielle». Les techniques nécessaires pour "maîtriser" dépendront de votre point de départ. Ce qui suit concerne principalement les systèmes qui ont déjà acquis une complexité inutile.
J’ai déjà participé à un certain nombre de grands projets pluriannuels dans lesquels la composante «accidentelle» l’emportait nettement sur l’aspect «essentiel», ainsi que dans les autres domaines.
En réalité, l’algorithme de Feynman s’applique dans une certaine mesure, mais cela ne signifie pas que «penser vraiment» ne signifie que de la magie qui ne peut pas être codifiée.
Je trouve qu'il y a deux approches à prendre. Prenez les deux - ils ne sont pas des alternatives. L'une consiste à régler le problème à la pièce et l'autre à procéder à une refonte majeure. Alors certainement, "écris le problème". Cela peut prendre la forme d’un audit du système - les modules de code, leur état (odeur, niveau de test automatisé, nombre d’employés prétendant le comprendre), l’architecture globale (il en existe une, même si elle «a des problèmes» ), état des besoins, etc. etc.
C'est la nature de la complexité «accidentelle» qu'il n'y a pas un seul problème à traiter. Donc, vous devez trier. Où est-ce que ça fait mal - en termes de capacité à maintenir le système et à faire progresser son développement? Certains codes sont peut-être vraiment nauséabonds, mais ce n’est pas une priorité absolue et il est possible de faire réparer les choses. Par ailleurs, il se peut que du code retourne rapidement le temps passé à la refactorisation.
Définissez un plan pour définir une meilleure architecture et essayez de vous assurer que les nouveaux travaux sont conformes à ce plan - il s'agit de l'approche incrémentielle.
Expliquez également le coût des problèmes et utilisez-le pour élaborer une analyse de rentabilisation afin de justifier un refactor. Le point clé ici est qu’un système bien conçu peut être beaucoup plus robuste et testable, ce qui permet de réduire considérablement le temps (coût et calendrier) pour mettre en œuvre les changements - c’est là une réelle valeur.
Un remaniement majeur vient dans la catégorie «pense vraiment» - il faut réussir. C'est là qu'avoir un "Feynman" (enfin, une petite fraction d'un serait très bien) paye énormément. Une refonte majeure qui ne donne pas une meilleure architecture peut être un désastre. Les réécritures de système complet sont notoires pour cela.
Dans toute approche, il est implicite de savoir distinguer entre «accidentel» et «essentiel» - c’est-à-dire que vous devez avoir un excellent architecte (ou une équipe d’architectes) qui comprend vraiment le système et son objectif.
Cela dit, l’essentiel pour moi est le test automatisé . Si vous en avez assez, votre système est sous contrôle. Si vous ne le faites pas. . .
la source
Permettez-moi d'esquisser mon algorithme personnel pour faire face à la complexité accidentelle.
Toute la magie du design se trouverait à l’étape 3: comment organisez-vous ces cours? Cela revient à la même question: comment imaginez-vous que vous avez une solution à votre problème avant d’avoir une solution à votre problème?
Remarquablement, imaginer que vous avez la solution semble être l’une des principales recommandations de ceux qui écrivent sur la résolution de problèmes (appelés "voeux pieux" par Abelson et Sussman dans Structure et interprétation des programmes informatiques et "travaillant en arrière" dans Polya, Comment faire Le résoudre )
D'autre part, tout le monde n'a pas le même " goût pour les solutions imaginées ": il existe des solutions que vous seul trouvez élégantes et d'autres plus compréhensibles par un public plus large. C'est pourquoi vous devez réviser votre code avec les autres développeurs, pas seulement pour optimiser les performances, mais pour vous mettre d'accord sur des solutions bien comprises. Cela conduit généralement à une nouvelle conception et, après quelques itérations, à un code bien meilleur.
Si vous vous contentez d'écrire des implémentations minimales pour réussir vos tests et écrivez des tests qui sont compris par de nombreuses personnes, vous devriez vous retrouver avec une base de code où il ne reste que la complexité irréductible .
la source
Complexité accidentelle
La question initiale (paraphrasée) était:
La complexité accidentelle survient lorsque les responsables du projet choisissent d’ajouter des technologies uniques et que la stratégie globale des architectes d’origine du projet n’a pas l’intention de s’intégrer au projet. Pour cette raison, il est important d’enregistrer le raisonnement qui sous-tend le choix de la stratégie.
La complexité accidentelle peut être évitée par un leadership qui s'en tient à sa stratégie initiale jusqu'à ce qu'il soit apparemment nécessaire de s'écarter de cette stratégie.
Éviter la complexité inutile
Sur la base du corps de la question, je la reformulerais comme suit:
Cette reformulation est plus à propos du corps de la question, où l'algorithme de Feynman a ensuite été introduit, fournissant un contexte qui propose que pour les meilleurs architectes, confrontés à un problème, disposent d'une gestalt à partir de laquelle ils construisent ensuite habilement une solution, et que le reste d'entre nous ne peut espérer apprendre cela. Avoir une gestalt de compréhension dépend de l'intelligence du sujet et de sa volonté d'apprendre les caractéristiques des options architecturales qui pourraient être de leur ressort.
Le processus de planification du projet utiliserait l'apprentissage de l'organisation pour dresser une liste des exigences du projet, puis tenter de construire une liste de toutes les options possibles, puis de réconcilier les options avec les exigences. La gestalt de l'expert lui permet de le faire rapidement, et peut-être avec peu de travail évident, ce qui lui donne l'air de lui venir facilement.
Je vous soumets que cela lui vient à cause de sa préparation. Avoir la gestalt de l'expert nécessite la connaissance de toutes vos options et la prévoyance de fournir une solution simple qui permette de répondre aux besoins futurs prévisibles que le projet devrait fournir, ainsi que la flexibilité nécessaire pour s'adapter aux besoins changeants des utilisateurs. le projet. Feynman se préparait à comprendre parfaitement diverses approches des mathématiques et de la physique, tant théoriques qu'appliquées. Il était naturellement curieux et assez brillant pour comprendre ce qu'il avait découvert sur le monde naturel qui l'entourait.
L’architecte expert en technologies aura une curiosité similaire, s’appuyant sur une profonde compréhension des principes fondamentaux ainsi qu’une large exposition à une grande diversité de technologies. Il (ou elle) aura la sagesse de s’appuyer sur les stratégies qui ont été couronnées de succès dans tous les domaines (tels que les principes de la programmation Unix ) et celles qui s’appliquent à des domaines spécifiques (tels que les modèles de conception et les guides de style ). Il n’est peut-être pas très au courant de chaque ressource, mais il saura où la trouver.
Construire la solution
Ce niveau de connaissance, de compréhension et de sagesse peut être tiré de l'expérience et de l'éducation, mais requiert de l'intelligence et une activité mentale pour élaborer une solution stratégique Gestalt qui fonctionne ensemble de manière à éviter toute complexité accidentelle et inutile. L’expert doit réunir ces principes fondamentaux; C’est ces connaissances que Drucker avait prévues lorsqu’il a été inventé pour la première fois.
Retour aux questions finales spécifiques:
Des méthodes spécifiques pour maîtriser la complexité accidentelle sont disponibles dans les types de sources suivants.
En suivant les principes de la programmation Unix, vous créerez des programmes modulaires simples qui fonctionnent bien et sont robustes avec des interfaces communes. Les modèles de conception suivants vous aideront à construire des algorithmes complexes qui ne sont pas plus complexes que nécessaire. Suivre les guides de style garantira que votre code est lisible, maintenable et optimal pour la langue dans laquelle votre code est écrit. Les experts auront intégré nombre des principes contenus dans ces ressources et seront en mesure de les rassembler de manière cohérente et homogène.
la source
C’était peut-être une question difficile il ya quelques années, mais il n’est plus difficile pour l’OMI d’éliminer la complexité accidentelle de nos jours.
Ce que Kent Becks a dit de lui-même à un moment donné: "Je ne suis pas un bon programmeur, je suis juste un bon programmeur avec de bonnes habitudes."
Deux choses méritent d’être soulignées, IMO: il se considère lui-même comme un programmeur et non comme un architecte. Il met l’accent sur les habitudes et non sur la connaissance.
La manière de Feynman de résoudre des problèmes difficiles est la seule façon de le faire. La description n'est pas forcément très facile à comprendre, je vais donc la disséquer. La tête de Feynman n'était pas seulement pleine de connaissances, elle était aussi pleine de compétences pour appliquer ces connaissances. Lorsque vous avez les connaissances et les compétences nécessaires pour l'utiliser, la résolution d'un problème difficile n'est ni difficile ni facile. C'est le seul résultat possible.
Il y a une manière complètement non magique d'écrire du code propre, qui ne contient pas de complexité accidentelle, et qui est la plupart du temps similaire à ce que Feynman a fait: acquérir toutes les connaissances requises, s'entraîner à s'habituer à le faire fonctionner, plutôt que de simplement le garder caché Dans un coin de votre cerveau, écrivez un code vierge.
Maintenant, beaucoup de programmeurs ne sont même pas au courant de toutes les connaissances nécessaires pour écrire du code en clair. Les jeunes programmeurs ont tendance à abandonner leurs connaissances sur les algorithmes et les structures de données, et la plupart des programmeurs plus âgés ont tendance à l'oublier. Ou grande notation O et analyse de la complexité. Les programmeurs plus âgés ont tendance à rejeter les motifs ou les odeurs de code - ou même à ignorer leur existence. La plupart des programmeurs de toutes les générations, même s'ils connaissent les modèles, ne se souviennent jamais du moment exact où utiliser et des composants de pilotes. Peu de programmeurs, quelle que soit leur génération, évaluent constamment leur code par rapport aux principes SOLID. De nombreux programmeurs mélangent tous les niveaux d'abstraction possibles. Je ne suis pas au courant qu'un collègue programmeur, pour le moment, évalue constamment son code par rapport aux stenches décrites par Fowler dans son livre de refactoring. Bien que certains projets utilisent un outil de métrique, la métrique la plus utilisée est la complexité, d'une manière ou d'une autre, tandis que deux autres métriques - couplage et cohésion - sont dans une large mesure ignorées, même si elles sont très importantes pour le code épuré. Un autre aspect que presque tout le monde ignore est la charge cognitive. Peu de programmeurs considèrent les tests unitaires comme de la documentation, et encore moins d’entre eux qui se rendent compte qu’il est difficile d’écrire ou de nommer des tests unitaires est encore une puanteur de code, qui indique généralement une mauvaise factorisation. Une infime minorité est consciente du mantra de la conception axée sur le domaine pour garder le modèle de code et le modèle de domaine métier aussi proches que possible les uns des autres, car les divergences sont vouées à créer des problèmes. Tous ces éléments doivent être pris en compte, tout le temps, si vous voulez que votre code soit propre. Et beaucoup d'autres dont je ne me souviens plus maintenant. la métrique la plus utilisée est la complexité, d'une sorte ou d'une autre, alors que deux autres métriques - couplage et cohésion - sont en grande partie ignorées, même si elles sont très importantes pour le code propre. Un autre aspect que presque tout le monde ignore est la charge cognitive. Peu de programmeurs considèrent les tests unitaires comme de la documentation, et encore moins d’entre eux sont conscients qu’il est difficile d’écrire ou de nommer des tests unitaires. Une infime minorité est consciente du mantra de la conception axée sur le domaine pour garder le modèle de code et le modèle de domaine métier aussi proches que possible les uns des autres, car les divergences sont vouées à créer des problèmes. Tous ces éléments doivent être pris en compte, tout le temps, si vous voulez que votre code soit propre. Et beaucoup d'autres dont je ne me souviens plus maintenant. la métrique la plus utilisée est la complexité, d'une sorte ou d'une autre, alors que deux autres métriques - couplage et cohésion - sont en grande partie ignorées, même si elles sont très importantes pour le code propre. Un autre aspect que presque tout le monde ignore est la charge cognitive. Peu de programmeurs considèrent les tests unitaires comme de la documentation, et encore moins d’entre eux sont conscients qu’il est difficile d’écrire ou de nommer des tests unitaires. Une infime minorité est consciente du mantra de la conception axée sur le domaine pour garder le modèle de code et le modèle de domaine métier aussi proches que possible les uns des autres, car les divergences sont vouées à créer des problèmes. Tous ces éléments doivent être pris en compte, tout le temps, si vous voulez que votre code soit propre. Et beaucoup d'autres dont je ne me souviens plus maintenant. alors que deux autres métriques - couplage et cohésion - sont en grande partie ignorées, même si elles sont très importantes pour le code épuré. Un autre aspect que presque tout le monde ignore est la charge cognitive. Peu de programmeurs considèrent les tests unitaires comme de la documentation, et encore moins d’entre eux sont conscients qu’il est difficile d’écrire ou de nommer des tests unitaires. Une infime minorité est consciente du mantra de la conception axée sur le domaine pour garder le modèle de code et le modèle de domaine métier aussi proches que possible les uns des autres, car les divergences sont vouées à créer des problèmes. Tous ces éléments doivent être pris en compte, tout le temps, si vous voulez que votre code soit propre. Et beaucoup d'autres dont je ne me souviens plus maintenant. alors que deux autres métriques - couplage et cohésion - sont en grande partie ignorées, même si elles sont très importantes pour le code épuré. Un autre aspect que presque tout le monde ignore est la charge cognitive. Peu de programmeurs considèrent les tests unitaires comme de la documentation, et encore moins d’entre eux sont conscients qu’il est difficile d’écrire ou de nommer des tests unitaires. Une infime minorité est consciente du mantra de la conception axée sur le domaine pour garder le modèle de code et le modèle de domaine métier aussi proches que possible les uns des autres, car les divergences sont vouées à créer des problèmes. Tous ces éléments doivent être pris en compte, tout le temps, si vous voulez que votre code soit propre. Et beaucoup d'autres dont je ne me souviens plus maintenant. Un autre aspect que presque tout le monde ignore est la charge cognitive. Peu de programmeurs considèrent les tests unitaires comme de la documentation, et encore moins d’entre eux sont conscients qu’il est difficile d’écrire ou de nommer des tests unitaires. Une infime minorité est consciente du mantra de la conception axée sur le domaine pour garder le modèle de code et le modèle de domaine métier aussi proches que possible les uns des autres, car les divergences sont vouées à créer des problèmes. Tous ces éléments doivent être pris en compte, tout le temps, si vous voulez que votre code soit propre. Et beaucoup d'autres dont je ne me souviens plus maintenant. Un autre aspect que presque tout le monde ignore est la charge cognitive. Peu de programmeurs considèrent les tests unitaires comme de la documentation, et encore moins d’entre eux sont conscients qu’il est difficile d’écrire ou de nommer des tests unitaires. Une infime minorité est consciente du mantra de la conception axée sur le domaine pour garder le modèle de code et le modèle de domaine métier aussi proches que possible les uns des autres, car les divergences sont vouées à créer des problèmes. Tous ces éléments doivent être pris en compte, tout le temps, si vous voulez que votre code soit propre. Et beaucoup d'autres dont je ne me souviens plus maintenant. s mantra pour garder le modèle de code et le modèle de domaine métier aussi proches que possible l'un de l'autre, car les divergences sont vouées à créer des problèmes par la suite. Tous ces éléments doivent être pris en compte, tout le temps, si vous voulez que votre code soit propre. Et beaucoup d'autres dont je ne me souviens plus maintenant. s mantra pour garder le modèle de code et le modèle de domaine métier aussi proches que possible l'un de l'autre, car les divergences sont vouées à créer des problèmes par la suite. Tous ces éléments doivent être pris en compte, tout le temps, si vous voulez que votre code soit propre. Et beaucoup d'autres dont je ne me souviens plus maintenant.
Vous voulez écrire du code propre? Il n'y a pas de magie requise. Allez simplement apprendre tout ce qui est nécessaire, puis utilisez-le pour évaluer la propreté de votre code et modifiez-le jusqu'à ce que vous soyez satisfait. Et continuez à apprendre - les logiciels sont encore jeunes et les nouvelles connaissances et connaissances sont acquises à un rythme soutenu.
la source