it-swarm-eu.dev

Que dois-je considérer lorsque les principes DRY et KISS sont incompatibles)?

Le principe DRY oblige parfois les programmeurs à écrire des fonctions/classes complexes et difficiles à maintenir. Un code comme celui-ci a tendance à devenir plus complexe et plus difficile à maintenir avec le temps. Violer le principe KISS .

Par exemple, lorsque plusieurs fonctions doivent faire quelque chose de similaire. La solution habituelle DRY consiste à écrire une fonction qui prend différents paramètres pour permettre les légères variations d'utilisation.

L'avantage est évident, DRY = un endroit pour faire des changements, etc.

L'inconvénient et la raison pour laquelle il viole KISS est parce que des fonctions comme celles-ci ont tendance à devenir de plus en plus complexes avec de plus en plus de paramètres au fil du temps. Au final, les programmeurs auront très peur de apporter des modifications à ces fonctions ou elles entraîneront des bogues dans d'autres cas d'utilisation de la fonction.

Personnellement, je pense qu'il est logique de violer le principe DRY pour le faire suivre KISS principe.

Je préfère avoir 10 fonctions super simples qui sont similaires plutôt que d'avoir une fonction super complexe.

Je préfère faire quelque chose de fastidieux, mais facile (faire le même changement ou un changement similaire à 10 endroits), que de faire un changement très effrayant/difficile à un endroit.

Évidemment, le moyen idéal est de le rendre aussi KISS que possible sans violer DRY. Mais parfois, cela semble impossible.

Une question qui se pose est "à quelle fréquence ce code change-t-il?" ce qui implique que s'il change souvent, il est plus pertinent de le rendre SEC. Je ne suis pas d'accord, car changer cette fonction complexe DRY la rendra souvent plus complexe et s'aggravera avec le temps.

Donc, fondamentalement, je pense que, en général, KISS> DRY.

Qu'est-ce que tu penses? Dans quels cas pensez-vous que DRY devrait toujours gagner KISS, et vice versa? Quels éléments considérez-vous pour prendre la décision? Comment éviter la situation?

71
user158443

KISS est subjectif. DRY est facile à appliquer trop. Les deux ont de bonnes idées derrière eux mais les deux sont faciles à abuser. La clé est l'équilibre.

KISS est vraiment dans l'œil de votre équipe. Vous ne savez pas ce que KISS est. Votre équipe le fait. Montrez-leur votre travail et voyez s'ils pensent que c'est simple. Vous êtes un mauvais juge de cela parce que vous savez déjà comment cela fonctionne. Découvrez à quel point votre code est difficile à lire pour les autres.

DRY ne concerne pas l'apparence de votre code. Vous ne pouvez pas repérer de vrais problèmes DRY en recherchant un code identique. Un vrai problème DRY pourrait être que vous résolvez le même problème avec une apparence complètement différente) code à un endroit différent. Vous ne violez pas DRY lorsque vous utilisez un code identique pour résoudre un problème différent à un endroit différent. Pourquoi? Parce que différents problèmes peuvent changer indépendamment. Maintenant, il faut changer et l'autre non.

Prenez des décisions de conception en un seul endroit. Ne diffusez pas de décision. Mais ne pliez pas toutes les décisions qui se ressemblent en ce moment au même endroit. Il est correct d'avoir à la fois x et y même lorsqu'ils sont tous deux définis sur 1.

Dans cette perspective, je ne mets jamais KISS ou DRY sur l'autre. Je ne vois pas la tension entre eux. Je me garde contre les abus de Ce sont deux principes importants, mais ce n'est pas non plus une solution miracle.

144
candied_orange

J'ai déjà écrit à ce sujet dans n commentaire à ne autre réponse par candied_orange à une question similaire et je l'ai aussi quelque peu abordé dans une réponse différente , mais il convient de répéter:

DRY est un acronyme mignon à trois lettres pour un mnémonique "Don't Repeat Yourself", qui a été inventé dans le livre The Pragmatic Programmer , où il s'agit d'un - section entière de 8,5 pages . Il a également un explication multi-page et discussion sur le wiki .

La définition dans le livre est la suivante:

Chaque élément de connaissance doit avoir une représentation unique, non ambiguë et faisant autorité au sein d'un système.

Notez qu'il s'agit clairement pas de supprimer la duplication. Il s'agit de identifier lequel des doublons est le canonique. Par exemple, si vous avez un cache, le cache contiendra des valeurs qui sont des doublons d'autre chose. Cependant, il doit être très clair que le cache est pas la source canonique.

Le principe est pas les trois lettres SEC. Ce sont ces quelque 20 pages du livre et du wiki.

Le principe est également étroitement lié à OAOO, qui est un acronyme à quatre lettres pas si mignon pour "Once And Only Once", qui à son tour est un principe de la programmation eXtreme qui a un explication et discussion sur plusieurs pages sur le wiki .

La page wiki OAOO contient une citation très intéressante de Ron Jeffries:

Une fois, j'ai vu Beck déclarer deux correctifs de code presque complètement différent comme "duplication", les changer pour qu'ils fussent duplication, puis supprimer la duplication nouvellement insérée pour arriver à quelque chose de mieux.

Sur quoi il élabore:

Je me souviens d'avoir vu Beck regarder deux boucles qui étaient assez différentes: elles avaient des structures et des contenus différents, ce qui n'est pratiquement rien en double, sauf le mot "pour", et le fait qu'ils bouclaient - différemment - sur la même collection.

Il a changé la deuxième boucle pour boucler de la même manière que la première. Cela a nécessité de changer le corps de la boucle pour ignorer les éléments vers la fin de la collection, car la version précédente ne faisait que l'avant de la collection. Maintenant, les déclarations for étaient les mêmes. "Eh bien, je dois éliminer cette duplication, dit-il, et déplacer le deuxième corps dans la première boucle et supprimer complètement la deuxième boucle.

Il avait maintenant deux types de traitements similaires en cours dans la même boucle. Il y a trouvé une sorte de duplication, extrait une méthode, fait deux ou trois autres choses, et le tour est joué! le code était bien meilleur.

Cette première étape - créer une duplication - était surprenante.

Cela montre: vous pouvez avoir une duplication sans code en double!

Et le livre montre le revers de la médaille:

Dans le cadre de votre application de commande de vin en ligne, vous saisissez et validez l'âge de votre utilisateur, ainsi que la quantité qu'il commande. Selon le propriétaire du site, ils doivent tous deux être des nombres et tous deux supérieurs à zéro. Vous codez donc les validations:

def validate_age(value):
 validate_type(value, :integer)
 validate_min_integer(value, 0)

def validate_quantity(value):
 validate_type(value, :integer)
 validate_min_integer(value, 0)

Lors de la révision du code, le résident sait tout rebondir sur ce code, affirmant qu'il s'agit d'une violation DRY: les deux corps de fonction sont identiques.

Ils ont tort. Le code est le même, mais les connaissances qu'ils représentent sont différentes. Les deux fonctions valident deux choses distinctes qui se trouvent avoir les mêmes règles. C’est une coïncidence, pas une duplication.

Il s'agit de code dupliqué qui n'est pas une duplication des connaissances.

Il y a une grande anecdote sur la duplication qui mène à une profonde compréhension de la nature des langages de programmation: de nombreux programmeurs connaissent le langage de programmation Scheme et qu'il s'agit d'un langage procédural dans la famille LISP avec d'abord- les procédures de classe et d'ordre supérieur, la portée lexicale, les fermetures lexicales et l'accent mis sur le code et les structures de données purement fonctionnels et référentiellement transparents. Ce que peu de gens savent cependant, c'est qu'il a été créé pour étudier la programmation orientée objet et les systèmes d'acteurs (que les auteurs de Scheme considéraient comme étroitement liés sinon la même chose).

Deux des procédures fondamentales de Scheme sont lambda, qui crée une procédure, et apply, qui exécute une procédure. Les créateurs de Scheme en ont ajouté deux autres: alpha, qui crée un a ctor (ou objet), et send , qui envoie un message à un acteur (ou un objet).

Une conséquence gênante d'avoir à la fois apply et send était que la syntaxe élégante pour les appels de procédure ne fonctionnait plus. Dans Scheme tel que nous le connaissons aujourd'hui (et dans presque tous les LISP), une simple liste est généralement interprétée comme "interprète le premier élément de la liste comme une procédure et apply le reste de la liste, interprété comme arguments ". Vous pouvez donc écrire

(+ 2 3)

et cela équivaut à

(apply '+ '(2 3))

(Ou quelque chose de proche, mon schéma est assez rouillé.)

Cependant, cela ne fonctionne plus, car vous ne savez pas si apply ou send (en supposant que vous ne voulez pas prioriser l'un des deux que les créateurs de Scheme n'ont pas fait 't, ils voulaient que les deux paradigmes soient égaux). … Ou alors? Les créateurs de Scheme ont réalisé qu'en réalité, il leur suffit de vérifier le type de l'objet référencé par le symbole: si + est une procédure, vous apply, si + est un acteur, vous send un message pour lui. Vous n'avez pas réellement besoin de apply et send séparés, vous pouvez avoir quelque chose comme apply-or-send.

Et c'est ce qu'ils ont fait: ils ont pris le code des deux procédures apply et send et les ont mis dans la même procédure, comme deux branches d'un conditionnel.

Peu de temps après, ils ont également réécrit l'interpréteur Scheme, qui jusque-là était écrit dans un langage d'assemblage de transfert de registre de très bas niveau pour une machine de registre, dans Scheme de haut niveau. Et ils ont remarqué quelque chose d'étonnant: le code dans les deux branches du conditionnel est devenu identique. Ils ne l'avaient pas remarqué auparavant: les deux procédures ont été écrites à des moments différents (elles ont commencé avec un "LISP minimal" puis y ont ajouté OO), ainsi que la verbosité et le bas niveau de l'Assemblée signifiait qu'ils étaient en fait écrits assez différemment, mais après les avoir réécrits dans une langue de haut niveau, il est devenu clair qu'ils faisaient la même chose.

Cela a conduit à une compréhension approfondie des acteurs et de l'OO: exécuter un programme orienté objet et exécuter un programme dans un langage procédural avec des fermetures lexicales et des appels de queue appropriés, c'est la même chose. La seule différence est de savoir si les primitives de votre langage sont des objets/acteurs ou des procédures. Mais opérationnellement, c'est pareil.

Cela conduit également à une autre réalisation importante qui n'est malheureusement pas encore bien comprise aujourd'hui: vous ne pouvez pas maintenir une abstraction orientée objet sans appels de queue appropriés, ou mettre plus agressivement: un langage qui prétend être orienté objet mais n'a pas d'appels de queue appropriés , n'est pas orienté objet. (Malheureusement, cela s'applique à toutes mes langues préférées, et ce n'est pas académique: j'ai ont rencontré ce problème, que j'ai dû interrompre l'encapsulation afin d'éviter un débordement de pile.)

Ceci est un exemple où la duplication très bien cachée en fait obscurci un élément de connaissance important, et à découvrir cette duplication a également révélé des connaissances.

39
Jörg W Mittag

En cas de doute, choisissez toujours la solution la plus simple possible qui résout le problème.

S'il s'avère que la solution simple était trop simple, elle peut facilement être modifiée. En revanche, une solution trop complexe est également plus difficile et risquée à changer.

KISS est vraiment le plus important de tous les principes de conception, mais il est souvent négligé, car notre culture de développeur accorde beaucoup d'importance à être intelligent et à utiliser des techniques sophistiquées. Mais parfois, un if est vraiment meilleur qu'un modèle de stratégie .

Le principe DRY oblige parfois les programmeurs à écrire des fonctions/classes complexes et difficiles à maintenir.

Arrête toi là! Le but du principe DRY est d'obtenir un code plus maintenable. Si l'application du principe dans un cas particulier conduirait à à moins de code maintenable, alors le principe ne devrait pas être appliqué.

Gardez à l'esprit qu'aucun de ces principes n'est un objectif en soi. Le but est de fabriquer des logiciels qui remplissent leur fonction et qui peuvent être modifiés adaptés et étendus si nécessaire. KISS, DRY, SOLID et tous les autres principes sont des moyens pour atteindre cet objectif. Mais tous ont leurs limites et peuvent être appliqués de manière à aller à l'encontre de l'objectif ultime, qui est d'écrire des logiciels fonctionnels et maintenables.

8
JacquesB

À mon humble avis: si vous arrêtez de vous concentrer sur le code KISS/DRY et commencez à vous concentrer sur les exigences régissant le code, vous trouverez la meilleure réponse que vous recherchez.

Je crois:

  1. Nous devons nous encourager mutuellement à rester pragmatiques (comme vous le faites)

  2. Nous ne devons jamais cesser de promouvoir l’importance des tests

  3. Se concentrer davantage sur les exigences résoudra vos questions.

TLDR

Si vous souhaitez que les pièces changent indépendamment, gardez les fonctions indépendantes en ne disposant pas de fonctions d'assistance. Si vos besoins (et toute modification future) sont les mêmes pour toutes les fonctions, déplacez cette logique dans une fonction d'assistance.

Je pense que toutes nos réponses jusqu'à présent font un diagramme de Venn: nous disons tous la même chose, mais nous donnons des détails à différentes parties.

De plus, personne d'autre n'a mentionné les tests, ce qui explique en partie pourquoi j'ai écrit cette réponse. Je pense que si quelqu'un mentionne que les programmeurs ont peur de faire des changements, alors il est très imprudent de ne pas parler de tests! Même si nous "pensons" que le problème concerne le code, il se peut que le vrai problème soit le manque de tests. Les décisions objectivement supérieures deviennent plus réalistes lorsque les gens ont investi en premier dans les tests automatisés.

Tout d'abord, éviter la peur est la sagesse - bon travail!

Voici une phrase que vous avez dite: les programmeurs auront très peur d'apporter des modifications à ces fonctions [d'assistance] ou ils causeront des bogues dans d'autres cas d'utilisation de la fonction

Je suis d'accord que cette peur est l'ennemi, et vous ne devez jamais vous accrocher aux principes s'ils ne font que craindre les bogues en cascade/le travail/les changements. Si copier/coller entre plusieurs fonctions est le seul moyen de supprimer cette peur (ce que je ne crois pas - voir ci-dessous), alors que c'est ce que vous devez faire.

Le fait que vous ressentiez cette peur de faire des changements, et que vous essayez de faire quelque chose à ce sujet, fait de vous un meilleur professionnel que beaucoup d'autres qui ne se soucient pas suffisamment de l'amélioration du code - ils font juste ce qu'on leur dit et apportez le strict minimum pour que leur ticket soit fermé.

Aussi (et je peux dire que je répète ce que vous savez déjà): les compétences des personnes les compétences de conception de Trump . Si les gens de la vie réelle dans votre entreprise sont carrément mauvais, alors peu importe si votre "théorie" est meilleure. Vous devrez peut-être prendre des décisions qui sont objectivement pires, mais vous savez que les personnes qui le maintiendront sont capables de comprendre et de travailler avec. De plus, beaucoup d'entre nous comprennent également la direction qui (IMO) nous gère et trouve des moyens de toujours refuser le refactoring nécessaire.

En tant que fournisseur qui écrit du code pour les clients, je dois y penser tout le temps. Je pourrais vouloir utiliser le curry et la méta-programmation car il y a un argument selon lequel c'est objectivement meilleur, mais dans la vraie vie, je vois des gens être confus par ce code parce que ce n'est pas visuellement évident ( ce qui se passe.

Deuxièmement, de meilleurs tests résolvent plusieurs problèmes à la fois

Si (et seulement si) vous disposez de tests automatisés efficaces, stables et éprouvés (unité et/ou intégration), alors je parie que vous verrez la peur disparaître. Pour les nouveaux arrivants aux tests automatisés, il peut être très effrayant de faire confiance aux tests automatisés; les nouveaux arrivants peuvent voir tous ces points verts et ont très peu confiance que ces points verts reflètent le travail de production dans la vie réelle. Cependant, si vous avez personnellement confiance dans les tests automatisés, vous pouvez commencer à encourager émotionnellement/relationnellement les autres à lui faire confiance.

Pour vous, (si vous ne l'avez pas déjà fait), la première étape consiste à rechercher des pratiques de test si vous ne l'avez pas déjà fait. Je suppose honnêtement que vous connaissez déjà ce genre de choses, mais comme je n'ai pas vu cela mentionné dans votre message d'origine, je dois en parler. Parce que les tests automatisés sont si importants et pertinents pour votre situation que vous avez posée.

Je ne vais pas essayer de résumer toutes les pratiques de test en une seule fois ici, mais je vous mets au défi de vous concentrer sur l'idée de tests "refactor-proof". Avant de valider un test unitaire/d'intégration en code, demandez-vous s'il existe des moyens valides de refactoriser le CUT (code en cours de test) qui casserait le test que vous venez d'écrire. Si c'est vrai, (IMO) supprime ce test. Il vaut mieux avoir moins de tests automatisés qui ne se cassent pas inutilement lorsque vous refactorisez, que d'avoir une chose qui vous dit que vous avez une couverture de test élevée (qualité sur quantité). Après tout, faciliter le refactoring est (IMO) l'objectif principal des tests automatisés.

Comme j'ai adopté cette philosophie "refactor-proof" au fil du temps, je suis parvenu aux conclusions suivantes:

  1. Les tests d'intégration automatisés sont meilleurs que les tests unitaires
  2. Pour les tests d'intégration, si vous en avez besoin, écrivez "simulateurs/faux" avec "contrats de test"
  3. Ne testez jamais une API privée - qu'il s'agisse de méthodes de classe privée ou de fonctions non exportées à partir d'un fichier.

Références:

Pendant que vous effectuez des recherches sur les pratiques de test, vous devrez peut-être prendre plus de temps pour écrire ces tests vous-même. Parfois, la seule meilleure approche consiste à ne dire à personne ce que vous faites, car ils vous microgéreront. Évidemment ce n'est pas toujours possible car le besoin de tests peut être plus important que le besoin d'un bon équilibre travail/vie. Mais, parfois, il y a des choses assez petites pour que vous puissiez vous en sortir en retardant secrètement une tâche d'un jour ou deux afin d'écrire simplement les tests/code nécessaires. Je sais que cela peut être une déclaration controversée, mais je pense que c'est la réalité.

De plus, vous pouvez évidemment être aussi prudent politiquement que possible pour aider les autres à prendre des mesures pour comprendre/écrire les tests eux-mêmes. Ou peut-être êtes-vous le chef de file technologique qui peut imposer une nouvelle règle pour les revues de code.

Lorsque vous parlez de tester avec vos collègues, nous espérons que le point n ° 1 ci-dessus (soyez pragmatique) nous rappelle à tous de continuer à écouter en premier et de ne pas devenir arrogant.

Troisièmement, concentrez-vous sur les exigences, pas sur le code

Trop souvent, nous nous concentrons sur notre code, et ne comprenons pas profondément l'image plus grande que notre code est censé résoudre! Parfois, vous devez arrêter de discuter si le code est propre et commencer à vous assurer que vous avez une bonne compréhension des exigences qui sont censées conduire le code.

Il est plus important que vous fassiez ce qui est correct que de sentir que votre code est "joli" selon des idées comme KISS/DRY. C'est pourquoi j'hésite à me préoccuper de ces slogans, car (en pratique) ils vous font accidentellement vous concentrer sur votre code sans penser au fait que les exigences sont ce qui fournit un bon jugement de bonne qualité de code.


Si les exigences de deux fonctions sont interdépendantes/identiques, mettez la logique d'implémentation de cette exigence dans une fonction d'assistance. Les entrées de cette fonction d'assistance seront les entrées de la logique métier pour cette exigence.

Si les exigences des fonctions sont différentes, copiez/collez entre elles. S'ils se trouvent tous les deux avoir le même code en ce moment, mais pourrait changer à juste titre indépendamment, alors une fonction d'aide est mauvais car il affecte une autre fonction dont l'exigence est de changer indépendamment.

Exemple 1: vous avez une fonction appelée "getReportForCustomerX" et "getReportForCustomerY", et ils interrogent tous les deux la base de données de la même manière. Imaginons également qu'il existe une exigence commerciale où chaque client peut personnaliser son rapport littéralement comme il le souhaite. Dans ce cas, par conception , les clients souhaitent des numéros différents dans leur rapport. Donc, si vous avez un nouveau client Z qui a besoin d'un rapport, il peut être préférable de copier/coller la requête d'un autre client, puis de valider le code et de le déplacer. Même si les requêtes sont exactement identiques, le point de définition de ces fonctions est de séparer changements d'un client impactant un autre. Dans les cas où vous fournissez une nouvelle fonctionnalité que tous les clients voudront dans leur rapport, alors oui: vous taperez peut-être les mêmes changements entre toutes les fonctions.

Cependant, disons que nous décidons d'aller de l'avant et de créer une fonction d'aide appelée queryData. La raison est mauvaise car il y aura plus de changements en cascade en introduisant une fonction d'assistance. S'il y a une clause "où" dans votre requête qui est la même pour tous les clients, dès qu'un client souhaite qu'un champ soit différent pour eux, alors au lieu de 1) changer la requête à l'intérieur de la fonction X, vous devez 1 ) modifiez la requête pour faire ce que le client X veut 2) ajoutez les conditions dans la requête pour ne pas le faire pour les autres. L'ajout de conditions supplémentaires dans une requête est logiquement différent. Je sais peut-être comment ajouter un sous-paragraphe dans une requête, mais cela ne signifie pas que je sais comment rendre ce sous-paragraphe conditionnel sans affecter les performances de ceux qui ne l'utilisent pas.

Vous remarquez donc que l'utilisation d'une fonction d'assistance nécessite deux modifications au lieu d'une. Je sais que c'est un exemple artificiel, mais la complexité booléenne à maintenir croît plus que linéairement, selon mon expérience. Par conséquent, l'acte d'ajouter des conditions compte comme "une chose de plus" dont les gens doivent se soucier et "une chose de plus" à mettre à jour à chaque fois.

Cet exemple, il me semble, pourrait ressembler à la situation dans laquelle vous vous trouvez. Certaines personnes grincent des dents émotionnellement à l'idée de copier/coller entre ces fonctions, et une telle réaction émotionnelle est OK. Mais le principe de "minimiser les changements en cascade" discernera objectivement les exceptions lorsque le copier/coller est OK.

Exemple 2: Vous avez trois clients différents, mais la seule chose que vous autorisez à être différent entre leurs rapports est le titre des colonnes. Notez que cette situation est très différente. Notre exigence commerciale n'est plus de "fournir de la valeur au client en permettant une flexibilité concurrentielle dans le rapport". Au lieu de cela, l'exigence commerciale est "d'éviter le travail excessif en ne permettant pas aux clients de personnaliser le rapport beaucoup". Dans cette situation, la seule fois où vous modifieriez la logique de requête, c'est quand vous devrez également vous assurer que tous les autres clients obtiennent le même changement. Dans ce cas, vous voulez vraiment créer une fonction d'aide avec un tableau en entrée - quels sont les "titres" pour les colonnes.

À l'avenir, si les propriétaires de produits décident de permettre aux clients de personnaliser quelque chose à propos de la requête, vous ajouterez plus d'indicateurs à la fonction d'assistance.

Conclusion

Plus vous vous concentrez sur les exigences au lieu du code, plus le code sera isomorphe aux exigences littérales. Vous naturellement écrivez un meilleur code.

4
Alexander Bird

Essayez de trouver un juste milieu raisonnable. Plutôt qu'une fonction avec beaucoup de paramètres et de conditions complexes dispersées à travers elle, divisez-la en quelques fonctions plus simples. Il y aura des répétitions dans les appelants, mais pas autant que si vous n'aviez pas déplacé le code commun vers les fonctions en premier lieu.

J'ai récemment rencontré cela avec du code sur lequel je travaille pour interfacer avec les magasins d'applications Google et iTunes. Une grande partie du flux général est le même, mais il y a suffisamment de différences pour que je ne puisse pas facilement écrire une fonction pour tout encapsuler.

Donc, le code est structuré comme:

Google::validate_receipt(...)
    f1(...)
    f2(...)
    some google-specific code
    f3(...)

iTunes::validate_receipt(...)
    some iTunes-specific code
    f1(...)
    f2(...)
    more iTunes-specific code
    f3(...)

Je ne suis pas trop préoccupé par le fait que l'appel de f1 () et f2 () dans les deux fonctions de validation viole le principe DRY, car les combiner le rendrait plus compliqué et n'effectuerait pas un seul, bien défini tâche.

3
Barmar

Kent Beck a adopté 4 règles de conception simple, liées à cette question. Selon la formule de Martin Fowler, ce sont:

  • Réussit les tests
  • Révèle l'intention
  • Pas de duplication
  • Moins d'éléments

Il y a beaucoup de discussions sur l'ordre des deux intermédiaires, il peut donc être utile de les considérer comme aussi importants.

DRY est le troisième élément de la liste, et KISS pourrait être considéré comme une combinaison des 2e et 4e, ou même la liste entière ensemble.

Cette liste offre une vue alternative à la dichotomie DRY/KISS. Votre code DRY révèle-t-il l'intention? Votre code KISS? Pouvez-vous rendre la version éther plus révélatrice ou moins dupliquée?)

Le but n'est pas DRY ou KISS, c'est du bon code. DRY, KISS, et ces règles ne sont que de simples outils pour y arriver.

3
Blaise Pascal