IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Voir le flux RSS

Réac' programming

Misères de la conception objet : notes et arrière-pensées

Note : 4 votes pour une moyenne de 3,75.
par , 03/03/2015 à 09h26 (1101 Affichages)
Quelques idées venues en écrivant le message précédent, livrées en vrac.

Que nous apprend l’exemple du poker ? Plusieurs choses à mon avis.

D’abord, que l’imitation du réel, qui nous vient naturellement quand on conçoit un programme, ne donne pas forcément la meilleure solution, ni même une bonne solution. C’était le sujet de l’article, inutile d’y revenir.

Ensuite, que notre architecture s’est améliorée en passant d’une description « physique » du problème (les cartes et les mains), à une description plus algorithmique (les figures et la fonction de comparaison), à la représentation des données nécessaires au fonctionnement de l’algorithme (les « mains triées »).Je crois que ces trois étapes sont au cœur de toute conception informatique. Pour écrire un programme, on part d’une description naïve du réel, qu’on doit abandonner pour une vision plus algorithmique de ses règles de fonctionnement (ou plus précisément, de la partie des règles de fonctionnement qui nous importent),qu’on doit à nouveau abandonner pour une réflexion sur la représentation des données, dont on tire l’architecture finale.

Dans la pratique, la dernière étape est souvent reportée à des jours meilleurs (c’est-à-dire jamais…), car elle est vue comme une « optimisation prématurée ». C’est à mon avis une très mauvaise idée (et un bien mauvais procès fait à Knuth). La réflexion sur les données, on le voit dans l’exemple du poker, et une façon de revenir sur les algorithmes, et d’arriver à une architecture plus simple (et plus facile à maintenir).

En fait, la seconde étape est souvent bâclée, elle aussi. Une fois qu’ils ont la description naïve du système, beaucoup de développeurs se précipitent sur Google (ou DVP) pour y chercher des solutions en boîte, librairies toutes faites, ou solutions à appliquer aveuglément (c’est exactement l’idée des design pattern). Ceci part d’un bon sentiment, mais prise trop tôt, cette recherche de solutions toutes faites tue la conception en la figeant prématurément (parce qu’une fois qu’on aura décidé que c’est un problème de « cartes » et qu’on aura choisi la librairie cartelib.dll qui modélise toutes les cartes possibles et imaginables, il sera très difficile d’abandonner la conception, au profit d’une autre fondée sur les figures…)

Et ceci m’amène à ce qui devrait peut-être être la vraie conclusion du billet précédent. La conception d’un programme part presque toujours d’une architecture naïve, qu’on critique et qu’on abandonne au profit d’une vision plus profonde, qu’on abandonnera probablement elle aussi pour une troisième. Plus le programme est important, plus il y aura d’itérations, et en général, très peu de code doit survivre d’une itération à l’autre (personnellement, je réécris complètement à chaque fois…).

Je ne crois pas qu’on puisse se passer de ces étapes. En fait, je crois même que c’est en persistant longtemps dans une mauvaise idée qu’on finit par en comprendre les limites, et trouver une meilleure solution. Il faudra alors accepter de jeter ce qu’on à fait, donc probablement ne pas trop fignoler ces premières étapes, sous peine de trop s’attacher aux mauvaises solutions du début.

Les mauvaises idées sont le fumier sur lequel poussent les bons programmes.



Pour ceux que la conception objet intéresse, je ne saurai trop recommander les écrits et les vidéos de Sandi Metz. C’est du Ruby et pas du C++, il y a un peu trop de tests unitaires à mon goût (j’y reviendrai), mais c’est toujours très clair. Dans les grands anciens, je recommande Brad Cox (l’inventeur de l’objective C) : Object Oriented Programming: An Evolutionary Approach.

Envoyer le billet « Misères de la conception objet : notes et arrière-pensées » dans le blog Viadeo Envoyer le billet « Misères de la conception objet : notes et arrière-pensées » dans le blog Twitter Envoyer le billet « Misères de la conception objet : notes et arrière-pensées » dans le blog Google Envoyer le billet « Misères de la conception objet : notes et arrière-pensées » dans le blog Facebook Envoyer le billet « Misères de la conception objet : notes et arrière-pensées » dans le blog Digg Envoyer le billet « Misères de la conception objet : notes et arrière-pensées » dans le blog Delicious Envoyer le billet « Misères de la conception objet : notes et arrière-pensées » dans le blog MySpace Envoyer le billet « Misères de la conception objet : notes et arrière-pensées » dans le blog Yahoo

Catégories
Programmation , C++

Commentaires

  1. Avatar de r0d
    • |
    • permalink
    Bonjour François,

    je te trouve un peu dur avec les "certains [qui] qualifieraient [ça] d’optimisation prématurée". Mais je te comprends, car en réalité, les logiciels qui ont vraiment besoin d'une réelle optimisation sont assez rares, donc peu de développeurs savent de quoi ils parlent lorsqu'ils parlent d'optimisation. De plus, la mode des langages objet dits de haut niveau (java, C#), qui ne permettent pas une gestion fine de la mémoire, fait que beaucoup de développeurs n'ont aucune idée de ce qu'il a "sous le capot", et pour eux, l'optimisation consiste juste à limiter le nombre d'indirection.

    Mais en fait, l'optimisation ce n'est pas ça. L'optimisation est une tâche complexe, qui consiste en deux étapes. La première, et la plus importante, consiste à détecter quels sont les morceaux de code qu'il faut optimiser. La deuxième consiste à reprogrammer ces morceaux de code, souvent en abandonnant les paradigmes, patrons et principes qui permettent une meilleure modularité (objet, généricité, patterns, idiomes, etc.). Et c'est en ce sens qu'il faut comprendre la problématique de "l'optimisation prématurée". Car dans la majorité des cas, le simple respect des règles élémentaires permet d'obtenir les performances suffisantes pour le logiciel que l'on est en train de fabriquer. Donc, dans la majorité des cas, on préfère avoir un logiciel un poil moins rapide, mais plus facile à maintenir. Il s'agit d'un problème de coût. Car l'optimisation et la maintenance ont un prix.

    J'ai donc l'impression que tu mélanges deux choses. D'une part, l'imitation du réel, et d'autre part l'optimisation.
    -> Pour l'imitation du réel, je suis entièrement d'accord avec toi. Mais je crois aussi que notre cerveau fonctionne ainsi, essentiellement par mimétisme (on reproduit ce que l'on voit), et que donc cet écueil est normal chez un jeune développeur. Et qu'il doit se corriger avec le temps. Sur ce point d'ailleurs, on retombe assez vite sur le problème de l'abstraction. Par exemple, si à la place d'une classe Jeu, qui contient les données de la partie en cours, on a une classe Modèle (référence au MVC), alors on se place à un niveau d'abstraction supplémentaire. Se pose alors le problème d'évaluer le rapport avantage/inconvénient de ce saut d'abstraction. C'est intéressant, mais c'est un autre débat.
    -> L'optimisation, quant à elle, est indépendant de l'architecture. Optimiser un logiciel ne consiste pas à prévoir à l'avance une architecture qui sera plus efficace: ça c'est ce qu'on appelle le génie logiciel (je préfère l'anglais: software engineering). Je te propose un exemple: l'addition de matrices. On voit dans cet exemple qu'on peut décider, dès la phase de conception, quel type d'architecture on va choisir. Si on estime à priori (avant de commence le dev), qu'il est important de pouvoir additionner rapidement plusieurs matrices, alors on choisira la version avec les opérateurs "templatisés" et à l'extérieur de la classe Matrix. Sinon on fera un simple conteneur "STL-like", qui contient lui-même ses opérateurs. Mais ce choix est un choix de conception, ce n'est pas de l'optimisation. La conception est à priori, l'optimisation est à posteriori. Donc dans ton exemple de jeu d'échec, en fait tu parles de conception, pas d'optimisation.