Choses à considérer lors de la construction d’un cadre

Nous prévoyons de créer un cadre: un cadre d’estimation des coûts qui sera utilisé dans tous les domaines de notre organisation.

L’exigence de haut niveau ressemble à ceci: si je développe un certain produit, combien cela me coûtera-t-il? Ce coût généré sera utilisé pour comparer avec le coût indiqué par les fournisseurs et pour décider quel fournisseur choisir.

Ma question est la suivante: quels éléments faut-il prendre en compte lors de l’élaboration d’un cadre?

Peu de mes pensées:

  1. Implémenter les exigences de haut niveau via les classes abstraites et les interfaces
  2. Fournissez des classes d’utilitaires pouvant être utiles aux utilisateurs de Framework.
  3. Considérez ce qui devrait être interne – type de métadonnées – qui ne devrait pas être montré aux utilisateurs du framework.
  4. Les modèles de conception à utiliser comme modèle.
  5. les propriétés et les méthodes des classes d’entrée.

Quelques idées:

  • Il est plus facile d’append des fonctionnalités utiles plus tard que de supprimer des fonctionnalités qui se sont révélées mal conçues ou nuisibles.
  • Concevoir ou interdire l’inheritance: l’inheritance introduit une couche supplémentaire de complexité, car vous devez définir les interactions entre les superclasses et les sous-classes. Cela ne veut pas dire que c’est mal, mais cela devrait être très soigneusement considéré.
  • D’après mon expérience, les interfaces sont généralement plus propres que les classes abstraites, car elles favorisent la composition plutôt que l’inheritance.
  • Pour les interfaces, documentez à la fois les attentes de l’appelant et celles de l’implémenteur . En gros, pensez au contrat des deux côtés et documentez-le. En particulier, les contraintes de nullité du document – les méthodes doivent-elles accepter null ou non? Devraient-ils garantir qu’ils ne retourneront jamais null?
  • Concevez pour la testabilité, à la fois pour votre framework et pour les autres utilisant votre framework. Quels éléments de la structure peuvent raisonnablement être utilisés dans le code de test et lesquels doivent être simulés?
  • Utilisez votre propre cadre, dès le début. Générez un exemple d’application que d’autres peuvent utiliser pour comprendre le cadre.

Certains des conseils ci-dessous varient selon que vous construisez un cadre ssortingctement destiné à un usage interne par une petite équipe sur un nombre limité de projets ou que vous construisez quelque chose destiné à de nombreux développeurs anonymes. De plus, gardez à l’esprit que tout dépend de la taille de votre framework et de son étendue. Certains de mes conseils ne s’appliquent vraiment qu’aux frameworks plus vastes et polyvalents.

Conseil général

  • Prenez le temps de parler à certains des développeurs qui utiliseront votre framework. Assurez-vous de bien comprendre ce qui sera utile et ce qui ne le sera pas.
  • Prenez le temps de vous assurer que l’abstraction que vous créez est compréhensible et intuitive pour vos futurs utilisateurs.
  • Sauf si vous construisez quelque chose d’unique et de révolutionnaire, prenez le temps de regarder les autres frameworks existant dans votre domaine . Évitez leurs erreurs, mais n’ayez pas peur d’emprunter des concepts couronnés de succès… tout n’a pas à être inventé par vous.
  • Produire de la documentation – à la fois sous la forme de documents d’API formels et d’un exemple de code. Si les gens ne comprennent pas comment appliquer votre framework, cela ne réussira pas.
  • Nommez les choses clairement mais de manière concise. C’est probablement l’une des tâches les plus difficiles pour les développeurs d’infrastructure – en particulier lors de l’implémentation de concepts abstraits ou généralisés. Parlez aux gens avant de choisir un nom. Certains noms ont plusieurs significations et peuvent être interprétés différemment de ceux auxquels vous vous attendiez.
  • Envisagez de rendre votre infrastructure compatible avec d’autres infrastructures de bas niveau (comme celles pour la journalisation, la simulation et l’dependency injection). Cela rendra vos utilisateurs heureux et réduira les obstacles à l’adoption.
  • Investissez dans de bons tests unitaires. Les frameworks ont généralement une grande surface avec laquelle les utilisateurs peuvent interagir … nombreuses classes, nombreuses méthodes, dérivation, implémentations d’interface. Sans une capacité de test de régression rapide, les frameworks peuvent rapidement dépasser un niveau où ils peuvent être maintenus.
  • Gardez vos interfaces publiques étroites et petites. Gardez à l’esprit le principe de responsabilité unique lors de la conception de fonctionnalités dans un cadre … c’est vraiment important à ce niveau.

Conseil de conception

  • Concevoir et tester le parallélisme. De nos jours, la plupart des frameworks sont utilisés pour créer des applications avec une activité de parallel processing (et souvent importante). Les frameworks destinés à être utilisés dans les applications Web, en particulier, nécessitent une reflection approfondie sur la manière dont l’access multithread les affectera. Voici quelques principes généraux que je suis:
    • Évitez les verrous lorsque cela est possible. Lorsque cela n’est pas possible, utilisez des objects de locking explicites plutôt que des instructions .NET lock (…).
    • Utilisez les verrous Reader / Writer pour les objects partagés lus plus souvent qu’écrits.
  • Fonctionnalité de conception en couches. Cela aide non seulement les fonctionnalités à découpler, mais permet également aux utilisateurs d’utiliser plus facilement la partie de leur infrastructure dont ils ont réellement besoin.
  • Pour les frameworks destinés à être utilisés avec .NET 2.0 et versions ultérieures, utilisez des collections génériques! Il est extrêmement difficile de raisonner sur ce qui est stocké dans un object [], ArrayList ou Hashtable … surtout dans un cadre large où de telles collections sont transmises en interne.
  • Évitez d’utiliser object ou object [] dans l’interface publique … c’est un problème dans un cadre et une cause majeure de bugs et de problèmes de maintenabilité. Vous pouvez presque toujours trouver une interface ou utiliser des génériques à la place de celle-ci. Dans ces rares cas, vous ne pouvez pas documenter exactement ce que vous attendez d’être transmis ou non … et revendiquez-le.
  • Préférez l’agrégation à l’inheritance. Bien que l’inheritance soit un concept utile et puissant, les auteurs du framework en abusent souvent ou en abusent. Réfléchissez bien pour savoir si l’inheritance est vraiment le bon outil pour résoudre un problème de conception.
  • Évitez les transformations de type et les vérifications de type à l’exécution lorsque cela est possible. Ce sont généralement une odeur de design dans mon expérience. Un lot de casting indique que vous ne tirez pas pleinement parti des interfaces, des génériques ou des contraintes génériques. Cela peut entraîner des bugs et de la confusion chez les développeurs quant à l’utilisation de votre infrastructure.
  • Permettre aux appelants d’injecter des fonctionnalités en utilisant des stratégies lorsque cela est possible. L’inheritance est excessif pour certains types de spécialisation. Étant donné que les fonctions de support deviennent des citoyens de l’écologie .NET, vous devriez envisager de les utiliser (sous forme de lambdas ou de delegates) pour permettre aux consommateurs de spécialiser les fonctionnalités que vous proposez.

Conseil de mise en oeuvre

  • Évitez les propriétés dont les getters produisent des effets secondaires. Parfois, cela est inévitable (tels que les getters qui effectuent la mise en cache interne ou instancient des objects paresseux). Cependant, selon mon expérience, les getters avec effets secondaires (en particulier dans le code de niveau cadre) constituent le moyen le plus rapide de présenter heisenbugs et de faire maudire votre nom par les utilisateurs lors du débogage.
  • Si possible, rendez les petits objects transitoires immuables. Appliquez-le à l’aide du mot clé readonly (ou équivalent) dans la langue. Les avantages de l’immutabilité sont énormes – et dans .NET (où les coûts d’atsortingbution sont réduits), ce n’est pas aussi coûteux que vous pourriez le penser.
  • Utilisez l’ auto-encapsulation lorsque cela est possible. Cette technique permet d’éviter les bogues et simplifie le refactoring en évitant des sémantiques d’access différentes aux données pour les appelants internes et externes.
  • Évitez les nombres magiques et les constantes codées en dur. Un framework est un type de code où il est très difficile d’anticiper les besoins exacts de vos utilisateurs. Laissez une certaine souplesse en utilisant la configuration plutôt que les constantes intégrées.
  • Gardez le nombre de parameters aux méthodes petit (moins de 7). Lorsque vous devez transmettre de nombreux parameters, envisagez de créer un object de données léger pour prendre en charge la méthode.
  • Préférez les méthodes génériques aux surcharges multiples de méthodes pour différents types. Laissez le langage et le compilateur faire le travail lorsque cela est possible. Cela permet également à votre code d’être plus flexible et utile. Examinez la conception de LINQ pour savoir comment cela fonctionne dans la pratique.

Voici comment je procéderais:

  1. Faites une conception large et de haut niveau – par exemple, une application Web ou un client lourd, existe-t-il un niveau intermédiaire, comment l’interaction de la firebase database aura-t-elle lieu, quelles API / technologies seront utilisées, etc.
  2. choisissez une fonctionnalité qui vous permettra de coder tous les niveaux de l’application (ce que l’on appelle communément une pointe).
  3. implémentez le ssortingct minimum pour que cette fonctionnalité fonctionne ( test d’implémentation, simplexe ) avec des tests pour prouver que cela fonctionne.
  4. choisissez une autre fonction goto 3 (refactoring si nécessaire).

J’ai toujours trouvé que cette façon de travailler faisait évoluer le système et que faire fonctionner quelque chose centrait votre dessin sur l’essentiel (plutôt que sur les fantasmes possibles avec les dessins sur papier).

Et je pensais que l’agiliste en moi était parti 😉

Outre les conseils généraux en matière de programmation, il convient de se pencher sur certaines des bases de la théorie de la conception de framework logiciel. Pour commencer, examinez le concept de “points chauds” et de “points gelés”. Bien que cela puisse ne pas sembler utile immédiatement, il est bon de l’avoir à l’esprit pendant le développement.

Comme toujours, wikipedia est un bon sharepoint départ:

http://en.wikipedia.org/wiki/Software_framework

Aussi un bon résumé ici:

http://www.acm.org/crossroads/xrds7-4/frameworks.html

Si vous voulez aller plus loin, jetez un coup d’œil aux citations dans ces deux articles.

Utiliser des interfaces dans les contrats d’API. Cela vous permet de garder les détails en désordre complètement découplés et de les décorer facilement si nécessaire. (Il suffit de voir les propriétés qui sont des cartes finement déguisées).

Un très bon conseil est d’utiliser Test Driven Design – c’est-à-dire d’écrire le test EN PREMIER, puis la mise en œuvre. Cela vous oblige à penser comme les utilisateurs plutôt que le concepteur, ce qui conduira éventuellement à une meilleure API.