Skip to content

Commit b568d30

Browse files
committed
Add software engineering principles and enhance Java documentation
1 parent 94e0a27 commit b568d30

10 files changed

Lines changed: 546 additions & 118 deletions

docs/.vitepress/config.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,16 @@ export default withMermaid({
7373
{ text: 'Structural', link: '/cours/design-patterns/4-structural' },
7474
{ text: 'Behavioral', link: '/cours/design-patterns/5-behavioral' },
7575
]
76+
},
77+
{
78+
text: 'Génie logiciel',
79+
items: [
80+
{ text: 'Introduction', link: '/cours/genie-logiciel/introduction' },
81+
{ text: 'Simplicité et clarté', link: '/cours/genie-logiciel/simplicite-et-clarte' },
82+
{ text: 'Réutilisabilité et maintenabilité', link: '/cours/genie-logiciel/reutilisabilite-et-maintenabilite' },
83+
{ text: 'Conception orientée objet', link: '/cours/genie-logiciel/conception-orientee-objet' },
84+
{ text: 'Robustesse et gestion des erreurs', link: '/cours/genie-logiciel/robustesse-et-erreurs' },
85+
]
7686
}
7787
]
7888
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# Conception orientée objet
2+
3+
La programmation orientée objet, telle une architecture savante, repose sur des principes qui en garantissent la solidité, la souplesse et la beauté. Ces principes, forgés par l’expérience et la réflexion, sont les fondations sur lesquelles s’élèvent les logiciels robustes et évolutifs. Parmi eux, les fameux SOLID, mais aussi la Loi de Demeter, tracent la voie d’un code élégant et pérenne. Plongeons dans ces piliers, en les éclairant d’exemples concrets et de réflexions issues du terrain.
4+
5+
## SOLID
6+
Les cinq principes SOLID sont des boussoles pour l’ingénieur logiciel. Ils guident la conception vers la clarté, la modularité et la facilité d’évolution.
7+
8+
### S — Single Responsibility Principle (Responsabilité unique)
9+
10+
Imaginez une classe comme un artisan spécialisé : elle doit n’avoir qu’une seule mission, une seule raison de changer. Plus une classe s’éparpille, plus elle devient fragile et difficile à maintenir.
11+
12+
**Exemple :**
13+
14+
```java
15+
// Mauvais exemple : une classe gère trop de choses
16+
class Rapport {
17+
void generer() {}
18+
void sauvegarder() {}
19+
}
20+
21+
// Bon exemple : séparation des responsabilités
22+
class Rapport {
23+
void generer() {}
24+
}
25+
class RapportSauvegarde {
26+
void sauvegarder(Rapport r) {}
27+
}
28+
```
29+
30+
---
31+
32+
### O — Open/Closed Principle (Ouvert/Fermé)
33+
34+
Un bon logiciel doit pouvoir évoluer sans être sans cesse remanié. Les entités doivent être ouvertes à l’extension, mais fermées à la modification. On ajoute, on enrichit, sans tout casser.
35+
36+
**Exemple :**
37+
38+
```java
39+
// Mauvais exemple : modification de la classe pour chaque nouveau type
40+
class Facture {
41+
double calculerRemise(String type) {
42+
if (type.equals("VIP")) return 0.2;
43+
else return 0.0;
44+
}
45+
}
46+
47+
// Bon exemple : extension par héritage
48+
interface Remise {
49+
double calculer();
50+
}
51+
class RemiseVIP implements Remise {
52+
public double calculer() { return 0.2; }
53+
}
54+
```
55+
56+
---
57+
58+
### L — Liskov Substitution Principle
59+
60+
L’héritage doit respecter le contrat de la classe mère. Une sous-classe doit pouvoir se substituer à sa classe parente sans altérer le comportement attendu. Sinon, gare aux bugs subtils !
61+
62+
**Exemple :**
63+
64+
```java
65+
// Mauvais exemple : une sous-classe casse le contrat
66+
class Rectangle {
67+
int largeur, hauteur;
68+
void setLargeur(int l) { largeur = l; }
69+
void setHauteur(int h) { hauteur = h; }
70+
}
71+
class Carre extends Rectangle {
72+
void setLargeur(int l) { largeur = hauteur = l; }
73+
void setHauteur(int h) { largeur = hauteur = h; }
74+
}
75+
76+
// Bon exemple : ne pas forcer l’héritage
77+
class Rectangle { /* ... */ }
78+
class Carre { /* ... */ }
79+
```
80+
81+
---
82+
83+
### I — Interface Segregation Principle
84+
85+
Il vaut mieux plusieurs interfaces précises qu’une seule interface fourre-tout. Ainsi, chaque classe n’implémente que ce dont elle a réellement besoin, et le code reste clair et flexible.
86+
87+
**Exemple :**
88+
89+
```java
90+
// Mauvais exemple : interface trop large
91+
interface Machine {
92+
void imprimer();
93+
void scanner();
94+
void faxer();
95+
}
96+
97+
// Bon exemple : interfaces spécifiques
98+
interface Imprimante { void imprimer(); }
99+
interface Scanner { void scanner(); }
100+
```
101+
102+
---
103+
104+
### D — Dependency Inversion Principle
105+
106+
Pour un code souple et testable, il faut dépendre d’abstractions plutôt que de classes concrètes. On injecte les dépendances, on ne les crée pas en dur.
107+
108+
**Exemple :**
109+
110+
```java
111+
// Mauvais exemple : dépendance directe
112+
class Service {
113+
private Database db = new Database();
114+
}
115+
116+
// Bon exemple : injection de dépendance
117+
class Service {
118+
private IDatabase db;
119+
public Service(IDatabase db) { this.db = db; }
120+
}
121+
```
122+
123+
---
124+
125+
## Law of Demeter (LoD)
126+
127+
La Loi de Demeter, ou « principe du moindre couplage », recommande de ne parler qu’à ses proches collaborateurs. Plus on limite les chaînes d’appels, plus le code est robuste et facile à faire évoluer.
128+
129+
**Exemple :**
130+
131+
```java
132+
// Mauvais exemple : chaîne d’appels
133+
client.getCommande().getFacture().payer();
134+
135+
// Bon exemple : délégation
136+
client.payerFacture();
137+
```
138+
139+
En respectant ces principes, on bâtit des architectures solides, prêtes à affronter les évolutions et les défis du temps.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Introduction au génie logiciel
2+
3+
Le génie logiciel est l’art et la science de concevoir, développer, tester et maintenir des logiciels de qualité. Bien plus qu’une simple activité de programmation, il s’agit d’une discipline structurée, qui s’appuie sur des principes, des méthodes et des outils pour répondre aux besoins des utilisateurs tout en maîtrisant la complexité croissante des systèmes informatiques.
4+
5+
## Pourquoi le génie logiciel ?
6+
7+
À mesure que les logiciels prennent une place centrale dans notre société, les enjeux de fiabilité, de maintenabilité, de performance et d’évolutivité deviennent cruciaux. Le génie logiciel vise à garantir que les applications développées soient robustes, évolutives et compréhensibles, même des années après leur création.
8+
9+
## Les grands principes
10+
11+
Le génie logiciel s’appuie sur des principes fondateurs, tels que la simplicité, la réutilisabilité, la robustesse, la modularité ou encore la séparation des responsabilités. Ces principes, détaillés dans les chapitres suivants, sont illustrés par des exemples concrets et des retours d’expérience issus du monde professionnel.
12+
13+
- [Simplicité et clarté](./simplicite-et-clarte.md)
14+
- [Réutilisabilité et maintenabilité](./reutilisabilite-et-maintenabilite.md)
15+
- [Conception orientée objet](./conception-orientee-objet.md)
16+
- [Robustesse et gestion des erreurs](./robustesse-et-erreurs.md)
17+
18+
## Un métier d’équipe
19+
20+
Développer un logiciel, c’est aussi collaborer : la communication, la documentation, la gestion de projet et le travail en équipe sont au cœur de la réussite. Le génie logiciel propose des méthodes (agiles, cycle en V, etc.) pour organiser efficacement le travail collectif.
21+
22+
## Pour aller plus loin
23+
24+
Ce module vous invite à explorer les fondements du génie logiciel, à travers des concepts théoriques, des bonnes pratiques et des exemples issus de la réalité du terrain. Bonne lecture et bonne exploration !
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
# Réutilisabilité et maintenabilité
2+
3+
Dans l’odyssée du développement logiciel, deux qualités font la différence entre un projet éphémère et une œuvre qui traverse le temps : la réutilisabilité et la maintenabilité. Un code réutilisable est un trésor, car il évite de réinventer la roue. Un code maintenable, lui, est une promesse de sérénité pour l’équipe qui devra le faire évoluer, corriger ou adapter. Ces principes, souvent cités, prennent tout leur sens à travers des pratiques concrètes et des exemples vécus.
4+
5+
## DRY (Don’t Repeat Yourself)
6+
7+
La duplication est l’ennemie du progrès. Chaque répétition de code est une source potentielle d’erreur, un piège pour celui qui devra un jour tout modifier. Le principe DRY nous invite à centraliser la logique, à n’avoir qu’une seule source de vérité pour chaque information ou comportement.
8+
9+
**Exemple :**
10+
11+
```java
12+
// Mauvais exemple : duplication
13+
public double surfaceCercle(double rayon) {
14+
return 3.14159 * rayon * rayon;
15+
}
16+
public double perimetreCercle(double rayon) {
17+
return 2 * 3.14159 * rayon;
18+
}
19+
20+
// Bon exemple : extraire la constante
21+
public static final double PI = 3.14159;
22+
public double surfaceCercle(double rayon) {
23+
return PI * rayon * rayon;
24+
}
25+
public double perimetreCercle(double rayon) {
26+
return 2 * PI * rayon;
27+
}
28+
```
29+
30+
Un changement de formule ou de constante ne doit se faire qu’à un seul endroit, sous peine de voir le code diverger et les bugs proliférer.
31+
32+
33+
## Single Source of Truth (SSOT)
34+
35+
Dans un système bien conçu, chaque information n’existe qu’à un seul endroit. Multiplier les copies, c’est s’exposer à l’incohérence et à la confusion. Le principe SSOT est le garant de la cohérence des données.
36+
37+
**Exemple :**
38+
39+
Imaginons une application qui communique avec une API distante. Si l’URL de cette API est dupliquée dans plusieurs classes, une modification future (changement de domaine, de version, etc.) risque d’être oubliée à un endroit, provoquant des bugs difficiles à diagnostiquer.
40+
41+
```java
42+
// Mauvais exemple : l’URL de l’API est dupliquée
43+
class UserService {
44+
private static final String API_URL = "https://api.exemple.com/v1/";
45+
// ...
46+
}
47+
class ProductService {
48+
private static final String API_URL = "https://api.exemple.com/v1/";
49+
// ...
50+
}
51+
52+
// Bon exemple : une seule source de vérité
53+
class Config {
54+
public static final String API_URL = "https://api.exemple.com/v1/";
55+
}
56+
class UserService {
57+
// Utilise Config.API_URL
58+
}
59+
class ProductService {
60+
// Utilise Config.API_URL
61+
}
62+
```
63+
64+
En centralisant l’information, on garantit la cohérence et on simplifie la maintenance.
65+
66+
67+
## Separation of Concerns (Séparation des préoccupations)
68+
69+
Un bon logiciel est comme un orchestre : chaque instrument a son rôle, chaque musicien sa partition. En séparant les responsabilités, on obtient un code plus lisible, plus testable, plus évolutif.
70+
71+
**Exemple :**
72+
73+
```java
74+
// Mauvais exemple : une classe fait tout
75+
class Application {
76+
void afficherUI() {}
77+
void sauvegarderDonnees() {}
78+
void envoyerEmail() {}
79+
}
80+
81+
// Bon exemple : séparation des responsabilités
82+
class UIManager { void afficherUI() {} }
83+
class DataManager { void sauvegarderDonnees() {} }
84+
class EmailService { void envoyerEmail() {} }
85+
```
86+
87+
Chaque classe, chaque module, doit avoir une mission claire et limitée.
88+
89+
90+
## Encapsulation
91+
92+
L’encapsulation, c’est l’art de protéger les secrets de fabrication. En cachant les détails internes d’une classe, on limite les risques d’erreur et on rend le code plus robuste face aux changements.
93+
94+
**Exemple :**
95+
96+
```java
97+
// Mauvais exemple : attributs publics
98+
class Compte {
99+
public double solde;
100+
}
101+
102+
// Bon exemple : attribut privé et méthodes d’accès
103+
class Compte {
104+
private double solde;
105+
public double getSolde() { return solde; }
106+
public void deposer(double montant) { solde += montant; }
107+
}
108+
```
109+
110+
L’utilisateur de la classe n’a accès qu’à ce qui est nécessaire, et rien de plus.
111+
112+
113+
## Information Hiding (Masquage d’information)
114+
115+
Proche de l’encapsulation, le masquage d’information vise à limiter l’exposition des détails d’implémentation. Moins on en montre, moins on risque de devoir tout changer si l’intérieur évolue.
116+
117+
**Exemple :**
118+
119+
```java
120+
// Mauvais exemple : exposer la structure interne
121+
class Stack {
122+
public Object[] elements;
123+
}
124+
125+
// Bon exemple : masquer la structure
126+
class Stack {
127+
private Object[] elements;
128+
public void push(Object o) { /* ... */ }
129+
public Object pop() { /* ... */ }
130+
}
131+
```
132+
133+
134+
## Composition Over Inheritance (Préférer la composition à l’héritage)
135+
136+
L’héritage est parfois tentant, mais il peut rendre le code rigide et difficile à faire évoluer. La composition, elle, offre souplesse et modularité. En assemblant des objets, on construit des systèmes plus adaptables.
137+
138+
**Exemple :**
139+
140+
Imaginons que l’on souhaite modéliser des périphériques bureautiques : certaines imprimantes peuvent aussi scanner ou faxer, d’autres non. Si l’on utilise l’héritage, on se retrouve vite avec une hiérarchie complexe et peu flexible. La composition permet d’assembler dynamiquement les fonctionnalités nécessaires.
141+
142+
```java
143+
// Mauvais exemple : héritage rigide
144+
class Imprimante {
145+
void imprimer() {}
146+
}
147+
class ImprimanteMultifonction extends Imprimante {
148+
void scanner() {}
149+
void faxer() {}
150+
}
151+
152+
// Bon exemple : composition flexible
153+
interface Scanner {
154+
void scanner();
155+
}
156+
interface Fax {
157+
void faxer();
158+
}
159+
class Imprimante {
160+
void imprimer() {}
161+
}
162+
class ImprimanteMultifonction {
163+
private Imprimante imprimante;
164+
private Scanner scanner;
165+
private Fax fax;
166+
ImprimanteMultifonction(Imprimante imprimante, Scanner scanner, Fax fax) {
167+
this.imprimante = imprimante;
168+
this.scanner = scanner;
169+
this.fax = fax;
170+
}
171+
void imprimer() { imprimante.imprimer(); }
172+
void scanner() { scanner.scanner(); }
173+
void faxer() { fax.faxer(); }
174+
}
175+
```
176+
177+
Avec la composition, on peut créer des objets multifonctions ou spécialisés sans multiplier les sous-classes, et faire évoluer les fonctionnalités indépendamment les unes des autres.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Robustesse et gestion des erreurs
2+
3+
Dans le monde du développement logiciel, la robustesse n’est pas un luxe, mais une nécessité. Un programme robuste est celui qui résiste aux imprévus, qui ne s’effondre pas au premier grain de sable dans les rouages. La gestion des erreurs, loin d’être une simple formalité, est un art subtil qui distingue l’amateur du professionnel. Parmi les principes fondamentaux, le « Fail Fast » occupe une place de choix.
4+
5+
## Fail Fast
6+
7+
Imaginez un navire dont l’équipage détecte immédiatement la moindre voie d’eau, plutôt que de laisser l’eau s’infiltrer silencieusement jusqu’au naufrage. Le principe « Fail Fast » invite le développeur à signaler toute anomalie dès qu’elle survient, sans attendre que le problème se propage et devienne inextricable.
8+
9+
Détecter tôt, c’est se donner la chance de corriger vite. Un code qui échoue rapidement est plus facile à déboguer, plus sûr, et inspire confiance à ceux qui l’utilisent ou le maintiennent.
10+
11+
**Exemple :**
12+
13+
```java
14+
// Mauvais exemple : ignorer les erreurs
15+
public void traiter(String fichier) {
16+
try {
17+
// ...
18+
} catch (Exception e) {
19+
// rien faire
20+
}
21+
}
22+
23+
// Bon exemple : signaler l’erreur immédiatement
24+
public void traiter(String fichier) {
25+
if (fichier == null) {
26+
throw new IllegalArgumentException("Le fichier ne peut pas être null");
27+
}
28+
// ...
29+
}
30+
```
31+
32+
Dans le premier cas, l’erreur est étouffée, masquée, et le programme continue sa route en terrain miné. Dans le second, l’exception est levée sans délai, permettant une réaction rapide et appropriée.
33+
34+
La robustesse, c’est aussi le courage de dire « stop » quand quelque chose ne va pas, plutôt que de laisser le système s’enfoncer dans l’incohérence. Adopter le « Fail Fast », c’est choisir la transparence, la sécurité, et la qualité.

0 commit comments

Comments
 (0)