Guide de bonnes pratiques du développement logiciel
Transcription
Guide de bonnes pratiques du développement logiciel
Guide de bonnes pratiques du développement logiciel Christophe Couronne GREYC, 8 juin 2016 Résumé Ce document est un recueil des bonnes et mauvaises pratiques de développement. Il constitue une suite de recommandations dont l’objectif est de faciliter la lecture des codes ou leur distribution. A ce titre il ne s’agit, en aucun cas, de consignes contraignantes. Cependant, l’intégration et la valorisation de vos développements seront facilités si vous suivez ces recommandations. La plupart des pratiques présentées dans ce document ont fait l’objet d’un recensement sélectif parmi des référentiels connus dont la liste figure en bibliographie. Les autres relèvent d’expériences concrètes et sont, par nature, empiriques. Il s’agit d’un document de travail participatif dont le contenu est destiné à évoluer suivant une démarche continue d’amélioration des méthodes de développement. Les pratiques présentées dans ce document sont classées en fonction de leurs portées (style de code, codage, conception...) ou par catégories (Java, Java Enterprise Edition (JEE), PHP...). 1 TABLE DES MATIÈRES TABLE DES MATIÈRES Table des matières 1 Remerciements 4 2 Pratiques Générales 2.1 Style de code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.1.1 Indentation du code . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.1.2 Accolades autour des structures de contrôles . . . . . . . . . . . . . . 2.1.3 Éviter les opérateurs ternaires . . . . . . . . . . . . . . . . . . . . . . 2.1.4 Éviter les affectations dans les conditions des structures de controles 2.2 Métriques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2.1 Longueur de classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2.2 Longueur des méthodes . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2.3 Nombre de paramètres . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2.4 Nombre de champs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2.5 Nombre de méthodes . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2.6 Complexité cyclomatique . . . . . . . . . . . . . . . . . . . . . . . . . 2.2.7 Complexité NPATH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3 Codage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3.1 Limiter autant que possible les instructions return par fonction . . . . 2.3.2 Éviter les instructions "en cascade" . . . . . . . . . . . . . . . . . . . 2.3.3 Éviter les instructions break . . . . . . . . . . . . . . . . . . . . . . . . 2.3.4 Éviter les instructions continue . . . . . . . . . . . . . . . . . . . . . . 2.3.5 Éviter les conditionnelles négatives . . . . . . . . . . . . . . . . . . . . 2.3.6 Remplacer les nombres et les chaînes par des constantes . . . . . . 2.4 Règles de conception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4.1 Le patron de conception singleton . . . . . . . . . . . . . . . . . . . . 2.4.2 Substituer les instructions switch par du polymorphisme . . . . . . . 2.4.3 Éviter les champs protégés dans les classes final . . . . . . . . . . 2.5 Couplage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5.1 Typer par des interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . 2.6 Documentation du code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.6.1 Langue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 6 6 6 7 8 9 9 10 11 13 15 17 18 19 19 20 22 23 24 25 26 26 27 29 31 31 32 32 3 Java 3.1 Documentation du code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.1 Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.2 Methodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.3 Héritage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1.4 Attributs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Règles de conception et de codage . . . . . . . . . . . . . . . . . . . . . . 3.2.1 Éviter les retours null . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2.2 Éviter les passages de paramètres null . . . . . . . . . . . . . . . . 3.2.3 La variable devrait être déclarée final . . . . . . . . . . . . . . . . . 3.2.4 Utiliser ArrayList au lieu de Vector . . . . . . . . . . . . . . . . . . . 3.2.5 Utiliser StringBuilder au lieu de StringBuffer . . . . . . . . . . . . . . 3.2.6 Utiliser des énumérations en lieu et place des listes de constantes . 3.2.7 Éviter de proposer un attribut d’instance de visibilité publique . . . . 3.2.8 Éviter de qualifier la visibilité dans les interfaces . . . . . . . . . . . 3.2.9 Qualifier "public", "protected" et "private" les méthodes des classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 33 33 34 35 36 36 36 38 39 41 42 44 45 46 47 2 . . . . . . . . . . . . . . . TABLE DES MATIÈRES TABLE DES MATIÈRES 4 Java Enterprise 4.1 Traitement par lots . . . . . . . . . . . . . . . . . 4.1.1 Pré-allocation des séquences . . . . . . . 4.1.2 Utiliser hibernate.jdbc.batch_size . . 4.2 Logging . . . . . . . . . . . . . . . . . . . . . . . 4.2.1 Éviter le println() . . . . . . . . . . . . 4.2.2 Éviter le printStackTrace() . . . . . . . 4.2.3 Un logger par classe . . . . . . . . . . . . 4.2.4 Bien logger un message en mode debug 4.3 Couplage . . . . . . . . . . . . . . . . . . . . . . 4.3.1 Utiliser Spring et l’inversion de contrôle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 48 48 49 49 49 51 52 53 54 54 5 PHP 5.1 PHP Standards Recommendations (PSR) . . . . . . . . . . . . . . . . . . . . . 5.1.1 PSR-1 : Basic Coding Standard . . . . . . . . . . . . . . . . . . . . . . 5.1.2 PSR-2 : Coding Style Guide . . . . . . . . . . . . . . . . . . . . . . . . . 5.1.3 PSR-4 : Autoloading Standard . . . . . . . . . . . . . . . . . . . . . . . 5.2 En vrac . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2.1 Développer en E_ALL|E_STRICT . . . . . . . . . . . . . . . . . . . . . . 5.2.2 Utiliser les structures de contrôle du langage C . . . . . . . . . . . . . . 5.2.3 Ne pas utiliser les short open tags . . . . . . . . . . . . . . . . . . . . . 5.2.4 Constructeurs PHP5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2.5 Ne jamais utiliser de variables globales . . . . . . . . . . . . . . . . . . 5.2.6 Éviter les conversions implicites . . . . . . . . . . . . . . . . . . . . . . 5.2.7 Toujours initialiser ses variables . . . . . . . . . . . . . . . . . . . . . . 5.2.8 Concaténation d’une variable valeur NULL . . . . . . . . . . . . . . . . . 5.2.9 Éviter l’appel de fonctions dans le corps dúne déclaration de boucle for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 57 57 57 58 58 58 59 60 61 62 63 64 65 66 6 Python 6.1 Exécuter l’interpréteur avec l’option -tt . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 67 Bibliographie 68 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 REMERCIEMENTS Remerciements Je tiens à remercier les contributeurs ci-dessous qui m’ont donné des conseils éclairés sur ce document. — — — — Davy Gigan ; Jean-Marc Lecarpentier ; Bruno Mermet ; Bruno Zanuttini. 4 2 2 PRATIQUES GÉNÉRALES Pratiques Générales Cette partie du document s’intéresse aux règles transverses qui s’appliquent, peu ou proue, à tous les langages objets. On y trouve des règles relatives : — au style de code ; — au codage ; — à la conception ; — au couplage. Ces règles s’appliquent aussi bien à Java, qu’à PHP ou C++. 5 2.1 Style de code 2.1 2 PRATIQUES GÉNÉRALES Style de code Les règles présentées dans ce paragraphe touchent principalement au style du code. Elles formalisent quelques pratiques d’écriture avec pour objectif d’en faciliter la lecture. 2.1.1 Indentation du code Il est préférable, pour la quasi totalité des langages objets, d’utiliser une indentation de 4 espaces, sans tabulation [doc14b] [Cor14]. Ceci permet d’éviter les problèmes avec les fichiers diff, les patches, l’historique CVS et les annotations. 2.1.2 Accolades autour des structures de contrôles Il est préférable de toujours mettre les accolades autour des structures de contrôle if, while, for, else... Cela facilite la lecture et lève toute ambiguïté. /∗ ∗ Mauvaise p r a t i q u e ∗/ i f ( isEnabled ( ) ) System . o u t . p r i n t l n ( " Enabled ! " ) ; /∗ ∗ Bonne p r a t i q u e ∗/ i f ( isEnabled ( ) ) { System . o u t . p r i n t l n ( " Enabled ! " ) ; } 6 2.1 2.1.3 Style de code 2 PRATIQUES GÉNÉRALES Éviter les opérateurs ternaires Les opérateurs ternaires sont jugés difficiles à lire par certains programmeurs. On préfère les éviter, d’autant plus qu’ils sont imbricables les uns dans les autres. /∗ ∗ Mauvaise p r a t i q u e ∗/ f i n a l I n t e g e r r e s u l t = ( isEnabled ( ) ) ? getValidCode ( ) : ( isBusy ( ) ) ? getBusyCode ( ) : getErrorCode ( ) ; /∗ ∗ Bonne p r a t i q u e ∗/ Integer result = getErrorCode ( ) ; i f ( isEnabled ( ) ) { r e s u l t = getValidCode ( ) ; } e l s e i f ( isBusy ( ) ) { r e s u l t = getBusyCode ( ) ; } 7 2.1 2.1.4 Style de code 2 PRATIQUES GÉNÉRALES Éviter les affectations dans les conditions des structures de controles Une règle simple, qui évite de nombreuses erreurs de programmation : éviter d’utiliser l’affectation dans la condition d’une structure de controle [Wik16]. /∗ ∗ Mauvaise p r a t i q u e ( j a v a ) ∗/ p u b l i c void foo ( ) { i n t a = 42; i n t b = 0; if ( ( a = b ) == 0 ) { / / skipped code ! } } /∗ ∗ Bonne p r a t i q u e ( j a v a ) ∗/ p u b l i c void foo ( ) { i n t a = 42; i n t b = 0; a = b; i f ( a == 0 ) { / / skipped code ! } } 8 2.2 Métriques 2.2 2 PRATIQUES GÉNÉRALES Métriques Quelques mesures destinées à fournir des indicateurs de la qualité logicielle. 2.2.1 Longueur de classe Les classes trop longues en font trop [Gri14]. Il s’agit de les restructurer afin qu’elles soient d’une longueur raisonnable. On procède alors à une opération de réusinage. La limite communément admise est de 1000 lignes par classe grand maximum. /∗ ∗ Mauvaise p r a t i q u e ( j a v a ) ∗/ p u b l i c c l a s s Foo { / / 2000 l i n e s o f code } /∗ ∗ Bonne p r a t i q u e ( j a v a ) ∗/ p u b l i c c l a s s Foo { / / 1000 l i n e s o f code } p u b l i c c l a s s Bar { / / 1000 l i n e s o f code } 9 2.2 Métriques 2.2.2 2 PRATIQUES GÉNÉRALES Longueur des méthodes Quand les méthodes sont excessivement longues, l’excès d’information provoque une perte d’attention du lecteur [Gri14]. Restructurer votre code en créant, par exemple, d’autres méthodes ou d’autres classes d’une longueur raisonnable. Limite communément admise : maximum 100 lignes par méthode. /∗ ∗ Mauvaise p r a t i q u e ( j a v a ) ∗/ /∗ ∗ h t t p : / / pmd . s o u r c e f o r g e . n e t / [ . . . ] # ExcessiveMethodLength ∗/ p u b l i c v o i d doSomething ( ) { System . o u t . p r i n t l n ( " H e l l o w o r l d ! " ) ; / / 200 c o p i e s o m i t t e d f o r b r e v i t y . } /∗ ∗ Bonne p r a t i q u e ( j a v a ) ∗/ p u b l i c v o i d doSomething ( ) { System . o u t . p r i n t l n ( " H e l l o w o r l d ! " ) ; / / 100 c o p i e s o m i t t e d f o r b r e v i t y . doSubRoutine ( ) ; } p u b l i c v o i d doSubRoutine ( ) { / / 100 c o p i e s o m i t t e d f o r b r e v i t y . } 10 2.2 Métriques 2.2.3 2 PRATIQUES GÉNÉRALES Nombre de paramètres Une longue liste de paramètres indique que de nouveaux objets devraient être créés pour les encapsuler [Gri14]. Essayez de grouper les paramètres entre eux. /∗ ∗ Mauvaise p r a t i q u e ( j a v a ) ∗ ∗ h t t p : / / pmd . s o u r c e f o r g e . n e t / [ . . . ] # E x c e s s i v e P a r a m e t e r L i s t ∗/ p u b l i c c l a s s Foo { p u b l i c v o i d addData ( i n t p0 , i n t p1 , i n t p2 , i n t p3 , i n t p4 , i n t p5 , i n t p5 , i n t p6 , i n t p7 , i n t p8 , i n t p9 , i n t p10 ) { /∗ ∗ method body ∗/ } } /∗ ∗ Bonne p r a t i q u e ( j a v a ) ∗/ p u b l i c c l a s s DataDto { p r i v a t e i n t p0 ; p r i v a t e i n t p1 ; p r i v a t e i n t p2 ; p r i v a t e i n t p3 ; p r i v a t e i n t p4 ; p r i v a t e i n t p5 ; p r i v a t e i n t p6 ; p r i v a t e i n t p7 ; p r i v a t e i n t p8 ; p r i v a t e i n t p9 ; p r i v a t e i n t p10 ; 11 2.2 Métriques 2 PRATIQUES GÉNÉRALES /∗ ∗ 10 g e t t e r s and s e t t e r s o m i t t e d . ∗/ } ... p u b l i c c l a s s Foo { p u b l i c v o i d addData ( f i n a l DataDto d t o ) { /∗ ∗ method body ∗/ } } 12 2.2 Métriques 2.2.4 2 PRATIQUES GÉNÉRALES Nombre de champs Les classes qui ont trop de champs devraient être réusinées pour en avoir moins [Gri14]. Il est possible d’utiliser des objets imbriqués qui groupent une partie de l’information. Par exemple, une classe avec des champs ville / état / code postal pourrait, à la place, avoir un seul champ "Adresse". La limite communément admise est de 15 champs par classe. /∗ ∗ Mauvaise p r a t i q u e ( j a v a ) ∗ ∗ h t t p : / / pmd . s o u r c e f o r g e . n e t / [ . . . ] / codesize . h t m l #TooManyFields ∗/ p u b l i c c l a s s Person { p r i v a t e S t r i n g one ; p r i v a t e i n t two ; private i n t three ; /∗ ∗ [ . . . many more p u b l i c f i e l d s ∗/ ...] private String city ; private String state ; private String zip ; /∗ ∗ code o m i t t e d ∗/ } /∗ ∗ Bonne p r a t i q u e ( j a v a ) ∗/ p u b l i c c l a s s Adresse { private String city ; private String state ; private String zip ; /∗ ∗ 3 g e t t e r s and 3 s e t t e r s o m i t t e d . ∗/ } /∗ ∗ h t t p : / / pmd . s o u r c e f o r g e . n e t / [ . . . ] / codesize . h t m l #TooManyFields 13 2.2 Métriques 2 PRATIQUES GÉNÉRALES ∗/ p u b l i c c l a s s Person { p r i v a t e S t r i n g one ; p r i v a t e i n t two ; private i n t three ; /∗ ∗ [ . . . many more p u b l i c f i e l d s ∗/ p r i v a t e Adresse adresse ; /∗ ∗ code o m i t t e d ∗/ } 14 ...] 2.2 Métriques 2.2.5 2 PRATIQUES GÉNÉRALES Nombre de méthodes Une classe avec de trop nombreuses méthodes est une bonne cible de réusinage [Gri14]. Cela permet de réduire sa complexité et d’avoir des objets d’une granularité plus fine. Limite communément admise : 10 méthodes par classe. /∗ ∗ Mauvaise p r a t i q u e ( j a v a ) ∗/ p u b l i c c l a s s Foo { p u b l i c v o i d foo1 ( ) { / / code o m i t t e d } p u b l i c v o i d foo2 ( ) { / / code o m i t t e d } p u b l i c v o i d foo3 ( ) { / / code o m i t t e d } /∗ ∗ 16 methods o m i t t e d ∗/ p u b l i c v o i d foo20 ( ) { / / code o m i t t e d } } /∗ ∗ Bonne p r a t i q u e ( j a v a ) ∗/ p u b l i c c l a s s Foo { p u b l i c v o i d foo1 ( ) { / / code o m i t t e d } p u b l i c v o i d foo2 ( ) { / / code o m i t t e d } p u b l i c v o i d foo3 ( ) { / / code o m i t t e d } 15 2.2 Métriques 2 /∗ ∗ 6 methods o m i t t e d ∗/ p u b l i c v o i d foo10 ( ) { / / code o m i t t e d } } p u b l i c c l a s s Bar { p u b l i c v o i d bar1 ( ) { / / code o m i t t e d } p u b l i c v o i d bar2 ( ) { / / code o m i t t e d } p u b l i c v o i d bar3 ( ) { / / code o m i t t e d } /∗ ∗ 6 methods o m i t t e d ∗/ p u b l i c v o i d bar10 ( ) { / / code o m i t t e d } } 16 PRATIQUES GÉNÉRALES 2.2 Métriques 2.2.6 2 PRATIQUES GÉNÉRALES Complexité cyclomatique Il s’agit d’un concept simple qui est bien documenté dans PHPMD [Mod13]. On compte certaines instructions. On commence par 1 point à la déclaration de la fonction. Il faut ensuite ajouter 1 pour chaque if, while, for et case. Par exemple, la fonction ci-après possède une complexité cyclomatique de 12. Le seuil standard de cette métrique est de 10 points. Si vous avez une fonction avec une complexité supérieure à 10, vous devez essayer de la réusiner. 1 p u b l i c f u n c t i o n example ( ) { 2 i f ( $a == $b ) { 3 i f ( $a1 == $b1 ) { fiddle (); 4 } e l s e i f ( $a2 == $b2 ) { fiddle (); } else { fiddle (); } 5 } e l s e i f ( $c == $d ) { 6 w h i l e ( $c == $d ) { fiddle (); } 7 } e l s e i f ( $e == $ f ) { 8 f o r ( $n = 0 ; $n > $h ; $n ++) { fiddle (); } } else { s w i t c h ( $z ) { 9 case 1 : fiddle (); break ; 10 case 2 : fiddle (); break ; 11 case 3 : fiddle (); break ; 12 default : fiddle (); break ; } } } 17 2.2 2.2.7 Métriques 2 PRATIQUES GÉNÉRALES Complexité NPATH La complexité NPath est le nombre de chemins qui constituent le flux d’une fonction [Mod13]. Prenons en exemple la fonction suivante. f u n c t i o n f o o ( $a , $b ) { i f ( $a > 10) { echo 1 ; } else { echo 2 ; } i f ( $a > $b ) { echo 3 ; } else { echo 4 ; } } Il y a 2 instructions if avec 2 sorties possibles chacune. On a donc 4 sorties possibles (2 * 2 = 4). Cela signifie que la complexité npath est de 4. Si nous avions une autre instruction if, nous aurions une complexité de 8, car (2 * 2 * 2 = 8). La complexité NPath est exponentielle et peut facilement devenir incontrôlable, dans du vieux code. Ne soyez pas surpris si vous trouvez des fonctions avec une complexité supérieure à 100 000. La valeur par défaut du seuil de cette métrique est de 200. Vous devez rester sous cette valeur. 18 2.3 Codage 2.3 2 PRATIQUES GÉNÉRALES Codage Les règles présentées dans ce paragraphe ciblent l’écriture même du code dans sa logique intrinsèque. 2.3.1 Limiter autant que possible les instructions return par fonction Dans l’idéal, une méthode/fonction ne devrait avoir qu’un et un seul point de sortie. Ce devrait être sa dernière instruction. L’instruction return fait partie des jump statements. Il y a 3 jump statements en java : continue, break et return. Ces instructions ont une action similaire à celle des instructions goto des langages BASIC ou Fortran : elles transfèrent le contrôle à un autre endroit du programme. Pour limiter la complexité, on cherche à minimiser l’usage de ces instructions. Cette règle fait partie des pratiques de développement dites de « programmation structurée » [ll14]. /∗ ∗ Mauvaise p r a t i q u e ( Java ) . ∗/ p u b l i c c l a s s OneReturnOnly1 { p u b l i c S t r i n g foo ( i n t x ) { i f ( x > 0) { r e t u r n " hey " ; / / oops , m u l t i p l e e x i t p o i n t s ! } return " hi " ; } } /∗ ∗ Bonne p r a t i q u e ( Java ) . ∗/ p u b l i c c l a s s OneReturnOnly1 { String result = " hi " ; p u b l i c S t r i n g foo ( i n t x ) { i f ( x > 0) { r e s u l t = " hey " ; } return result ; } } 19 2.3 2.3.2 Codage 2 PRATIQUES GÉNÉRALES Éviter les instructions "en cascade" Les instructions en cascade peuvent être sources d’erreurs et compliquent parfois inutilement le débogage des programmes. Les piles d’appels et les erreurs de compilations sont bien souvent imprécises lorsqu’on ne respecte pas cette règle. Attention toutefois, cette règle est à adapter à votre contexte de programmation car il arrive que ce style soit recommandé dans certains cas précis, p. ex. pour l’usage des StringBuilder ou des Stream en Java. Dans ce cas spécifique, il convient de veiller à respecter un strict retour à la ligne entre chaque appel de méthode afin que les messages soient précis en cas d’erreurs. /∗ ∗ Mauvaise p r a t i q u e (PHP ) . ∗/ $message = Swift_Message : : newInstance ( ) −>s e t C h a r s e t ( s e l f : : $ c o n f i g s [ ’ c h a r s e t ’ ] ) −>s e t S u b j e c t ( $ t h i s −>s u b j e c t ) −>setFrom ( $assocAdressesFrom ) −>setTo ( $assocAdressesTo ) −>setBody ( $messageHtml , ’ t e x t / html ’ ) −>addPart ( s t r i p _ t a g s ( $messageHtml ) , ’ t e x t / p l a i n ’ ) ; /∗ ∗ Bonne p r a t i q u e (PHP ) . ∗ ∗ Dans c e t exemple , chaque i n s t r u c t i o n e s t décomposée . ∗ ∗ En cas d ’ e r r e u r s , l a p i l e d ’ appel e s t p r é c i s e . ∗/ $message = Swift_Message : : newInstance ( ) ; $charset = s e l f : : $configs [ ’ charset ’ ] ; $ p a r t = s t r i p _ t a g s ( $messageHtml ) ; $message−>s e t C h a r s e t ( $ c h a r s e t ) ; $message−>s e t S u b j e c t ( $ t h i s −>s u b j e c t ) ; $message−>setFrom ( $assocAdressesFrom ) ; $message−>setTo ( $assocAdressesTo ) ; $message−>setBody ( $messageHtml , ’ t e x t / html ’ ) ; $message−>addPart ( $ p a r t , ’ t e x t / p l a i n ’ ) ; 20 2.3 Codage 2 PRATIQUES GÉNÉRALES /∗ ∗ Mauvaise p r a t i q u e ( Java ) . ∗/ L i s t <EtablissementUna > r e s u l t s = ( L i s t <EtablissementUna >) s e s s i o n F a c t o r y . getCurrentSession ( ) . createCriteria ( " f r . univbordeaux . [ . . . ] . EtablissementUna " ) . add ( c r e a t e ( i n s t a n c e ) ) . l i s t ( ) ; /∗ ∗ Bonne p r a t i q u e ( Java ) . ∗/ f i n a l Session = s e s s i o n F a c t o r y . g e t C u r r e n t S e s s i o n ( ) ; f i n a l C r i t e r i a c r i t e r i a = session . c r e a t e C r i t e r i a ( " f r . univbordeaux . [ . . . ] . EtablissementUna " ) ; f i n a l C r i t e r i o n c r i t e r i o n = create ( instance ) ; c r i t e r i a . add ( c r i t e r i o n ) ; f i n a l L i s t <EtablissementUna > r e s u l t s = c r i t e r i a . l i s t ( ) ; 21 2.3 Codage 2.3.3 2 PRATIQUES GÉNÉRALES Éviter les instructions break L’instruction break fait partie des « jump statements ». Il y a 3 « jump statements » en java : continue, break et return. Ces instructions ont une action similaire à celle des instructions goto des langages BASIC ou Fortran : elles transfèrent le contrôle à un autre endroit du programme. Pour limiter la complexité, on cherche à minimiser l’usage de ces instructions. Cette règle fait partie des pratiques de développement dites de « programmation structurée » [ll14]. /∗ ∗ Mauvaise p r a t i q u e ( Java ) . ∗/ f o r ( i n t i = 0 ; i <4; i ++) { i f ( i == 2 ) { break ; } System . o u t . p r i n t l n ( " i = " + i ) ; } /∗ ∗ Bonne p r a t i q u e ( Java ) . ∗/ f o r ( i n t i = 0 ; i < 2 ; i ++) { System . o u t . p r i n t l n ( " i = " + i ) ; } 22 2.3 Codage 2.3.4 2 PRATIQUES GÉNÉRALES Éviter les instructions continue L’instruction continue fait partie des « jump statements ». Il y a 3 « jump statements » en java : continue, break et return. Ces instructions ont une action similaire à celle des instructions goto des langages BASIC ou Fortran : elles transfèrent le contrôle à un autre endroit du programme. Pour limiter la complexité, on cherche à minimiser l’usage de ces instructions. Cette règle fait partie des pratiques de développement dites de « programmation structurée » [ll14]. f o r ( i n t i = 0 ; i <4; i ++) { i f ( i == 2 ) { continue ; } System . o u t . p r i n t l n ( " i = " + i ) ; } f o r ( i n t i = 0 ; i <4; i ++) { i f ( i != 2) { System . o u t . p r i n t l n ( " i = " + i ) ; } } 23 2.3 Codage 2.3.5 2 PRATIQUES GÉNÉRALES Éviter les conditionnelles négatives Les expressions négatives sont plus difficiles à comprendre que les expressions positives. Les expressions devraient être exprimées de manière positive [Mar09]. /∗ ∗ Mauvaise p r a t i q u e ∗/ if ( ! b u f f e r . shouldNotCompact ( ) ) /∗ ∗ Bonne p r a t i q u e ∗/ i f ( b u f f e r . shouldCompact ( ) ) 24 2.3 Codage 2.3.6 2 PRATIQUES GÉNÉRALES Remplacer les nombres et les chaînes par des constantes Il convient d’éviter de conserver les nombres et les chaînes de caractères en brut dans le code. La bonne pratique est d’utiliser des constantes nommées. Par exemple, le nombre 3 600 000 devrait être affecté à la constante MILLIS_PER_HOUR [Mar09]. En règle générale, les seuls nombres « en dur » que l’on peut trouver dans le code sont -1, 0, 1 et 2. /∗ ∗ Mauvaise p r a t i q u e ( Java ) . ∗/ f i n a l Calendar c a l e n d a r = new GregorianCalendar ( ) ; f i n a l i n t dayOfMonth = c a l e n d a r . g e t ( 5 ) ; ... f i n a l new Bear ( " Teddy " ) ; /∗ ∗ Bonne p r a t i q u e ( Java ) . ∗/ f i n a l Calendar c a l e n d a r = new GregorianCalendar ( ) ; f i n a l i n t dayOfMonth = c a l e n d a r . g e t ( Calendar .DAY_OF_MONTH ) ; ... f i n a l Bear bear = new Bear ( Bear .NAME_OF_TEDDY ) ; 25 2.4 Règles de conception 2.4 2.4.1 2 PRATIQUES GÉNÉRALES Règles de conception Le patron de conception singleton Si une classe ne contient que des méthodes statiques, il est préférable d’en faire un singleton [Gri14]. Il faut alors ajouter un constructeur private (i.e. privé) pour éviter toute instanciation exterieure à cette classe. — cf. http://pmd.sourceforge.net/rules/design.html#UseSingleton. — cf. https://pmd.github.io/pmd-5.4.1/pmd-java/rules/java/design.html#UseUtilityClass. p u b l i c c l a s s ShouldBeASingleton { p u b l i c s t a t i c v o i d f o o ( ) { / / skipped code } p u b l i c s t a t i c v o i d bar ( ) { / / skipped code } } / / Singleton classique . p u b l i c c l a s s MySingleton { / / Constructeur privé . p r i v a t e MySingleton ( ) { } / / I n s t a n c e unique non p r é i n i t i a l i s é e . p r i v a t e s t a t i c MySingleton INSTANCE = n u l l ; / / Accesseur pour l ’ unique i n s t a n c e de l a c l a s s e . p u b l i c s t a t i c MySingleton g e t I n s t a n c e ( ) { i f ( INSTANCE == n u l l ) { INSTANCE = new MySingleton ( ) ; } r e t u r n INSTANCE ; } / / La méthode d ’ i n s t a n c e f o o ( ) . p u b l i c void foo ( ) { / / skipped code . } / / La méthode d ’ i n s t a n c e bar ( ) . p u b l i c v o i d bar ( ) { / / skipped code . } } 26 2.4 Règles de conception 2 PRATIQUES GÉNÉRALES Substituer les instructions switch par du polymorphisme 2.4.2 On peut substituer les instructions switch lorsqu’elles sont utilisées pour choisir entre plusieurs comportements en fonction d’un type d’objet [Sou14]. Il s’agit de déplacer chaque composante de la condition dans une méthode surchargée au sein d’une sous classe. On rend la méthode originelle abstraite. /∗ ∗ Java , mauvaise p r a t i q u e . ∗ ∗ h t t p : / / sourcemaking . com / r e f a c t o r i n g / r e p l a c e −c o n d i t i o n a l −w i t h −polymorphism ∗/ double getSpeed ( ) { s w i t c h ( _type ) { case EUROPEAN: r e t u r n getBaseSpeed ( ) ; case AFRICAN : r e t u r n getBaseSpeed ( ) − getLoadFactor ( ) ∗ _numberOfCoconuts ; case NORWEGIAN_BLUE: r e t u r n ( _ i s N a i l e d ) ? 0 : getBaseSpeed ( _ v o l t a g e ) ; } throw new RuntimeException ( " Should be unreachable " ) ; } Le polymorphisme permet d’utiliser une même interface avec différentes implémentations. Il s’agit de remplacer les instructions des différents cas fonctionnels, par des implémentations distinctes qui mettent en oeuvre la même interface de programmation. public interface Bird { double getSpeed ( ) ; } 27 2.4 Règles de conception 2 PRATIQUES GÉNÉRALES p u b l i c c l a s s European implements B i r d { p u b l i c double getSpeed ( ) { r e t u r n getBaseSpeed ( ) ; } } p u b l i c c l a s s A f r i c a n implements B i r d { p u b l i c double getSpeed ( ) { r e t u r n getBaseSpeed ( ) − getLoadFactor ( ) ∗ numberOfCoconuts ; } } p u b l i c c l a s s NorwegianBlue implements B i r d { p u b l i c double getSpeed ( ) { i n t value = 0; if ( ! isNailed ) { v a l u e = getBaseSpeed ( v o l t a g e ) ; } r e t u r n value ; } } p u b l i c double getSpeed ( t y p e ) { f i n a l Map< S t r i n g , B i r d > map = new HashMap< S t r i n g , B i r d > ( ) ; map . p u t (EUROPEAN, new European ( ) ) ; map . p u t ( AFRICAN , new A f r i c a n ( ) ) ; map . p u t (NORWEGIAN_BLUE, new NorwegianBlue ( ) ) ; f i n a l B i r d b i r d = map . g e t ( t y p e ) ; r e t u r n b i r d . getSpeed ( ) ; } 28 2.4 Règles de conception 2.4.3 2 PRATIQUES GÉNÉRALES Éviter les champs protégés dans les classes final Il est inutile d’utiliser des champs protected dans les classes final car elles ne peuvent pas être sous classées. Il convient d’ailleurs, dans la mesure du possible, d’éviter les classes « final ». Clarifiez votre intention en utilisant le qualificatif private ou friendly à la place. /∗ ∗ Java , mauvaise p r a t i q u e . ∗/ p u b l i c f i n a l c l a s s Bar { private int x ; /∗ ∗ Bar ne peut pas ê t r e sous classé , ∗ champ p r i v a t e ou f r i e n d l y . ∗/ protected i n t y ; Bar ( ) { } } /∗ ∗ Java , bonne p r a t i q u e ( o p t i o n 1 ) ∗/ p u b l i c f i n a l c l a s s Bar { private int x ; /∗ ∗ Bar ne peut pas ê t r e sous classé , ∗ on rend l e champ p r i v a t e . ∗/ private int y ; Bar ( ) { } } 29 i l s ’ a g i t donc d ’ un 2.4 Règles de conception 2 /∗ ∗ Java , bonne p r a t i q u e ( o p t i o n 2 ) ∗ ∗ On enlève l e m o d i f i e r f i n a l . ∗/ p u b l i c c l a s s Bar { private int x ; /∗ ∗ Bar peut ê t r e sous classé , ∗ on l a i s s e l e champ p r o t e c t e d . ∗/ protected i n t y ; Bar ( ) { } } 30 PRATIQUES GÉNÉRALES 2.5 Couplage 2.5 2 PRATIQUES GÉNÉRALES Couplage Ces règles servent à réduire le couplage entre les différents composants des applications. 2.5.1 Typer par des interfaces Les références de types d’implémentation complexifient la mise en oeuvre d’évolutions futures [Gri14]. Typer par des interfaces fournit beaucoup plus de flexibilité. Il est alors possible de changer facilement l’implémentation. /∗ ∗ Java , mauvaise p r a t i q u e . ∗ ∗ h t t p : / / pmd . s o u r c e f o r g e . n e t / [ . . . ] # LooseCoupling ∗/ / / sub−o p t i m a l approach p r i v a t e A r r a y L i s t <Foo> l i s t = new A r r a y L i s t <Foo > ( ) ; p u b l i c HashSet<Bar > getBarSet ( ) { r e t u r n new HashSet<Bar > ( ) ; } /∗ ∗ Java , bonne p r a t i q u e . ∗ ∗ h t t p : / / pmd . s o u r c e f o r g e . n e t / [ . . . ] # LooseCoupling ∗/ / / p r e f e r r e d approach p r i v a t e L i s t <Foo> l i s t = new A r r a y L i s t <Foo > ( ) ; p u b l i c Set <Bar > getBarSet ( ) { r e t u r n new HashSet<Bar > ( ) ; } 31 2.6 2.6 Documentation du code 2 PRATIQUES GÉNÉRALES Documentation du code Il s’agit de conseils relatifs à la documentation du code en règle générale, indépendamment des langages de programmation. 2.6.1 Langue Il est conseillé d’écrire la documentation en anglais (ainsi que les noms des classes, des méthodes, etc.) et ce, pour que le code puisse être repris par quiconque. 32 3 3 JAVA Java 3.1 3.1.1 Documentation du code Classes La déclaration d’une classe doit être précédée d’un commentaire javadoc ou doxygen destiné à expliquer son fonctionnement. package f r . unicaen . r e a c t o r ; /∗∗ ∗ Une c l a s s e q u i met en oeuvre l e p a t r o n de c o n c e p t i o n « Reactor » a f i n de ∗ g é r e r l e s t r a i t e m e n t s a s s o c i é s aux évènements m é t i e r . ∗ ∗ @author C h r i s t o p h e ∗ @see Handler ∗ ∗ @param E l e t y p e d ’ évènement que l ’ on t r a i t e . ∗ @param T l e t y p e q u i i d e n t i f i e l e c a l l b a c k dans l e r e a c t e u r . ∗/ p u b l i c c l a s s Reactor <T , E> { / / skipped code } 33 3.1 Documentation du code 3.1.2 3 JAVA Methodes La déclaration d’une méthode, même privée, doit faire l’objet d’un commentaire explicite qui expose : — Son fonctionnement, c’est à dire ce qu’elle fait ; — Le type et le sens de chaque paramètre attendu ; — Si la méthode est une fonction (et non une procédure), le commentaire doit exprimer le type d’objet retourné et sa signification. package f r . unicaen . r e a c t o r ; /∗∗ ∗ Une i n t e r f a c e pour l e s « c a l l b a c k s » du r e a c t e u r . ∗ ∗ @author C h r i s t o p h e ∗ ∗ @see Reactor ∗ ∗ @param E l e t y p e d ’ évènement que l ’ on t r a i t e . ∗ @param T l e t y p e q u i i d e n t i f i e e l e c a l l b a c k . ∗/ p u b l i c i n t e r f a c e Handler <T , E> { /∗∗ ∗ C e t t e méthode donne l e t y p e " i d e n t i f i a n t " q u i ∗ c a r a c t é r i s e c e t o b j e t au s e i n du r é a c t e u r . ∗ ∗ @return l e t y p e sous forme de chaîne de c a r a c t è r e ∗/ T getHandlerType ( ) ; /∗∗ ∗ T r a i t e m e n t a s s o c i é au t y p e r e t o u r n é par l a méthode ∗ { @link # getHandlerType ( ) getHandlerType ( ) } ∗/ v o i d handleEvent ( E event ) ; } 34 3.1 Documentation du code 3.1.3 3 JAVA Héritage Pour la documentation des classes dérivées, on peut éviter la redondance des commentaires à l’aide du tag javadoc {@inheritDoc} Il convient, par ailleurs, de marquer les méthodes à l’aide de l’annotation @Override. package f r . unicaen . r e a c t o r ; /∗∗ ∗ Une i m p l e m e n t a t i o n de l ’ i n t e r f a c e Handler pour l e r e a c t o r . ∗ ∗ @author C h r i s t o p h e ∗ ∗ @see Reactor ∗ @see Handler ∗ ∗ @see Caddie ∗ ∗ @param E l e t y p e d ’ évènement que l ’ on t r a i t e . ∗ @param T l e t y p e q u i i d e n t i f i e l e c a l l b a c k dans l e r e a c t e u r . ∗/ p u b l i c c l a s s HandleTeddyBear implements Handler < S t r i n g , Caddie > { /∗∗ ∗ Une c o n s t a n t e pour l a c l é ( T ) du r e a c t e u r . ∗/ p r i v a t e s t a t i c f i n a l S t r i n g TEDDY_BEAR_TYPE = " TeddyBear " ; /∗∗ ∗ { @inheritDoc } ∗/ @Override p u b l i c S t r i n g getHandlerType ( ) { r e t u r n TEDDY_BEAR_TYPE ; } /∗∗ ∗ { @inheritDoc } ∗/ @Override p u b l i c v o i d handleEvent ( Caddie caddie ) { caddie . add ( new TeddyBear ( ) ) ; } } 35 3.2 Règles de conception et de codage 3.1.4 3 JAVA Attributs La déclaration d’un attribut ou d’une constante doit, en général, faire l’objet d’un commentaire javadoc ou doxygen destiné à en expliciter la présence. Il faut cependant éviter les commentaires qui paraphrasent le code. Auquel cas, il est préférable de ne pas commenter l’attribut. /∗∗ ∗ Le l o g g e r l o g 4 j . ∗/ p r i v a t e s t a t i c f i n a l LOGGER = Logger . getLogger ( Reactor . c l a s s ) ; /∗∗ ∗ Map d e s t i n é e à r e c e v o i r l e s h a n d l e u r s . ∗/ p r i v a t e Map< S t r i n g , Caddie > h a n d l e r s = new HashedMap< S t r i n g , Caddie > ( ) ; 3.2 3.2.1 Règles de conception et de codage Éviter les retours null Quand on retourne null, on se crée du travail en imposant à l’appelant de faire un contrôle des données. Un contrôle qui manque sur le null et l’application est plantée [Mar09]. Si vous souhaitez retourner null, vous devriez lever une exception ou retourner un objet vide à la place. Si vous appelez une méthode d’une API tierce qui retourne null, il faut envelopper cette méthode dans une autre méthode qui lève une exception ou retourne un objet vide. Dans de nombreux cas, les objets vide sont des solutions pratiques. Si l’on étudie le code suivant : /∗ ∗ Clean Code , A Handbook o f A g i l e Software Craftsmanship ∗/ f i n a l L i s t <Employee> employees = getEmployees ( ) ; i f ( employees ! = n u l l ) { f o r ( f i n a l Employee e : employees ) { t o t a l P a y += e . getPay ( ) ; } } getEmployees() peut retourner null, mais le doit-il vraiment ? si on change getEmployee() afin qu’il retourne une liste vide, on peut nettoyer le code ainsi : 36 3.2 Règles de conception et de codage 3 JAVA /∗ ∗ Clean Code , A Handbook o f A g i l e Software Craftsmanship ∗/ f i n a l L i s t <Employee> employees = getEmployees ( ) ; f o r ( f i n a l Employee e : employees ) { t o t a l P a y += e . getPay ( ) ; } L’API java propose une méthode Collections.emptyList() qui retourne une liste immuable prédéfinie que l’on peut utiliser dans ce cas précis : /∗ ∗ Clean Code , A Handbook o f A g i l e Software Craftsmanship ∗/ p u b l i c L i s t <Employee> getEmployees ( ) { i f ( . . t h e r e are no employees . . ) { return Collections . emptyList ( ) ; } } Si vous codez de cette manière, vous minimisez le risque NullPointerException et le code est bien meilleur. 37 3.2 3.2.2 Règles de conception et de codage 3 JAVA Éviter les passages de paramètres null Une méthode qui retourne null est mauvaise, mais passer null en paramètre de méthode est encore pire. Sauf si vous travaillez sur une API qui attend que vous passiez null, il faut éviter autant que possible de passer null dans le code [Mar09]. 38 3.2 Règles de conception et de codage 3.2.3 3 JAVA La variable devrait être déclarée final Une variable assignée une seule fois doit être déclarée final [Gri14]. De même, on ne réassigne jamais les paramètres d’une fonction. Ceux-ci devraient donc toujours être notés final. /∗ ∗ Mauvaise p r a t i q u e Java ∗ ∗ PMD example . ∗ h t t p : / / pmd . s o u r c e f o r g e . n e t / [ . . . ] # MethodArgumentCouldBeFinal h t t p : / / pmd . s o u r c e f o r g e . n e t / [ . . . ] # L o c a l V a r i a b l e C o u l d B e F i n a l ∗/ p u b l i c c l a s s Bar { p u b l i c v o i d foo1 ( S t r i n g param ) { /∗ ∗ do s t u f f w i t h param never a s s i g n i n g i t ∗/ / / skipped code } p u b l i c void foo ( ) { /∗ ∗ i f t x t A and t x t B w i l l n o t be assigned again . ∗/ String txtA = "a " ; String txtB = "b " ; / / skipped code } } /∗ ∗ Bonne p r a t i q u e Java ∗ ∗ PMD example . ∗ h t t p : / / pmd . s o u r c e f o r g e . n e t / [ . . . ] # MethodArgumentCouldBeFinal h t t p : / / pmd . s o u r c e f o r g e . n e t / [ . . . ] # L o c a l V a r i a b l e C o u l d B e F i n a l 39 3.2 Règles de conception et de codage 3 JAVA ∗/ p u b l i c c l a s s Bar { p u b l i c v o i d foo2 ( f i n a l S t r i n g param ) { /∗ ∗ b e t t e r , do s t u f f w i t h param never a s s i g n i n g i t ∗/ / / skipped code } p u b l i c void foo ( ) { /∗ ∗ I t i s b e t t e r t o do t h i s . ∗/ f i n a l String txtA = "a " ; f i n a l String txtB = "b " ; / / skipped code } } 40 3.2 Règles de conception et de codage 3.2.4 3 JAVA Utiliser ArrayList au lieu de Vector La classe Vector de l’API Java standard prend en charge les logiques d’exclusion mutuelle propres aux contextes concurrentiels. On dit qu’elle est thread safe. ArrayList est une meilleure implémentation de l’interface Collection si l’on ne travaille pas dans un contexte concurrentiel. On gagne en performances. /∗ ∗ Mauvaise p r a t i q u e ( Java ) ∗ ∗ On u t i l i s e V e c t o r dans un c o n t e x t non c o n c u r r e n t i e l . ∗/ p u b l i c c l a s s SimpleTest extends TestCase { public void testX ( ) { f i n a l C o l l e c t i o n c1 = new V e c t o r ( ) ; / / skipped code } } /∗ ∗ Bonne p r a t i q u e ( Java ) ∗ ∗ On u t i l i s e A r r a y L i s t dans un c o n t e x t non c o n c u r r e n t i e l . ∗/ p u b l i c c l a s s SimpleTest extends TestCase { public void testX ( ) { f i n a l C o l l e c t i o n c1 = new A r r a y L i s t ( ) ; / / skipped code } } 41 3.2 Règles de conception et de codage 3.2.5 3 JAVA Utiliser StringBuilder au lieu de StringBuffer L’utilisation de l’opérateur += pour les chaînes de caractères oblige la machine virtuelle à créer un StringBuilder interne à chaque opération [Gri14]. Il est préférable d’utiliser un StringBuilder unique et explicite. La classe StringBuffer de l’API Java standard prend en charge les logiques d’exclusion mutuelle propres aux accès concurrents des contextes concurrentiels. On dit qu’elle est thread-safe. On préfère l’usage de StringBuilder à celle du StringBuffer si l’on ne travaille pas dans un contexte concurrentiel. On gagne alors en performances. /∗ ∗ Mauvaise p r a t i q u e ( Java ) ∗ ∗ On u t i l i s e += s u r une chaine de c a r a c t è r e . ∗/ p u b l i c c l a s s Foo { p u b l i c v o i d bar ( ) { String a; a = " foo " ; a += " bar " ; / / l a VM crée un S t r i n g B u i l d e r . a += " bar + + " ; / / l a VM crée un a u t r e S t r i n g B u i l d e r . / / skipped code } } 42 3.2 Règles de conception et de codage 3 JAVA /∗ ∗ Mauvaise p r a t i q u e ( Java ) ∗ ∗ On u t i l i s e S t r i n g B u f f e r dans un c o n t e x t e non c o n c u r r e n t i e l . ∗/ p u b l i c c l a s s Foo { p u b l i c v o i d bar ( ) { f i n a l S t r i n g B u f f e r b u f f e r = new S t r i n g B u f f e r ( ) ; b u f f e r . append ( " f o o " ) . append ( " bar " ) ; / / skipped code } } /∗ ∗ Bonne p r a t i q u e ( Java ) ∗ ∗ On u t i l i s e S t r i n g B u i l d e r dans un c o n t e x t e non c o n c u r r e n t i e l . ∗/ p u b l i c c l a s s Foo { p u b l i c v o i d bar ( ) { f i n a l S t r i n g B u i l d e r b u i l d e r = new S t r i n g B u i l d e r ( ) ; b u i l d e r . append ( " f o o " ) . append ( " bar " ) ; / / skipped code } } 43 3.2 3.2.6 Règles de conception et de codage 3 JAVA Utiliser des énumérations en lieu et place des listes de constantes Les énumérations sont une évolution de java 5. Elles proposent une alternative aux listes de constantes dans la mesure où celles-ci sont homogènes (ie. de même type). L’énumération devient alors un type d’objet à part entière au même titre qu’une classe. /∗ ∗ Mauvaise p r a t i q u e j a v a . ∗/ p u b l i c s t a t i c f i n a l c l a s s CaddyItemTypes { p u b l i c s t a t i c f i n a l S t r i n g BEAR = " Bear " ; p u b l i c s t a t i c f i n a l S t r i n g RABBIT = " R a b b i t " ; } /∗ ∗ Bonne p r a t i q u e j a v a . ∗/ p u b l i c enum CaddyItemType { BEAR ( " Bear " ) , RABBIT ( " R a b b i t " ) ; p r i v a t e S t r i n g value ; p r i v a t e CaddyItemType ( S t r i n g v a l u e ) { t h i s . value = value ; } p u b l i c S t r i n g getValue ( ) { r e t u r n value ; } } 44 3.2 Règles de conception et de codage 3.2.7 3 JAVA Éviter de proposer un attribut d’instance de visibilité publique D’une manière générale, une classe est responsable de ses attributs et elle ne doit jamais proposer d’accès "public" sur ceux-ci. L’usage du qualifier "protected" est controversé car les classes qui héritent peuvent avoir besoin d’accéder au champ de la super classe. Toutefois, il ne faut pas oublier qu’un qualifier "protected" autorise les classes du paquetage à accéder au champ, ce qui est finalement très ouvert. La pratique courante est de protéger les champs à l’aide du qualifier "private" et de proposer, au cas par cas, des méthodes dites getters et setters pour y accéder si besoin est. La classe est alors garante de l’intégrité de ses données. Il s’agit du concept d’encapsulation. 45 3.2 Règles de conception et de codage 3.2.8 3 JAVA Éviter de qualifier la visibilité dans les interfaces Une interface spécifie un ensemble de méthodes abstraites. Il s’agit d’un type très abstrait qui ne contient que le strict nécessaire à la mise en oeuvre ultérieure par des classes dérivées. Java autorise, pour chaque méthode abstraite de déclarer (ou non) sa visibilité. Il s’agit conceptuellement d’un détail d’implémentation qui est souvent considéré comme inutile pour la lecture des interfaces de programmation. On préfère écrire les interfaces sans les informations relatives à la visibilité. /∗ ∗ Java , mauvaise p r a t i q u e ∗/ p u b l i c i n t e r f a c e Bear { p u b l i c v o i d e a t ( Salmon salmon ) ; p u b l i c v o i d walkAlong ( R i v e r r i v e r ) ; } /∗ ∗ Java , bonne p r a t i q u e ∗/ p u b l i c i n t e r f a c e Bear { / / le q u a l i f i e r public disparait , i l / / sera d é c l a r é dans l a c l a s s e d é r i v é . v o i d e a t ( Salmon salmon ) ; v o i d walkAlong ( R i v e r r i v e r ) ; } 46 3.2 3.2.9 Règles de conception et de codage 3 JAVA Qualifier "public", "protected" et "private" les méthodes des classes Une règle de bon sens. On évite d’utiliser l’absence de qualifier, c’est à dire le qualifier "friendly" qui s’approche de "protected" mais sans l’accès aux sous méthodes héritées. Il est préférable d’expliciter clairement la visibilité des méthodes de chaque classe parmi les 3 qualifiers suivants : — public ; — private ; — protected. 47 4 4 JAVA ENTERPRISE Java Enterprise 4.1 4.1.1 Traitement par lots Pré-allocation des séquences Les générateurs d’identifiants de JPA et d’hibernate utilisent par défaut une pré-allocation de séquence de taille 1[Sut11]. Dans cette configuration, chaque instruction insert ou update provoque l’appel à une autre instruction select qui sert à récupérer la nouvelle valeur de la séquence. En conséquence, les accès sont doublés en base de données lors des traitements par lots. Cette configuration est excessive. Si l’on modifie ce critère pour 500 ou 1000, on réduit de moitié les accès dans les procédures de traitement par lots. Les identifiants ne sont cependant plus contigus en base, mais les performances sont au rendezvous. < h i b e r n a t e −mapping> < c l a s s name=" f r . univbordeaux . [ . . . ] . I n d i v i d u U n a " t a b l e =" i n d i v i d u _ u n a " > < i d name=" i d I n d i v i d u U n a " t y p e =" i n t " > <column name=" i d _ i n d i v i d u _ u n a " / > < g e n e r a t o r c l a s s =" sequence " > <param name=" sequence " > s e q _ i n d i v i d u _ u n a < / param> <!−− − A l l o c a t i o n S i z e v a u t maintenant 1000. −−> <param name=" a l l o c a t i o n S i z e " >1000 </param> </ g e n e r a t o r > </ i d > ... </ c l a s s > </ h i b e r n a t e −mapping> 48 4.2 4.1.2 Logging 4 JAVA ENTERPRISE Utiliser hibernate.jdbc.batch_size Sans une configuration adéquate, JPA et hibernate ne sont pas prêts pour gérer correctement les traitements par lots. Les nouvelles instances sont insérées dans le cache de second niveau[Doc14a] ce qui provoque généralement une OutOfMemoryException aux alentours du 50 000 ème objet traité. On configure donc le framework afin qu’il place les objets dans le cache de premier niveau et ce, avec une fenêtre raisonnable (10-50) h i b e r n a t e . j d b c . b a t c h _ s i z e 20 Lorsque vous rendez de nouveaux objets persistants ou lorsque vous les mettez à jour, vous devez régulièrement appeler flush() et puis clear() sur la session, pour contrôler la taille du cache de premier niveau[Doc14a]. Session s e s s i o n = s e s s i o n F a c t o r y . openSession ( ) ; Transaction t x = session . beginTransaction ( ) ; f o r ( i n t i =0; i <100000; i ++) { Customer customer = new Customer ( . . . . . ) ; s e s s i o n . save ( customer ) ; i f ( i % 20 == 0 ) { /∗ ∗ 20 , same as t h e JDBC batch s i z e ∗ ∗ f l u s h a batch o f i n s e r t s and r e l e a s e memory : ∗/ session . f l u s h ( ) ; session . c l e a r ( ) ; } } t x . commit ( ) ; session . close ( ) ; 4.2 4.2.1 Logging Éviter le println() Dans les applications d’entreprise, il convient d’éviter les instructions de type System.out.println(). Il est préférable d’utiliser un logger [Gri14]. 49 4.2 Logging 4 JAVA ENTERPRISE /∗ ∗ Java , mauvaise p r a t i q u e ∗/ c l a s s Foo { /∗∗ ∗ Corps de l a f o n c t i o n . ∗/ public void testA ( ) { System . o u t . p r i n t l n ( " E n t e r i n g t e s t " ) ; } } /∗ ∗ Java , bonne p r a t i q u e ∗/ c l a s s Foo { /∗∗ ∗ Le l o g g e r l o g 4 j . ∗/ p u b l i c s t a t i c f i n a l Logger LOGGER = Logger . getLogger ( Foo . c l a s s . getName ( ) ) ; /∗∗ ∗ Corps de l a f o n c t i o n . ∗/ public void testA ( ) { / / B e t t e r use t h i s LOGGER. f i n e ( " E n t e r i n g t e s t " ) ; } } 50 4.2 Logging 4.2.2 4 JAVA ENTERPRISE Éviter le printStackTrace() Dans les applications d’entreprise, évitez d’appeler printStackTrace(), il est préférable d’utiliser un logger. On conserve ainsi les exceptions dans un log [Gri14]. p u b l i c c l a s s Foo { /∗ ∗ Java e n t e r p r i s e , mauvaise p r a t i q u e . ∗/ /∗∗ ∗ Corps de l a f o n c t i o n . ∗/ p u b l i c v o i d bar ( ) { try { / / do something } catch ( f i n a l Exception e ) { e . printStackTrace ( ) ; } } /∗ ∗ Java , bonne p r a t i q u e . ∗/ p u b l i c c l a s s Foo { /∗∗ ∗ Le l o g g e r l o g 4 j . ∗/ p r i v a t e s t a t i c f i n a l Logger LOGGER = Logger . getLogger ( Foo . c l a s s . getName ( ) ) ; /∗∗ ∗ Corps de l a f o n c t i o n . ∗/ p u b l i c v o i d bar ( ) { try { / / do something } catch ( f i n a l Exception e ) { LOGGER. e r r o r ( " Uncaught e x c e p t i o n " , e ) ; } } } 51 4.2 4.2.3 Logging 4 JAVA ENTERPRISE Un logger par classe Normallement, un seul et unique logger est utilisé pour une classe et il devrait être private static final [Gri14]. /∗ ∗ Java , bonne p r a t i q u e . ∗/ p u b l i c c l a s s Foo { /∗∗ ∗ Le l o g g e r l o g 4 j . ∗/ p r i v a t e s t a t i c f i n a l Logger LOGGER = Logger . getLogger ( Foo . c l a s s . getName ( ) ); / / skipped code } 52 4.2 Logging 4.2.4 4 JAVA ENTERPRISE Bien logger un message en mode debug On utilise isDebugEnabled() pour optimiser le traitement des messages en mode nominal. Quand le debug n’est pas activé, on gagne en temps de traitement : log4j ne cherche alors pas à calculer le niveau du message au regard de la configuration complète. Il se contente de dire si le debug est activé et ne cherche pas à étudier la pile des niveaux de logs autorisés. On gagne en temps de traitement. /∗ ∗ Java , bonne p r a t i q u e . ∗/ p u b l i c c l a s s Foo { /∗∗ ∗ Le l o g g e r l o g 4 j . ∗/ p r i v a t e s t a t i c f i n a l Logger LOGGER = Logger . getLogger ( Foo . c l a s s . getName ( ) ); /∗∗ ∗ f u n c t i o n body . ∗/ p u b l i c v o i d bar ( f i n a l S t r i n g name ) { i f (LOGGER. isDebugEnabled ( ) ) { f i n a l S t r i n g B u i l d e r b u i l d e r = new S t r i n g B u i l d e r ( ) ; b u i l d e r . append ( " name i s [ " ) ; . append ( name ) ; . append ( ’ ] ’ ) ; f i n a l S t r i n g message = b u i l d e r . t o S t r i n g ( ) ; LOGGER. debug ( message ) ; } } } 53 4.3 Couplage 4.3 4.3.1 4 JAVA ENTERPRISE Couplage Utiliser Spring et l’inversion de contrôle Spring est un conteneur léger d’application javaee. Il prend en charge l’instanciation des objets à l’aide d’un patron de conception qui réduit le couplage entre les classes : l’inversion de contrôle (IOC, Inversion Of Control). L’inversion de contrôle remplace l’instanciation des dépendances par une injection de celles-ci à l’aide d’un framework, en l’occurence, spring. Exemple : nous avons une dépendance directe d’une classe A vers une classe B. Il s’agit d’introduire un typage par interfaces afin de réduire le couplage entre les classes A et B. La classe A ne dépend donc plus de B directement, mais de I qui peut être implémenté par n’importe quelle autre classe. Les dépendances sont instanciées et injectées par le framework. Mise en oeuvre public interface I { v o i d executeMethod ( ) ; } 54 4.3 Couplage 4 JAVA ENTERPRISE public class A { p r i v a t e I dependanceI ; public A() { } p u b l i c A ( f i n a l I dependanceI ) { t h i s . dependanceI = dependanceI ; } p u b l i c v o i d setDependanceI ( f i n a l I dependanceI ) { t h i s . dependanceI = dependanceI ; } p u b l i c v o i d process ( ) { dependanceI . executeMethod ( ) ; } } p u b l i c c l a s s B implements I { public B() { } p u b l i c v o i d executeMethod ( ) { / / skipped code } } 55 4.3 Couplage 4 JAVA ENTERPRISE Injection des dépendances à l’aide de Spring <beans xmlns =" h t t p : / / www. s p r i n g f r a m e w o r k . org / schema / beans " xmlns : x s i =" h t t p : / / www. w3 . org / 2 0 0 1 /XMLSchema−i n s t a n c e " x s i : schemaLocation =" h t t p : / / www. s p r i n g f r a m e w o r k . org / schema / beans h t t p : / / www. s p r i n g f r a m e w o r k . org / schema / beans / s p r i n g −beans −2.5. xsd " > <bean name=" beanB " c l a s s =" f r . univbordeaux . i o c . B" / > <bean name=" beanA " c l a s s =" f r . univbordeaux . i o c . A" > < p r o p e r t y name=" dependanceI " r e f =" beanB " / > </ bean> </ beans> 56 5 5 PHP PHP Pratiques qui s’intéressent, quasi exclusivement, à la programmation en PHP. Par nature, PHP est complaisant et permissif avec de nombreuses pratiques. Il convient de prendre quelques habitudes pour rendre le code moins complexe à analyser et éviter des problèmes de sécurité. 5.1 PHP Standards Recommendations (PSR) Si l’on suit le processus de validation des "PHP Standard Recommendation" (PSR), chaque PSR a un statut de sorte que l’on puisse travailler dessus. Une fois que la proposition a passé le vote d’entrée, elle est alors marquée comme "Brouillon". Tant qu’une PSR n’est pas marquée "Acceptée", elle est sujette à des changements. Les brouillons peuvent changer drastiquement. Les "Review" seront seulement sujettes à des changements mineurs.[Gro16] Dans ce processus, l’éditeur ou les éditeurs d’une proposition sont essentiellements les contributeurs principaux qui ont écrit la PSR et ils sont appuyés par 2 membres qui votent. Les membres qui votent sont le coordinateur (qui est responsable du pilotage de l’étape de relecture "Review") ainsi qu’un second membre dit "Sponsor". N◦ 1 2 3 4 6 7 Titre Basic Coding Standard Coding Style Guide Logger Interface Autoloading Standard Caching Interface HTTP Message Interface Editeur Paul M. Jones Paul M. Jones Jordi Boggiano Paul M. Jones Larry Garfield Matthew Weier O’Phinney Coordinateur N/A N/A N/A Phil Sturgeon Paul Dragoonis Beau Simensen Sponsor N/A N/A N/A Larry Garfield Robert Hafner Paul M. Jones Ce paragraphe présente succinctement les PSR 1, 2 et 4. 5.1.1 PSR-1 : Basic Coding Standard Cette partie du document comprend ce qui doit etre considéré comme les éléments de codage standard nécessaires pour assurer un haut niveau d’interopérabilité entre les morceaux de code PHP partagés. Lire la suite : http://www.php-fig.org/psr/psr-1/ 5.1.2 PSR-2 : Coding Style Guide Cette partie du document hérite et étend la norme PSR-1 c’est-a-dire, les éléments de codage de base. L’objectif est de reduire la friction cognitive qui résulte de l’analyse des codes de différents auteurs. On y arrive en partageant un ensemble de règles et d’attentes sur la manière dont doit etre formaté le code PHP. Le style des règles présentées ici sont dérivées des points communs relatifs à un certain nombre de projets. Quand divers auteurs collaborent sur plusieurs projets, il est utile d’avoir un ensemble de lignes directrices qu’il convient de respecter sur ces projets. C’est pourquoi les bénéfices de cette norme n’est pas dans le contenu des règles, en tant que telles, mais dans le partage de celles-ci. Lire la suite : http://www.php-fig.org/psr/psr-2/ 57 5.2 En vrac 5.1.3 5 PHP PSR-4 : Autoloading Standard Cette norme décrit la manière dont les classes sont chargées depuis le système de fichier. Elle est entièrement interopérable et peut etre utilisée en supplément de n’importe quelle autre méthode de chargement, ce qui inclue la PSR-0. Cette PSR présente également l’endroit où placer les fichiers qui seront auto-chargés en accord avec la spécification. Lire la suite : http://www.php-fig.org/psr/psr-4/ 5.2 En vrac Des règles en vrac, relevées de manière empiriques. 5.2.1 Développer en E_ALL|E_STRICT E_ALL et E_STRICT sont d’une aide précieuse pour écrire un code de qualité. — E_ALL affiche toutes les erreurs, les warnings ; — E_STRICT affiche des suggestions pour améliorer l’interopérabilité et l’évolutivité du code. Dans l’idéal, il faudrait toujours développer ainsi. /∗ ∗ Bonne p r a t i q u e de développement : u t i l i s e r E_STRICT ∗/ e r r o r _ r e p o r t i n g ( E_ALL | E_STRICT ) ; La fonction error_reporting est parfois désactivée, notamment si PHP s’exécute en safe-mode. On peut, dans ce cas, forcer le mode E_ALL | E_STRICT dans un fichier .htaccess de la manière suivante : php_value e r r o r _ r e p o r t i n g 4095 On peut également ajouter les paramètres de configuration suivants pour forcer l’affichage d’un maximum d’informations. php_flag php_flag php_flag php_flag php_flag php_flag d i s p l a y _ e r r o r s On t r a c k _ e r r o r s On h t m l _ e r r o r s On report_memleaks On d i s p l a y _ s t a r t u p _ e r r o r s On l o g _ e r r o r s On 58 5.2 5.2.2 En vrac 5 PHP Utiliser les structures de contrôle du langage C En PHP, il est possible d’écrire des structures de contrôle (if, else, for, while, switch) en respectant les styles des langages C ou BASIC. Les structures de contrôle du langage C sont reprises par les langages C, Java, C# et C++. De ce fait, elles sont familières pour la plupart des développeurs. Les structures de contrôle en style BASIC sont à éviter. /∗ ∗ Mauvaise p r a t i q u e : é c r i r e l e s s t r u c t u r e s de c o n t r ô l e dans ∗ l e s t y l e du langage BASIC . ∗/ i f ( $a == 5 ) : echo " a e s t é g a l à 5 " ; echo " . . . " ; else : echo " a n ’ e s t pas é g a l à 5 " ; endif ; /∗ ∗ Bonne p r a t i q u e : é c r i r e l e s s t r u c t u r e s de c o n t r ô l e dans l e s t y l e ∗ du langage C . ∗/ i f ( $a == 5 ) { echo " a e s t é g a l à 5 " ; echo " . . . " ; } else { echo " a n ’ e s t pas é g a l à 5 " ; } 59 5.2 En vrac 5.2.3 5 PHP Ne pas utiliser les short open tags Les « short open tags » posent des problèmes de portabilité. Tous les serveurs ne les supportent pas. L’interpréteur PHP CLI les considère d’ailleurs comme des erreurs de syntaxe. Il est préférable d’utiliser l’instruction complète <?php <? /∗ ∗ Mauvaise p r a t i q u e (PHP) ∗/ echo ’PHP code w r i t t e n u s i n g s h o r t open t a g s ’ ; ?> <?php /∗ ∗ Bonne p r a t i q u e (PHP) ∗/ echo ’PHP code w r i t t e n u s i n g f u l l php t a g s ’ ; ?> 60 5.2 En vrac 5.2.4 5 PHP Constructeurs PHP5 Il est préférable de nommer les constructeurs des classes __construct(). Les conventions de nommage de PHP4 sont toujours supportées pour des raisons de compatibilité ascendante. Elles sont cependant déconseillées (dépréciées) dans la documentation de PHP. /∗ ∗ Mauvaise p r a t i q u e (PHP) ∗/ c l a s s DBConnect { /∗∗ ∗ C o n s t r u c t e u r par d é f a u t . ∗ ∗ C o n s t r u i t une i n s t a n c e de DBConnect . ∗/ p u b l i c DBConnect ( ) { /∗ ∗ Bonne p r a t i q u e (PHP) ∗/ c l a s s DBConnect { /∗∗ ∗ C o n s t r u c t e u r par d é f a u t . ∗ ∗ C o n s t r u i t une i n s t a n c e de DBConnect . ∗/ public __construct ( ) { 61 5.2 En vrac 5.2.5 5 PHP Ne jamais utiliser de variables globales Les variables globales peuvent être modifiées par l’interpréteur PHP depuis d’autres endroits du code, ce qui peut produire des effets de bord. Il convient de garder des variables de portées locales. Le code s’en trouve plus simple et plus propre. C’est une aide pour son débugage, sa relecture et sa pérénité. D’une manière générale, lorsque le mot clé global est utilisé, on considère suspect le code et on procède à une opération de réusinage pour le corriger. 62 5.2 En vrac 5.2.6 5 PHP Éviter les conversions implicites PHP peut convertir des types de manière implicite en silence et sans précautions. C’est notamment le cas si l’on additionne une chaîne de caractères (qui représente un entier) avec un entier. La valeur de la chaîne de caractères est alors extraite puis convertie en entier. Le développeur distrait n’a plus conscience du type de données qu’il manipule ! On prèfère évidemment une conversion explicite de type. /∗ ∗ Mauvaise p r a t i q u e (PHP) ∗/ /∗ ∗ $groupe [ ’ count_etapes ’ ] e s t une chaîne de c a r a c t è r e ∗ q u i r e p r é s e n t e un e n t i e r . ∗ ∗ On cherche i c i à s a v o i r s i c e t t e v a l e u r e s t s u p é r i e u r e à zéro . ∗ ∗ I l f a u t l a c o n v e r t i r en e n t i e r pour p o u v o i r t e s t e r sa ∗ v a l e u r numérique . ∗/ $count_etapes = $groupe [ ’ count_etapes ’ ] i f ( ( $count_etapes + 0 ) > 0 ) { ... } /∗ ∗ Bonne p r a t i q u e (PHP) ∗/ /∗ ∗ Pour c o n v e r t i r $count_etapes en e n t i e r , i l e s t p r é f é r a b l e ∗ d ’ utiliser l ’ instruction intval (). ∗/ $count_etapes = i n t v a l ( $groupe [ ’ count_etapes ’ ] ) ; i f ( $count_etapes > 0 ) { ... } 63 5.2 En vrac 5.2.7 5 PHP Toujours initialiser ses variables Il n’est pas cohérent d’utiliser une variable sans l’avoir préalablement déclarée et affectée. Le développeur paresseux peut être heureux car PHP va automatiquement déclarer ces variables pour lui. Charge au relecteur de trouver s’il s’agit ou non d’un oubli. Le code est brouillon et difficile à comprendre. Il convient donc de toujours déclarer et initialiser ses variables de manière explicite. /∗ ∗ Mauvaise p r a t i q u e (PHP) ∗/ function retrieveValues ( ) { /∗ ∗ La méthode r e t r i e v e V a l u e s I m p l ( ) r e n s e i g n e l e t a b l e a u ∗ $data passé par r é f é r e n c e . ∗ ∗ Dans c e t exemple $data e s t d é c l a r é de manière i m p l i c i t e . ∗ C ’ e s t une mauvaise p r a t i q u e , b i e n que PHP l ’ a u t o r i s e . ∗/ r e t r i e v e V a l u e s I m p l ( $data ) ; r e t u r n $data ; } /∗ ∗ Bonne p r a t i q u e (PHP) ∗/ function retrieveValues ( ) { /∗ ∗ On d é c l a r e de manière e x p l i c i t e $data avant de ∗ l e passer à l a f o n c t i o n r e t r i e v e V a l u e s I m p l ( ) ∗ ∗ C ’ e s t l a bonne p r a t i q u e . ∗/ $data = array ( ) ; r e t r i e v e V a l u e s I m p l ( $data ) ; r e t u r n $data ; } 64 5.2 5.2.8 En vrac 5 PHP Concaténation d’une variable valeur NULL Une variante de la règle présentée précédemment : PHP permet de concaténer une variable NULL avec une chaine de caractères. Le code ainsi créé est, là encore, confus et brouillon. Il est préférable d’initialiser la variable avant de la concaténer. $where = NULL ; i f ( empty ( $cod_cge ) === FALSE ) { /∗ ∗ A t t e n t i o n , on va i c i concaténer une v a r i a b l e NULL ∗ avec une chaîne de c a r a c t è r e s ! ∗/ $where . = " ( ETP . cod_cge = ’ " ; ... } /∗ ∗ Bonne p r a t i q u e de développement : i n i t i a l i s e r ∗ $where à une a u t r e v a l e u r que NULL : ) ∗/ $where = ’ ’ ; i f ( empty ( $cod_cge ) === FALSE ) { /∗ ∗ $where n ’ e s t pas NULL , on peut ∗ concaténer l e s yeux fermés . ∗/ $where . = " ( ETP . cod_cge = ’ " ; ... } 65 5.2 5.2.9 En vrac 5 PHP Éviter l’appel de fonctions dans le corps dúne déclaration de boucle for Appeler une fonction dans le corps d’une déclaration de boucle for est inutilement couteux en calcul et peut être source d’erreurs. Il vaut mieux écrire une ligne de plus. /∗ ∗ Mauvaise p r a t i q u e (PHP) ∗/ f o r ( $ i = 0 ; $ i < count ( $ a r r a y ) ; $ i ++) { ... } /∗ ∗ Bonne p r a t i q u e (PHP) ∗/ $count = count ( $ a r r a y ) ; f o r ( $ i =0; $ i < $count ; $ i ++) { ... } 66 6 6 6.1 PYTHON Python Exécuter l’interpréteur avec l’option -tt Il est préférable de lancer l’interpréteur avec l’option -tt et ce, afin de lever des erreurs si l’indentation n’est pas concistante. 67 RÉFÉRENCES RÉFÉRENCES Bibliographie Références [Cor14] Oracle Corp. Code conventions for the java programming language : Contents, 2014. http: //www.oracle.com/technetwork/java/codeconvtoc-136057.html. [Doc14a] Hibernate Community Documentation. Chapitre 14. traitement par lot, 2014. http://docs. jboss.org/hibernate/core/3.5/reference/fr-FR/html/batch.html. [doc14b] The PEAR documentation. Indentation et longueur de lignes, 2014. http://pear.php.net/ manual/fr/standards.indenting.php. [GHJV94] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns : Elements of Reusable Object-Oriented Software. Addison-Wesley professional computing series, 1994. [Gri14] Miguel Griffa. Pmd rulesets index, 2014. http://pmd.sourceforge.net/pmd-5.1.1/rules/ index.html. [Gro16] PHP Framework Interop Group. Moving php forward through collaboration and standards, 2016. http://www.php-fig.org/. [ll14] Wikipedia l’encyclopédie libre. Programmation structurée – wikipédia, 2014. http://fr. wikipedia.org/wiki/Programmation_structur%C3%A9e. [Mar09] Robert C. Martin. Clean Code, A Handbook of Agile Software Craftmanship. Prentice Hall, 2009. [Mer10] Bruno Mermet. Code smells, 2010. CoursPDF/codeSmells.pdf. [Mer11] Bruno Mermet. Vérification automatique de la qualité de code, 2011. https://mermet. users.greyc.fr/Enseignement/CoursPDF/verificationAutomatiqueQualiteCode.pdf. [Mod13] Niklas Modess. Cyclomatic and npath complexity explained, 2013. http://codingswag. ghost.io/cyclomatic-and-npath-complexity-explained/. https://mermet.users.greyc.fr/Enseignement/ [PHP14a] Manuel PHP. Php : Constructors and destructors - manual, 2014. http://php.net/manual/ en/language.oop5.decon.php. [PHP14b] Manuel PHP. Php : Syntaxe alternative - manual, 2014. control-structures.alternative-syntax.php. http://php.net/manual/fr/ [Sou14] SourceMaking. Replace conditional with polymorphism, 2014. http://sourcemaking.com/ refactoring/replace-conditional-with-polymorphism. [Sut11] James Sutherland. Java persistence performance : How to improve jpa performance by 1 825 %, 2011. http://java-persistence-performance.blogspot.fr/2011/06/ how-to-improve-jpa-performance-by-1825.html. [Tea14] Checkstyle Development Team. checkstyle - available checks, 2014. http://checkstyle. sourceforge.net/availablechecks.html. [Wik16] Wikipedia. Règles de codage, 2016. https://fr.wikipedia.org/wiki/R%C3%A8gles_de_ codage. 68