Explorer les Livres électroniques
Catégories
Explorer les Livres audio
Catégories
Explorer les Magazines
Catégories
Explorer les Documents
Catégories
INTRODUCTION
Un logiciel peut être confectionné de plusieurs façons différentes. En fait, une même
fonctionnalité peut être codée sous des designs complètement différents et c’est exactement la
source du problème qui fait que les projets de développement ratent souvent leur cible en termes
d’estimation d’efforts. En effet, bien qu’il y ait une architecture prédéterminée, le développeur
est souvent laissé à lui-même lorsque vient le temps d’implémenter la fonctionnalité. Pour faire
une comparaison avec le monde de la construction, c’est un peu comme si on laissait le
menuisier choisir comment monter les murs et arranger les pièces… vous imaginez le bordel
dans une équipe de 10 menuisiers qui travaillent sur une même maison ? Heureusement pour
eux (et pour nous !), ils ont des standards à respecter. Pour notre part, nous avons les patrons
de conceptions et les principes de programmation. On peut donc dire que les design patterns
(patrons de conception en français) naissent via l’expérience. En effet, être confronté plusieurs
fois à un même problème permet d’améliorer et d’affiner à chaque fois la solution qu’on y
apporte. Au bout d’un moment, en fédérant les travaux d’autres personnes ayant été confrontées
au même problème, on va finir par aboutir à une solution qui s’avère être la mieux adaptée pour
ce problème précis. Il suffit ensuite d’en retirer la moelle pour obtenir un modèle réutilisable
permettant de résoudre le problème de manière efficace et performante.
Un design pattern est donc une capitalisation du travail. On peut y voir 3 points positifs :
• Livrer plus vite
• Gérer le changement
• Gérer la complexité
Historiquement, les design patterns proviennent des travaux de Christopher Alexander
(architecte) dans les années 70 et ont été formalisés dans le livre “Design Patterns – Elements
of Reusable Object-Oriented Software” du Gang Of Four en 1995 (ou GoF : groupe de 4
informaticiens, Erich Gamma, Richard Helm, Ralph Johnson et John Vlissides, auteurs de
nombreux ouvrages en programmation orientée objet.
L’acronyme SOLID a été inventé par Michael Feathers, auteur du livre Working Effectively
With Legacy Code, mais a été popularisé par Robert C. Martin.
Ces principes de programmation sont la base de tout code qui se veut clair, propre, facilement
maintenable et facile à faire évoluer. Lorsqu’on parle « facilité » de maintenance ou
d’évolution à propos du code, il faut comprendre que cela signifie que le coût nécessaire pour
effectuer un changement à l’application devrait toujours être inférieur aux bénéfices
directement apportés par le changement.
1/10
ARCHITECTURE D’APPLICATION CS2I 3 / 3IAC
Généralités.
• Au début de la phase de la conception, le système semble beau, élégant, pur…
• …mais ensuite, pendant le développement, on a des hacks, des implémentations vites
faites et négligentes pour respecter les délais.
• Le logiciel commence à pourrir !
• Quels sont les symptômes d’une conception en train de pourrir ?
• Pour s’assurer de maintenir la qualité de la conception, on doit se baser sur des
principes
• Quels sont ces principes ?
1. SRP (Single Responsibility Principle)
« Parce que tu peux ne signifie pas que tu dois. »
Une classe doit avoir une seule responsabilité.
• Une classe ne devrait avoir qu’une seule responsabilité.
• …mais qu’est-ce que ça veut dire ?
• Une classe ne devrait avoir qu’une seule raison de changer.
• Est-il possible de prévoir les changements d’une classe ?
Exemple :
/* Cette classe encapsule les données d’un utilisateur */
public class User {
public String firstName;
public String lastName;
public String phoneNumber;
}
2/10
ARCHITECTURE D’APPLICATION CS2I 3 / 3IAC
/* Cette classe encapsule les données d’un utilisateur et valide les informations */
package com.oca.solid.srp;
// getters...
}
• Les entités logicielles doivent être ouvertes aux extensions, mais fermées aux
modifications.
L’OCP ou principe ouvert/fermé est beaucoup moins compris que le premier. Lorsqu’on dit
qu’une classe est fermée aux modifications et ouverte à l’extension, il faut comprendre qu’il est
préférable de créer une sous-classe ou d’ajouter des membres pour lui apporter une modification
d’état ou de comportement que de modifier les membres existants.
Donc, si vous devez modifier le corps d’une méthode, sa signature ou encore le type d’une
propriété d’une classe, vous avez de très forte chance d’être en train de briser l’OCP.
3/10
ARCHITECTURE D’APPLICATION CS2I 3 / 3IAC
Exemple
Voici une classe qui applique des validations sur l’âge d’un utilisateur :
package com.oca.solid.ocp;
Si nous voulons ajouter de l’information concernant la region et qu’on ne respecte pas l’OCP,
on peut arriver à :
package com.oca.solid.ocp;
package com.oca.solid.ocp;
4/10
ARCHITECTURE D’APPLICATION CS2I 3 / 3IAC
5/10
ARCHITECTURE D’APPLICATION CS2I 3 / 3IAC
package com.oca.solid.lsp;
L’ISP ou principe de ségrégation de l’interface est un autre principe nébuleux que nous
allons démystifier. Le couplage est un principe orienté-objet qui se quantifie en déterminant les
cas d’utilisation des classes. On dit de deux classes qu’elles ont un couplage fort lorsqu’elles
s’utilisent. Afin de diminuer le couplage, il est possible de dépendre d’une abstraction, cachant
ainsi l’implémentation à l’appelant. Le problème avec l’ISP, c’est lorsqu’une interface ou une
classe abstraite devient trop volumineuse et expose trop d’information via son API.
On peut comprendre que l’ISP est lié avec le SRP par le fait que l’interface peut définir plusieurs
concepts qui ne sont pas nécessairement liés.
Exemple
Dans l’exemple ci-dessous, la classe Vehicule a deux comportements. Nous pouvons démarrer
la voiture ou allumer les lumières.
6/10
ARCHITECTURE D’APPLICATION CS2I 3 / 3IAC
En supposant qu’une deuxième classe aurait la responsabilité d’allumer les lumières comme
suit :
class VehiculeLightTurner
{
public Vehicule vehicule;
Afin de respecter au maximum l’ISP, il faut se demande pourquoi une classe responsable
d’allumer les lumières devrait savoir qu’un véhicule peut être démarrer. On peut alors extraire
l’interface afin que notre classe ne connaisse que ce dont elle a besoin :
public interface VehiculeWithLights {
void turnLightsOn();
}
class VehiculeLightTurner {
public VehiculeWithLights vehicle;
7/10
ARCHITECTURE D’APPLICATION CS2I 3 / 3IAC
Le DIP ou principe d’inversion de dépendance nous dit que les dépendances d’une classe ne
devraient jamais être concrètes. Puisqu’elle ne doit pas connaître l’implémentation de ses
dépendances, nous pouvons nous assurer du respect de ce principe en implémentant le patron
de conception d’injection de dépendances, soit via le constructeur, soit via les mutateurs.
Supposons que vous avez une classe responsable de la journalisation. Cette classe est utilisée
dans un service afin de journaliser les entrées et sorties :
8/10
ARCHITECTURE D’APPLICATION CS2I 3 / 3IAC
class Logger {
public void log(String msg) {
System.out.println(msg);
}
}
class SomeService {
private Logger logger;
public SomeService() {
this.logger = new Logger();
}
class SomeService {
private Logger logger;
public SomeService() {
this.logger = new ConsoleLogger();
}
9/10
ARCHITECTURE D’APPLICATION CS2I 3 / 3IAC
class SomeService {
private Logger logger;
CONCLUSION
Ces principes, règles et patterns ne sont que des outils permettant de faciliter la rédaction du
code et la création d’applications robustes et évolutives et ils ne sont donc pas toujours à prendre
au pied de la lettre. En fonction de la criticité du module que vous écrivez, il ne sera pas
forcément indispensable de mettre en œuvre une usine à gaz ! Vous pouvez aussi très bien faire
une première version “simple” que vous ferez évoluer au fur et à mesure des besoins (et à ce
moment il sera peut-être nécessaire d’appliquer ces principes).
10/10