La solution doit-elle être aussi générique que possible ou aussi spécifique que possible?

124

Disons que j'ai une entité qui a l'attribut "type". Il pourrait y avoir plus de 20 types possibles.

Maintenant, on me demande d'implémenter quelque chose qui permettrait de changer le type de A-> B, qui est le seul cas d'utilisation.

Devrais-je donc implémenter quelque chose qui permet des changements de type arbitraires tant qu'ils sont valables? Ou devrais-je SEUL le laisser changer de A-> B selon l'exigence et refuser tout autre changement de type tel que B-> A ou A-> C?

Je peux voir les avantages et les inconvénients des deux côtés, lorsqu'une solution générique représenterait moins de travail au cas où une exigence similaire se présenterait à l'avenir, mais cela signifierait également plus de chances de se tromper (même si nous contrôlons à 100% l'appelant à ce stade. point).
Une solution spécifique est moins sujette aux erreurs, mais nécessite davantage de travail dans le futur si une exigence similaire se présente.

J'entends toujours qu'un bon développeur devrait essayer d'anticiper les changements et de concevoir le système de manière à ce qu'il soit facile à étendre à l'avenir, ce qui semble être une solution générique.

Modifier:

Ajouter plus de détails à mon exemple pas si spécifique: La solution "générique" dans ce cas nécessite moins de travail que la solution "spécifique", car la solution spécifique nécessite une validation sur l'ancien type ainsi que sur le nouveau type, tandis que la solution générique seulement besoin de valider le nouveau type.

LoveProgramming
la source
97
C'est une question intéressante. J'ai eu une discussion à propos de quelque chose comme ça avec mon grand-père (un très, très vieux programmateur) et sa réponse était quelque chose dans les lignes de "la chose la plus générique qui résout votre problème spécifique", ce qui revient à une fantaisie " Ça dépend". Les instructions générales en développement logiciel fonctionnent rarement - il faut toujours agir au cas par cas.
T. Sar
2
@ T.Sar ajoute ceci comme réponse et je voterai :-)
Christophe
4
Qu'est-ce qu'une "solution générique" à votre avis? De plus, veuillez clarifier ce que vous entendez par «seul cas d'utilisation». Voulez-vous dire que seule une transition de A-> B est autorisée ou que seule cette transition est spécifiée, et qu'il ne s'agirait pas d'une condition d'erreur pour passer d'un autre état à un autre état? En tant que développeur, vous devez demander à l'auteur du cas d'utilisation de clarifier. Si aucune autre transition n'est autorisée et que votre code le permet, quel que soit le contrôle de l'appelant, votre code n'a pas satisfait aux exigences.
RibaldEddie
5
Le principe selon lequel si X est une bonne idée, alors seulement tout le temps doit être optimal, semble avoir un attrait particulier pour les développeurs (ou au moins un groupe vocal parmi eux), mais considérons ceci: les règles de base de la programmation sont: comme des proverbes, en ce que vous pouvez souvent trouver une paire avec des implications opposées. Ceci est un signe que vous devez utiliser votre jugement (comme le préconisent les réponses ici), et méfiez-vous du dogme.
sdenham
2
La généralisation prématurée peut causer autant de brûlures d'estomac que l'optimisation prématurée - vous finissez par écrire beaucoup de code qui peut ne jamais être utilisé. Résolu pour le problème spécifique en premier, puis généralisez au besoin.
John Bode

Réponses:

296

Ma règle de base:

  1. la première fois que vous rencontrez le problème, ne résolvez que le problème spécifique ( principe de YAGNI )
  2. la deuxième fois que vous rencontrez le même problème, envisagez de généraliser le premier cas, si cela ne demande pas beaucoup de travail
  3. une fois que vous avez trois cas spécifiques où vous seriez en mesure d’utiliser la version généralisée, vous devriez alors commencer à planifier réellement la version généralisée - à présent, vous devez bien comprendre le problème pour pouvoir le généraliser.

Bien sûr, il s’agit d’une ligne directrice et non d’une règle absolue: la vraie solution consiste à utiliser votre meilleur jugement, au cas par cas.

Daniel Pryden
la source
1
Pouvez-vous expliquer ce qu'est YAGNI?
Bernhard
7
@ Bernard Vous n'en aurez pas besoin . Un principe de conception de logiciel très utile.
Angew
4
thing1, thing2, pensez peut-être à utiliser un tableau. À thing1, thing2, thing3, utilisez presque certainement un thing[]tableau à la place." est une règle similaire pour décider entre plusieurs variables ou un seul tableau.
Joker_vD
15
Une autre façon d’énoncer la règle n ° 1: "Vous ne pouvez pas généraliser une chose."
Wayne Conrad
2
@SantiBailors: Comme le dit Doc Brown dans sa réponse, nous surestimons souvent énormément les efforts inutiles que nous pourrions consacrer à la construction du premier à jeter. Dans le mois mythique de l'homme , Fred Brooks déclare: "Prévoyez en jeter un, vous le ferez de toute façon." Cela dit: si vous rencontrez immédiatement plus d'un usage pour quelque chose - par exemple, en répondant à un ensemble d'exigences dans lesquelles vous devrez clairement résoudre le même problème plusieurs fois - vous avez déjà plusieurs cas à généraliser. de, et c'est tout à fait bien et pas en conflit avec ma réponse.
Daniel Pryden
95

Une solution spécifique nécessite plus de travail dans le futur si des exigences similaires sont nécessaires

J'ai entendu cet argument plusieurs dizaines de fois et, selon mon expérience, il s'avère régulièrement être une erreur. Si vous généralisez maintenant ou plus tard, lorsque la deuxième exigence similaire se présentera, le travail sera presque le même au total. Il est donc absolument inutile d'investir des efforts supplémentaires dans la généralisation, sans savoir que cet effort sera rentable.

(Évidemment, cela ne s'applique pas lorsqu'une solution plus générale est moins compliquée et nécessite moins d'effort qu'une solution spécifique, mais d'après mon expérience, il s'agit de cas rares. Un tel type de scénario a ensuite été intégré à la question, et ce n'est pas une ma réponse est à propos de).

Lorsque le "deuxième cas similaire" apparaît, il est temps de penser à généraliser. Il sera alors beaucoup plus facile de généraliser correctement , car cette seconde exigence vous donne un scénario dans lequel vous pouvez valider si vous avez génériqué les bonnes choses. Lorsque vous essayez de généraliser un seul cas, vous tirez dans le noir. Il y a de fortes chances que vous généralisiez trop certaines choses qu'il n'est pas nécessaire de généraliser et que vous manquiez d'autres parties qui le devraient. Et quand un deuxième cas se présente et que vous réalisez que vous avez généralisé les mauvaises choses, vous avez encore beaucoup de travail à faire pour y remédier.

Je recommande donc de retarder toute tentation de faire les choses "au cas où". Cette approche ne conduira à davantage d'efforts de travail et de maintenance que lorsque vous aurez manqué l'occasion de généraliser trois, quatre ou plus, puis que vous aurez une pile de code similaire (donc dupliqué) à gérer.

Doc Brown
la source
2
Pour moi, cette réponse n'a pas de sens dans le contexte de OP. Il dit qu'il passera moins de temps à généraliser maintenant et à l'avenir, à moins que, dans le futur, la mise en œuvre ne soit spécifique. Vous vous opposez à «un effort supplémentaire pour généraliser», alors que OP n'investira qu'un effort supplémentaire s'il ne généralise pas . (pensez) .... bizarre: $
msb
2
@msb: ce contexte a été ajouté après que j'ai écrit ma réponse et va à l'encontre de ce que disait le PO, en particulier dans la partie que j'ai citée. Voir mon édition.
Doc Brown
2
En outre, la solution généralisée sera plus compliquée. Par conséquent, le temps nécessaire pour l'adapter au second cas, sera beaucoup plus long à comprendre.
AndreKR
4
Doc, un aparté, mais je n'aurais jamais deviné que vous n'étiez pas un locuteur natif. Vos réponses sont toujours bien écrites et bien argumentées.
user949300
2
J'imagine votre accent lorsque je lis vos réponses futures. :-)
user949300
64

TL; DR: cela dépend de ce que vous essayez de résoudre.

J'ai eu une conversation similaire avec mes Gramps à ce sujet, alors que nous parlions de la façon dont Func et Action en C # sont géniaux. Mon Gramps est un très ancien programmateur, qui utilise les codes sources depuis que les logiciels ont été exécutés sur des ordinateurs qui occupaient toute une pièce.

Il a changé de technologie plusieurs fois dans sa vie. Il a écrit du code en C, COBOL, Pascal, BASIC, Fortran, Smalltalk, Java et a finalement commencé à utiliser le C # comme passe-temps. J'ai appris à programmer avec lui, assis sur ses genoux alors que j'étais tout petit, découpant mes premières lignes de code sur l'éditeur bleu de SideKick d'IBM. À 20 ans, j'avais déjà passé plus de temps à coder qu'à jouer à l'extérieur.

C’est un peu de mes souvenirs, alors excusez-moi si je ne suis pas tout à fait pratique lorsque je les raconte. J'aime un peu ces moments.

C'est ce qu'il m'a dit:


"Devrions-nous vous demander de généraliser un problème ou de le résoudre de manière spécifique? Eh bien, c'est une ... question."

Gramps prit une pause pour y réfléchir un instant tout en fixant la position de ses lunettes sur son visage. Il jouait un match 3 sur son ordinateur, tout en écoutant le disque d'un Deep Purple sur son ancien système audio.

"Cela dépend du problème que vous essayez de résoudre", m'a-t-il dit. «Il est tentant de croire qu’une solution unique et sacrée existe pour tous les choix de conception, mais qu’il n’en existe pas. L’architecture logicielle est comme le fromage, vous voyez».

"... Du fromage, Gramps?"

"Peu importe ce que tu penses de ton favori, il y aura toujours quelqu'un qui pense que ça sent mauvais".

Je clignai des yeux de confusion pendant un moment, mais avant que je puisse dire quoi que ce soit, poursuivit Gramps.

"Quand vous construisez une voiture, comment choisissez-vous le matériau d'une pièce?"

"Je ... Je suppose que cela dépend des coûts impliqués et de ce que la pièce devrait faire, je suppose."

"Cela dépend du problème que cette partie tente de résoudre. Vous ne ferez pas un pneu en acier, ni un pare-brise en cuir. Vous choisissez le matériau qui résoudra le mieux le problème que vous avez sous la main. solution générique? Ou un problème spécifique? À quel problème, à quel cas d'utilisation? Devrait-on adopter une approche fonctionnelle complète pour donner un maximum de flexibilité à un code qui ne sera utilisé qu'une seule fois? Faut-il écrire un code très spécialisé et fragile? Des choix de conception comme ceux-ci sont comme les matériaux choisis pour une partie de voiture ou la forme de la brique Lego que vous choisissez pour construire une petite maison. Quelle brique Lego est la meilleure? "

Le programmeur âgé chercha un petit modèle de train Lego qu'il avait sur sa table avant de continuer.

"Vous ne pouvez répondre à cela que si vous savez pour quoi vous avez besoin de cette brique. Comment diable saurez-vous que la solution spécifique est meilleure que la solution générique, ou inversement, si vous ne savez même pas quel problème vous êtes Vous ne pouvez pas voir au-delà d’un choix que vous ne comprenez pas. "

"..Vous venez de citer The Matrix? "

"Quoi?"

"Rien, continue."

"Eh bien, supposons que vous essayez de créer quelque chose dans le système national de facturation. Vous savez à quoi cette API infernale et son fichier XML de trente mille lignes ressemble de l'intérieur. A quoi ressemblerait une solution" générique "pour la création de ce fichier Le fichier contient de nombreux paramètres facultatifs, remplis de cas que seules des branches d'activité spécifiques doivent utiliser. Dans la plupart des cas, vous pouvez les ignorer en toute sécurité. Vous n'avez pas besoin de créer un système de facture générique si vous ne voulez Créez simplement un système de vente de chaussures et faites-en le meilleur système de facturation de vente de chaussures dans le monde. Maintenant, si vous deviez créer un système de facturation pour tout type de client, pour une application plus large - être revendu en tant que système de vente générique indépendant,par exemple, il est maintenant intéressant de mettre en œuvre les options qui ne sont utilisées que pour le gaz, les aliments ou l’alcool.Maintenant, ce sont des cas d'utilisation possibles. Avant qu’ils ne soient que des cas hypothétiques Ne pas utiliser de cas et vous ne voulez pas mettre en œuvre Ne pas utiliser de cas. Ne l'utilisez pas, c'est le petit frère de Pas besoin . "

Gramps a remis le train de lego à sa place et est revenu à son match de match 3.

"Ainsi, pour pouvoir choisir une solution générique ou spécifique à un problème donné, vous devez d'abord comprendre en quoi il consiste. Sinon, vous devinez, et deviner, c'est le travail des gestionnaires, pas celui des programmeurs. tout dans l'informatique, ça dépend. "


Donc, là vous l'avez. "Ça dépend". C'est probablement l'expression la plus puissante de deux mots lorsque l'on pense à la conception de logiciels.

T. Sar
la source
14
Je suis sûr qu'il y a quelque chose d'utile dans cette histoire, mais c'était trop pénible à lire, désolée
GoatInTheMachine
28
Votre premier message était une courte anecdote amusante - et bien sûr, c'est une question d'opinion - mais à moins que j'aime vraiment le style d'écriture, je trouve les histoires longues comme celle-ci vraiment complaisante et un peu inappropriée en dehors d'un blog personnel
GoatInTheMachine
16
@ T.Sar n'écoutez pas les ennemis, votre message est un joyau des conseils utiles d'un gourou. +1
LLlAMnYP
7
La partie "architecture logicielle, c'est comme le fromage" était tout simplement géniale. En effet, cette réponse est un joyau!
Mathieu Guindon
3
Peut-être que cette réponse est comme le fromage aussi? ;) Mais s'il vous plaît, "SmallTalk" devrait être "Smalltalk", et oui, je suis ce mec, désolé.
fede s.
14

En premier lieu, vous devez essayer de prévoir s’il est probable qu'un tel changement se produira - et pas seulement une possibilité lointaine quelque part dans le futur.

Sinon, il vaut généralement mieux opter pour la solution simple maintenant et l'étendre plus tard. Il est fort possible que vous ayez une image beaucoup plus claire de ce qui est nécessaire à ce moment-là.

vous double
la source
13

Si vous travaillez dans un domaine qui vous est nouveau, il convient d'appliquer la règle de trois que Daniel Pryden a mentionnée. Après tout, comment êtes-vous censé construire des abstractions utiles si vous êtes novice dans ce domaine? Les gens sont souvent sûrs de leur capacité à capturer des abstractions, bien que ce soit rarement le cas. D'après mon expérience, l'abstraction prématurée n'est pas moins un mal que la duplication de code. Les abstractions erronées sont vraiment pénibles à comprendre. Parfois encore plus pénible à refactoriser.

Il existe un livre qui traite de mon point sur une zone inconnue dans laquelle le développeur travaille. Il est constitué de domaines spécifiques avec des abstractions utiles extraites.

Zapadlo
la source
La question est claire à propos d'un problème concret.
RibaldEddie
4
La réponse est suffisamment générique pour aborder ce problème concret. Et la question n’est pas assez précise pour donner un reçu concret: comme vous pouvez le constater, aucun détail de domaine n’est mentionné dans une question. Même les noms de classe ne sont pas spécifiés (A et B ne comptent pas).
Zapadlo
7
"Une réponse stackoverflow doit-elle être aussi générique que possible ou aussi spécifique que possible?"
Lyndon White
@ LyndonWhite une question de stackoverflow devrait-elle être aussi générique que possible (trop large!) Ou aussi spécifique que possible (quel que soit le nom de cet échec!)? Ha.
4

Compte tenu de la nature du corps de votre question, en supposant que je l’aie bien comprise, j’envisage cela comme une question de conception des caractéristiques du système central plus qu’une question de solutions génériques ou spécifiques.

Et en ce qui concerne les fonctionnalités et les capacités du système central, les plus fiables sont celles qui n'existent pas. Il est rentable de privilégier le minimalisme, d'autant plus qu'il est généralement plus facile d'ajouter des fonctionnalités de manière centralisée, longtemps souhaitée, que de supprimer des fonctionnalités problématiques, de longues années non souhaitées, avec de nombreuses dépendances, car il a été d'autant plus difficile de travailler avec le système. que cela doit être tout en soulevant des questions de conception sans fin avec chaque nouvelle fonctionnalité.

En fait, étant donné que je ne saurais trop si cela sera souvent nécessaire à l'avenir, je chercherais à éviter de le considérer comme un remplacement de type de A à B si possible, mais plutôt à le chercher simplement comme moyen de transformer l'état de A. Par exemple, définissez certains champs dans A de manière à ce qu'ils se transforment et s'affichent comme B à l'utilisateur sans changer réellement de "type" d'objet - vous pouvez potentiellement rendre A magasin B privé en utilisant des fonctions de composition et d'appel dans B lorsque l'état de A est défini pour indiquer qu'il doit imiter B afin de simplifier si possible la mise en œuvre. Cela devrait être une solution très simple et peu invasive.

Quoi qu’il en soit, comme dans beaucoup d’autres, je vous conseillerais plutôt d’éviter les solutions génériques dans ce cas, mais c’est encore plus grave, car j’imagine qu’il s’agit d’ajouter une capacité très audacieuse au système central. suggérer de pécher par excès de l’abandonner, en particulier pour le moment.


la source
"Vous manquez tous les bugs que vous ne codez pas." (de l'affiche de basket-ball: vous manquez tous les coups que vous ne prenez pas)
3

Il est difficile de donner une réponse générique à ce problème spécifique ;-)

Plus il est générique, plus vous gagnerez de temps pour les modifications futures. Par exemple, pour cette raison, de nombreux programmes de jeu utilisent le modèle de composant d'entité au lieu de créer un système de types très élaboré mais rigide des personnages et des objets du jeu.

D'autre part, créer quelque chose de générique nécessite un investissement initial en conception beaucoup plus rapide qu'en efforts de conception. Cela comporte un risque d'ingénierie excessive, voire même de se perdre dans les futures exigences potentielles.

Il vaut toujours la peine de voir s’il existe une généralisation naturelle qui vous permettra de faire une avancée décisive. Cependant, à la fin, c’est une question d’équilibre, entre l’effort que vous pouvez dépenser maintenant et l’effort dont vous pourriez avoir besoin à l’avenir.

Christophe
la source
3
  1. Hybride. Cela ne doit pas être une question de choix. Vous pouvez concevoir l'API pour les conversions de types généraux tout en implémentant uniquement la conversion spécifique dont vous avez besoin maintenant. (Assurez-vous simplement que si quelqu'un appelle votre API générale avec une conversion non prise en charge, elle échoue avec un statut d'erreur "non pris en charge".)

  2. Essai. Pour la conversion A-> B, je vais devoir écrire un (ou un petit nombre) de tests. Pour une conversion générique x-> y, il se peut que je doive écrire toute une matrice de tests. C'est beaucoup plus de travail, même si toutes les conversions partagent une implémentation générique unique.

    Si, en revanche, il existe un moyen générique de tester toutes les conversions possibles, il n’ya alors plus beaucoup de travail à faire et je pourrais être enclin à passer à une solution générique plus tôt.

  3. Couplage. Un convertisseur de A à B peut nécessairement avoir besoin de connaître les détails de la mise en œuvre des A et des B (couplage étroit). Si A et B évoluent encore, cela signifie que je devrais peut-être continuer à revenir sur le convertisseur (et ses tests), ce qui est nul, mais au moins, il est limité aux A et aux B.

    Si j’avais opté pour une solution générique nécessitant l’accès à tous les types de détails, alors même si les C et D évoluaient, je devrais peut-être continuer à peaufiner le convertisseur générique (et toute une série de tests), ce qui pourrait même me ralentir. bien que personne n'a besoin encore de se convertir à un C ou un D .

    Si les conversions génériques et spécifiques peuvent être implémentées d'une manière qui n'est que faiblement couplée aux détails des types, alors je ne m'inquiéterais pas pour cela. Si l'une de ces méthodes peut être réalisée de manière faiblement couplée alors que l'autre nécessite un couplage étroit, alors c'est un argument de poids en faveur de l'approche faiblement couplée dès la sortie de la grille.

Adrian McCarthy
la source
2
Le test est un bon point. C'est un gros avantage si vous concevez des solutions génériques basées sur des concepts de la théorie des catégories , car vous obtenez souvent des théorèmes libres qui prouvent que la seule implémentation possible d'une signature (que le vérificateur de types du compilateur accepte) est la bonne , ou du moins que si l'algorithme fonctionne pour un type particulier, il doit également fonctionner pour tous les autres types.
gauche du
Je suppose qu'il existe une raison spécifique à un domaine pour laquelle une seule conversion de type a été demandée, ce qui signifie que la plupart des conversions de types sont des actions non valides dans le domaine posant problème et que, pour cette raison, l'application ne devrait pas être prise en charge tant qu'elles ne sont pas compatibles. sont officiellement autorisés. Cette réponse se rapproche le plus de cette argumentation.
Ralf Kleberhoff
3

La solution doit-elle être aussi générique que possible ou aussi spécifique que possible?

Ce n'est pas une question de réponse.

Le mieux que vous puissiez raisonnablement obtenir, c’est quelques heuristiques permettant de déterminer la nature générale ou spécifique d’une solution donnée. En effectuant quelque chose comme le processus ci-dessous, l'approximation du premier ordre est généralement correcte (ou suffisante). Lorsque ce n'est pas le cas, la raison en est probablement trop spécifique à un domaine pour être utilement traitée en détail ici.

  1. Approximation de premier ordre: la règle habituelle de YAGNI de trois telle que décrite par Daniel Pryden, Doc Brown, et al .

    C'est une heuristique généralement utile car c'est probablement le mieux que vous puissiez faire, cela ne dépend pas du domaine ni d'autres variables.

    Donc, la présomption initiale est: nous faisons la chose la plus spécifique.

  2. Approximation de second ordre: sur la base de votre connaissance approfondie du domaine de la solution , vous dites

    La solution "générique" dans ce cas nécessite moins de travail que la solution "spécifique"

    de sorte que nous pourrions réinterpréter YAGNI comme recommandant d’éviter un travail inutile , plutôt que d’éviter une généralité inutile. Nous pourrions donc modifier notre présomption initiale et faire la chose la plus facile .

    Toutefois, si les connaissances de votre domaine de solution indiquent que la solution la plus simple risque de générer beaucoup de bogues, d’être difficile à tester de manière adéquate ou de poser tout autre problème, être plus facile à coder n’est pas nécessairement une raison suffisante pour changer notre système. choix d'origine.

  3. Approximation de troisième ordre: votre connaissance du domaine problématique suggère-t-elle que la solution la plus simple est en fait correcte ou autorisez-vous beaucoup de transitions que vous savez être sans signification ou erronées?

    Si la solution simple mais générique vous semble problématique, ou si vous n’avez pas confiance en votre capacité à juger de ces risques, il est probablement préférable de faire davantage de travail et de ne pas perdre votre temps initial.

  4. Approximation de quatrième ordre: votre connaissance du comportement du client ou son lien avec les autres, les priorités de la gestion de projet ou ... toute autre considération non strictement technique qui modifie votre décision de travail actuelle?

Inutile
la source
2

Ce n'est pas une question facile à répondre avec une réponse simple. Beaucoup de réponses ont donné des heuristiques construites autour d'une règle de 3, ou quelque chose de similaire. Il est difficile de dépasser ces règles empiriques.

Pour vraiment vraiment répondre à votre question, vous devez considérer que votre travail est le plus susceptible de ne pas implémenter quelque chose qui change de A-> B. Si vous êtes un entrepreneur, c'est peut-être une exigence, mais si vous êtes un employé, vous avez été engagé pour effectuer de nombreuses tâches plus petites pour la société. Changer A-> B n'est qu'une de ces tâches. Votre entreprise se préoccupera également de la possibilité d'apporter de futurs changements, même si cela n'est pas indiqué dans la demande. Pour trouver "TheBestImplementation (tm)", vous devez regarder la plus grande image de ce que l'on vous demande réellement de faire, puis l'utiliser pour interpréter la petite demande de modification A-> B que vous avez reçue.

Si vous êtes un programmeur débutant sortant de l'université, il est souvent conseillé de faire exactement ce que l'on vous a demandé de faire. Si vous avez été embauché en tant qu'architecte de logiciel avec 15 ans d'expérience, il est généralement conseillé de réfléchir à une question globale. Chaque travail réel se situera quelque part entre "faire exactement ce que la tâche est étroite" et "penser à la grande image". Vous saurez où se situe votre travail dans ce spectre si vous parlez suffisamment avec les gens et si vous faites assez de travail pour eux.

Je peux donner quelques exemples concrets dans lesquels votre question a une réponse définitive basée sur le contexte. Pensez au cas où vous écrivez un logiciel critique pour la sécurité. Cela signifie que vous avez une équipe de testeurs qui veille à ce que le produit fonctionne comme promis. Certaines de ces équipes de test doivent tester chaque chemin possible dans le code. Si vous parlez avec eux, vous constaterez peut-être que si vous généralisez le comportement, vous ajouterez 30 000 USD à leurs coûts de test, car ils devront tester tous ces chemins supplémentaires. Dans ce cas, n’ajoutez pas de fonctionnalité généralisée, même si vous devez dupliquer le travail 7 ou 8 fois à cause de cela. Économisez de l'argent à l'entreprise et faites exactement ce que la demande a indiqué.

D'autre part, considérez que vous créez une API pour permettre aux clients d'accéder aux données d'un programme de base de données créé par votre société. Un client demande d'autoriser les modifications A-> B. Les API ont généralement un aspect de menottes en or: une fois que vous ajoutez une fonctionnalité à une API, vous n'êtes généralement pas censé supprimer cette fonctionnalité (jusqu'au prochain numéro de version majeur). Beaucoup de vos clients peuvent ne pas être disposés à payer le coût de la mise à niveau vers le prochain numéro de version majeure, de sorte que vous risquez de vous retrouver avec la solution de votre choix pour une longue période. Dans ce cas, je recommande fortement de créer la solution générique dès le début. Vous ne voulez vraiment pas développer une mauvaise API remplie de comportements ponctuels.

Cort Ammon
la source
1

Hmm ... pas beaucoup de contexte pour une réponse ... faisant écho aux réponses précédentes, "ça dépend".

En un sens, vous devez vous reposer sur votre expérience. Si ce n'est pas le vôtre, alors quelqu'un de plus haut placé dans le domaine. Vous pouvez interroger sur les critères d'acceptation. Si cela ressemble à «l'utilisateur devrait pouvoir changer le type de" A "en" B "" par rapport à "l'utilisateur devrait pouvoir changer le type de sa valeur actuelle à toute autre valeur autorisée".

Les critères d'acceptation sont souvent sujets à interprétation, mais le personnel chargé de l'assurance qualité peut écrire des critères appropriés à la tâche à exécuter, minimisant ainsi l'interprétation nécessaire.

Existe-t-il des restrictions de domaine qui ne permettent pas de passer de "A" à "C" ou à toute autre option, mais uniquement de "A" à "B"? Ou est-ce juste une exigence étroitement spécifiée qui n'est pas "prospective"?

Si le cas général était plus difficile, je demanderais avant de commencer le travail, mais dans votre cas, si je pouvais "prédire" que d'autres demandes de changement de "type" arriveraient à l'avenir, je serais tenté de: a) écrire quelque chose de réutilisable pour le cas général, et b) l'envelopper dans une condition qui ne permet que A -> B pour l'instant.

Assez facile à vérifier pour le cas actuel dans les tests automatisés, et assez facile à ouvrir à d'autres options plus tard si / quand différents cas d'utilisation se présentent.

chien de train
la source
1

Pour moi, une ligne directrice que j'ai établie il y a quelque temps est la suivante: "Pour des exigences hypothétiques, écrivez uniquement du code hypothétique." En d’autres termes, si vous prévoyez des exigences supplémentaires, réfléchissez un peu à la façon de les implémenter et structurez votre code actuel de sorte qu’il ne bloque pas ainsi.

Mais n'écrivez pas le code réel pour ceux-ci maintenant, pensez simplement à ce que vous feriez. Sinon, vous rendrez généralement les choses inutilement complexes et vous serez probablement ennuyé plus tard lorsque les besoins réels seront différents de ceux que vous aviez prévus.

Quatre votre exemple: si vous avez tous les usages de la méthode convert sous votre contrôle, vous pouvez simplement l’appeler convertAToB pour le moment et prévoir d’utiliser un refactoring "méthode renommée" dans l’EDI pour le renommer si vous avez besoin de fonctionnalités plus générales plus tard. Cependant, si la méthode de conversion fait partie d'une API publique, cela pourrait être très différent: être spécifique bloquerait la généralisation plus tard, car il est difficile de renommer les choses dans ce cas.

Hans-Peter Störr
la source
0

J'entends toujours qu'un bon développeur devrait essayer d'anticiper le changement et concevoir le système de manière à ce qu'il soit facile à étendre à l'avenir,

En principe oui. Mais cela ne conduit pas nécessairement à des solutions génériques.

En ce qui me concerne, il existe deux types de sujets dans le développement logiciel pour lesquels vous devez anticiper les changements futurs:

  • Les bibliothèques destinées à être utilisées par des tiers, et
  • architecture logicielle globale.

Le premier cas est résolu en surveillant votre cohésion / couplage, l'injection de dépendance ou autre. Le second cas est plus abstrait, par exemple en choisissant une architecture orientée service plutôt qu’un gros bloc de code monolothique pour une application volumineuse.

Dans votre cas, vous demandez une solution spécifique à un problème spécifique, qui n’a aucun impact prévisible sur l’avenir. Dans ce cas, YAGNI et DRY sont de bonnes devises à tirer pour:

  • YAGNI (vous n'en aurez pas besoin) vous demande de mettre en œuvre les éléments de base absolument minimaux dont vous avez besoin et que vous utilisez maintenant . Cela signifie implémenter le minimum qui oblige votre suite de tests actuelle à passer du rouge au vert, si vous devez utiliser le développement de style TDD / BDD / FDD. Pas une seule ligne de plus.
  • DRY (ne vous répétez pas) signifie que si vous rencontrez à nouveau un problème similaire, vous devez alors examiner de près si vous avez besoin d'une solution générique.

Combiné à d'autres pratiques modernes (telles qu'une bonne couverture de test pour pouvoir refactoriser en toute sécurité), cela signifie que vous vous retrouvez avec un code rapide, écrit, maigre et moyen, qui grandit au besoin.

qui ressemble à une solution générique est la voie à suivre?

Non, il semble que vous devriez avoir des environnements de programmation, des langages et des outils qui rendent le remodelage facile et amusant lorsque vous en avez besoin. Les solutions génériques ne fournissent pas cela; ils découplent l'application du domaine réel.

Jetez un coup d'œil aux frameworks ORM ou MVC modernes, par exemple Ruby on Rails; au niveau de l'application, tous les efforts sont concentrés sur le travail non générique. Les bibliothèques de rails elles-mêmes sont évidemment génériques à presque 100%, mais le code de domaine (sur lequel porte votre question) devrait faire des manigances minimes à cet égard.

AnoE
la source
0

Une autre façon de penser au problème est de considérer ce qui a du sens.

Par exemple, il y avait une application que je développais qui comportait des sections qui faisaient presque la même chose mais dont les règles de permission étaient incohérentes. Comme il n'y avait aucune raison de les garder différents, lorsque j'ai refactoré cette section, je leur ai demandé de faire les autorisations de la même manière. Cela a rendu le code global plus petit, plus simple et l'interface plus cohérente.

Lorsque la direction a décidé d'autoriser d'autres personnes à accéder à une fonctionnalité, nous avons pu le faire en modifiant simplement un indicateur.

Évidemment, il est logique de procéder à la conversion de type spécifique. Est-il également judicieux d’effectuer des conversions de type additionnel?

N'oubliez pas que si la solution générale est plus rapide à mettre en œuvre, le cas particulier est également facile, vérifiez qu'il s'agit bien du seul type de conversion que vous autorisez.

Si l'application se trouve dans une zone hautement réglementée (application médicale ou financière), essayez de faire participer davantage de personnes à la conception.

Robert Baron
la source