Skip to content

Linux Attitude

Le libre est un état d'esprit

Archive

Tag: Théorie

Niveau :      
Résumé : écrire, réécrire

Factoring

Supposons que vous développiez un projet personnel. Vous êtes le seul à spécifier les besoins, le seul à spécifier l'architecture, le langage ... Malgré cela vous constatez la plupart du temps que le résultat est moyen, voire médiocre (ou acceptable si vous êtes très doués). Pourquoi ? Simplement parce qu'un programme doit toujours être développé au moins deux fois.

Vous devez être conscient que la première version d'un programme sera toujours un prototype. Sans exception. Mais cela va me coûter cher me direz-vous ! Hé bien pas tant que ça. Puisque vous êtes conscients que la première version sera un prototype, vous y mettrez beaucoup moins d'efforts. D'autre part la deuxième version sera plus courte à écrire puisque vous avez acquis toute l'expérience nécessaire. Et enfin les bugs de conceptions, les plus durs à résoudre, pourront être évités et donc vous gagnerez du temps.

Un prototype c'est un programme qui a toutes les fonctionnalités du produit fini (ou presque, les demandes évoluant souvent en cours de route). Mais il n'intègre pas nécessairement tous les détails, toutes les options ou une interface graphique soignée. Un prototype ne doit pas être la base de la version suivante du programme. La version finale doit être repensée en partant de 0 (on pourrait même dire que le langage doit être changé). Par contre, rien n'interdit de faire du copier/coller depuis le prototype vers la version finale, c'est même recommandé car un grand nombre de fonctions ont déjà été développées correctement.

Vous aurez compris que ce que je viens de vous décrire est le refactoring. Rien de bien nouveau, seulement vous devez être conscient que pour faire un logiciel dans lequel vous ne perdrez pas votre temps, vous devrez refactorer au moins une fois.

Refactoring

Maintenant , si vous développez pour une entreprise, le processus de développement est quasiment toujours le même. Un client a fait un cahier des charges plus ou moins complet, assisté d'un commercial qui en a profité pour lui faire de nombreuses promesses. Ensuite ce cahier des charges a été traduit par un analyste (peut-être vous même) en un schéma d'architecture ou un schéma UML avec des use case pour les plus méticuleux. Très bien, on pourrait aller jusqu'à dire que c'est fait dans les règles de l'art. C'est ici que le boulot de développeur (et les ennuis) commence. Il s'agit de prendre l'analyse et d'en faire, presque mécaniquement, le logiciel désiré.

Et vous en avez tous fait l'expérience, ça ne marche jamais comme il faut. Il y a de nombreux endroits où le bât blesse. Tout d'abord le client ne sait pas ce qu'il veut, normal il s'agit d'un produit qu'il n'a jamais vu ni utilisé. Ensuite le commercial en a profité pour lui vendre quelque chose de génial, normal c'est son boulot, mais pas nécessairement réalisable. Ensuite l'analyste a fait ce qu'il a pu pour déduire de ce cahier des charges écrit en langage courant un schéma qui peut être informatisé. Et enfin le développeur fait ce qu'il peut en fonction des contraintes du langage utilisé.

C'est le même cas que précédemment, en légèrement plus compliqué surtout s'il y a beaucoup d'intervenants. L'extreme programming pallie ce problème en prônant un refactoring permanent et un bouclage fréquent avec le client.

Ne perdez plus votre temps, mettez des bouts d'extreme programming dans votre activité.

Niveau :      
Résumé : const int UN=1

Qui n'a jamais entendu de son chef de projet : pas de constante sans nom dans le code c'est une règle ! Oui, mais comme toute règle, elle a ses exceptions. Plutôt que de l'appliquer bêtement, réfléchissons au pourquoi du comment.

Les constantes constantes

Si vous utilisez le code suivant :

l = 6.2832 * r;

Alors vous êtes dans l'erreur. 6.2832 c'est 2*pi (environ). Vous utilisez une constante connue de tous, vous devez donc l'appeler par son nom. C'est une règle élémentaire de lisibilité. Bon, celle-là vous la connaissiez. En plus définir PI en constante dans votre code vous permettra le jour venu de changer la précision facilement.

Les constantes variables

Si vous utilisez quelque chose comme

char buffer[4096];

Alors là aussi vous êtes dans l'erreur. Non pas parce que définir la constante BUFFER_SIZE aidera à la lecture , mais parce que votre constante n'en est pas vraiment une. Même si vous êtes persuadés que structurellement dans votre algorithme cela représente quelque chose, rien ne dit que sur une autre planète, ou dans 1000 ans tout ceci aura changé (et 1000 ans se réduisent parfois à quelques jours).

D'autre part, si votre constante est calculée, alors cela peut éventuellement servir à la lisibilité :

char buffer[2 * PACKET_SIZE];

continue reading...

Niveau :      

Prototypage

L'optimisation est un processus qui cherche à accélérer le fonctionnement de ce que vous avez développé. Cette amélioration intervient à plusieurs étapes. La première se trouve tôt dans le développement (en gros après ou pendant le prototype) et est le choix des algorithmes à utiliser. C'est eux qui détermineront si votre application tournera en O(n) ou en O(2^n)

Note : O(n) veut dire que la mesure du temps d'exécution de votre application (ou de son occupation en RAM selon le problème considéré) sera de la forme a*n avec a constante et n le nombre de données à traiter (pour n grand). O(n^2) -> a*n^2 + b*n + c . On considère que pour n suffisamment grand les termes après le premier sont non significatifs. Mais il ne faut pas oublier que pour n petit ils le deviennent ...

Développement

Ensuite vous développerez en respectant un certain nombre de standards ou de normes. Vous vous retrouverez alors avec les recommandations de milliers de consultants et surtout de votre chef. Et attention, ce n'est qu'après ce développement qu'interviendra l'optimisation. Ce qui veut dire que si votre chef vous demande de dérouler les boucles, soit il sait que c'est un cas particulier qui l'exigera (très rare) soit vous lui dites qu'il peut aller ennuyer un autre collègue.

Profiling

En pratique, toute optimisation doit être précédée d'un profiling. L'optimisation sans profiling, c'est la loi sans justice, la répression sans prévention ... ça ne sert à rien si ce n'est faire chier sans aucune raison autre que vos idées reçues. Pour preuve une expérience très simple. Une application développée, demandez à un développeur dans quelle fonction il pense que le plus de temps est dépensé. Ensuite effectuez un profiling et déterminez le temps réellement dépensé dans cette fonction. Dans la majorité des cas, il aura tort (sauf s'il a quelques années de profiling derrière lui).

La plupart des langages disposent maintenant d'outils de profiling adapté. A vous de le trouver (notez que je ne l'ai pas encore trouvé pour javascript). Un certain nombre de ces outils permet de fournir des données au format Kcachegrind (wincachegrind sous windows). Kcachegrind est un outil formidable qui permet de suivre l'arbre d'appel des fonctions, d'avoir les temps d'exécution de chaque fonction de façon très visuelle. Vous verrez tout de suite où agir.

Et ce n'est qu'après avoir vu de vos yeux dans kcachegrind quelle partie du code prend du temps ou quelle fonction est appelée fréquemment, que vous pourrez vous atteler à l'optimisation.

Optimisation

Et cette fois, c'est parti, optimisation à fond, la règle est qu'il n'y a plus de règle, tout est bon pour optimiser. Casser des standards de codage, dérouler des boucles, copier/coller des fonctions ... Mais tout ceci n'est valable que parce que cela se fait sous le contrôle d'un profiling qui vous indique que ce que vous faites sert vraiment. Attention, à partir du moment où l'optimisation change ou égratigne des bonne pratiques de codage, elle doit être localisée et commentée.

Je sais tout ceci n'est que du blabla, pas de cas concret, mais ça permet de mettre un peu les idées en place, éviter quelques erreurs. À bientôt pour de nouvelles aventures !