Dangers d'une énorme application monolithique


20

Le gros projet sur lequel je travaille depuis quelques années est une application de contrôle (et tout) d'un appareil avancé, cœur de son firmware.

L'appareil est assez avancé, avec plus de fonctionnalités différentes que je pourrais dire de la mémoire, et 98% d'entre eux sont gérés par cet énorme exécutable. D'une part, le programme est assez maintenable, bien modulaire à l'intérieur, correctement documenté, il y a une séparation raisonnable des fonctionnalités par répertoires et fichiers et ainsi de suite.

Mais au final, tout est regroupé dans une seule application qui fait tout, de la communication de base de données à distance, la manipulation de l'écran tactile, la gestion d'une douzaine de protocoles de communication divers, les mesures, plusieurs algorithmes de contrôle, la capture vidéo, l'heure et la date du lever du soleil de Pâques (sérieusement, et ils sont nécessaire à des fins très sérieuses!) ... En général, les choses qui sont très peu reliées, souvent liées uniquement à certaines données qui ruissellent entre certains modules éloignés.

Cela peut se faire sous la forme de plusieurs exécutables distincts communiquant entre eux, par exemple via des sockets, dans un but plus spécifique, peut-être chargés / déchargés selon les besoins, etc. Aucune raison précise pour laquelle il est fait de cette façon.

D'une part, cela fonctionne, et cela fonctionne bien. Le projet est plus simple, sans maintenir la construction de plusieurs binaires. La structure interne est également plus facile, lorsque vous pouvez simplement appeler une méthode ou lire une variable au lieu de parler via des sockets ou de la mémoire partagée.

Mais d'un autre côté, la taille, l'échelle de cette chose me font peur, c'est comme piloter Titanic. On m'a toujours appris à modulariser, et tout regrouper dans un fichier gargantuesque me semble mal. Un problème que je connais est un plantage important d'un module (même insignifiant) qui plante tout - mais la qualité du code garantit que cela ne se produit pas vraiment dans les versions. Sinon, la séparation interne et la programmation défensive garantissent que cela fonctionnera toujours correctement, même si la moitié des modules internes échouent normalement pour une raison quelconque.

Quels autres dangers ai-je négligés? Pourquoi est-ce que ça me fait peur? Est-ce juste une peur irrationnelle de l'inconnu? Faire de gros projets sérieux de cette façon est-il une pratique acceptée? Soit calmer mes craintes ou me donner une bonne raison de refactoriser la version 2.0 en plusieurs binaires plus petits.


7
Si le soleil se lève trop tôt, l' Angleterre dérivera vers la mer.
Maxpm

1
Ou la pression dans le noyau terrestre augmente légèrement.
StuperUser

1
@Maxpm Je vois ce que vous y avez fait ... xkcd.com/687
teto

3
@Maxpm: Heureusement, notre application ne conduit pas les levers et couchers de soleil. Nous espérons que la princesse Celestia n'échouera pas dans son travail.
SF.

1
@rwong: 1. L'appareil est arrêté pour les mises à niveau. Bien qu'il survivrait aux mises à jour à la volée, nous ne voulons pas de résultats inattendus dans le cas où la mise à jour se passe mal pour une raison quelconque. 2. ARM9 monocœur avec Linux intégré. Il y a un deuxième, supervisant le CPU fonctionnant sans OS, vérifiant que le CPU principal produit une sortie saine.
SF.

Réponses:


5

À l'exception du petit commentaire à la fin (deuxième, CPU superviseur), vous pourriez décrire mon entreprise. Oui, nous avons aussi besoin de Pâques.

Eh bien, nous sommes un peu plus loin. Nous avons divisé le grand exécutable et essayé d'utiliser des composants standard pour des bits standard. Pas exactement la grande amélioration que vous espérez. En fait, les performances deviennent une difficulté majeure, même sur un matériel plus costaud. Et les coûts de maintenance n'ont pas vraiment baissé maintenant qu'il y a des tonnes de code pour sérialiser et synchroniser les données sur des interfaces étroites.

La leçon que j'ai apprise? Avoir un seul exécutable est une solution éprouvée pour les petits systèmes, et nous avons des décennies d'expérience dans sa gestion. Tous nos outils le supportent nativement. La modularité peut également être effectuée dans un seul exécutable, et lorsque vous devez faire des compromis sur la modularité pour d'autres raisons, le piratage reste faible.


Merci - aucune entrée «meilleures pratiques à suivre / sacrifiées» et «pondération des avantages potentiels par rapport aux inconvénients potentiels» n'est aussi utile qu'une personne ayant une expérience directe de l'autre côté de la clôture.
SF.

23

L'appareil est assez avancé, avec plus de fonctionnalités différentes que je pourrais dire de la mémoire, et 98% d'entre eux sont gérés par cet énorme exécutable. D'une part, le programme est assez maintenable, bien modulaire à l'intérieur, correctement documenté, il y a une séparation raisonnable des fonctionnalités par répertoires et fichiers et ainsi de suite.

Vous l'avez dit vous-même - il est assez maintenable, bien modulaire ...

À mon avis, et la plupart des membres de la direction seront d'accord avec moi sur ce point, des changements ne devraient jamais être apportés pour des raisons de changements. Il n'y a rien de mal à ce programme (votre description) à part qu'il ne suit pas les dernières tendances de programmation (qui sont mentionnées dans d'autres réponses).

Oui, c'est un programme plus vaste ... beaucoup l'ont été auparavant. Il est également bien documenté, donc tout ce que vous avez à faire est d'étudier son organisation interne et vous en verrez la logique. Je doute que tous ceux qui l'ont écrit avant vous étaient incompétents. Alors, explorez-le un peu, apprenez-le ... après cela, maintenez-le tel quel jusqu'à ce qu'une raison solide de le réécrire apparaisse. Votre manager vous sera reconnaissant d'avoir un bon rapport coût / effet.

Quels autres dangers ai-je négligés? Pourquoi est-ce que ça me fait peur? Est-ce juste une peur irrationnelle de l'inconnu? Faire de gros projets sérieux de cette façon est-il une pratique acceptée? Soit calmer mes craintes ou me donner une bonne raison de refactoriser la version 2.0 en plusieurs binaires plus petits.

Il vous fait peur parce qu'il est grand - mais encore une fois, personne ne s'attend à ce que vous appreniez tout par cœur en une semaine. Travaillez donc, morceau par morceau, petit à petit, jusqu'à ce que vous compreniez. En fin de compte, vous apprendrez qu'il est probablement bien organisé tel quel et comment il est organisé.

Si vous le réécriviez, vous accomplirez la même chose, mais en même temps, vous le ruinerez pour tous ceux qui étaient habitués à l'organisation précédente du code. De cette façon, vous seul devez vous "adapter".


16

Je me sentirais mieux si vous disiez que vous aviez tout emballé dans des tests unitaires. Si vous ne le faites pas, vous devez créer une suite de tests avant même de penser à reconcevoir l'application.

Avoir une suite de tests améliorera votre compréhension de l'application et vous dira quand un changement dans l'application casse quelque chose.


2
Mais cela s'applique aux deux architectures possibles ...
SF.

3
Oui, c'est vrai ...
Robert Harvey

10
... et donc cette réponse n'ajoute rien à la discussion sauf pour promouvoir les tests unitaires.
benzado

2
@benzado: Ce qui, dans le scénario du PO, est à peu près d'une importance capitale.
Robert Harvey

2
@ironcode: jetez un œil à un livre comme "Travailler efficacement avec le code hérité". La première chose qu'il dit dans ce livre est "Si vous n'avez pas déjà une suite de tests unitaires avec une couverture de code élevée, écrivez-les d'abord, avant de faire autre chose. " Je dirais que les conseils sont plus que pertinents ici, étant donné que le PO a spécifiquement demandé «quels autres dangers ai-je négligés».
Robert Harvey

8

Si le code est bien modulaire avec un faible couplage et une forte cohésion, il est effectivement partitionné. Les frais généraux de communication devraient être plus faibles au sein d'un même processus que ce ne serait le cas avec plusieurs processus.

Pour les systèmes embarqués, votre seul processus peut éliminer la nécessité d'implémenter un O / S pour exécuter tous les processus que vous créez. Vous devrez également implémenter un système pour vérifier que tous les processus sont en cours d'exécution et les redémarrer si possible. Si ce n'était pas possible, vous devrez réagir en conséquence.

La division du code en exécutables séparés augmenterait également la taille globale du code source car vous auriez besoin d'implémenter tout le code client / serveur entre les modules. Vous auriez également besoin de plus de cas de test pour gérer ce code, et des cas où le processus serveur n'était pas là. Les grands projets sont grands, éliminer les complexités inutiles comme cela semble avoir été fait ici permet de les garder aussi petits que possible.

Les tests sont une sorte de hareng rouge ici, car les problèmes seront toujours là avec ou sans tests. De bons tests avec l'un ou l'autre choix de conception devraient certainement être encouragés. Je m'attends à ce que les tests soient plus simples avec le code monolithique.

Forcer un crash lorsque cela est nécessaire est également plus facile avec un exécutable monolithique.


1
+1, l'ingénierie concerne les compromis, les binaires plus petits ont aussi un coût
Benzado

+1 Je suis entièrement d'accord. Aucune raison spécifique n'est donnée pour justifier plusieurs exécutables. La communication et la coordination entre les exécutables ont leur prix.
Erick Robertson

+1: Si ce n'est pas cassé, ne le réparez pas.
Bob Murphy

1

Si je devais travailler sur une si grande application monolithique, les choses qui me feraient peur sont le manque d'encapsulation, la faible cohésion, le couplage élevé et la façon de tester tout cela. Les gros monolithes sont souvent une invitation à abandonner une architecture propre et à entamer la descente dans une grosse boule de boue .

Une fois que cela se produit, les tests deviennent un cauchemar et vous êtes bien sur la voie de l'obsolescence.

Cependant, si votre code est bien structuré et bien maintenu et que les principes de haute cohésion, de faible couplage et d'encapsulation appropriée sont respectés, je ne vois pas de raison de le refactoriser en unités plus petites.

Vous voulez cependant avoir de bons tests en place.


1

Idéalement, la réponse est oui. Avoir plusieurs binaires a le potentiel de le rendre plus stable ....

... cependant, vous avez également mentionné que le code dans la base de code monolithique est bien écrit et modularisé, ce qui signifie que vous n'avez pas à faire face à un énorme gâchis enchevêtré, juste une énorme base de code ...

Dans l'ensemble, je dirais que le dicton applicable est: "Ne laissez pas le parfait être l'ennemi du bien." Bien que je pense que vous avez raison de dire qu'une base de code monolithique est mauvaise, je pense également que cela ne vaut pas la peine de s'en inquiéter.

Il serait raisonnable d'avancer en mettant de nouveaux morceaux de code dans leurs propres binaires, mais revenir en arrière et refactoriser ne vaut probablement pas la peine.


1

Si vous utilisez un seul processus, il est possible qu'un pointeur sauvage provenant de l'un de vos sous-modules endommage un morceau de mémoire critique (et bloque le tout).

Si vous utilisez différents processus, vous n'utilisez pas au moins le même tas ou la même pile d'appels et il peut également être plus facile de redémarrer un seul sous-processus.

La structure interne est également plus facile, lorsque vous pouvez simplement appeler une méthode ou lire une variable au lieu de parler via des sockets ou de la mémoire partagée.

La division de tout en plusieurs processus vous obligera également à nettoyer la conception et à éviter que chaque module ne commence à utiliser les méthodes internes des autres modules.

Cela étant dit, c'est probablement une tâche ardue.

Ce que vous pourriez commencer à faire, c'est de décider que chaque nouveau module devrait être un processus isolé.


Vous en supposez énormément sur le matériel d'exécution et l'environnement du système d'exploitation, en particulier lorsque des pare-feux et des périphériques intégrés sont impliqués.
Patrick Hughes

0

Lorsque j'arrive dans le domaine où le projet est trop grand pour tout faire d'un coup, je construis un tableau à accrocher au mur qui présente toutes les grandes sections et comment elles s'emboîtent. Ensuite, lorsque je travaille, je peux référencer le module sur lequel je me concentre et avoir un rappel visuel de la façon dont il s'intègre dans l'ensemble.

Il est tout à fait possible que la complexité et les dangers de la maintenance d'un système de génération et de versionnage pour plusieurs binaires déconnectés l'emportent de loin sur votre malaise avec un projet aussi vaste et monolithique.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.