Freeeeeeeeeze !!

Posted by Alexandre Heimburger Sat, 08 Mar 2008 13:28:00 GMT

 Hier se déroulait la plus grande freeze du monde. Après New-York, Londres et d’autres, celle de Paris a réuni près de 3000 personnes autour des fontaines du Trocadéro.

A 14h36, tout le monde s’est immobilisé dans des positions assez démentes.

Merci à Charles Nouÿrit pour l’organisation. On a passé un super moment.

La vidéo officielle devrait être publiée en début de semaine. 

En attendant, vous pouvez allez voir ici et .

En tout cas, ça m’a permis de voir pas mal de monde de la blogosphère et donc…de me bouger pour écrire sur mon blog.

Design smell : code dupliqué

Posted by Alexandre Heimburger Sun, 09 Mar 2008 13:25:00 GMT

 Je commence aujourd’hui une série de billets sur les "design smells". Derrière cette expression se cachent les problématiques qui ont poussé un jour le Gang Of Four (Erich Gamma, Richard Helm, Ralph Johnson et John Vlissides) à écrire les premiers design patterns.

Je lis beaucoup d’articles traitant de ces recettes magiques et souvent le constat est le même : on apprend à faire un template, une factory, un proxy….mais on ne sait pas quand les utiliser. Alors on tombe dans le syndrome de la "paternite aiguë" qui consiste à vouloir les implémenter systématiquement et à toutes les sauces. Et là c’est le drame. Ce qui aurait pu être codé en quelques ligne requiert 4 classes, une interface, de la réflexion…. L’exemple paraît extrême mais on le retrouve souvent chez les développeurs qui viennent de lire "Head First in Design Pattern" mais qui n’avaient pas forcement de notions d’architecture avant cela. Les conséquences, des coûts de développement supplémentaires et une frustration de la part des développeurs qui se rendent vite compte que rien est magique.

Voilà donc pourquoi j’apprécie l’approche "Code Smells" qui apprend tout d’abord à identifier les portions de code mal écrites et les besoins de refactorisation. Le design pattern est alors un outil et non un objectif en soi.

Let’s rock !

Aujourd’hui, ce billet sera dédié au Smell le plus facile à identifier : "le code dupliqué"

Première chose, pourquoi essayer de lutter contre la duplication de code :

- tout d’abord parce que plus le code est compact, plus il est facile à tester et à maintenir
- imaginons qu’il y ait un bug dans une des portions dupliquées. Souvent, la correction n’est pas reportée dans les autres portions et le même bug risque de réapraître plus tard. Il sera considérer comme une régression, gloups…

On peut distingue 2 sortes de code dupliqué : le code dupliqué explicite, le code dupliqué subtil.

Le code dupliqué explicite est le plus facile à identifier. On retrouve les mêmes lignes de code à plusieurs endroits.

Le code dupliqué subtile quant à lui est bien plus fourbe car il s’agit de plusieurs portions de code exécutant les même traitements, mais codé différemment.

Exemple 1 :

La même méthode est implémentée de manière presque similaire dans 2 sous-classes. On retrouve alors des lignes de code communes et des lignes de code spécifiques.
Une solution possible est d’utiliser le pattern "Form template method" qui consiste à créer une méthode ayant la même signature dans la classe mère. Cette implémentation contiendra le code commun puis déléguera à ses filles les comportements spécifiques via des méthodes abstraites (hook)

Un exemple de code ici.

Exemple 2 :

Si une classe contient plusieurs constructeurs avec du code dupliqué, l’utilisation du pattern "Chained Constructor" peut résoudre le problème.
En exemple de code ici.

Exemple 3 :

2 classes exécutent sensiblement les même traitements mais n’implémentent pas d’interface commune. Si les 2 interfaces ne peuvent pas être mergées, une solution peut être de créer une interface commune à ces 2 classes afin de simplifier le code appelant. L’utilisation du pattern "Unify interface with Adapter" permet de créer un point de jonction.
Un exemple de code ici.

Exemple 4 :

On introduit souvent une logique conditionnelle dans le cas où un objet est nul. Et cette logique est répercutée dans tout le code. En utilisant le pattern, "Null Object", cette duplication peut être évitée.
Un exemple de code ici.

Et bien voilà, 4 exemples de Smell, 4 solutions…et non le contraire.

Dans le prochain billet, je parlerais d’un autre cauchemar de développeur : les longues méthodes, ou comment éviter d’avoir des méthodes de 400 lignes qui deviennent très vite impossible à maintenait.

 

Design smell : long method

Posted by Alexandre Heimburger Sun, 23 Mar 2008 13:24:00 GMT

 Quoi de plus désagréable que d’arriver dans un code dans lequel les méthodes font 400 à 500 lignes !

Au delà du fait qu’il faut 2 heures pour arriver à comprendre ce que fait cette méthode, "long method" pose 2 problèmes d’architecture :

  • partage de logique : souvent dans 2 méthodes longues, voire au sein de la même, on retrouve du code dupliqué
  • maintenance : qui peut garantir qu’il se souviendra de ce que font exactement les 400 lignes de codes plusieurs mois après

Lorsqu’on jette un oeil à des frameworks tels que le Zend Framework en PHP ouHibernate en JAVA, il est plaisant de constater que beaucoup de méthodes ne dépassent pas 10 à 20 lignes et que les noms choisis sont explicites. En parcourant le code d’une classe, on comprend instantanément son fonctionnement.

Evidemment personne n’est là pour fixer un nombre maximum de lignes par méthode. Personnellement je pense que le nombre optimal se situe entre 30 et 40.

Comment procéder pour réduire la taille du contenu d’une méthode ?

Le cas le plus simple

La méthode se contente d’appeler une longue série d’instructions, utilisant des variables locales et renvoyant un résultat.
Dans ce cas, le pattern Extract Method qui propose de découper le contenu en sous ensembles de code, suffira à simplifier la méthode. L’attention doit être portée sur le nom 
des "sous-méthodes", afin qu’il soit le plus explicite possible. Attention à leur portées. Dans la majorité des cas, ces méthodes extraites doivent être privées. Inutile d’exposer du code inutilement.

Ma méthode concatène des informations dans une variable avant de la renvoyer

On observe souvent ce genre de choses dans du code manipulant des chaînes de caractères, ou des tableaux. Tout le contenu de la méthode accumule des données.
Une solution est d’adopter le pattern "move accumulation to collecting parameters".

Identifier la variable qui collecte les données, puis extraire des sous-méthodes qui prennent en paramètre cette variable et qui contribuent à son "remplissage".

Ma méthode contient un switch énorme (aussi appelé râteau) pour traiter les données ou appeler d’autres codes

Nicolas le jardinier doit être content. Cependant, nous, développeurs que nous sommes préférons les patterns "command dispatcher" ou "Strategy".
On peut trouver ces "conditional statements" dans des codes d’analyses numériques qui appellent un algorithme en fonction de paramètres d’entrées, ou bien dans des servlets ou des contrôleurs qui traitent les requêtes http avant de les dispatcher.

Que se passe-t-il si on souhaite rajouter une nouvelle logique ? Et bien il faut modifier le switch appelant. On se retrouve alors avec un couplage fort entre les composants.

Les patterns command et strategy, proposent de déléguer à des classes ou des méthodes ces différentes logiques. L’instantiation se fait dynamiquement, par réflexionou via une factory. Rajouter une nouvelle logique revient alors à rajouter une méthode ou une classe, sans toucher à la méthode appelante. Bien utilisé, ce pattern permet d’étendre des fonctionnalités d’un code dont on ne dispose pas des sources.

De tous les design smells, je considère celui-ci comme l’un des pires pour la compréhension, la maintenance, les tests, et la réutilisabilité (je viens d’inventer un mot ?) du code.

Ces quelques recettes devraient permettre de réduire la taille des méthodes de classe, dans la majorité des cas. Je suis preneur de cas particuliers qui ne seraient pas résolus par les patterns évoqués ci-dessus. A vos claviers !