| Accueil >> Varia >> Génie logiciel

Boum, sur les foufounes!

1) Introduction

Nous avons tous vu à la télévision une patineuse artistique manquer son coup et tomber sur la glace. À part les gorges chaudes causées par ces derrières refroidis, il y a plusieurs leçons à tirer de ces chutes, pour ce qui est de l'architecture orientée-objet des systèmes informatiques.

2) De quoi a l'air un architecte de système qui manque son coup?

D'abord, sommes-nous au moins capables de remarquer quand un architecte de système informatique manque son coup? Sait-on de quoi à l'air un architecte qui «se ramasse sur le derrière» alors qu'il tente de faire un découpage orienté-objet d'un système complexe? Imaginez des spectateurs qui ne seraient même pas capable de faire la différence entre une triple boucle piquée superbe, et une chute ridicule!

Voici quelques indices qui permettent de mieux déceler la «chute» d'un architecte, en examinant son code C++:

2.1) Passage de soi en argument. Si vous voyez des «this» se faire passer en argument un peu partout, il y a fort probablement un grave problème. Si vous avez un objet «Porte-avion» et que ce porte-avion contient un objet «Machine à café», il est plutôt comique de passer le porte-avion en argument à la machine à café!

void CAircraftCarrier::MakeCoffee()
{
     m_coffeeMachine.MakeCupCoffee( this );
}

2.2) Surabondance de fonctions d'accès. Il est assez tordant de voir certains architectes mettre systématiquement toutes les variables membres privées, et ensuite se précipiter pour déclarer des fonctions d'accès «Get-Set» pour chacune d'entre elles! À quoi bon déclarer privés les membres «NIP» et «JournalIntime» d'une classe «Personne», pour ensuite déclarer des fonctions publiques «GetNIP()» et «GetJournalIntime()»?

2.3) Enchevêtrement de fichiers d'interface «.H». Si pour compiler une classe, vous devez inclure les fichiers d'interface de toutes les autres classes, quelque chose ne tourne pas rond (ou plutôt l'inverse: ça tourne en rond)!

2.4) Dédoublement des constructeurs. Par définition, un constructeur en C++ est une fonction qui crée un objet et le place dans un état normal et utilisable. Mais on voit souvent des classes qui en plus d'un constructeur, ont une fonction du genre "Create()" qui doit absolument être appelée avant de se servir de cet objet. Et effet, si deux objets sont pathologiquement interconnectés, il faut faire le genre de pirouette suivante:

// Créer le porte-avion
CAircraftCarrier* pAircraftCarrier = new CAircraftCarrier;

// Créer la machine à café, en lui passant le porte-avion
// à moitié existant.
CCoffeeMachine pCoffeeMachine = new CCoffeeMachine( pAircraftCarrier );

// Maintenant qu'on a une machine à café, on peut terminer
// la construction du porte-avion
pAircraftCarrier->Create( pCoffeeMachine );

2.5) Navigabilité illimitée. Aussi connu sous le nom de «Test du Mulot»: prenez la copie papier d'un programme, coupez l'immense tas de feuilles comme vous le feriez pour un jeux de cartes, et placez votre doigt au hasard sur une ligne de code. Si vous êtes capable à partir de cet endroit de naviguer jusqu'à tous les autres objets, en cheminant d'un «GetPointeurSurTelObjet()» en «m_pointeurSurTelAutreObjet» comme un petit mulot qui se faufile par des tunnels inconnus, alors l'architecte est tombé sur ses foufounes.

3) Pourquoi est-ce mauvais d'avoir tant d'interconnections?

Dans le mauvais vieux temps, on codait en COBOL. Un programme COBOL était d'une certaine façon assez simple: on déclarait toutes nos variables au début du programme dans la «DATA DIVISION», pour ensuite décrire toutes nos fonctions dans le «PROCEDURE DIVISION». Chaque fonction pouvait appeler n'importe quelle autre fonction, et accéder à n'importe laquelle des variables, n'importe quand. En d'autre mots, on avait un tas de code plutôt qu'un programme, un magma informe plutôt qu'une architecture.

L'absence d'une architecture entraîne de nombreux problèmes:

3.1) Pour comprendre une partie du système, il faut comprendre tout le système. Vous ne pouvez pas prendre un sous-ensemble du système et tenter de le comprendre isolément, parce que chaque partie est reliée à toutes les autres.

3.2) Les modifications locales dérangent globalement. La maintenance de système représente une grande partie de l'investissement total, et si chaque petite modification entraîne des conséquences imprévisibles dans le reste du système, on peut facilement multiplier les coûts de maintenance.

3.3) Difficulté de réutiliser du code. Si votre machine à café s'attend à recevoir un porte-avion en paramètre, comment allez-vous la placer dans un édifice à bureau, ou sur un paquebot?

La façon nouvelle et «orientée-objet» de faire un mauvais vieux programme COBOL, c'est de donner à chaque objet un pointeur sur tous les autres objets, et de déclarer pour chaque variable privée une fonction d'accès publique. On revient donc à notre «tas de code» original: n'importe quelle fonction peut accéder à n'importe quelle variable ou fonction, n'importe quand. En en plus, on peut se gargariser d'expressions comme «encapsulation» et «polymorphisme», et chevaucher comme de preux chevaliers orientés-objets, alors qu'en réalité on est des gueux pré-structurés!

Bien sûr, comme les vraies patineuses artistiques, on ne trouve pas des systèmes informatiques complètement mauvais. Ce qu'on rencontre surtout, ce sont des systèmes relativement bien faits, sauf pour les parties les plus difficiles. C'est quand le degré de difficulté monte un peu, que les architectes comme les patineuses tombent. On remarque alors dans les parties les plus délicates de l'architecture les fameux pointeurs sur soi, fonctions d'accès publiques, etc.

4) Quelques suggestions pour les architectes

Comment faire pour concevoir des architectures de système bien découpées? En gros, c'est comme pour le patinage artistique: ce n'est pas une question d'acheter de nouveaux patins, ni d'apprendre une nouvelle technique, mais bien de raffiner l'utilisation de ce qu'on a déjà. Par exemple, vous pouvez:

4.1) Raffiner votre compréhension des responsabilités de l'objet. D'une certaine manière, faire une architecture, c'est répartir intelligemment les responsabilités. Si vous sous sentez obligé de donner à votre classe «Garagiste» des pointeurs sur la caisse enregistreuse, le téléphone et le lavabo (pour aller se dégraisser les mains avant de tripoter la carte de crédit du client), peut-être que vous devriez plutôt inventer une nouvelle classe «Caissière» qui s'occuperait de faire payer les clients. Votre objet «Garagiste» pourrait alors se concentrer sur la réparation des voitures, et votre objet «Caissière» pourrait même être réutilisé dans un autre programme!

4.2) Offrir des services, cacher les outils dont on se sert pour les rendre. Pourquoi voulez-vous donner une fonction «getNIP()» à votre classe «Personne»? Ne pourriez vous pas plutôt déclarer une fonction «PayerFacture()»? Votre objet conserverait alors le contrôle sur son compte de banque, tout en ne payant que le montant nécessaire. Pourquoi déclarer une fonction d'accès «getTorqueWrench()» à votre garagiste? Ses outils (ou variables membres) lui appartiennent: il doit les utiliser pour vous rendre service. Vous devriez pouvoir lui passer votre voiture brisée, et recevoir en retour votre voiture complètement réparée, c'est tout.

4.3) Raffiner ce qui est passé en paramètre. De quoi a-t-on réellement besoin de passer en argument à telle ou telle fonction? De quoi cet objet a-t-il besoin pour vous rendre le service que vous lui demandez? Pour revenir à notre machine à café, vous pourriez dire:

void CAircraftCarrier::MakeCoffee()
{
    m_coffeeMachine.MakeCupCoffee( m_cup, m_waterSource, m_electricalSource );

    // remarquez qu'on aurait pu être dans un paquebot
    // ou un édifice à bureau.
}

4.4) Trouver et écouter de bons entraîneurs. Comme les patineurs artistiques, les architectes de système bénéficient toujours d'avoir de bons entraîneurs. Bjarne Stroustrup, Grady Booch et Steve McConnell représentent un très bon commencement.

5) Conclusion

En conclusion, doit-on rappeler à notre lecteur que nous n'accusons pas les autres architectes de système de manquer de talent? Notre intention n'est que d'aider les architectes moins expérimentés, et nous visitons nous-mêmes la surface de la patinoire trop souvent à notre goût!

© Stefan Jetchick, 10 août 1997.

| Accueil >> Varia >> Génie logiciel