Semaine 1: Introduction + Modèle de développement
L'ingénieur conçoit des solutions innovatrices, durables et adaptées à l'environnement. Il est guidé par la rigueur et la recherche de garantie. Un ingénieur utilise des outils précis et une méthodologie de travail.
Le logiciel est fondamentalement de nature conceptuelle. Il décrit un ensemble de programmes (chemins).
Propriétés inhérentes du logiciel: Complexité, Versatilité, Invisibilité, Discontinuité
Si Distanceacteurs est élevé le modèle présentera peu d'interactions entre les acteurs =>
linéaire ou incrémental. Sinon, il sera itératif.
Si Coutressources est élevé le modèle minimisera les activités d'implémentation et de déploiement =>
linéaire ou itératif. Sinon, il sera incrémental.
Le modèle linéaire permet de développer de manière séquentiel. Il est pratique pour des projets où les exigences sont fixes.
Le modèle itératif permet de raffiner les exigences et la conception tout au long du développement. Il répond bien au changement, mais peut être long (temps).
Le modèle incrémental permet de développer de manière modulaire, suivant les priorités du client.
Il peut être combiné au modèle itératif =>
modèle itératif-incrémental.
Contenu
Semaine 2: Processus de développement + Exigences
Les méthodes agiles servent à developper en incluant tous les acteurs prenant parts au projet.
Elles sont orienté résultat et favorise donc les courts incréments et des validations fréquentes.
Exemples: TDD, XP, Srum
Le Scrum est un framework de travail suivant les principes agiles. Il est caractérisé par des petites équipes diversifiés (< 10 membres), et un découpage du développement en courtes phases (sprints) favorisant l'agilité et le suivi.
Le processus unifié suit un développement itératif et incrémental, où le projet est décomposé en phase dans laquelle plusieurs flux de travail sont actifs à différent degré.
La base de tout projet à succès est une bonne communication permettant une bonne compréhension des besoins (exigences). Plusieurs techniques peuvent être utilisées pour recueillir les besoins (entrevue, sondage, observation, études de documents et solutions existantes). Plusieurs outils existent pour analyser les besoins et itérer avec le client (persona, prototype, user story).
Un besoin peut se traduire en fonctionnalité/action ou en caractéristique/contrainte. Lorsqu'il décrit une fonctionnalité, il s'agit d'un besoin fonctionnel (Ex: Le système lit les fiches des employés et imprime des chèques de paie). Lorsqu'il décrit une caractéristique, il s'agit d'un besoin non-fonctionnel (Ex: Temps de réponse, Licenses, Utilisabilité).
Contenu
Semaine 3: Cas d'utilisation + Analyse
Le diagramme de cas d'utilisation permet de répertorier toutes les interactions entres les différents acteurs d'un système et le système. Un acteur ici n'est pas forcément un humain (ex: horloge, capteur). Il est important de se rappeler que l'objectif est de comprendre et modéliser les besoins du client.
Un cas d'utilisation (CU) est décrit à travers un scénario principal présentant l'exécution du CU étapes par étapes et des scénarios alternatifs présentant le traitement des erreurs et les alternatives. La description du CU peut aussi être accompagnée de préconditions et postconditions imposant des contraintes sur l'état du système avant et après le scénario principal.
L'analyse consiste à encadrer le projet de sorte à pouvoir concevoir une solution. Durant l'analyse nous élaborons les contraintes conceptuelles (structure de données, manipulation et présentation d'information, contrôle d'accès) et physiques (support nécessaire, environnement, interactions possibles).
L'activité d'analyse utilise et produit de nombreux modèles d'analyse (fonctionnel, dyanmique, objet) permettant de visualiser et communiquer le cadre de la solution. Le diagramme d'activités permet de présenter une vue de haut-niveau du comportement dynamique attendu par la solution.
Contenu
Semaine 4: Analyse + Conception
Le modèle d'objet fournit une vue de haut-niveau des objets encapsulant la structure du système. Le formalisme ECB catégorise les objets en classes d'entités (concepts et information qui vit et persiste dans le système), classes d'interfaces (interactions entre le système et l'environnement) et en classes de contrôle (traitement de données, calculs et algorithmes complexes).
Dans un modèle ECB robuste, un acteur ne peut communiquer avec le système que via une classe d'interface. Celle-ci peut communiquer avec une classe de contrôle (pouvant se succéder) qui fait le lien avec les classes entités. Le modèle ECB facilite le travail de conception (en OO) et favorise une architecture MVC.
Contenu
Semaine 5: Conception
La conception permet d'esquisser la solution indépendamment de l'implémentation finale (code). On distingue 2 niveaux de conception: haut-niveau (conception architecturale) qui définit la structure et l'organisation générale du logiciel et bas-niveau (conception détaillée) qui se concentre sur le fonctionnement interne de chaque module.
Pour concevoir un système complexe, il est pratique de le décomposer en petits modules qui sont individuellement plus faciles à concevoir et implémenter. La décomposition fonctionnelle consiste à décomposer le système en modules (ex: méthode, classe, paquet) par fonctionnalité.
Un modèle offre une abstraction d'un système réduisant la complexité apparente de celui-ci. Un langage permet de décrire un modèle, mais ne constitue pas un modèle en soi. Plus le formalisme est précis, plus on peut l'utiliser pour générer l'implémentation (voir MDE, ingénierie dirigée par les modèles).
UML est une norme de l'OMG (Object Management Group) pour la modélisation orientée-objet et un standard ISO. UML comprend plusieurs langages de modélisation graphique offrant différentes vues du système étudié. UML n'est pas un langage de programmation, mais peut-être couplé à un générateur de code pour le traduire en un langage de programmation donné.
Contenu
Semaine 6: Modélisation + Révision
Le diagramme de classe permet de représenter la structure du logiciel en termes orienté-objet. Les attributs et méthodes peuvent être spécifiés avec 4 niveaux de visibilité (private, protected, package, public). À travers les associations, nous pouvons définir des collections et leur cardinalité.
Dans un diagramme de classe, chaque relation d'association, de composition ou d'agrégation se traduit en attribut. Si la relation porte un nom en fin d'association, celui-ci sera utilisé pour nommer l'attribut.
Le diagramme de séquence illustre le comportement du logiciel au niveau de l'exécution. Il permet de distinguer les classes participantes (via objets) dans la réalisation d'un cas d'utilisation et les appels (messages) fait entre eux. Des fragments (ex: alt, loop, opt) peuvent être utilisés pour apporter plus de structure et contrôle au flux de messages.
Le diagramme de séquence doit rester cohérent avec le diagramme de classe. Toutes les méthodes utilisées dans les appels entre objets doivent figurer dans leurs classes correspondantes. Pour que deux objets puissent s'envoyer des messages, une relation doit exister entre leur classe respective.
Contenu
Semaine 7: Intra + Architecture
La conception architecturale présente une vue de haut niveau du système (composants principaux, interactions). Elle est guidé par les exigences non-fonctionnelles (portabilité, fiabilité, robustesse...). En général, une conception modulaire est préférable à une conception monolithique qui peut vite devenir difficile à comprendre et modifier.
Une conception modulaire maximise les relations au sein de chaque module (forte cohésion) et minimise les relations entre les modules (faible couplage). On évite de baser la dépendance sur des structures complexes, mais sur des paramètres homogènes. On s'assure que chaque fonction d'une même classe est (assez) indépendante et travaille sur la même structure de données.
On distingue 2 types de réutilisation: réutilisation opportuniste (accidentelle, ajustement en cours de route) et réutilisation systématique (plannifié, construction de composants réutilisables). La programmation orientée composants consiste à emballer des librairies dans du code que la plateforme peut invoquer.
Contenu
Semaine 9: Style d'architecture + OOP
La plupart des systèmes emploient une formule hybride pour optimiser chaque secteur de service. Le choix du style architectural est dirigé par les besoins non fonctionnelles. Il représente une approche générale de résolution (haut niveau) qui sera ensuite spécifié à travers un design implémentable. Il est donc difficile (couteux) de pivoter d'un style architectural à un autre.
Le modèle MVC divise une application en 3 parties interconnectées: Modèle, Vue, Controleur. Le modèle communique son état à la vue chargé de la présentation. Le contrôleur traite les interactions reçues par la vue et envoie des requêtes au modèle. Il ne faut pas le confondre avec l'architecture 3-tier (complémentaire) qui divise un système en 3 couches distinctes, où une couche ne peut communiquer qu'avec ces couches voisines.
L'architecture pipe-et-filtre permet de traiter efficacement les flux comme le traitement d'images, la compilation et le déploiement automatisé. Les actions du flux sont décrits comme des filtres à appliquer sur une entrée donnée.
Dans une architecture client-serveur (centraliséEn général le serveur fournissant les services aux clients est centralisé),
les nœuds (machine) participants à un système se divisent en deux parties: serveur et clients. Le serveur fourni des services aux clients qui contacte le serveur.
Dans une architecture peer-to-peer (décentralisé), chaque nœud (peer) joue à la fois le rôle du client et du serveur.
Le paradigme orienté-objet favorise la modularité par la classification, la réutilisabilité par l'héritage et la généricité et la flexibilité le polymorphisme. Il offre aussi de bons mécanismes d'abstraction et dissimulation (modificateurs, classes abstraites, interfaces). Cependant, il résulte sur des programmes plus larges que d'autres paradigmes et n'est pas idéal pour certains développements (ex: interface graphique).
Les patrons de conception découlent d'expériences pratiques. Les patrons sont formulés comme schéma générique d'une solution à un problème récurrent dans un contexte donné. Chaque patron a une portée clairement définie et a un effet sur la construction, la structure ou le comportement des classes et objets. L'usage de patron promeut la réutilisabilité et facilite la compréhension du programme entre experts (ingénieur, architecte, développeur).
L'usage systématique de patrons peut inutilement complexifier un programme. Provenant de la pratique, ils ne sont pas fondamentaux à la réalisation d'une bonne conception. Le respect des principes de conception comme SOLID, GRASP ou KISS amène naturellement à des programmes flexibles, modulaires et maintenables.
Contenu
Semaine 10: Implémentation
Dans le flux d'implémentation, nous utilisons les langages de programmation pour implémenter le produit logiciel cible. Cependant, de nombreuses contraintes (contrat, environnement de déploiement, équipe de développement) peuvent limitées le choix du langage.
Le code décrit un programme exécuté par la machine, mais maintenu par des humains. Donc, il doit être lisible, facile à comprendre et modifier. Ceci est obtenu en respectant les bonnes pratiques (nomenclature pratique et cohérente) et documentant tous les aspects publiques du code.
Les outils de programmation couramment utilisés sont les environnement de développement intégré (IDE) et les éditeurs. Un IDE regroupe tous les outils (éditeur, débugger, controle de version) nécessaires pour le développement dans une interface commune et uniforme. Un éditeur permet principalement d'écrire et d'explorer du code. Certains éditeurs peuvent être augementé de services additionnelles via de extensions et plugins.
Durant le développement et après le déploiement, le programme peut présenter certains défauts (bugs) classés comme bloqueur, critique, majeur, mineur, inconséquent.
Pour les repérer et les corriger, plusieurs méthodes de débogage peuvent être utilisées:
Assertion
Vérifier une condition lors de l'exécution (if-else
) et mettre fin au programme en cas d'échec. Aussi utilisé dans les tests unitaires
,
Exception
Détecter une erreur logique ou un cas extrême. Lancer une exception quand une erreur se produit. Traiter une exception pour corriger l'erreur
,
Traçage
Produire la trace d'appels (stack trace) retraçant l'historique d'exécution du programme
,
Log manuel
Afficher l'information sur l'état du programme ou son flux de contrôle dans un log (ex: fichier texte)
,
Débogage interactif,
Débogage en direct.
Contenu
Semaine 11: Vérification & Validation
Afin de caractériser ou évaluer un logiciel, il nous faut établir des critères de qualité. Ces critères permettront d'assembler des métriques reflétant dans quelle proportion ce critère est favorisé dans le logiciel. Le standard ISO 25010 offre 8 critères de qualité: Pertinence fonctionnelle, Performance, Compatibilité, Utilisabilité, Fiabilité, Sécurité, Maintenabilité, Portabilité.
La vérification consiste à comparer la solution produite aux spécifications établies. On se demande ici si le logiciel a été fait correctement, indépendamment de l’usage réel qui en sera fait. La validation consiste à évaluer la solution produite en fonction des besoins actuels des clients et utilisateurs. On se demande si le logiciel fait la bonne chose, pour répondre aux besoins.
Dans un test à la boite noire, on vérifie si le comportement externe du logiciel est conforme aux exigences. On vérifie que pour une entrée, on obtient la sortie attendue. Dans un test à la boite blanche, on vérifie si l'implémentation du logiciel est correcte. On s'intéresse ici à la couverture de la structure interne (branchement, appel, boucle) du module.
Afin de tester un système de manière intégrale, nous commençons par vérifier le comportement individuel de chaque module (test unitaire). Nous les intégrons graduellement les uns aux autres (test d'intégration) jusqu'au plus grand ensemble de dépendance couvrant tout le système (test système). Finalement, le système est mis dans les mains du client pour validation (test d'acceptation).
Contenu
Semaine 12: Tests unitaires & Déploiement
Les tests unitaires visent à démontrer la présence d'erreur, c.-à-d. que l'implémentation d'une unité donnée contredit sa spécification. Pour une unité donnée, diverses formes (types) de tests peuvent être formuler pour vérifier son cas de succès (sortie est correcte pour une entrée correcte), d'échec (échoue, tel qu'attendu, pour une mauvaise entrée) ou son invariance (test sanitaire).
Pour assurer une bonne couverture des tests, il faut une bonne variabilité dans les valeurs utilisées pour les tests. Ainsi, nous pouvons identifier des valeurs « normales » (couvrant l'usage habituel), des valeurs extrêmes (0, tableau vide, valeur maximale), des valeurs inattendues (null, index négatif) et autres combinaisons de valeurs servant à parcourir tous les chemins de l'unité.
Contenu
Semaine 13: Maintenance
La maintenance représente plus de 60% du cout des activités de développement logiciel. Elle incorpore tous les flux de développement et regroupe tout changement nécessaire après le déploiement: perfectif (ajout/amélioration de fonctionnalités), adaptatif (ajustement aux changements de l'environnement), correctif (correction des défauts), préventif (anticipation de changement).
La modification d'un système suit certaines étapes clés, en commençant par l'initiation, où les programmeurs découvrent les problèmes et exigences et planifient leur résolution. Suite à cela, ils identifient (via recherche textuelle ou graphes de dépendances) les concepts (modules) concernés par le problème et analysent l'impact du changement (modules à modifier). Ils modifient ensuite le programme accompagné de nouveaux tests, et optimisent sa structure par des opérations de refactoring. Finalement ils déploient la nouvelle version du programme.