Une autre façon de le demander est; pourquoi les programmes ont-ils tendance à être monolithiques?
Je pense à quelque chose comme un package d'animation comme Maya, que les gens utilisent pour différents workflows différents.
Si les capacités d'animation et de modélisation étaient divisées en leur propre application distincte et développées séparément, avec des fichiers transmis entre elles, ne seraient-elles pas plus faciles à maintenir?
Oui. En général, deux petites applications moins complexes sont beaucoup plus faciles à entretenir qu'une seule grande.
Cependant, vous obtenez un nouveau type de bogue lorsque les applications fonctionnent toutes ensemble pour atteindre un objectif. Afin de les faire travailler ensemble, ils doivent échanger des messages et cela orchestration peut mal tourner de différentes manières, même si chaque application peut fonctionner parfaitement. Avoir un million de petites applications a ses propres problèmes particuliers.
Une application monolithique est vraiment l'option par défaut avec laquelle vous vous retrouvez lorsque vous ajoutez de plus en plus de fonctionnalités à une seule application. C'est l'approche la plus simple lorsque vous considérez chaque fonctionnalité séparément. Ce n'est qu'une fois qu'il est devenu grand que vous pouvez regarder l'ensemble et dire "vous savez quoi, cela fonctionnerait mieux si nous séparions X et Y".
Le fractionnement d'une application potentiellement monolithique en plusieurs applications plus petites permet-il d'éviter les bogues
Les choses sont rarement aussi simples en réalité.
Le fractionnement n'aide certainement pas à éviter ces bogues en premier lieu. Cela peut parfois aider à trouver des bogues plus rapidement. Une application qui se compose de petits composants isolés peut permettre des tests plus individuels (genre de "unités" -) pour ces composants, ce qui peut parfois faciliter la détection de la cause première de certains bogues, et ainsi lui permettre de les corriger plus rapidement.
Cependant,
même une application qui semble être monolithique de l'extérieur peut se composer de beaucoup de composants testables par unité à l'intérieur, donc les tests unitaires ne sont pas nécessairement plus difficiles pour une application monolithique
comme Ewan l'a déjà mentionné, l'interaction de plusieurs composants introduit des risques et des bugs supplémentaires. Et le débogage d'un système d'application avec une communication interprocessus complexe peut être beaucoup plus difficile que le débogage d'une application à processus unique
Cela dépend également beaucoup de la capacité d'une application plus grande à se diviser en composants, de la largeur des interfaces entre les composants et de la façon dont ces interfaces sont utilisées.
En bref, c'est souvent un compromis, et rien où une réponse "oui" ou "non" est correcte en général.
pourquoi les programmes ont-ils tendance à être monolithiques
Est-ce qu'ils? Regardez autour de vous, il y a des millions d'applications Web dans le monde qui ne me semblent pas très monolithiques, bien au contraire. Il existe également de nombreux programmes disponibles qui fournissent un modèle de plugin (AFAIK même le logiciel Maya que vous avez mentionné le fait).
ne seraient-ils pas plus faciles à entretenir
La "maintenance plus facile" ici vient souvent du fait que différentes parties d'une application peuvent être développées plus facilement par différentes équipes, donc une meilleure charge de travail répartie, des équipes spécialisées avec une orientation plus claire, etc.
Je devrai être en désaccord avec la majorité sur celui-ci. Le fractionnement d'une application en deux applications distinctes ne facilite pas en soi la maintenance ou le raisonnement du code.
La séparation du code en deux exécutables modifie simplement la structure physique du code, mais ce n'est pas ce qui est important. Ce qui décide de la complexité d'une application est de savoir comment étroitement couplé les différentes parties qui la composent. Ce n'est pas une propriété physique, mais une logique une.
Vous pouvez avoir une application monolithique qui a une séparation claire des différentes préoccupations et des interfaces simples. Vous pouvez avoir une architecture de microservices qui repose sur les détails d'implémentation d'autres microservices et est étroitement couplée à toutes les autres.
Ce qui est vrai, c'est que le processus de division d'une grande application en plus petites est très utile lorsque vous essayez d'établir des interfaces et des exigences claires pour chaque partie. Dans DDD parler, cela reviendrait à vos contextes bornés. Mais que vous créiez ensuite de nombreuses applications minuscules ou une grande qui ait la même structure logique est plus une décision technique.
Plus facile à entretenir une fois que vous avez fini de les séparer, oui. Mais les diviser n'est pas toujours facile. Essayer de séparer un morceau d'un programme en une bibliothèque réutilisable révèle où les développeurs originaux n'ont pas réussi à penser où les coutures devraient être. Si une partie de l'application atteint profondément une autre partie de l'application, il peut être difficile à corriger. Extraire les coutures vous oblige à définir plus clairement les API internes, et c'est ce qui rend finalement la base de code plus facile à maintenir. La réutilisabilité et la maintenabilité sont les deux produits de coutures bien définies.
Il est important de se rappeler que la corrélation n'est pas un lien de causalité.
Construire un grand monolithe puis le diviser en plusieurs petites parties peut ou non conduire à une bonne conception. (Il peut améliorer la conception, mais ce n'est pas garanti.)
Mais une bonne conception conduit souvent à la construction d'un système en plusieurs petites pièces plutôt qu'en un grand monolithe. (Un monolithe peut être le meilleur design, il est beaucoup moins probable.)
Pourquoi les petites pièces sont-elles meilleures? Parce qu'ils sont plus faciles à raisonner. Et s'il est facile de raisonner sur l'exactitude, vous êtes plus susceptible d'obtenir un résultat correct.
Pour citer C.A.R. Hoare:
Il existe deux façons de construire une conception logicielle: l'une consiste à la rendre si simple qu'il n'y a évidemment aucune lacune, et l'autre consiste à la rendre si compliquée qu'il n'y a pas évidentes déficiences.
Si tel est le cas, pourquoi quelqu'un construirait-il une solution inutilement compliquée ou monolithique? Hoare fournit la réponse dans la toute prochaine phrase:
La première méthode est bien plus difficile.
Et plus tard dans la même source (la conférence du prix Turing de 1980):
Le prix de la fiabilité est la poursuite de la plus grande simplicité. C'est un prix que les très riches trouvent le plus difficile à payer.
Ce n'est pas une question avec une réponse oui ou non. La question n'est pas seulement la facilité d'entretien, c'est aussi une question d'utilisation efficace des compétences.
Généralement, une application monolithique bien écrite est efficace. La communication entre processus et entre appareils n'est pas bon marché. La rupture d'un seul processus diminue l'efficacité. Cependant, tout exécuter sur un seul processeur peut surcharger le processeur et ralentir les performances. Il s'agit du problème d'évolutivité de base. Lorsque le réseau entre en scène, le problème se complique.
Une application monolithique bien écrite qui peut fonctionner efficacement en tant que processus unique sur un seul serveur peut être facile à entretenir et à conserver sans défauts, mais ne constitue pas toujours une utilisation efficace des compétences de codage et d'architecture. La première étape consiste à diviser le processus en bibliothèques qui s'exécutent toujours comme le même processus, mais sont codées indépendamment, en suivant des disciplines de cohésion et de couplage lâche. Un bon travail à ce niveau améliore la maintenabilité et affecte rarement les performances.
L'étape suivante consiste à diviser le monolithe en processus séparés. C'est plus difficile car vous entrez en territoire difficile. Il est facile d'introduire des erreurs de conditions de concurrence. Les frais généraux de communication augmentent et vous devez faire attention aux "interfaces bavardes". Les récompenses sont grandes parce que vous brisez une barrière d'évolutivité, mais le potentiel de défauts augmente également. Les applications multi-processus sont plus faciles à maintenir au niveau du module, mais le système global est plus compliqué et plus difficile à dépanner. Les corrections peuvent être diaboliquement compliquées.
Lorsque les processus sont distribués sur des serveurs séparés ou sur une implémentation de style cloud, les problèmes deviennent plus difficiles et les récompenses plus importantes. L'évolutivité monte en flèche. (Si vous envisagez une implémentation cloud qui ne produit pas d'évolutivité, réfléchissez bien.) Mais les problèmes qui surviennent à ce stade peuvent être incroyablement difficiles à identifier et à réfléchir.
Non. il ne facilite pas l'entretien. Si quoi que ce soit bienvenue à plus de problèmes.
Pourquoi?
Vous avez maintenant deux produits qui nécessitent:
Vous avez maintenant trois marchés de consommation: les modélisateurs, les animateurs et les modélisateurs animateurs
Cela étant dit, des bases de code plus petites sont plus faciles à maintenir au niveau de l'application, vous n'allez tout simplement pas obtenir un déjeuner gratuit. C'est le même problème au cœur de Micro-Service/Any-Modular-Architecture. Ce n'est pas une panacée, les difficultés de maintenance au niveau de l'application sont échangées contre des difficultés de maintenance au niveau de l'orchestration. Ces problèmes sont toujours des problèmes, ils ne sont tout simplement plus dans la base de code, ils devront être soit évités, soit résolus.
Si la résolution du problème au niveau de l'orchestration est plus simple que sa résolution à chaque niveau d'application, il est logique de le diviser en deux bases de code et de traiter les problèmes d'orchestration.
Sinon non, ne le faites pas, vous seriez mieux servi en améliorant la modularité interne de l'application elle-même. Transférer des sections de code dans des bibliothèques cohérentes et plus faciles à gérer que l'application agit comme un plugin. Après tout, un monolithe n'est que la couche d'orchestration d'un paysage de bibliothèque.
Il y a eu beaucoup de bonnes réponses, mais comme il y a presque une scission morte, je vais aussi jeter mon chapeau sur le ring.
D'après mon expérience en tant qu'ingénieur logiciel, j'ai trouvé que ce n'était pas un problème simple. Cela dépend vraiment de taille, échelle et but de l'application. Les applications plus anciennes, en raison de l'inertie nécessaire pour les changer, sont généralement monolithiques car c'était une pratique courante pendant longtemps (Maya serait admissible dans cette catégorie). Je suppose que vous parlez des nouvelles applications en général.
Dans les applications suffisamment petites qui sont plus ou moins simples, le surcoût requis pour maintenir de nombreuses pièces séparées dépasse généralement l'utilité de la séparation. S'il peut être entretenu par une seule personne, il peut probablement être rendu monolithique sans causer trop de problèmes. L'exception à cette règle est lorsque vous avez de nombreuses parties différentes (un frontend, un backend, peut-être quelques couches de données entre les deux) qui sont commodément séparées (logiquement).
Dans de très grandes applications, même pour une seule préoccupation, le fractionnement est logique selon mon expérience. Vous avez l'avantage de réduire un sous-ensemble de la classe de bogues possible en échange d'autres bogues (parfois plus faciles à résoudre). En général, vous pouvez également avoir des équipes de personnes travaillant isolément, ce qui améliore la productivité. De nos jours, de nombreuses applications sont cependant divisées assez finement, parfois à leur détriment. J'ai également fait partie d'équipes où l'application a été répartie sur tellement de microservices inutilement qu'elle a introduit beaucoup de frais généraux lorsque les choses cessent de se parler. De plus, le fait d'avoir à posséder toutes les connaissances sur la façon dont chaque partie communique avec les autres parties devient beaucoup plus difficile à chaque division successive. Il y a un équilibre, et comme vous pouvez le voir par les réponses ici, la façon de le faire n'est pas très claire, et il n'y a vraiment pas de norme en place.
Pour les applications d'interface utilisateur, il est peu probable que le nombre total de bogues diminue, mais l'équilibre du mélange de bogues vers les problèmes causés par la communication sera modifié.
Parlant d'applications/sites d'interface utilisateur - les utilisateurs sont extrêmement peu patients et exigent un temps de réponse faible. Cela fait de tout retard de communication un bogue. En conséquence, on échangera une diminution potentielle des bogues en raison de la complexité réduite d'un seul composant avec des bogues très durs et des délais de communication inter-processus/inter-machine.
Si les unités de données traitées par le programme sont volumineuses (c'est-à-dire des images), les retards inter-processus seraient plus longs et plus difficiles à éliminer - quelque chose comme "appliquer la transformation à une image de 10 Mo" gagnera instantanément + 20 Mo de disque/réseau IO en plus de 2 conversions du format en mémoire au format serializabe et inversement. Il n'y a vraiment pas grand-chose que vous puissiez faire pour cacher le temps nécessaire à l'utilisateur.
De plus, toute communication et en particulier le disque IO est soumis aux vérifications AntiVirus/Firewall - cela ajoute inévitablement une autre couche de bogues difficiles à reproduire et encore plus de retards.
Le fractionnement du "programme" monolithique brille là où les retards de communication ne sont pas critiques ou déjà inévitables
Notez que cela s'applique aux applications de bureau ainsi qu'aux sites Web - la partie utilisateur du programme a tendance à être "monolithique" - tout le code d'interaction utilisateur lié à une seule donnée est généralement exécuté en un seul processus (il n'est pas inhabituel de fractionner processus sur une base de données comme une page HTML ou une image mais elle est orthogonale à cette question). Même pour la plupart des sites de base avec une entrée utilisateur, vous verrez une logique de validation s'exécuter du côté client, même si le rendre côté serveur serait plus modulaire et réduirait la complexité/duplication de code.
Est-ce que cela aide à prévenir les bogues?
Prévenir? Eh bien non, pas vraiment.
Je ne dirais donc pas que vous empêchez les bogues simplement en cassant une application monolithique en composants plus petits, mais vous facilitez en effet d'atteindre un point où les bogues peuvent être plus facilement évités.