Les 6 règles d`architecture pour sécuriser le développement logiciel

Transcription

Les 6 règles d`architecture pour sécuriser le développement logiciel
Les 6 règles d’architecture
pour sécuriser le développement logiciel
Ce document propose une démarche et des règles simples et
puissantes pour créer l’architecture d’un logiciel.
Sa lecture ne demande pas une technicité particulière en
informatique1.
Son double objectif est d’aider les architectes en leur proposant
des repères, mais aussi de mieux faire comprendre aux autres
professionnels ce qu’est le travail d’un architecte logiciel.
Prologue
L’architecture d’un logiciel
Le présent document propose des règles simples, minimales et efficaces, dont le respect
augmente sensiblement les chances de parvenir à une architecture logicielle saine, et au
final, un développement réussi.
Le domaine d’application de ces règles est très large
- Ces règles s’appliquent, que le logiciel soit développé pour étendre un catalogue de
produits logiciels, généralement à l’initiative d’un chef de produit, ou pour répondre à des
besoins spécifiques, généralement à l’initiative d’un client.
- Ces règles concernent le développement d’un logiciel ou l’évolution d’un logiciel existant.
- Elles s’appliquent aux logiciels qui ont une identité autonome, et à ceux qui sont intégrés
dans une solution globale aux côtés d’autres logiciels et matériels, comme dans
l’informatique embarquée.
Elles ont déjà été mises en oeuvre dans de nombreux développements, et par exemple:
logiciels embarqués dans des équipements réseaux à très hauts débits, logiciels
de sécurité, plates-formes d’administration de réseaux critiques, et aussi, systèmes
d’information.
Le développement d’un logiciel est une activité de conception complexe, qui inclut
l’architecture comme élément structurant
Le développement du logiciel intègre l’ensemble des activités de conception aboutissant
à l’écriture du logiciel sous forme du code source, ce code étant le document final de
conception.
Note: au-delà du développement, se trouve la production proprement dite du logiciel.
1En cas de difficulté, sauter des paragraphe pour lire les lignes en caractères gras et les encadrés des règles.
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
1
Celle-ci est automatisée autour du compilateur et de l’éditeur de liens.
On peut distinguer plusieurs niveaux de zoom dans la conception d’un même objet logiciel, et
le poids relatif de chaque niveau dépend du contexte :
- L’architecture, qui consiste à décrire (1) l’organisation du logiciel en blocs de premier
niveau avec leurs responsabilités et relations, (2) les principes permettant d’obtenir par leur
collaboration les comportements attendus et de répondre aux contraintes techniques
structurantes, et enfin, (3) les règles et choix techniques guidant leur conception détaillée.
Le document d’architecture est le premier document à consulter pour comprendre un
logiciel, par exemple, pour le maintenir.
- La conception détaillée, qui consiste à décrire l’organisation des éléments à coder
(fonctions, structures de données), à définir leurs responsabilités, et à choisir les règles et
techniques guidant leur codage.
- Le codage, qui aboutit au “plan détaillé” (le code source) utilisable par un environnement de
production (le compilateur).
A chaque niveau, des décisions sont prises. Le processus de conception a pour objectif
de permettre la prise de chaque décision au bon niveau, tout en gérant dans le temps les
impacts (interactions entre les niveaux, améliorations par itérations).
Les règles d’architecture sont un complément efficace à une méthode de conception
Le présent document prend en compte les erreurs et problématiques récurrentes auxquelles
sont confrontées les concepteurs de l’architecture de logiciels. Pour y répondre, il propose
des règles d’architecture.
Ces règles sont focalisées sur le logiciel en lui-même, son contenu et sa structure
(le “Quoi ?”). Elles sont un complément efficace à une méthodologie de conception qui décrit
un processus (le “Comment ?”), mais ne s’y substituent pas.
Ces règles sont énoncées pour être :
○ Simples à comprendre et à partager, et en particulier, elles sont compréhensibles
sans qu’il soit nécessaire d’avoir une expertise technologique particulière ;
○ Minimales, en ce sens qu’elles sont peu nombreuses, qu’elles s’appliquent à la
grande majorité des projets de développement logiciel, et que le retrait de l’une
d’entre elles ouvrirait la porte à des erreurs sérieuses ;
○ Efficaces, car si une architecture est conforme à ces règles, alors il y a de grandes
chances pour que le développement se fasse dans de bonnes conditions.
Afin d’introduire les idées de façon plus simple, les règles sont décrites à travers un parcours
fait d’une succession d’actes. Cela pourrait suggérer à tort une démarche séquentielle.
En fait, c’est la méthode de conception choisie qui doit préciser l’articulation des différentes
activités (notamment, l’enchaînement ou le parallélisme des activités et leur caractère itératif)
et leur mode opératoire précis (en particulier, la formalisation des éléments de conception
produits). Par exemple, l’acte 3 (rattacher la solution au monde réel) et l’acte 4 (mutualiser
par des composants génériques) doivent être joués en fort recouvrement et en forte relation
pour en tirer le meilleur bénéfice.
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
2
Acte #1
S'affranchir des fausses contraintes
Face à un développement à faire, il faut préciser le comportement attendu du logiciel en
termes
- de fonctions rendues disponibles aux utilisateurs,
- de critères de qualité (par exemple: disponibilité, performances, sécurité, sûreté),
- et de contraintes techniques (par exemple: choix techniques imposés par le client).
Le principal écueil du développement logiciel est l’introduction de fausses contraintes
Les fausses contraintes peuvent être des exigences fonctionnelles ou techniques introduites
de manière implicite ou sans justification.
Plusieurs phénomènes peuvent y contribuer :
- Les critères de qualité de fonctionnement sont parfois formulés sans prendre compte le
niveau de service réellement attendu par les utilisateurs, ou la faisabilité technique au coût
objectif ;
- Le besoin client est parfois traduit trop rapidement en réponses techniques, en faisant le
rapprochement avec un produit sur étagère, puis en listant ses fonctionnalités, aboutissant
ainsi à une lecture des besoins sous l’influence des fournisseurs ou des médias
spécialisés ;
- Les préconisations techniques du client sont parfois entérinées sans phase de réflexion et
de dialogue, et elles induisent des contraintes fortes dans le cadre du projet ;
- Des demandes clients issues d’effets de mode ;
- Le besoin est parfois exprimé par quelqu’un qui projette ses propres représentations
intellectuelles sans en avoir conscience, et elles peuvent induire des contraintes fortes et
limitatives;
- Des choix techniques historiques sont parfois reconduits alors que le contexte d’emploi du
logiciel ou les technologies disponibles sur le marché ont fortement évolué. Réutiliser les
compétences d’une équipe ne doit pas induire un immobilisme technique.
Les fausses contraintes aboutissent à une complexité accrue du logiciel (donc un coût et un
délai accru, voire à une incapacité à développer) sans avantage en terme de service rendu.
On estime que 40% des échecs logiciels sont liés à ce phénomène.
Il faut absolument rejeter les fausses contraintes
Pour sécuriser le projet, la première chose à faire au début des travaux d'architecture est
d'exclure ces fausses contraintes.
Comme elle proviennent souvent de traductions "trop automatiques" des besoins en
réponses techniques, il peut être utile de considérer les quelques exemples suivants.
Ex 1: “Temps réel” n’implique pas “hautes performances”
Face à une exigence exprimée en tant que "temps réel", la première action est de décoder la
vraie signification de ce terme:
- " engagement de temps " : garantie du délai d'exécution des tâches
- " faible latence "
: traitement rapide des événements ou des messages
- " système embarqué "
: la solution doit fonctionner sans opérateur
Dans les années 60, le terme "temps réel" signifiait "interactif" par opposition à "différé"
(batch).
Un faible latence suppose de hautes performances. En revanche, un engagement de délai
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
3
ne suppose pas obligatoirement un traitement très rapide (par exemple, La Poste a un
engagement d'acheminement de 48h pour une lettre, et de même, la paie se doit d’être
mensuelle). De la même façon, un logiciel embarqué peut ne pas revendiquer de rapidité de
calcul (par exemple, un lave-linge programmable).
Ex 2: “Haute disponibilité” n’implique pas matériel ou système d'exploitation spécial
De la même façon que les RAID2 fournissent une haute disponibilité de stockage par un
assemblage judicieux de disques standards, une solution répartie sur des ordinateurs
standards en réseau peut être plus robuste qu'une solution reposant sur un matériel ou d’un
système d’exploitation spéciaux.
Ex 3: “Gestion de données” n’implique pas “base de données relationnelle (SQL)”
Les bases de données relationnelles permettent de faire des opérations ensemblistes sur
des données organisées sous forme de tables en garantissant la cohérence des données au
cours de l’exécution de lots de traitement.
Dans l’informatique de gestion, et depuis les années 80, les bases de données relationnelles
sont souvent utilisées comme système de gestion de données par défaut.
Lorsque le problème ne relève pas de données naturellement organisées en tables, ni
d’opérations sur des tables, un autre type d’organisation et de stockage des données peut
être plus adapté: système de fichiers, base clé/valeur, base géographique, base colonne,
base graphe.
Ex 4: “Cohérence de la donnée” n’implique pas “moteur transactionnel”
Un moteur transactionnel est un logiciel qui garantit la cohérence des traitements lancés
en parallèle: il calcule et contrôle en un point central l’ordre d’exécution des traitements. Il
privilégie ainsi la cohérence sur la rapidité de traitement et la capacité de montée en charge.
Une attitude courante est d’utiliser des moteurs transactionnels systématiquement comme
assurance contre le risque d’incohérence. D’ailleurs, le fait que les bases de données
relationnelles intègrent souvent un moteur transactionnel est une des raisons de leur succès.
D’une part, cette assurance est souvent utilisée de manière systématique et implicite alors
que dans la majeure partie des cas (plusieurs lecteurs, un écrivain unique), elle n’est
pas justifiée. Il convient d’identifier les réels besoins de cohérence des données et des
traitements, et d’envisager l’ensemble des solutions permettant d’y répondre (gestion explicite
par le logiciel par exemple) ;
D’autre part, cette assurance est trompeuse car partielle. Une bonne partie des incohérences
provient de défauts dans la logique de l’application et survient avec ou sans moteur
transactionnel. Il convient en particulier de mettre en oeuvre en complément des mécanismes
d’identification et de correction des incohérences ;
Cette assurance est donc souvent inutile, toujours coûteuse, et par nature partielle.
Ex 5: “SOA” n’implique pas “ESB” et “ESB” n’implique pas “SOA”
Un logiciel SOA (respectant une architecture orientée service) est structuré sous forme
de modules chacun fournissant des services aux autres et répondant à des principes
d’interaction entre modules. Ces principes d’interaction ont un impact sur l’ensemble de
l’architecture du système (décomposition en modules, interfaces entre modules).
L’utilisation des produits décrits par les éditeurs comme “outil SOA” (en particulier les bus de
services d’entreprise “ESB”) ne garantit pas l’application des principes SOA. Au contraire,
leur utilisation sert parfois de fausse preuve du caractère SOA de l’architecture, au risque de
ne pas tirer avantage de la signification véritable de SOA qui porte sur l’architecture, et non
les outils.
2Redundant Array of Inexpensive Disks, gestion d’un groupe de disques comme un tout pour apporter de la résistance aux
pannes et/ou de la performance
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
4
Ex 6: “Performance” n’implique pas un langage de bas niveau.
Contrairement aux idées reçues, aujourd'hui, les langages de programmation à haut niveau
d’abstraction (par exemple Java) sont souvent plus efficaces que les langages de plus bas
niveau (par exemple C ou C++). Ils transfèrent l'optimisation du code des programmeurs aux
compilateurs, et les compilateurs modernes utilisent avec plus d'efficacité les processeurs
récents en exécutant de façon systématique des algorithmes d'optimisation très avancés
parfois peu accessibles aux langages de plus bas niveau.
Ex 7: “Service Web” n’implique pas “SOAP” et “SOAP” n’implique pas “Service Web”.
Le Web repose sur des notions de navigation au sein de documents (puisqu’un clic sur un
lien d’une page web permet de visualiser la page cible obtenue du serveur). Les services web
étendent ces notions pour permettre l’échange de machine à machine.
Plusieurs protocoles d’échange sous forme de services web existent, ayant chacun des
propriétés et des qualités différentes :
- Web Services SOAP (Simple Object Access Protocol) : en continuité des langages de
développement objet, il permet d’exprimer la richesse métier du logiciel à l’aide de
fonctions, et nécessite une gestion du catalogue de fonctions et de son mode d’emploi ;
- Web Services REST (REpresentational State Transfer) : en continuité du “World Wide
Web”, il permet d’exprimer la richesse métier du logiciel à l’aide d’une hiérarchie de
ressources, tout en facilitant leur utilisation (interface uniforme et navigable) et assure par
construction une limitation des erreurs en cas d’appels concurrents (échanges plus sûrs car
sans état).
Historiquement, les web services SOAP ont été plus utilisés que les web services REST,
notamment parce qu’ils sont de conception plus ancienne, et qu’ils sont plus proches des
concepts utilisés par les développeurs d’applications classiques.
Néanmoins, lorsque la croissance itérative du nombre de fonctions et la capacité de montée
en charge sont des enjeux clés, les web services REST peuvent constituer une meilleure
réponse.
Règle
#1
L’architecture doit exclure les fausses contraintes, souvent issues d’une
traduction trop rapide des besoins en choix techniques, car elles peuvent être
à l’origine de dangereuses décisions d’architecture.
Pour vérifier la conformité à cette règle
- L’équipe qui répond à une demande client doit écrire la
liste des contraintes techniques qu’elle estime devoir
prendre en compte.
- Pour chaque contrainte de cette liste, l’équipe doit écrire
en quoi cette contrainte est justifiée.
- Au final, cette liste doit avoir été challengée et validée par
les équipes de direction technique et de direction du
projet, et par le client lorsque cela est possible.
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
5
Acte #2
Rechercher une découpe saine et robuste
Pour développer un logiciel de taille importante, on est conduit à le découper en parties, pour
le rendre maîtrisable et développable par plusieurs équipes.
Quand chaque partie du logiciel a un rôle bien défini et une certaine autonomie, on parle de
découpage en “modules logiciels”.
Cette “modularité” a des avantages majeurs:
- elle permet d’augmenter la qualité du logiciel, car quand le logiciel est plus clair, ses
défauts sont plus facilement localisés, identifiés et traités,
- elle permet de mieux planifier, gérer et contrôler les activités de conception (spécification,
architecture, conception, codage, test, intégration).
Techniquement, la forme que peut prendre un module est très variable:
- un ensemble de fonctions travaillant dans un même domaine
- une ou plusieurs classes au sens des langages objets (C++, Java) regroupant
naturellement des fonctions et des données ;
- un “sous-logiciel” autonome que l’on démarre ou arrête et qui communique avec les autres,
par exemple en Web Services...
On découpe le logiciel en modules pour le maîtriser en divisant la complexité
Décomposer en modules permet de diviser la complexité en plusieurs points à traiter:
- au niveau global, choisir les principes d’interaction entre modules qui répondent aux
contraintes fonctionnelles et techniques structurantes, tout en étant simples.
- au niveau de chaque module, l’activité de conception doit être focalisée sur les attentes vis
à vis de ce module et les contraintes qu’il doit respecter.
La conception d’une architecture modulaire commence donc par la recherche d’un optimum
assurant la maîtrise globale du système d’information par une découpe en modules à forte
cohésion interne et faible couplage externe.
Pourquoi parler d’optimum? Parce que selon la taille des modules et les responsabilités que
l’on donne à ces modules, on obtient une complexité totale différente:
- trop peu de modules (voire un seul!), et l’on ne tire pas partie de la modularité et l’on se
retrouve avec des modules trop complexes et peu maîtrisables
- trop de petits modules peut conduire à une simplicité interne aux modules, mais en
projetant la complexité au niveau global
- un découpage inapproprié peut engendrer trop d’interactions entre modules, et des
interactions trop complexes pour être bien comprises et maîtrisées.
Tout au long du travail de découpage en modules de l’idée initiale à ses remises en cause
par améliorations successives, on peut évaluer la qualité de la décomposition en modules.
Pour cela, on déroule les principaux cas d’utilisation du logiciel et on vérifie que les besoins
fonctionnels sont bien pris en compte, que les contraintes techniques structurantes sont
identifiées et que des réponses y sont apportées, et que les interactions restent d’une
complexité maîtrisable et maîtrisée.
Ainsi, par une succession de choix et améliorations, on arrive à une architecture satisfaisante.
Cette démarche intellectuelle sous-tend la plupart des méthodes d’architecture logicielle.
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
6
Celles-ci se différencient par l’organisation dans le temps des différentes activités
d’ingénierie, et le formalisme des documentations associées.
Si des éléments de cette démarche peuvent se retrouver hors du domaine du logiciel,
l’activité d’architecture logicielle présente des caractères spécifiques. La suite donne pour
cela quelques bons principes de conception d’une architecture logicielle modulaire. Chaque
principe est expliqué afin de faciliter son utilisation de manière pertinente, projet après projet.
On définit des modules intelligibles pour simplifier le développement logiciel
La définition d’un module (les fonctions qu’il assure, les données qu’il gère, et ses modalités
d’utilisation) doit privilégier la cohésion et l’intelligibilité.
Un module dont on peut facilement expliquer, entendre et comprendre la responsabilité est
plus facile à concevoir, développer et maintenir.
Regrouper dans un module un ensemble cohérent de fonctions centrées sur un seul sujet
permet également de simplifier et rendre plus efficace son intégration et son utilisation au
sein d’une solution. Une brique de Lego à forme simple est plus facile à placer qu’une brique
à dessin complexe.
“Définition facile à donner”, “un seul sujet”, voilà qui rappelle les bons conseils de Boileau
dans son “Art Poétique” :
“Ce que l'on conçoit bien s'énonce clairement,
Et les mots pour le dire arrivent aisément” (chant I)
...
“Qu'en un lieu, qu'en un jour, un seul fait accompli,
Tienne jusqu'à la fin le théâtre rempli.” (chant III)
Chaque module doit regrouper données et fonctions en rapport
Si des données sont modifiées par plusieurs modules, les conséquences peuvent être
graves :
- difficulté à identifier la source du problème si ces données ont des valeurs incohérentes ;
- difficulté à assurer la sécurité de ces données ainsi partagées ;
- risques de conflits avec plusieurs modules accédant en même temps aux mêmes données;
- difficulté pour évaluer ce qu’il faut changer dans les différentes parties du logiciel si on fait
évoluer la structure des données.
Pour éviter ces inconvénients, les données, telles que fichiers ou bases de données ne
doivent pas être partagées entre plusieurs modules, mais être intégrées dans des modules
responsables de leur gestion.
Chaque module contient des données, dont il est responsable au plan de l’intégrité et de la
sécurité. Il est le seul à pouvoir y accéder directement.
Un module est donc le regroupement:
- de données passives (nombres ou tableaux, textes, fichiers, tables de bases de données...)
- de fonctions qui, pour rendre des services, peuvent lire ou modifier ces données.
Ni les données passives, ni même leur structure, ne sont visibles directement de l’extérieur.
Les données d’un module ne peuvent être modifiées que par les fonctions de ce même
module. Celles-ci sont en nombre limité et sont normalement écrites avec le souci de
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
7
préserver l'intégrité et la cohérence des données.
Ce confinement des données améliore la qualité. En particulier, si les données d’un module
prennent des valeurs anormales ou incohérentes, il est normal de suspecter le module:
- le codage du module est-il défectueux?
- a-t-il accepté une demande qu’il aurait dû refuser?
Pour prévenir cette possible corruption des données d’un module,
- les fonctions du modules doivent systématiquement contrôler les appels reçus (droits/
sécurité, validité de forme et de fond des paramètres) avant d'exécuter des actions
susceptibles de compromettre la cohérence des données
- le module doit mettre en oeuvre des fonctions de détection et d’auto-réparation des
incohérences de ses données.
Les interactions entre modules peuvent être simples grâce à la conception orientée
service
Afin d’assurer la simplicité et l’évolutivité des interactions entre modules, une bonne pratique
consiste à les définir en respectant l’esprit des principes d’architecture SOA :
1.absence de partage entre modules : chaque module a la pleine responsabilité de son
état, et en particulier, de ses propres données ;
2.collaboration sous forme d’appel de services : les modules interagissent par le biais
d’appels respectant des principes de couplage lâche, c’est-à-dire des appels consistants
(chaque appel forme un tout), sans état (par de relation implicite entre deux appels), et
indépendants de la technologie de développement (les partenaires de l’appel n’ont pas à
partager la même technologie) ;
3.facilité d’utilisation et de combinaison des services : les services offerts par les modules
sont définis explicitement, simples (intelligibilité, facilité d’emploi) de manière à être
facilement composés pour réaliser des fonctions.
Ce sont ces principes qui font l’apport essentiel de SOA en matière d’idées sur l’architecture.
Au-delà de ces principes, un certain nombre de technologies permettent de faciliter la
conception orientée service:
- pour les appels locaux (c’est-à-dire entre modules sur une même machine):
Avec les langages de programmation orientés objet, on peut choisir de réaliser un module
comme une ou plusieurs classes d’objets, et les appels entre modules comme appels de
fonctions. Le résultat n’est pas strictement conforme à l’esprit, car faire un appel direct
de fonction suppose que les fonctions soient dans le même environnement technique
(“couplage fort”), mais il permet de mettre en oeuvre les principes d’interaction SOA;
- pour les appels à travers un réseau:
Les services web constituent un bon moyen d’outiller simplement la mise en œuvre de la
conception orientée service. Parmi les styles de définition de services web, REST facilite
l’évolution du logiciel de par sa simplicité d’interaction, ses propriétés de navigabilité et de
croissance par incréments.
On notera qu’une conception de logiciel basée sur des modules capables de communiquer
en réseau est une bonne base pour tirer profit du "cloud computing" car on va pouvoir
répartir les modules sur plusieurs serveurs pour utiliser aux mieux ces machines.
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
8
La modularité doit accompagner les contraintes techniques non fonctionnelles
Les contraintes non fonctionnelles (robustesse, sécurité, sûreté, performances...) doivent être
propagées dans les différents modules de manière intelligible. Par exemple...
Chaque module doit contribuer à la robustesse du logiciel
L’architecture d’un logiciel fait apparaître en général des modules spécialisés dans la gestion
de la robustesse du logiciel (supervision, démarrage/arrêt, sauvegarde/restauration).
Cependant, et en complément de ces modules, l’ensemble des modules de la solution doit
prendre en compte l’objectif de robustesse.
A l’intérieur de chaque module, on doit mettre en oeuvre des moyens internes permettant de
diminuer les conséquences des erreurs de fonctionnement et des pannes internes au module
ou impactant son environnement.
Ces moyens internes peuvent comprendre :
- des modes de fonctionnement “dégradés” ou “à minima”, permettant de réagir aux
défaillances de composants logiciels ou matériels;
- un système de gestion d’exceptions permettant de réagir aux erreurs d’exécution du logiciel;
- un système de gestion de la sauvegarde (par gestion de journaux ou de points d’arrêt) et
de la restauration du module.
Entre les modules, un bon principe permettant d’augmenter la robustesse du logiciel est
d’augmenter la souplesse des interfaces. Ce principe a été énoncé par John Poster et est
entré dans la norme Internet RFC761 comme principe de robustesse sous la forme suivante :
“Soyez conservateur dans ce que vous envoyez; soyez libéral dans ce que vous
acceptez”.
- chaque module doit être conçu de façon à ce qu’il envoie soit le plus strictement possible
conforme à ce qui est attendu, et le moins susceptible de poser des problèmes au
récepteur,
- en sens inverse, le récepteur doit être capable de comprendre les messages qu’il reçoit de
façon la plus tolérante possible.
Chaque module doit contribuer à la sécurité du logiciel
Au sein d’un système d’information, la sécurité des accès vise à assurer que les traitements
et les informations ne sont rendus accessibles que dans les cas d’utilisation prévus.
De manière classique, sont mis en oeuvre des modules spécialisés responsables de
l’identification, de l’autorisation des accès, de la sécurisations de communications, etc.. qui
agissent de manière transverse.
Comme pour la robustesse, et au-delà de ces modules spécialisés, c’est l’ensemble des
modules de la solution qui doit prendre en compte l’objectif de sécurisation des accès.
C’est d’autant plus important que les modules transverses ne peuvent pas gérer facilement
les besoins d’accès fins et se limitent souvent à la gestion de droits d’utilisation à des groupes
de fonctions. cela peut conduire à des failles de sécurité et à une inadéquation du logiciel visà-vis des exigences de sécurité (trop ou pas assez sécurisé).
C’est pourquoi chaque module doit en complément mettre en oeuvre des contrôles internes
sur les demandes qu’il reçoit.
- le module qui connaît le métier et qui est responsable de la fourniture des fonctions peut
accepter ou non une requête selon le contexte de la demande ;
- comme il connaît la nature des données qu’il possède, un module peut exercer des
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
9
contrôles plus fins sur les valeurs reçues selon la fonction appelée, et par exemple, filtrer
les données en fonction du rôle de l’utilisateur ;
- au-delà de la protection vis-à-vis des appels utilisateur, un module peut se protéger des
autres modules et vérifier leurs demandes (cela correspond à un mode de “programmation
paranoïaque”, aussi connu sous le nom de “programmation par contrat”). Par exemple, si
l’on donne l’ordre au module “parent d’élèves” d’enregistrer comme nombre d’enfants la
valeur -1, le module doit refuser de s’exécuter ; ...
Exemple : la sécurité des cartes de crédit
Le modèle classique est illustré par la carte magnétique qui contient les données
passives qui sont partagées par l’ensemble des terminaux de paiement utilisés.
Le modèle objet est représenté par une carte à puce qui encapsule les données passives
qui, ainsi, ne sont pas partagées, i.e. qui ne sont pas à la disposition du tout-venant.
Les terminaux de paiement envoient des requêtes à la carte qui peut les accepter ou les
refuser. Le haut niveau de sécurité globale est assuré par l’association de la sécurisation
du terminal (“l’extérieur”) et de la carte à puce (“le module”).
Règle
#2
Le logiciel doit être composé de modules qui coopèrent entre eux, chaque
module assurant le contrôle et l'intégrité de ses données.
Il ne doit y avoir aucun partage de données entre modules que ce soit en
mémoire, sous la forme de fichiers ou de bases de données.
Chaque module doit contribuer activement à la robustesse et à la sécurité du
logiciel.
Pour vérifier la conformité à cette règle
- La documentation du logiciel doit démontrer la qualité de
la décomposition (modules intelligibles, interactions
simples)
- La documentation de chaque module doit décrire ses
données auxquelles il accède de manière exclusive
- Il est important de vérifier qu'aucune donnée passive n'est
hors de contrôle d’un module.
- Il est important de vérifier que les contraintes techniques
sont bien propagées et traitées module par module
(robustesse, sécurité, sûreté...)
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
10
Acte #3
Rattacher la solution au monde réel
Afin de bien découper l’application à développer en modules, il faudrait disposer d’un moyen
pour suggérer et vérifier la pertinence d’un tel découpage.
Pour être réussie, l’architecture doit s’appuyer sur des images mentales maîtrisées
Comprendre le logiciel, pour avoir confiance en lui et pour le faire évoluer, suppose avoir une
image claire des éléments qui le composent.
Pour cela, l’architecte s’appuie sur des concepts qui sont autant d’images mentales à sa
disposition :
- les concepts provenant du métier des utilisateurs du logiciel (ou de la vie courante), par
exemple: compte-client, commande, abonnement, voyage ;
- les concepts provenant de l’informatique, par exemple: fichier, journal, objet, base de
données, page web...
Parmi ces concepts, certains représentent des “choses” (bon de commande, permis de
conduire, client, rapport d’exécution...), et d’autres, des organisations techniques du logiciel
(aussi appelés patterns d’architecture).
Un premier lot de modules est fait de ceux qui modélisent des éléments de la réalité
L’objectif de clarté du logiciel, qui conduit à utiliser des concepts maîtrisés (issus du métier ou
de l’informatique), conduit à faire en sorte que les modules soient définis en relation directe
avec ces concepts, comme représentation de tout ou partie de ces concepts, et en particulier,
ceux qui désignent des “choses”.
Rien n’oblige, a priori, l’architecte à utiliser ces concepts comme base pour la modularité. Il
pourrait découper le problème autrement, par exemple, sur la base de similitudes techniques
ou de traitement qu’il identifierait. Mais alors, il prendrait un risque important, car s’il
reçoit davantage de précisions à propos des besoins du client ou s’il progresse dans la
compréhension du problème il peut découvrir que ce découpage devient inadapté.
Quand les modules sont choisis pour modéliser chacun un élément de la réalité, les risques
de mauvaises surprises sont bien moindres, la réalité servant de référence solide. On peut
s’attendre à ce qu’un complément d’information sur une expression de besoin se traduise
simplement en complément de développement à faire, sans impact sur le découpage.
C’est particulièrement important pour les logiciels à forte complexité fonctionnelle.
Une analyse descendante permet de définir des modules qui modélisent la réalité
Pour aboutir à ce découpage en modules “réalistes”, le premier moyen qui est à la disposition
de l’architecte est de partir de la description des besoins des utilisateurs du logiciel.
Cette démarche d’analyse est dite descendante, car elle part des besoins métier (niveau
haut) dans l’objectif de rallier les solutions techniques (niveau bas).
Cette démarche permet d’aboutir de manière naturelle à des modules qui utilisent des
concepts provenant du métier des utilisateurs du logiciel.
Elle a aussi d’autres avantages comme celui de faciliter le dialogue avec le client tout au long
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
11
du projet, d’éviter de partir sur une impasse par manque de points de repère, et surtout, il
rend l’architecture et le logiciel intelligibles, donc concevables, développables, vérifiables et
porteurs de confiance.
Règle
#3
La première raison qui peut justifier l’existence d’un module logiciel est d’être
une modélisation d’un élément de la réalité.
Cette première catégorie de modules est issue de l’analyse descendante,
c’est-à-dire en partant des besoins et en allant vers le code. Cette analyse est
particulièrement importante pour les logiciels à complexité fonctionnelle forte.
Pour vérifier la conformité à cette règle
- Les modules créés par l'analyse descendante doivent être
nommés et décrits explicitement par référence à des
objets du monde réel.
- Dans cette phase, aucun module ne doit avoir été créé à
des fins de confort de programmation (pour le partage de
code, d'autres mécanismes doivent être utilisés).
- La modélisation doit être compréhensible et validée par les
responsables métiers du domaine d'activité.
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
12
Acte #4
Mutualiser avec des modules génériques
L’analyse ascendante permet de réutiliser des composants génériques
On a vu que la première piste pour créer des modules est l’approche descendante vers des
modules, chacun représentant un élément de la réalité du métier.
La deuxième piste et source d’images mentales maîtrisées est l’informatique elle-même.
En effet, elle fournit à la fois des concepts utilisables pour la définition d’une architecture
modulaire, mais également des composants logiciels qui mettent en oeuvre certains de
ces concepts : il s’agit de composants logiciels disponibles dans l’entreprise, auprès des
organisations Open Source ou auprès d’éditeurs de logiciels commerciaux (“COTS”,
Commercial Off-The-Shelf).
Le deuxième moyen qui est à la disposition de l’architecte pour aboutir à une décomposition
modulaire du logiciel est donc de partir du catalogue des composants logiciels génériques,
et de l’étendre par des composants nouveaux si le besoin est identifié. Cette démarche est
dite ascendante, car elle part des solutions techniques (niveau bas) dans l’objectif de rallier le
besoin métier (niveau haut).
La conception d’un logiciel en particulier peut amener à enrichir la collection des
composants génériques disponibles
Le catalogue des composants génériques accessibles pour un développement est large
mais il n’est pas infini. On peut donc être amené à définir de nouveaux modules génériques.
Il s’agit de composants logiciels qu’on aurait bien aimé trouver dans le bestiaire des
composants logiciels disponibles et dans de bonnes conditions (adéquation au problème,
qualité, prix, propriété intellectuelle, contraintes d’utilisation, etc.).
Quelques exemples de composants génériques :
- objets graphiques à intégrer dans une page web
- gestionnaire de fautes
- serveur de présence
- gestionnaire de traces
- module de génération de rapport
- module de statistiques
- service de synchronisation
- installateur de logiciel et de mise à jour
- ...
Quand on recherche un composant générique très riche, il peut correspondre à un besoin
trop spécialisé, et il y a peu de chance de le trouver disponible.
Quand il faut développer un composant générique, donc par nature destiné à être réutilisé,
il est normal de valider sa définition par des experts techniques venant d'autres projets ou
domaines.
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
13
Le bon usage de composants génériques peut réduire très sensiblement le code à
écrire spécifiquement pour un client
Lorsqu’ils sont utilisés à bon escient, les composants génériques (à récupérer ou à créer),
introduits par la démarche ascendante contribuent à limiter la quantité, la complexité et le
coût du développement.
Avec le développement de grandes bibliothèques de composants en interne aux entreprises
et en Open Source, il est de plus en plus courant que les composants génériques
représentent plus de 80% des lignes de code du logiciel.
Ces composants peuvent constituer un actif majeur pour une entreprise en réduisant ses
coûts projet après projet, et en la rendant plus attractive commercialement, avec des clients
rassurés, et une concurrence qui aurait plus de code à créer.
Règle
#4
Le seconde et seule autre raison qui peut justifier l’existence d’un module
logiciel est d’être un composant générique, c’est-à-dire qui a un sens général
en informatique, même loin du besoin métier considéré.
Cette deuxième catégorie de modules est issue de l’analyse ascendante,
c’est-à-dire en partant des objets de base de l’informatique et en allant vers
les besoins. Cette analyse est particulièrement importante pour les logiciels à
complexité technique forte.
Pour vérifier la conformité à cette règle
- Le projet doit documenter la liste des composants
introduits par la méthode ascendante.
- Les nouveaux composants introduits par importation (en
général à partir d'Open Source) ou par développement
interne doivent avoir une documentation comme des
produits autonomes : ce sont des actifs de l'entreprise.
Une entreprise a tout intérêt à organiser un partage grâce
à une forge (dépôt du logiciel et de sa documentation).
- La définition des composants à partir de la conception
ascendante doit être validée par des ingénieurs externes
au projet afin de vérifier leur attractivité pour une
réutilisation potentielle.
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
14
Entracte: De l’esprit des règles et de leur application
Les règles précédemment énoncées, comme toute règle de conception, ne sont pas à l’abri
d’une utilisation abusive avec une interprétation littérale qui n’en respecte pas l’esprit.
Le présent entracte présente deux exemples de mauvaise application des règles par
interprétation trop littérale. Il finit par une discussion sur l’articulation des règles #3 et #4 qui
permet d’en éclairer l’esprit.
La réutilisation à mauvais escient de composants logiciels peut complexifier le logiciel
et augmenter les coûts de développement
Pour rendre la réalisation du logiciel moins coûteuse et moins risquée qu’un développement
nouveau, on essaie souvent d’utiliser des composants génériques riches et de haut niveau3
(ex: ERP4). La réalité est plus complexe, et cette approche peut avoir un effet inverse que
celui escompté.
Lorsque le problème à traiter est proche des fonctions du composant générique, son
adaptation et son enrichissement sont simples. Le composant générique est utilisé dans sa
zone de confort, et il amène de la valeur dans le logiciel dans un cadre maîtrisé.
Lorsque le problème à traiter est plus éloigné des fonctions du composant générique, son
adaptation peut générer une complexité additionnelle forte.
Pourquoi? parce que les concepts d’un composant de haut niveau sont de même niveau
d’abstraction que les concepts de la demande du clients. S’ils sont différents, il est difficile
d’utiliser les uns pour construire les autres.
Dans les cas les plus extrêmes, on peut s’apercevoir au cours du développement que les
deux ensembles de concepts sont contradictoires, ce qui conduit à un constat de difficulté
forte, voire d’infaisabilité du développement.
Exemple: calculs et affichage de graphiques
Que l’on considère par exemple les exemples extrêmes : JEE5 (un composant de bas
niveau) et Excel (un composant de haut niveau).
- Excel est un composant générique bâti à partir du concept de feuilles de calcul. Il
s’accompagne d’un langage de haut niveau (fonctions, macros) permettant
d’obtenir un résultat applicatif en très peu de temps et d’efforts ;
- JEE est une plate-forme logicielle associée à Java, un langage de développement
générique mettant en oeuvre les concepts de programmation objet.
Si le problème à traiter est proche des usages habituels des tableurs, par exemple
si on souhaite faire des calculs sur des séries limitées de données tabulaires et
représenter les résultats sous forme de graphique, il faudra peu de temps avec
Excel: moins sans doute que pour la simple l’installation de l’environnement de
développement et d’exécution Java.
3Un composant est de haut niveau quand il est proche des problèmes clients (abonné, commandes, factures,...), et qu’il est de
bas niveau quand il est proche des concepts informatiques (bases de données, générateur de rapport,...)
4Enterprise Resource Planning: progiciel de gestion intégré comme, par exemple, SAP ERP
5
__________
Java Enterprise Edition: environnement logiciel Java pour faire des applications Web
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
15
Utiliser Excel est justifié car il est dans sa zone de confort.
Mais voilà, quand le travail se complique (on a besoin de processus métier et pas
seulement de fonctions, on doit gérer plusieurs utilisateurs...), le développeur Java
peut absorber les nouvelles demandes, tandis que le développeur sous Excel voit
la complexité de sa tâche exploser: profusion de fonctions, de macros, des tables
intermédiaires de plus en plus nombreuses, au final tout un arsenal d’astuces pour
contourner les limitations, et un logiciel qui devient non maîtrisable.
En règle générale, plus un logiciel porte une valeur ajoutée grande (richesse et haut niveau),
plus il a été fait d’hypothèses sur son environnement et plus son domaine d’application est
réduit, et plus vite s’écroule la productivité quand on s’écarte du domaine. Une analyse
montre que c’est la combinaison ad-hoc de fonctions de natures différentes qui restreint
le domaine d’application. On peut noter que les grands succès de l’Open Source sont des
logiciels mono-fonction (“loi de Boileau”).
Malheureusement, il n’est pas rare que la peur de lancer un développement à partir d’une
feuille blanche peut conduire à utiliser un logiciel existant quitte à le tordre loin de son
domaine d’application, et obtenir au final plus de développements à faire, un coût énorme et
une maintenabilité hasardeuse.
La volonté d’organiser l’architecture ne doit pas conduire à rendre le logiciel
incompréhensible
L’esprit des règles d’architecture 3 et 4 est qu’il faut donner un sens aux modules créés, pour
cette modularité aide à maîtriser le logiciel. Ces règles s’opposent donc à la création d’objets
pour la simple commodité de programmation.
Cela peut générer un conflit avec le principe de programmation dit “DRY” (Do not Repeat
Yourself). L’interprétation littérale de ce principe est qu’il faut absolument éviter de recoder
les lignes de code identiques ou similaires, et pour cela il faut les placer dans un module
unique et appeler ce module plusieurs fois.
Si l’on peut éviter une redondance de code à travers la création d’un objet générique (règle
#4), c’est bien. Mais il ne faut pas créer des objets incompréhensibles (ni signification métier,
ni signification générique) uniquement pour éviter une redondance. Dans ce cas d’espèce,
l’esprit de la règle #4 s’impose sur la lettre du principe DRY.
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
16
Un peu de philosophie sur l’informatique et les sciences
Le mode opératoire des sciences physiques est assez connu de nos jours: le physicien jette
des ponts entre la réalité et les concepts mathématiques.
Pour cela, le physicien définit un modèle de la réalité en utilisant des objets mathématiques et
des relations entre ces objets. Ce modèle permet de calculer sur les objets mathématiques et
d’obtenir des résultats, pour le compte du monde réel.
Par exemple, le physicien dit que la table est modélisée par un rectangle. Le mathématicien
a fabriqué l’objet de haut niveau “rectangle” à partir de ses objets géométriques de base et a
obtenu la formule “longueur x largeur” pour calculer sa surface. Le physicien utilise alors cette
formule pour la table.
Par analogie, on pourrait dire que la démarche descendante de la règle #3 qui crée des
modules associés au réel est une démarche de type “sciences physiques”. Et de même, la
démarche ascendante de la règle #4 qui élabore des composants génériques à partir d’autres
composants informatiques de base, est une démarche de type “mathématiques”.
Dans une équipe d’architectes logiciels, certains travaillent plutôt sur la modélisation du réel,
comme les physiciens, d’autres sur l’élaboration ou la combinaison d’objets informatiques,
comme les mathématiciens. C’est de cette démarche bi-directionnelle que naissent les
bonnes architectures.
Il est bon de garder un équilibre entre les approches descendantes et ascendantes
On peut remarquer que, selon le type de logiciel, l’approche descendante ou l’approche
ascendante peut être dominante, et en particulier:
- les logiciels soumis à de fortes demandes fonctionnelles (ex: nombreux écrans), comme
les logiciels de gestion, font plus appel à la démarche descendante pour bien prendre en
compte ces demandes.
- les logiciels soumis à de fortes contraintes techniques (ex: tolérance aux pannes), comme
les logiciels de réseaux, font plus appel à la démarche ascendante pour relever les défis
techniques.
Il est cependant nécessaire d’éviter une seule démarche, car une trop grande exclusive
d’approche descendante nuit à la réutilisation des développements, et une trop grande
approche ascendante nuit à la prise en compte des demandes clients.
Comme la plupart des architectes privilégient l’un ou l’autre de ces modes, la présence et la
discussion entre ces deux courants de pensée dans l’équipe de conception est un facteur clé
de succès.
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
17
Acte #5
Rechercher l'indépendance et les degrés de liberté
Un peu de rangement des modules peut être utile
A ce stade, la compréhension du travail d’architecture a progressé:
- le tri doit être fait entre vraies et fausses contraintes ;
- le logiciel doit être une collection de modules qui interagissent sans partager de données ;
- des modules modélisent des éléments du réel...
- ...tandis que les autres réalisent des fonctions informatiques génériques.
Le nombre d’éléments manipulés (modules, sous-modules, composants logiciels) est
important. Le maillage entre ces éléments peut être complexe.
L’objectif maintenant considéré est de faire en sorte que l’architecture soit simple,
compréhensible et puisse réduire l’ampleur du développement.
Rappel: comme expliqué dans le prologue, l’introduction des règles est faite à travers un
parcours dans le but de faciliter la présentation, sans que cela n’implique un caractère
séquentiel dans les travaux opérationnels. En particulier, l’objectif d’orthogonalité est pris en
compte pendant le découpage en modules et pas a posteriori.
Le concept d’orthogonalité aide à structurer les logiciels
Si l’on considère deux axes perpendiculaires, on dit aussi orthogonaux, le déplacement d’un
point parallèlement à un axe n’a pas d’impact sur sa projection le long de l’autre axe.
Le concept d'orthogonalité logicielle est ainsi dérivé de la géométrie et de l’idée
d’indépendance entre deux choix (ou “positions”), chacun parmi une liste (ou “axe”).
Pour bien comprendre cette notion, considérons, par exemple, le cas d’un ordinateur
individuel.
On installe sur cet ordinateur une collection de logiciels d’application: traitement de texte,
tableur, éditeur de présentations, navigateur web, etc.
Comme il faut parfois imprimer, on s’assure que l’on peut soumettre des impressions à
une ou plusieurs imprimantes. Mais, pour qu’un ordinateur puisse envoyer un travail à une
imprimante, il lui faut parler son “langage”. Pour que ce soit le cas, on installe sur l’ordinateur
un petit logiciel appelé “pilote” (en anglais, “driver”) et ce, pour chaque type d’imprimante.
Il y a donc sur l’ordinateur 2 groupes de logiciels
- les applications
- les pilotes.
On remarque que l’on peut utiliser n’importe quelle application avec n’importe quel pilote. On
peut aussi ajouter ou retrancher une application ou un pilote sans impact sur le reste.
Une façon géométrique à 2 dimensions de représenter ces logiciels est de tracer deux axes
orthogonaux: l’axe des applications et l’axe des pilotes.
Sur chaque axe on place les logiciels correspondants.
A partir de ces deux axes perpendiculaires, “embrochant” l’un les applications, l’autre les
pilotes, on peut retrouver sur le plan défini par les axes, tous les cas d’usage fonctionnel avec
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
18
une application A soumettant une impression à une imprimante P.
On dit que l’on a une orthogonalité à deux dimensions entre les applications et les pilotes des
imprimantes.
L’avantage est clair par rapport à une situation où il faudrait faire des logiciels intégrant à la
fois du code application (ex: un traitement de texte) et le support de plusieurs imprimantes.
C’était le cas autrefois avec MS-DOS.
Grâce à l’orthogonalité entre applications et pilotes, si l’on a 30 applications et 10 pilotes
d’imprimantes, on supporte 30x10=300 cas d’usage, alors qu’il n’aura fallut développer que
30+10=40 logiciels.
On retrouve le même avantage pour la mise au point et les tests. Imaginons que l’on ait à
développer cet ensemble fonctionnel: une équipe “application” peut utiliser un pilote factice
(qui affiche simplement ce qu’il reçoit) tandis qu’une équipe “pilote” utilisera une application
factice (qui ne fait qu’envoyer quelque chose de connu vers l’imprimante). Par la suite, on
peut garder des logiciels factices à côté des vrais pour faciliter la maintenance.
L’idée générale, est que l’architecture doit mettre le maximum de modules sur des axes, et
sur le maximum d’axes. On dit alors que l’on a maximisé l’orthogonalité.
Certains axes peuvent ne porter qu’un seul logiciel. Cet axe apporte l’indépendance du
logiciel par rapport aux autres axes: c’est le premier avantage de l’orthogonalité.
Les axes qui portent plusieurs logiciels apportent, en plus, une flexibilité et extensibilité à
bon compte: ajouter un logiciel sur un axe n’a pas d’impact sur le reste: c’est le deuxième
avantage de l’orthogonalité.
Quelques exemples de dimensions:
- l’axe sur lequel on place les fonctions de calcul du rabais consenti au client (selon la
catégorie du client, le rabais est un pourcentage fixe, ou augmente avec le volume de la
commande, etc.)
- l’axe sur lequel on place les fonctions qui font la saisie d’un formulaire de permis de
conduire (selon la catégorie du véhicule il faut des informations différentes)
- l’axe sur lequel on place les fonctions de décodage de vidéos (mpeg2, mpeg4, wmv, etc.)
- etc.
Pour chaque axe, on a une collection de logiciels et on utilise un indicateur pour aiguiller le
traitement vers celui qui correspond au besoin.
L’orthogonalité est un puissant moyen de lutte contre la complexité des logiciels
Augmenter l’orthogonalité est le moyen architectural le plus efficace pour lutter contre la
complexité, et rendre ainsi humainement maîtrisables les logiciels les plus imposants.
Il s'agit d’un concept d'architecture assez abstrait, mais son efficacité justifie des efforts.
Un code orthogonal favorise la maintenance et l'évolution:
- Un nouveau logiciel ajouté sur un axe va pouvoir fonctionner avec les autres de la même
manière que ses pairs de l’axe (ex: l’ajout d’un pilote d’imprimante n’oblige pas à changer
le traitement de texte): les temps et les coûts de développement en sont réduits.
- La qualité est améliorée car il est plus facile de tester chaque partie du code,
indépendamment des autres, et pas simplement le code global.
- Il est plus facile pour répartir le travail entre de petites équipes indépendantes, qui peuvent
être plus motivées puisque chaque module est indépendant: le Lego plutôt que le puzzle.
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
19
- Le code total à écrire est moins volumineux comme on l’a vu avec l’exemple des
applications et des pilotes d’imprimante. On a remplacé des multiplications par des
additions.
- Lors de la phase de développement, l'orthogonalité facilite la mise en place progressive
des modules. Au début du développement, on peut valider le squelette de l'application en
mettant en place des modules quasi-vides et réaliser un test global de fonctionnement
(le "Hello Word !" de la solution). Puis, on code les modules véritables au côté
des “factices”. Pour la même raison, l’orthogonalité facilite l’introduction de nouvelles
versions d’un module en commençant par les placer à côté des anciennes.
Dans chaque environnement technique, il y a des moyens pour mettre en oeuvre
pratiquement l’orthogonalité
La mise en pratique du concept architectural d’orthogonalité dans le code dépend de la
technologie générale du logiciel.
- en langage C, un axe est matérialisé par un tableau de pointeurs de fonctions, chaque
pointeur correspondant à un module de la dimension. On retrouve cela avec Unix.
- quand les modules d’un axe sont appelés par des Web Services, chacun est identifié par
son adresse Web, et donc une dimension est matérialisée par une table d’adresses web
(url).
- en Java, une dimension est souvent caractérisée par une “interface” qui définit les fonctions
attendues. Chaque module est une classe qui doit implémenter cette interface pour être sur
l’axe.
- ...
Un peu d’histoire de l’orthogonalité
Le premier usage du terme “orthogonalité” a été fait à propos des compilateurs.
Un compilateur est un programme qui traduit automatiquement le “code source” d’un logiciel
écrit dans un langage compréhensible par les humains (ex: langage C), en un “code objet”
écrit dans le langage compréhensible par le processeur (ex: Intel 386), afin que celui-ci
puisse l’exécuter.
Le langage des premiers microprocesseurs était très irrégulier. Deux des registres6 du
processeur étaient les seuls utilisables pour les multiplications. Un autre registre servait à
faire une lecture dite “indexée” dans la mémoire de l’ordinateur, etc.
Une bonne traduction automatique est très difficile avec les processeurs irréguliers. Elle
est beaucoup plus efficace avec des processeurs plus récents et orthogonaux: toutes les
instructions de calcul peuvent porter sur toutes les données (n’importe quel registre, mémoire
directement désignée, etc.)
Un peu d’histoire encore.
Quand on traite d’orthogonalité, on doit aussi citer Unix (1970) comme un exemple
particulièrement réussi. Ses concepts ont toujours du succès plus de 40 ans après sa
6un registre est une mémoire interne au processeur
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
20
création, à travers différentes mises en oeuvre: iOS de iPhone/iPad, Android, Mac OS X ou
Linux.
Règle
#5
L’architecture doit placer le plus possible de modules, métiers ou techniques,
sur des axes orthogonaux.
Un module placé sur un axe n'est connu des autres qu’en tant que membre de
cet axe. Si plusieurs modules sont sur le même axe, les autres modules les
utiliseront de manière unifiée, et le logiciel global n’en sera que simplifié.
Pour vérifier la conformité à cette règle
- L’appartenance ou non-appartenance à des axes pour un
module doit être vérifiée avec le critère d’indépendance.
- Les architectes doivent vérifier si on ne peut pas créer des
axes sur lesquels on peut placer le plus grand nombre
possible de modules
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
21
Acte #6
Faciliter les autres activités de conception (codage,
tests, etc.)
Les règles vues précédemment conduisent à une architecture qui fait du logiciel un ensemble
de modules bien choisis et communiquants.
Cependant, l’architecture ne doit pas tenir compte uniquement des services que doit rendre la
solution: elle doit aussi faciliter le codage et les tests du logiciel.
Les constructeurs automobiles savent qu'une partie importante de l'effort d’architecture d'un
nouveau véhicule à pour objet de faciliter sa construction et d’en réduire le coût.
En logiciel, il n’y a pas de coût de production, celle-ci étant automatisée (assurée par le
compilateur et l’éditeur de liens), mais il y a un coût de conception important: l’écriture des
lignes de codes, les tests et les corrections.
Le travail à plusieurs personnes ou équipes, est le défi permanent du développement
logiciel, qui, comme la plupart des activités de conception, s’y prête a priori mal
- comment sera-t-il possible de partager le travail entre les équipes de façon à ce qu’il ne soit
pas nécessaire pour chacune de maîtriser l’ensemble?
ex: en définissant plusieurs modules, chaque module étant responsable d’un
ensemble de données métier et d’actions possibles sur elles → le défi est la
rigueur dans l'intégrité des données,
et en définissant des modules orchestrant la progression des processus en
invoquant les premiers → le défi est l'interaction globale ;
- comment sera-t-il possible de tirer profit de la diversité des talents humains?
ex: en séparant les travaux sur le contenu des écrans de ceux sur l’apparence
visuelle, ce qui est facilité si ces travaux correspondent à des modules différents.
ex: en tirant profit des goûts et facilités des développeurs pour les attributions des
modules. Certains modules sont proches des métiers et des utilisateurs avec une
difficulté qui tient à la gestion de la richesse fonctionnelle, et d’autres modules
sont plus internes et qui portent des difficultés techniques précises
L’architecture doit faciliter le travail de codage et de mise au point
- comment va être codé le logiciel: technologies, outils individuels et collectifs
ex: choisir, par exemple, une architecture basée sur Android pour un équipement,
fait bénéficier l’équipe de codage d’une large base d’outils et d’environnements
matériels pour les tests.
- comment seront gérés les incidents de traitement?
ex: quand un incident se produit sur un module au cours d’un traitement global, la
reprise du cours des opérations peut être difficile avec des risques
d’incohérence. Si l’architecture prévoit que les requêtes entre modules soient
idempotentes7, les modules peuvent simplement relancer leurs requêtes après
un incident, évitant des mécanismes de resynchronisation délicats.
7On dit qu’une fonction est idempotente quand le fait de l’appliquer plusieurs fois est équivalent à l’appliquer une seule. Par
exemple, “effacer l’article 23561” est idempotent, alors que “ajouter 1 au nombre de visites” ne l’est pas.
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
22
- comment sera testé chaque module?
ex: si les modules communiquent entre eux par des messages simples et lisibles par
des humains cela facilite la mise au point. Si le mécanisme d’envoi est de type
mail ou web, c’est une facilité supplémentaire.
L’architecture prépare l’assemblage des modules en un logiciel global
- comment les objets communiqueront entre eux?
ex: la communication entre objets par REST est testable avec un navigateur, la
communication entre objets par mail est testable avec un client de messagerie
- comment sera testée la solution lors son installation éventuelle dans un site éloigné?
ex: des auto-tests intégrés dans le logiciel lui-même permettent aux équipes de
déploiement de les activer sur site à des fins de contrôle
- comment sera assuré le suivi des anomalies détectées par le logiciel lui-même?
ex: la mise en oeuvre d’une centralisation des tickets d’anomalies venant des divers
modules et le transfert vers un site web d’aide à la maintenance
Règle
#6
L’architecture d’un logiciel doit faire des choix sur le découpage en modules
et sur leurs interactions afin de faciliter les autres activités de conception:
codage, test, maintenance.
En particulier, le découpage doit permettre à des équipes différentes de
travailler en parallèle et sans que chacune ait à maîtriser l’ensemble.
Le mode d’interaction entre modules doit faciliter les tests et la maintenance.
Pour vérifier la conformité à cette règle
- Le document d'architecture doit couper la solution en
éléments à réaliser séparément: les équipes de
développement doivent s’en assurer
- Pour s’assurer que l’architecture prend bien en compte le
codage qui va suivre, il est bien qu’il donne la voie à suivre
(environnement de développement, de test et de
débogage, approche à suivre pour la mise au point).
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
23
Épilogue Les 6 règles d’architecture
Règle
#1
L’architecture doit exclure les fausses contraintes, souvent issues d’une
traduction trop rapide des besoins en choix techniques, car elles peuvent être
à l’origine de dangereuses décisions d’architecture.
Règle
#2
Le logiciel doit être composé de modules qui coopèrent entre eux, chaque
module assurant le contrôle et l'intégrité de ses données.
Il ne doit y avoir aucun partage de données entre modules que ce soit en
mémoire, sous la forme de fichiers ou de bases de données.
Chaque module doit contribuer activement à la robustesse et à la sécurité du
logiciel.
Règle
#3
La première raison qui peut justifier l’existence d’un module logiciel est d’être
une modélisation d’un élément de la réalité.
Cette première catégorie de modules est issue de l’analyse descendante,
c’est-à-dire en partant des besoins et en allant vers le code. Cette analyse est
particulièrement importante pour les logiciels à complexité fonctionnelle forte.
Règle
#4
Le seconde et seule autre raison qui peut justifier l’existence d’un module
logiciel est d’être un composant générique, c’est-à-dire qui a un sens général
en informatique, même loin du besoin métier considéré.
Cette deuxième catégorie de modules est issue de l’analyse ascendante,
c’est-à-dire en partant des objets de base de l’informatique et en allant vers
les besoins. Cette analyse est particulièrement importante pour les logiciels à
complexité technique forte.
Règle
#5
L’architecture doit placer le plus possible de modules, métiers ou techniques,
sur des axes orthogonaux.
Un module placé sur un axe n'est connu des autres qu’en tant que membre de
cet axe. Si plusieurs modules sont sur le même axe, les autres modules les
utiliseront de manière unifiée, et le logiciel global n’en sera que simplifié.
Règle
#6
L’architecture d’un logiciel doit faire des choix sur le découpage en modules
et sur leurs interactions afin de faciliter les autres activités de conception:
codage, test, maintenance.
En particulier, le découpage doit permettre à des équipes différentes de
travailler en parallèle et sans que chacune ait à maîtriser l’ensemble.
Le mode d’interaction entre modules doit faciliter les tests et la maintenance.
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
24
Les explications des chapitres précédents auront peut être montré que ces règles sont bien
comme voulu:
○ Simples à comprendre et à partager, et en particulier, elles sont compréhensibles
sans avoir une expertise technologique particulière ;
○ Minimales, en ce sens qu’elles sont peu nombreuses, qu’elles s’appliquent pour
la grande majorité des projets de développement logiciel, et que le retrait de l’une
d’elles ouvrirait la porte à un danger sérieux ;
○ Efficaces, car si une architecture est conforme à ces règles, alors il y a de grandes
chances pour que le développement se fasse dans de bonnes conditions.
Les règles d’architecture sont indépendantes des méthodologies
À partir des années 70, des méthodologies ont été inventées pour maîtriser la complexité des
projets logiciels depuis le classique "cycle en V" jusqu'aux méthodes agiles.
L'approche présentée ici avec ces règles est complémentaire des méthodologies, car il s'agit
là non pas de maîtriser la complexité, mais de la réduire. Aucune méthodologie spécifique
n'est encouragée ici, même si ces règles peuvent faciliter les approches incrémentales.
Les règles d’architecture sont indépendantes du domaine d’application
Elles sont génériques et applicables pour la conception de solutions logicielles de tous types.
Cela inclut, par exemple, aussi bien les systèmes d'information que les logiciels “temps réels”
des équipements embarqués.
La politique technique que se choisit une organisation doit aller bien sûr au-delà de ces
règles avec des choix de technologies, de logiciels, d’outils de développement, de pratiques,
etc.
Ces choix, eux, doivent être faits selon le type de problèmes à traiter.
Ces règles ont pour objet la sécurisation des développements logiciels grâce à une
architecture saine, plaçant la qualité en objectif premier. Elles n’entraînent en elles-mêmes ni
modernité, ni conformité par rapport à telle ou telle orientation technique.
Les règles d’architecture sont indépendantes des générations de l’informatique
Pour mémoire...
Les années 1980 ont vu la “Génération Unix” prendre le dessus sur les mainframes
- une solution est alors une application qui tourne sur un ordinateur (départemental ou
personnel); elle traite chaque touche appuyée par l’utilisateur et l’écran
- les technologies sont Unix, le PC MS-DOS, le langage C, les terminaux asynchrones
- Digital Equipment (DEC) est le leader; les standards Unix et DOS ont dé-verticalisé
l’industrie avec des éditeurs de logiciel, des fabricants de matériel et des sociétés de
services.
Les années 1990 ont vu la “Génération Informatique Distribuée” tirer parti des réseaux
- les solutions informatiques sont pour la première fois réparties entre plusieurs applicatifs
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
25
tournant sur des ordinateurs en réseau
- les technologies mettent en oeuvre le modèle client-serveur avec souvent le poste de
travail Windows comme client, le partage des fichiers, les serveurs de bases de données
- Microsoft côté ordinateurs personnels et Sun côté stations et serveurs sont les leaders;
l’industrie découvre la production de masse des ordinateurs; l’éclatement des solutions sur
plusieurs machines en réseau favorise la segmentation du marché des logiciels (bases de
données, ERP, middleware transactionnel, etc.)
Les années 2000 voit la “Génération Java” dominer
- les solutions sont basées sur des applications Web et les utilisateurs y accèdent par un
navigateur à travers un réseau, l’accès à Internet étant devenu banal
- les technologies sont Java, JEE, HTML, l’architecture Web avec le protocole http
- Oracle (BEA, Sun Javasoft) et IBM (WebSphere) sont les leaders de ce monde Java/Web;
l’économie du Web s’envole avec l’e-commerce, le multimédia en ligne (légal ou pas), les
nombreux sites d’information, les modèles économiques basés sur la publicité, etc.
Les années 2010 et la “Génération Google” prennent le leadership
- des solutions centrées sur l’utilisateur individu ou la communauté; des smartphones et des
tablettes; des communautés Facebook ou autres
- les technologies iPhone/iPad (Apple) et Android (Google); Web2.0 et Google Web Toolkit;
(Google); bases NoSQL comme BigTable (Google) et Cassandra (Facebook); les
échanges entre les applications de Facebook et Google et ceux de leurs partenaires;
l’architecture Web généralisée, les clouds d’Amazon, Google et Apple
- Google, Facebook et Apple sont les leaders technologiques et les leaders en notoriété,
les “decisions makers” ont connu l’informatique dans leur jeunesse et sont exigeants;
l’Open Source devient le lieu de l’innovation
Comme on le voit, les règles d’architecture ne se rapportent ni à une génération particulière,
ni à une technologie spécifique, même si les dernières générations fournissent des
technologies favorables.
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
26
Un peu d’histoire, avec les principes d’architecture de l’Internet
La clairvoyance de Robert Kahn, co-inventeur de l'architecture Internet avec Vinton Cerf, l’a
conduit à faire quatre choix fondateurs:
“- Chaque réseau distinct devrait être autonome et aucun changement interne ne devrait être
nécessaire au niveau de ce réseau pour pouvoir le connecter à Internet.
- Les communications devraient s'effectuer selon un service sans garantie. Si un paquet de
données ne parvenait pas à la destination finale, il devrait être retransmis à partir de la
source dans un court délai.
- Des boîtes noires devraient être utilisées pour connecter les réseaux [On les appellera plus
tard des passerelles et des routeurs]. Aucune information ne devrait être conservée par les
passerelles concernant les flux de paquets individuels qui les traversent, favorisant ainsi
leur simplicité et évitant une adaptation et une récupération complexes à partir de divers
modes d'échec.
- Il ne devrait y avoir aucun contrôle global au niveau opération.”
Il est intéressant de noter que Internet, pourtant loin du
sujet “architecture du logiciel”, respecte les 6 règles.
On plaçait beaucoup de contraintes sur les anciens
réseaux: pas de pertes de données, séquencement
respecté, facturation, etc. Au final, Internet l’a emporté,
et il exclut ces fausses contraintes en traitant le seul
service attendu d’un réseau: vaincre la distance. (Ceci
étant acquis, il reste du travail sur les autres services
comme voix, web, chat, commerce, etc.) → règle #1
La modularité est exemplaire avec des fonctions simples
et segmentées (du LAN au routeur) → règle #2
La modélisation est faite à la fois sur les services vus
par les utilisateurs (paquet ou flux) → règle #3, et sur les
bases informatiques (réseaux physiques) → règle #4
Internet créé une orthogonalité entre les applications
connectées et les réseaux physiques. Ce n’était pas le
cas avant, dans les télécommunications, où il y avait
une intégration verticale → règle #5
Les services et protocoles sont conçus pour faciliter la
mise au point avec, par exemple, des protocoles simples
à visualiser, voire en clair → règle #6
__________
Les 6 règles d’architecture pour sécuriser le développement logiciel
par Denis Attal, Raymond Wei
27