38
Coder propre aka Clean Code Joseph Pachod https://twitter.com/josephonit Credit: http://xkcd.com/292/ Précisions sur la présentation : Coder propre est applicable à tous les langages Pas d'atelier ou d'exemple précis, que des pistes : à chacun de parcourir le chemin. Exemples en Java mais triviaux et à la portée de tout développeur.

Coder propre !

Embed Size (px)

Citation preview

Coder propreaka Clean Code

Joseph Pachod https://twitter.com/josephonit

Credit: http://xkcd.com/292/

Précisions sur la présentation :

Coder propre est applicable à tous les langages

Pas d'atelier ou d'exemple précis, que des pistes : à chacun de parcourir le chemin.

Exemples en Java mais triviaux et à la portée de tout développeur.

“Make things as simple as possible — but no simpler.” Albert Einstein

“Complicated is not a sign that you are clever. It is a sign that you failed.” Gilad Bracha

“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.” Martin Fowler

"Simplicity is a great virtue but it requires hard work to achieve it and education to appreciate it." Edsger Dijkstra

Pourquoi ?

Raisons "traditionnelles" :● On lit + le code qu'on ne l'écrit● Évolutivité de l'application● Développer la prochaine version plutôt que de corriger

l'actuelle

Raison réelle :Coder propre ou ne pas faire d'informatique !

Code sale :● Fragile● Développement laborieux, répétitif et aléatoire● Chaque évolution est une nouvelle galère● Délais et surprises pour la moindre modification (gestion

de projet peu agréable)● Expérience utilisateur mauvaise (régressions & bugs

fréquents)

=> coder propre voie de salut pour le développeur, le management et les utilisateurs

Comment ?

Faire complexe est facile, faire simple est difficile.

Savez vous coder propre ?

Coder sale n'apprend pas comment coder propre...

Besoin de culture informatique et de réflexion personnelle.

Quelques pistes, à vous de trouver le chemin :● Bonnes pratiques● Outils● Etat d'esprit

Attention !

Il s'agit de conseils, pas de dogmes religieux.

Chaque langage/framework/développeur a ses bonnes pratiques : se renseigner, discuter et se mettre d'accord avec les autres développeurs

Exemples de code à venir : mise en avant de points, pas code parfait...

Utilisation fréquence des termes « Foo » et « Bar », pour se concentrer sur le code et non le fonctionnel. Par exemple : public class Foo {

public Bar doBar() {return new Bar();

}}=> on ne sait rien du fonctionnel, on peut parler du code

Quelques bonnes pratiques

public class BadComment {

private Bar var1 ;

public void foo() { // on teste l'état if( var1.state == null || var1.state == 0 /* foo.state == 1 || */ ) { //... } }}

Le premier commentaire dit ce que fait le test : aucune valeur ajoutée.

Noms et valeurs d'aucune aide : var1, state, entier 0 et 1... Génériques, interchangeables à volonté => vides de sens : on ignore de quel « state » on parle ainsi que le sens des valeurs testées

Qu'indique la ligne commentée ci dessous ? /* foo.state == 1 || */

La valeur 1 n'est plus présente ? La valeur 1 n'est plus à tester ?Quelqu'un a fait un test et a oublié de dé commenter ?=> soulève de nombreuses questions, alors qu'elle ne fait

rien !!=> gaspillage de ressources mentales

Mort aux commentaires !

Le moins possible de commentaires ● Signes d'un manque d'expressivité du code● Faciles à bâcler, dur à écrire proprement, quasi

impossible à maintenir - commentaires alors trompeurs et erronés● Ne PAS commenter le code modifié

- on a un gestionnaire de source pour cela

A réserver● Au code servant d'interface avec le monde extérieur

(API)● Pour expliciter des contraintes extérieures/contexte

- par ex. « initialisation précoce de ce composant car sinon XYZ passe avant (mal) » => toujours des « défaites »

Utiliser les commentaires visibles depuis les outils de génération de doc dès que possible

Refactoring

Actualiser le code existant● noms mis à jour● évolutions de la structure même si besoin

=> le code doit refléter l'état actuel des connaissances métier

Du code qu'on n'ose plus modifier est du code mort et de la dette technique : cela ira en empirant.

Pas de connaissance en dehors du code

final String CHRISTMAS_DAY = "25/12";final String NEW_YEAR_DAY = "01/01";final String FRENCH_NAT_DAY = "14/07";final String workersDay = "1/1";

Quelle ligne a ajouté le nouveau venu dans l'équipe ?

Respecter le style en vigueur

Uniformité du style => lecture plus aisée

Code résultat d'une action collective● par défaut, respecter le style en place● si besoin, discuter et décider en équipe du nouveau

style et des modalités de transition

Evite de se faire haïr... et accessoire : le style en vigueur n'a pas d'effet sur la qualité du code.

public class GoodComment {

private Bar bar;

public void foo() {

if (bar.isInProgress()) { // ... } }

}

Nommage explicite des classes, méthodes et variables

Pas de « bruit » inutile.

Bon niveau de détail : ● si on veut savoir comment est fait le test, on va voir

dans la méthode. ● Sinon on peut continuer à explorer le code actuel sans

surcharge cognitive.

Et en fait aucun commentaire :)

A. List<String> list = new ArrayList<String>();B. List<String> names = new ArrayList<String>();

C. if(bar.isNotDone() == false)D. if(bar.isDone())

=> B : dire le pourquoi, pas le comment. Le code dira toujours le comment, le pourquoi peut être impossible à déterminer s'il n'est pas indiqué...

=> D : penser à être facile à lire : nommer positivement est préférable à la double négation

Privilégier les méthodes courtes● Même une ligne est mieux

Exemple : statut == 0 vs isValide()● Petites méthodes bien plus réutilisables

Code auto descriptif

Les deux diapos précédant montrent du code qui s'explique de lui même

● Facilite la compréhension● Facilite la modification● Découpe le code et le structure

A la portée de tout le monde, suffit d'y penser !

Don't Repeat Yourself ( DRY )Aka Ne pas se répéter

(raté)

A appliquer partout & tout le temps● Tant pour le code que les constantes

Pas de duplication : un besoin qui change égal un endroit à modifier

● certitude de changer le bon morceau● pas de chasse épique aux doublons (parfois

fonctionnellement identiques mais écrits différemment dans le code : bonne chance pour les trouver)

● pas de surprise une fois en production « quand je fais ça ça ne marche toujours pas.. »

A. public int id;B. public Identifier<Good> id;

Cas A : les entiers sont communément utilisés : si vous voyez un entier quelque part, cela sera t il pour autant l'identifiant que vous cherchez ?

Si l'identifiant a des contraintes particulières, impossible de le voir avec un entier : besoin de regarder autour/en base pour comprendre les valeurs autorisées et le fonctionnement.

=> B : ● permet de voir tous les usages de l'identifiant en

question (via les références dans le code)● Permet d'aisément ajouter ou supprimer des

comportements ● N'importe où dans le code où ce type est présent, on

sait de suite de quoi il s'agit ou, au pire, il suffit d'aller voir la classe en question pour avoir le détail

Nommer et typer

Besoin spécifique => nom/classe spécifique

Exemple A précédent, un identifiant entier : peu clair, fragile, peu évolutif

Exemple B précédent, un type dédié : explicite, évolutif (ajouts aisés de comportements sans modifier le code existant)

Le type est :● le point unique pour les actions communes,● la documentation (auto descriptif donc).

public void doStuff() { // plein de choses faites puis... sendEmail("[email protected]", "Stuff done", "Details");}

private void sendEmail(String to, String subject, String text) { String from = "[email protected]"; String host = "smtp.acme.com"; Properties props = new Properties(); props.put("mail.smtp.host", host); Session session = Session.getInstance(props); Message msg = new MimeMessage(session); (...) Transport.send(msg);}

2 choses différentes au même endroit : le but initial de la classe, doStuff, et l'envoi de mail

Conséquences● Longueur de la classe● Détails et mises en œuvre très différents

Plein de problèmes latents :● Réutilisation difficile● Changements difficiles car plein de valeurs codées en

dur● Si le code de l'envoi de mail est copié ailleurs, sera t il

bien iso fonctionnel ?● Quid en cas d'erreur/exception lors de l'envoi du mail ?

Impacts sur doStuff() ?

=> mauvais

private final Mailer mailer;

public Good(Mailer mailer) { this.mailer = mailer;}

public void doStuff() { // plein de choses faites puis... mailer.sendEmail("[email protected]", "Stuff done", "Details");}

Rendre indépendant au maximum les différents modules les uns des autres

● le service d'envoi de mail ne doit faire que ça, sans dépendre ou appliquer des logiques relevant d'autres choses

● Pas de logique en fonction du contexte (utilisateur courant par exemple)

● Utilisation possible du service en dehors d'un contexte web

=> Augmente la réutilisation

Se concentrer sur l'essentiel d'une fonctionnalité permet de la traiter correctement

● Notamment le traitement des cas d'erreurs● En proposant différentes méthodes correspondant aux

différents besoins d'appels

=> meilleur

private final Notifier notifier;

public Open(Notifier notifier) { this.notifier = notifier;}

public void doStuff() { // plein de choses faites puis... notifier.notify(userAcme, "Details", "Stuff done");}

Bien réfléchir au nommage et au périmètre des services● L'envoi de mails n'est qu'une des façons de notifier● L'idée était de notifier, pas d'envoyer un mail● Permet de généraliser : on passe désormais

l'utilisateur et non plus directement l'adresse

Ne pas hésiter à séparer la déclaration de l'implémentation ● Initialement peut être que seul l'envoi de mail marche● Distingue bien le comment du pourquoi

=> encore meilleur

Découplage !

Exemples précédent : mise en œuvre de découplage● Une classe, une responsabilité● Augmente le niveau d'abstraction : plus pérenne

Principe aussi connu sous les noms d'orthogonalité ou de séparation des responsabilités (Separation of Concerns)

Outils

Maîtrisez votre IDE !

Votre IDE peut faire beaucoup, apprenez ses capacités, notamment :

● génération de code ● via des templates pour des éléments récurrents (le

logger par exemple)● en écrivant un code minimal, qui ne compile pas, et

en le laissant créer le reste● découverte/lecture du code

● liste des appelants● références● hiérarchie des classes

● propositions de refactoring● renommage & déplacements● création de méthode

● formatage automatique ● plus simple pour relire le code du collègue

Apprenez aussi ses raccourcis pour être efficace

Commencez par les tests !

Soyez le premier utilisateur de votre code via les tests● Avant même que le code ne soit écrit : permet de voir

si l'utilisation correspond aux attentes● Changer d'avis ne coute alors rien !

● Documente votre code : suffit de regarder les tests pour comprendre comment l'utiliser

Plusieurs niveaux de tests :● Tests unitaires : que pour un point précis (une classe,

une méthode)● Rapides à jouer, à exécuter à chaque changement

du code● Tests d'intégration : mettent en jeu plusieurs classes,

voir des ressources externes (base de données)● Lents ● Fragiles

Etat d'esprit

Less is more

Moins il y a de code à maintenir, mieux c'est

Du code non fréquemment exercé tend à devenir rapidement obsolète

Mieux peu qui tourne que beaucoup qui plante

Code flexible != 2000 options de config

But : avoir du code simple facile à changer, pas du code complexe "qui fait tout" dur à modifier.

Les besoins de demain seront différents des prévisions d'aujourd'hui

Eviter les usines à gaz de paramétrage avec 2000 choix, mais (généralement) pas celui désiré

Si code propre, alors modification aisée.=> KISS (Keep It Simple Stupid)

Egoless programming

Critique du code != critique de soi

=> les discussions et critiques autour du code sont primordiales. Elles ne doivent pas être prises comme des attaques personnelles.

Etre accessible et prêt à discuter

Pensez !

Ne répliquez pas des fonctionnements sans les comprendre

Vous ne comprenez pas ? Des doutes ? Demandez, creusez !

Démarche cartésienne : ne corrigez pas la cause probable mais la causée avérée.=> des preuves, pas des soupçons ou de l'intuition

Faire propre de suite

Même pour un prototype ● qui peut évoluer● qui peut être repris● qui peut être utilisé par un collègue

Eviter de faire une mise en prod aujourd'hui et du bugfix pendant 10 ans...

Emergence naturelle de l'architecture=> Meilleure compréhension des besoins

Code == communication => il faut pouvoir montrer son code sans se sentir "sale"

Pas de raccourcis !

Règle du Boy Scout

Laisser le code plus propre qu'en arrivant

Préoccupez vous du code !

Retour à la réalité

Formez vous !

Lecture● De livres, par exemple Clean code● De code "propre" -> nombreux projets Open Source (mais pas tous, souvent un signe de maturité, ex lucene, wicket, jquery)

Ateliers lors de conférence ● Qu'ils soient dédiés au code propre (tests...)● Ou sur un autre sujet : les échanges avec du code sont toujours très instructifs, tout comme voir un autre coder (et se servir de son environnement)

Coût du coder propre

Coût intellectuel● Remise en cause● Changement

Coût initial● Premières lignes codées propres laborieuses● Beaucoup de réflexions (salutaire)

Coût au quotidien● Léger surcoût au premier dév d'une fonctionnalité● Gain dès qu'on a besoin de relire, retoucher ou réutiliser

=> arrive généralement bien plus tôt qu'on ne le pense

Mieux vaut passer un peu plus de temps au début pour bien faire que de supporter ensuite longtemps quelque chose de mal fait !

Du (mauvais) code...

Immense majorité du code en entreprise non propre● Et même en pratique souvent très sale, voir terrifiant...

Le mauvais code n'apporte que très de satisfaction à ses auteurs : ce n'est pas plaisant !

Grande demande de code propre mais savoir qu'on fait du sale ne permet pas de savoir comment faire propre (du vécu).

Besoin et demande réels...Choisissez votre travail avec soin

Réelle attente de compétences=> Formez vous & pratiquez !

Certaines structures se moquent du code propre (et des développeurs) en général : évitez les si vous aimez coder.

Prendre le chemin du code propre est coûteux en temps et, surtout, en changements : il faut une vraie envie de la structure, pas un simple discours non étayé dans les faits.

When I'm working on a problem, I never think about beauty. I think only how to solve the

problem.

But when I have finished, if the solution is not beautiful, I know it is wrong.

R. Buckminster Fuller