Une bibliothèque commune est-elle une bonne idée?

16

J'ai toujours pensé qu'une "bibliothèque commune" était une bonne idée. J'entends par là une bibliothèque qui contient les fonctionnalités communes qui sont souvent nécessaires à quelques applications différentes. Il en résulte moins de duplication / redondance de code.

J'ai récemment lu un article (impossible à trouver maintenant) qui disait que c'était en fait une mauvaise idée et suis allé jusqu'à dire que c'était un "anti-pattern"

Bien qu'il y ait des avantages à cette approche. Le contrôle de version et la gestion des modifications signifient un test de régression pour la suite d'applications qui utilisent cette bibliothèque.

Je suis un peu coincé dans une ornière pour mon nouveau projet (Golang). La déduplication du code a été martelée en moi au fil des ans, mais je pense que je devrais l'essayer cette fois-ci.

En écrivant ceci, je commence à penser que cette approche "lib commun" est le résultat d'un écrémage sur l'architecture? Peut-être que mon design a besoin de plus de réflexion?

Intéressé à entendre des pensées.

Jim
la source
2
Mes 2 cents ... Si vous devez apporter des modifications à une API commune si l'un des systèmes l'utilise, il faut que cette modification, alors cette API ou cette bibliothèque n'est pas du tout une bibliothèque commune
Raja Anbazhagan
1
Je trouve qu'il y a un compromis fondamental entre la duplication de code et le couplage. Votre question en est un excellent exemple. L'équilibre que vous établissez entre les deux dépendra probablement de l'environnement dans lequel votre code s'exécutera finalement.
Joel Cornett
La plupart des développeurs C que je connais ont une collection d'utilitaires qu'ils appellent leur "boîte à outils". Cependant, il n'est généralement pas collecté dans une seule bibliothèque inclus. C'est plus "choisir et choisir".
Mark Benningfield
2
Quelqu'un appelle Apache et corrige cette folie. Apache commons
Laiv

Réponses:

21

Les bibliothèques et la réutilisation sont absolument une bonne chose. Ils ont un inconvénient géant, c'est que s'ils ne sont pas gérés avec soin, ils deviennent l'équivalent du tiroir de votre cuisine qui détient toutes les chances qui ne vont nulle part ailleurs.

Je l'ai vu en action lorsque je suis devenu responsable des premiers ports de la valeur de code d'une unité commerciale entière (principalement nouvelle pour moi) vers des systèmes 64 bits et en faisant une refonte complète de notre construction et de notre emballage, dont une grande partie était en cours. à la main et parfois pas très bien. * Nous avons eu tendance à construire ce que nous avons expédié à partir d'une pile d'applications, où le client disait: «J'aimerais un système qui fait A, B, D et F, plus les choses M et N que vous ne faites pas encore et une colle légèrement différente en les intégrant tous. " Ce que tout cela avait en commun était une bibliothèque de tiroir-poubelle qui avait, au cours des deux dernières décennies, ** accumulé tout ce que les gens pensaient être réutilisable. Pour faire court, une fraction du code de la bibliothèque n'était pas. Nous passions beaucoup de temps à construire et à maintenir ces dépendances juste pour que la bibliothèque commune s'installe, pas parce que nous en avions réellement besoin.

La morale est que les bibliothèques doivent être traitées comme des classes et non surchargées de trop de responsabilités. Ne placez pas votre analyseur JSON dans la même bibliothèque avec vos fonctions d'algèbre linéaire même si chaque programme que vous écrivez utilise les deux.

Les garder discrets présente de nombreux avantages, dont le plus important est qu'ils obligent vos développeurs et packageurs à établir une comptabilité détaillée de ce dont leurs propres produits ont réellement besoin au lieu de simplement inclure le tiroir à ordures et les bagages qui l'accompagnent. Lorsque vous configurez un système à l'aide des packages intégrés, les dépendances à granularité fine garantissent que seules les pièces nécessaires sont installées. Même si vous négligez votre référentiel et continuez à compiler les vieux trucs cruels, rien de ce qui n'est plus utilisé ne fuit dans ce que vous expédiez.

Il y a, bien sûr, des exceptions telles que libccelle qui rassemble un tas de fonctions dans une seule bibliothèque. C'est l'un des cas où les avantages de le faire de cette façon peuvent être raisonnés au lieu de tenir aveuglément le fanatique dans le couloir, qui insiste sur le fait que toute autre manière que X est toujours une mauvaise pratique.


* Dans le processus, j'ai découvert un binaire qui avait été distribué et qui n'avait pas été recompilé à partir de zéro en six ans.

** Il n'y a rien de mal avec un code vieux de plusieurs décennies. Nous avions un certain nombre d'algorithmes critiques qui avaient été si bien prouvés que nous aurions été idiots de les réécrire uniquement dans l'intérêt de la modernité.

Blrfl
la source
1
Ma règle d'or est que si vous avez l'intention de nommer votre bibliothèque quelque chose comme "commun", vous vous dirigez vers des ennuis.
Karl Bielefeldt
9

Embarrassant, j'ai introduit une bibliothèque "commune", nommée ainsi, dans un environnement d'équipe il y a quelques décennies. À l'époque, je ne comprenais pas vraiment la dynamique de ce qui pouvait se produire dans une équipe mal coordonnée en quelques mois seulement.

Quand je l'ai présenté, je pensais l'avoir précisé et documenté également que c'est pour des choses que nous serions tous d'accord que nous trouvons utiles au quotidien, qu'elle est destinée à être une bibliothèque minimaliste et que la bibliothèque ne devrait dépendre de rien d'autre que de la bibliothèque standard pour un déploiement aussi simple que possible dans les nouveaux projets. À l'époque, je pensais que c'était notre propre petite extension de la bibliothèque standard pour des choses que, dans notre domaine particulier, nous trouvions utiles au quotidien.

Et ça a commencé assez bien. Nous avons commencé avec une bibliothèque mathématique ( common/math*) de routines que nous utilisions tous quotidiennement, car nous travaillions en infographie souvent lourde sur l'algèbre linéaire. Et comme nous interopérions souvent avec du code C, nous nous sommes mis d'accord sur certaines fonctions utilitaires utiles find_indexqui, contrairement àstd::finden C ++, retournerait un index à un élément trouvé dans une séquence au lieu d'un itérateur qui imite le fonctionnement de nos fonctions C - des choses de ce genre - un peu éclectique mais minimaliste et largement utilisé pour rester familier et pratique pour tout le monde , et la familiarité instantanée est un critère extrêmement important tel que je le vois en essayant de faire tout ce qui est "commun" ou "standard" car s'il est vraiment "commun", il devrait avoir cette qualité familière à cause de sa large adoption et usage quotidien.

Mais au fil du temps, les intentions de conception de la bibliothèque m'ont échappé lorsque les gens ont commencé à ajouter des choses qu'ils utilisaient personnellement qu'ils pensaient simplement être utiles à quelqu'un d'autre, pour ne trouver personne d'autre l'utilisant. Et plus tard, quelqu'un a commencé à ajouter des fonctions qui dépendaient d'OpenGL pour les routines courantes liées à GL. Plus loin, nous avons adopté Qt et les gens ont commencé à ajouter du code qui dépendait de Qt, donc déjà la bibliothèque commune dépendait de deux bibliothèques externes. À un moment donné, quelqu'un a ajouté des routines de shader communes qui dépendaient de notre bibliothèque de shaders spécifique à l'application, et à ce moment-là, vous ne pouviez même pas le déployer dans un nouveau projet sans apporter Qt, OGL, et notre bibliothèque de shader spécifique à l'application et écrire un script de construction non trivial pour votre projet. Il s'est donc transformé en ce gâchis éclectique et interdépendant.

Mais j'ai également découvert en débattant de ce qui devrait et ne devrait pas entrer dans cette bibliothèque que ce qui est considéré comme "commun" peut facilement se transformer en une idée très subjective si vous ne définissez pas une règle de ligne très stricte selon laquelle ce qui est "commun" est ce que tout le monde a tendance à trouver utile au quotidien. Tout relâchement des normes et il se dégrade rapidement des choses que tout le monde trouve utiles au quotidien à quelque chose qu'un développeur unique trouve utile qui pourrait avoir la possibilité d'être bénéfique pour quelqu'un d'autre, et à ce moment-là, la bibliothèque se dégrade en un gâchis éclectique très rapidement .

Mais en outre, lorsque vous atteignez ce point, certains développeurs peuvent commencer à ajouter des choses pour la simple raison qu'ils n'aiment pas le langage de programmation. Ils pourraient ne pas aimer la syntaxe d'une boucle for ou d'un appel de fonction, à quel point la bibliothèque commence à se remplir de choses qui ne font que combattre la syntaxe fondamentale du langage, remplaçant quelques lignes de code simple qui n'est pas vraiment duplication de toute logique vers une seule ligne laconique de code exotique familier au développeur qui a introduit un tel raccourci. Un tel développeur pourrait alors commencer à ajouter plus de fonctionnalités à la bibliothèque commune implémentée à l'aide de tels raccourcis, À ce stade, des sections importantes de la bibliothèque commune deviennent entrelacées avec ces raccourcis exotiques qui peuvent sembler beaux et intuitifs pour le développeur qui les a présentés, mais laids et étrangers et difficiles à comprendre pour tout le monde. Et à ce stade, je pense que vous savez que tout espoir de faire quelque chose de vraiment «commun» est perdu, car «commun» et «inconnu» sont des idées polaires opposées.

Il y a donc toutes sortes de boîtes de vers là-bas, au moins dans un environnement d'équipe peu coordonné, avec une bibliothèque avec des ambitions aussi larges et aussi généralisées que des "trucs couramment utilisés". Et bien que le problème sous-jacent ait pu être la coordination lâche par-dessus tout, au moins plusieurs bibliothèques destinées à servir un objectif plus singulier, comme une bibliothèque destinée à fournir des routines mathématiques et rien d'autre, ne se dégraderaient probablement pas de manière aussi significative en termes de concevoir la pureté et les dépendances comme une bibliothèque "commune". Donc, rétrospectivement, je pense qu'il serait beaucoup mieux de se tromper du côté des bibliothèques qui ont des intentions de conception beaucoup plus claires. J'ai également constaté au fil des ans que le but et l'applicabilité sont des idées radicalement différentes.

De plus, je suis certes au moins un peu impraticable et me soucie peut-être un peu trop de l'esthétique, mais la façon dont j'ai tendance à percevoir mon idée de la qualité d'une bibliothèque (et peut-être même de la "beauté") est jugée davantage par son maillon le plus faible que C'est le plus fort, de la même manière que si vous me présentiez la nourriture la plus appétissante du monde mais, dans la même assiette, y mettez quelque chose de pourri qui sent vraiment mauvais, j'ai tendance à vouloir rejeter toute l'assiette. Et si vous êtes comme moi à cet égard et que vous faites quelque chose qui invite toutes sortes d'ajouts comme quelque chose appelé "commun", vous pourriez vous retrouver à regarder cette plaque analogique avec quelque chose de pourri sur le côté. Donc, de même, je pense que c'est bien si une bibliothèque est organisée, nommée et documentée d'une manière telle qu'elle ne fonctionne pas. t inviter de plus en plus et plus d'ajouts au fil du temps. Et cela peut même s'appliquer à vos créations personnelles, car j'ai certainement créé des trucs pourris ici et là, et ça "tache" beaucoup moins si ce n'est pas ajouté à la plus grande assiette. Séparer les choses en petites bibliothèques très singulières a également tendance à mieux découpler le code, ne serait-ce que par la simple vertu qu'il devient beaucoup moins pratique de commencer à tout coupler.

La déduplication du code a été martelée en moi au fil des ans, mais je pense que je devrais l'essayer cette fois-ci.

Ce que je pourrais suggérer dans votre cas, c'est de commencer à vous détendre sur la déduplication de code. Je ne dis pas de copier et coller de gros extraits de code mal testé et sujet aux erreurs ou quoi que ce soit de ce genre, ou de dupliquer d'énormes quantités de code non trivial qui ont une probabilité décente d'exiger des modifications à l'avenir.

Mais surtout si vous êtes d'humeur à créer une bibliothèque "commune", pour laquelle je suppose que votre désir est de créer quelque chose de largement applicable, hautement réutilisable, et peut-être idéalement quelque chose que vous trouvez tout aussi utile aujourd'hui que vous le feriez dans une décennie. , alors parfois vous pourriez même avoir besoin ou vouloir une duplication pour atteindre cette qualité insaisissable. Parce que la duplication pourrait en fait servir de mécanisme de découplage. C'est comme si vous voulez séparer un lecteur vidéo d'un lecteur MP3, alors vous devez au moins dupliquer certaines choses comme les piles et les disques durs. Ils ne peuvent pas partager ces choses ou bien ils sont couplés de manière indivisible et ne peuvent pas être utilisés indépendamment les uns des autres, et à ce stade, les gens pourraient ne plus être intéressés par l'appareil s'ils ne veulent que lire des MP3. Mais quelque temps après avoir séparé ces deux appareils, vous pourriez constater que le lecteur MP3 peut bénéficier d'une conception de batterie différente ou d'un disque dur plus petit que le lecteur vidéo, auquel cas vous ne dupliquez plus rien; ce qui a commencé au départ comme une duplication pour permettre à ce périphérique interdépendant de se diviser en deux périphériques distincts et indépendants pourrait s'avérer plus tard produire des conceptions et des implémentations qui ne sont plus du tout redondantes.

Cela vaut la peine de considérer les choses du point de vue de celui qui utilise une bibliothèque. Souhaitez-vous réellement utiliserune bibliothèque qui minimise la duplication de code? Il y a de fortes chances que vous ne le fassiez pas car celui qui en dépend dépendra naturellement d'autres bibliothèques. Et ces autres bibliothèques peuvent dépendre d'autres bibliothèques pour éviter de dupliquer leur code, et ainsi de suite, jusqu'à ce que vous ayez besoin d'importer / lier 50 bibliothèques différentes pour simplement obtenir des fonctionnalités de base comme le chargement et la lecture d'un fichier audio, et cela devient très lourd . Pendant ce temps, si une telle bibliothèque audio choisit délibérément de dupliquer certaines choses ici et là pour atteindre son indépendance, elle devient tellement plus facile à utiliser dans de nouveaux projets, et il est probable qu'elle n'aura pas besoin d'être mise à jour presque aussi souvent depuis qu'elle a gagné. t besoin de changer à la suite du changement d'une de ses bibliothèques externes dépendantes qui pourrait essayer de remplir un objectif beaucoup plus généralisé que ce dont la bibliothèque audio a besoin.

Donc, parfois, il vaut la peine de choisir délibérément de dupliquer un peu (consciemment, jamais par paresse - en fait par diligence) afin de découpler une bibliothèque et de la rendre indépendante parce que, grâce à cette indépendance, elle atteint un plus large éventail d'applicabilité pratique et même stabilité (plus de couplages afférents). Si vous souhaitez concevoir les bibliothèques les plus réutilisables possibles qui vous dureront d'un projet à l'autre et au fil des ans, alors en plus de restreindre sa portée au minimum, je suggère en fait d'envisager de dupliquer un peu ici. Et naturellement, écrivez des tests unitaires et assurez-vous qu'il est vraiment minutieusement testé et fiable dans ce qu'il fait. C'est uniquement pour les bibliothèques que vous voulez vraiment prendre le temps de généraliser à un point qui va bien au-delà d'un seul projet.


la source
3

Il existe trois catégories différentes de fonctions que vous pourriez envisager de mettre dans les bibliothèques:

  1. Des trucs qui valent la peine d'être réutilisés pour tout le monde.
  2. Des trucs qui ne valent la peine d'être réutilisés que pour votre organisation.
  3. Les choses ne valent pas la peine d'être réutilisées.

La première catégorie est quelque chose pour laquelle une bibliothèque standard devrait exister, mais pour une raison quelconque, personne n'a réussi à en créer une (ou quelqu'un a-t-il fait une recherche approfondie?). Dans ce cas, envisagez de rendre votre bibliothèque open source. Le partage de votre travail n'aide pas seulement les autres, il vous aide également, car vous recevrez des rapports de bogues et des correctifs d'autres utilisateurs. Lorsque vous doutez que quelqu'un puisse contribuer à votre bibliothèque, vous avez peut-être affaire à des fonctionnalités de catégorie 2 ou 3.

La deuxième catégorie comprend les choses dont vous avez besoin à maintes reprises, mais personne d'autre au monde n'en a besoin. Par exemple, la mise en œuvre du protocole réseau obscur pour communiquer avec votre système backend développé en interne. Dans ce cas, il pourrait être judicieux de mettre ces éléments dans une bibliothèque interne pour améliorer la vitesse de développement de nouvelles applications. Assurez-vous simplement qu'il ne soit pas trop affecté par le fluage des fonctionnalités et commence à contenir des éléments qui correspondent réellement aux catégories 1 ou 3. En outre, les conseils de Blrfl concernant la modularisation sont très bons: ne créez pas une bibliothèque monolithique Conor Corp. Créez plusieurs bibliothèques distinctes pour des fonctionnalités distinctes.

La catégorie trois est une fonctionnalité qui est si triviale à implémenter que le déplacer vers une bibliothèque n'en vaut pas la peine ou lorsque vous n'êtes pas sûr d'en avoir besoin à nouveau exactement sous cette forme dans une autre application. Cette fonctionnalité doit rester intégrée à l'application pour laquelle elle a été développée. En cas de doute, il appartient probablement à cette catégorie.

Philipp
la source
1

Presque toutes les langues ont une bibliothèque commune / standard, c'est donc largement reconnu comme une bonne idée. L'utilisation de bibliothèques en tiers pour diverses tâches plutôt que de réinventer la roue est également généralement considérée comme une bonne idée, bien que le rapport coût / bénéfice et la qualité de la bibliothèque doivent évidemment être évalués dans chaque cas.

Ensuite, il y a les bibliothèques «utilitaires communs» utilisées par un développeur individuel ou une institution pour des projets qui ne sont pas liés par ailleurs. C'est le genre de bibliothèque qui pourrait être considérée comme un anti-modèle. Dans le cas que j'ai vu, ces bibliothèques reproduisent simplement les fonctionnalités des bibliothèques standard ou des bibliothèques tierces plus connues d'une manière non standard et mal documentée.

JacquesB
la source
these libraries just replicate functionality from standard librariesce n'est pas entièrement une mauvaise chose, en javascript vous avez ajouté des bibliothèques qui implémentent déjà des choses existantes pour ajouter du support sur les anciens moteurs js, vous avez également des bibliothèques de support android pour les anciens sdk, etc.
svarog
@svarog: Pensez-vous à des "polyfills" qui émulent des fonctionnalités dans de nouvelles normes pour des moteurs plus anciens qui ne les prennent pas en charge nativement? Je ne vois aucune raison de les écrire vous-même, car il existe des bibliothèques open source bien connues disponibles à ces fins.
JacquesB
0

La plupart des bibliothèques partagées entre les équipes posent plus de problèmes qu'elles n'en résolvent. "La route de l'enfer est pavée de bonnes intentions."

Les exceptions sont les bibliothèques qui satisfont la plupart des éléments ci-dessous:

  • Avoir un financement de maintenance à long terme sûr
  • Avoir une équipe / communauté de support dédiée
  • Avoir un bugtracker
  • Avoir une couverture de test étendue
  • Avoir un but unique et bien défini
  • N'ont pas de dépendances elles-mêmes (à la fois lors de la construction et de l'exécution), autres que les bibliothèques standard ou quasi standard
  • Ayez une nette distinction entre les API publiques et les internes
  • Avoir un canal de communication et un processus permettant à tous / à de nombreux utilisateurs de convenir de nouvelles fonctionnalités et versions

Dans les entreprises typiques (hors démarrage), presque aucune des conditions ci-dessus n'est présente pour les bibliothèques partagées entre les équipes. En effet, la plupart des équipes de l'entreprise sont payées pour livrer des produits, pas des bibliothèques. Certaines entreprises ont des stratégies de partage réussies, comme le monorepo de Google, mais cela s'accompagne d'investissements très élevés dans la construction et les tests d'infrastructure.

tkruse
la source