Les patterns
D'abord, il y a la conception du logiciel, le "software design".
Sa raison d'être c'est avant tout codage frénétique sans réfléchir, la notion inversée de réfléchir avant d'agir et d'interposer entre la bête volonté de faire exister et l'objet plus ou moins bâtard qui en résulte, une "pensée", motivée par un souci essentiel: comment faire pour que l'objet à produire puisse changer le plus facilement possible afin de s'adapter à de nouveaux besoins ?
La conception a donc pour objet de prévoir le possible changement. Exactement comme l'Architecture a pour objet de définir ce qui ne changera pas.
Cette "changeabilité", caractéristique normalisée du "bon produit" doit en fait s'entendre comme "flexibilité", c'est-à-dire comme un évitement de la modification. Cette exigence paradoxale, voire contradictoire est le principe tout aussi contradictoire en apparence de "ouvert/fermé" (open close) fondamental en matière de logiciel.
L'objet à produire doit être fermé, c'est-à-dire non modifiable, afin de garantir son intégrité d'objet testé et adapté à sa première fonction, et "en même temps" ouvert, soit capable d'être utilisé autrement avec des extensions qu'il a rendu possible, de par sa conception.
Revenons à la nécessité d'étendre, ou d'adapter. Deux grandes stratégies s'offrent à nous. D'abord, évidemment la modification directe. C'est le célèbre "SI "dans ce cas", ALORS "faisons cela". Moyen sûr de déstabiliser un existant et de le "véroler", voire de concevoir le monstre logiciel, vrai responsable de l'injuste accusation "c'est la faute à l'ordinateur".
On peut aussi copier, c'est-à-dire ne modifier qu'une copie entière de l'original laissé intact à sa fonction. La modification de la copie aboutit cependant exactement au cas précédent, seul l'original gardant ses qualités, s'il en avait.
C'est alors que fut inventé l'héritage, caractéristique de la conception dite "orientée objet" qui permet de copier ET de modifier de manière organisée, mais qui revient strictement au même en terme de génération de logiciels fragiles aux défauts impossibles à vraiment corriger. Il faut cependant noter que la notion d'héritage a une variante "saine" qui est celle de l'héritage de "type", quand ce qui est hérité est pur de tout code.
La notion d'objet ne va pas sans la notion de "classe" ou implémentation codée de son "type", "type" et "classe" étant manipulés simultanément dans les langages dits à objet. Disons que les entités effectivement vivantes partagent ces abstractions, un type pouvant être représenté par plusieurs classes, et une classe pouvant implémenter plusieurs types, l'essentiel étant qu'une opération donnée soit restreinte à ne prendre pour paramètre que des objets d'un certain type et qu'elle ne prenne effectivement pour arguments que des instances de classes implémentant ce type-là.
La différence type-classe se résume souvent à la notion d'interface qui abstrait un objet en ne spécifiant absolument aucun code, mais exclusivement les types des paramètres d'entrée et de sortie des opérations. L'héritage d'interface se distingue ainsi nettement de l'héritage de classe.
Parlons de grands principes. On connait l'exigence "SOLID", groupe de 5 principes fondamentaux qui sont (c'est à savoir):
- une Seule responsabilité par abstraction implémentée, soit par classe.
- ce principe s'exprime aussi par "je refuse toute autre responsabilité"
- Ouvert fermé: le fameux principe décrit plus haut.
- ce principe s'exprime aussi par "je ne peux que m'étendre"
- Liskov et son principe de substituabilité, soit la notion de type décrite plus haut.
- ce principe s'exprime aussi par "on peut danser avec un obèse"
- Interface ségrégation: une variante de la responsabilité solitaire, mais s'appliquant aux types.
- ce principe s'exprime aussi par "je ne dépends pas de ce que je ne fais pas"
- L'inversion des Dépendances, le concret devant dépendre de l'abstrait et non pas l'inverse
- ce principe s'exprime aussi par "une abstraction ne se détaille pas".
On remarquera ainsi que l'héritage de classe viole O et D. Cela fait beaucoup.
La violation des principes SOLID définit ce qu'on appelle la puanteur d'une conception (design smell) mal faite.
Et voilà ce qu'on peut dire des bons et grands principes en programmation (du logiciel).
Un pattern essentiel pour pallier l'horrible héritage de classe consiste alors pour une classe donnée à typer un de ses attributs par une interface qui sera étendue autant de fois que nécessaire par différentes autres classes. Typée proprement et uniquement, notre classe sera alors instanciée avec les instances des classes d'extension et satisfera aux bon principes. Elle sera extensible à coup nul et conservera son intégrité. Vive la science !