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