Cette page vous donne les différences entre la révision choisie et la version actuelle de la page.
conception [2017/04/24 21:31] gbdivers |
conception [2017/04/26 04:11] (Version actuelle) gbdivers |
||
---|---|---|---|
Ligne 202: | Ligne 202: | ||
</note> | </note> | ||
- | ===== Le copier-coller ===== | + | ==== Le copier-coller ==== |
Pour savoir si un code est réutilisable, il faut se poser la question de comment il pourra être réutilisé et quels seront les freins à sa réutilisation. | Pour savoir si un code est réutilisable, il faut se poser la question de comment il pourra être réutilisé et quels seront les freins à sa réutilisation. | ||
Ligne 212: | Ligne 212: | ||
Le copie-coller de code est donc possible pour le code non critique (commentaires, documentation, etc) mais est à éviter dans les autres cas. | Le copie-coller de code est donc possible pour le code non critique (commentaires, documentation, etc) mais est à éviter dans les autres cas. | ||
- | ===== Les macros ===== | + | ==== Les macros ==== |
Un moyen d'éviter le problème de maintenance d'un code que vous copiez-collez est d'avoir une seule version d'un code et de faire appelle a celui-ci quand vous en avez besoin. | Un moyen d'éviter le problème de maintenance d'un code que vous copiez-collez est d'avoir une seule version d'un code et de faire appelle a celui-ci quand vous en avez besoin. | ||
Ligne 229: | Ligne 229: | ||
Les macros permettent certaines fonctionnalites specifiques, donc il est parfois intéressant de les utiliser. Mais elles presentent egalement de gros problèmes (en particulier que c'est du remplacement de chaînes sans tenir compte du contexte et qu'il n'y a pas de vérification des types de paramètres). Il est donc préférable de limiter leur utilisation et préférer les fonctions (et les templates pour le code générique). | Les macros permettent certaines fonctionnalites specifiques, donc il est parfois intéressant de les utiliser. Mais elles presentent egalement de gros problèmes (en particulier que c'est du remplacement de chaînes sans tenir compte du contexte et qu'il n'y a pas de vérification des types de paramètres). Il est donc préférable de limiter leur utilisation et préférer les fonctions (et les templates pour le code générique). | ||
- | ===== Les fonctions ===== | + | ==== Les fonctions ==== |
Les fonctions sont la base de la réutilisabilité en programmation procédurale. C'est même pour cela que les fonctions ont ete initialement creees. | Les fonctions sont la base de la réutilisabilité en programmation procédurale. C'est même pour cela que les fonctions ont ete initialement creees. | ||
Ligne 244: | Ligne 244: | ||
Plus généralement, créer une bibliothèque logicielle permet de faciliter la réutilisation du code. C'est pour cela qu'une partie importante de la conception se focalise sur la création de bibliothèques logicielles, une application n'étant au final qu'un ensemble de bibliothèques qui interagissent entre elles. | Plus généralement, créer une bibliothèque logicielle permet de faciliter la réutilisation du code. C'est pour cela qu'une partie importante de la conception se focalise sur la création de bibliothèques logicielles, une application n'étant au final qu'un ensemble de bibliothèques qui interagissent entre elles. | ||
- | ===== Pourquoi un code réutilisable n'est pas réutilisé ? ===== | + | ==== Pourquoi un code réutilisable n'est pas réutilisé ? ==== |
Malgré le soin que vous pouvez apporter pour que votre code soit le plus réutilisable possible, il peut arriver que votre code ne soit en pratique pas (ou peu) réutilisé. Essayer de comprendre pourquoi les utilisateurs ne réutilisent pas votre code peut aider à améliorer sa réutilisabilité. | Malgré le soin que vous pouvez apporter pour que votre code soit le plus réutilisable possible, il peut arriver que votre code ne soit en pratique pas (ou peu) réutilisé. Essayer de comprendre pourquoi les utilisateurs ne réutilisent pas votre code peut aider à améliorer sa réutilisabilité. | ||
Ligne 253: | Ligne 253: | ||
* organisez correctement vos projets. Décomposez en modules facilement identifiables, créez des répertoires pour ranger vos fichiers (l'organisation en modules et répertoires sera détaillé dans un prochain chapitre). | * organisez correctement vos projets. Décomposez en modules facilement identifiables, créez des répertoires pour ranger vos fichiers (l'organisation en modules et répertoires sera détaillé dans un prochain chapitre). | ||
- | * écrivez de la documentation techniques, expliquant l'organisation du projet, les informations importantes a connaître, comment vous avez conçus le code. (Plus les utilisateurs comprendront comment vous avez pensé votre code, plus ils arriveront à trouver facilement les informations dont ils ont besoin). | + | * écrivez de la documentation techniques, expliquant l'organisation du projet, les informations importantes à connaître, comment vous avez conçus le code. (Plus les utilisateurs comprendront comment vous avez pensé votre code, plus ils arriveront à trouver facilement les informations dont ils ont besoin). |
* transmettez vos connaissances et faites en sorte que les autres développeurs partagent aussi leurs connaissances. Une technique classique pour cela est de faire du //peer-reviewing//, qui consiste à se relire mutuellement le code entre développeurs. (Cela sera détaillé dans le chapitre sur la gestion de projet). | * transmettez vos connaissances et faites en sorte que les autres développeurs partagent aussi leurs connaissances. Une technique classique pour cela est de faire du //peer-reviewing//, qui consiste à se relire mutuellement le code entre développeurs. (Cela sera détaillé dans le chapitre sur la gestion de projet). | ||
Ligne 265: | Ligne 265: | ||
La testabilité d'un code correspond a la facilite ou non de tester un code. Comme pour la réutilisabilité, il faut distinguer un code testable et un code testée. La testabilité est une propriété intrinsèque d'un code, qu'il soit effectivement testé ou non. | La testabilité d'un code correspond a la facilite ou non de tester un code. Comme pour la réutilisabilité, il faut distinguer un code testable et un code testée. La testabilité est une propriété intrinsèque d'un code, qu'il soit effectivement testé ou non. | ||
- | Pour savoir si un code est testable, il faut vous poser la question "est-il facile d'écrire des tests sur mon code ?". | + | ==== Tests automatiques et manuels ==== |
+ | Les tests ont une importance particulière dans certaines méthodes de gestion de projets, en particulier dans les méthodes Agile, qui sont utilisées dans ce cours. Plus spécifiquement, vous verrez dans les prochains chapitres le développement dirigé par les tests (TDD, pour //Tests Driven Development//), qui consiste à écrire en premier les tests et les utiliser comme point de départ pour écrire votre code. | ||
+ | Il existe plusieurs types de tests, en fonction de ce que vous voulez tester et comment vous tester. | ||
+ | * les tests automatiques sont réalisés par des programmes, qui suivent un ensemble de tâches prédéfinies (appeler une fonction en utilisant des valeurs spécifiques, lire un fichier, telecharger des données en ligne, etc) puis vérifient que le résultat obtenu est conforme à ce que vous avez prévu. | ||
+ | * les tests manuels sont réalisés par des personnes, qui suivent une liste de tâches prédéfinies et vérifie le résultat obtenu. | ||
+ | Les tests automatiques sont tres rapides a executer, alors que les tests manuels sont limités par la rapidité de celui qui fait les tests. (Et plus une personne se précipite, plus il risque de faire des erreurs). Il est donc préférable de privilégier les tests automatiques en priorité, mais ce n'est pas toujours possible. (Par exemple, si vous écrivez un programme qui va rechercher une image de chaton sur internet, il faudra bien qu'un humain vérifie l'image pour etre sur que c'est bien un chaton). | ||
+ | Pour simplifier, plus il sera facile d'écrire des tests automatiques, plus un code sera testable. | ||
+ | ==== Tests unitaires ==== | ||
- | probleme de testabilite : par exemple gui | + | Un autre critère important de la testabilité est la granularité du code (c'est-a-dire a quelle point vous pouvez tester des parties minimalistes de votre code). Prenez un exemple simple : imaginez que vous devez écrire un code qui réalise deux tâches successives et retourne un résultat. |
+ | <code cpp> | ||
+ | int do_something() { | ||
+ | int result { 0 }; | ||
+ | |||
+ | // code pour la tâche 1 | ||
+ | ... | ||
+ | |||
+ | // code pour la tâche 2 | ||
+ | ... | ||
+ | |||
+ | return result; | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Vous devez tester si vous code est valide ou non. | ||
+ | |||
+ | Dans cet exemple simple, le résultat attendu sera toujours le même, donc il est possible d'écrire un test qui appelle cette fonction et compare le résultat retourné. Par exemple : | ||
+ | |||
+ | <code cpp> | ||
+ | int main() { | ||
+ | const auto result { do_something() }; | ||
+ | assert(result == expected_result); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Ce simple code est un test : si vous exécutez ce code, si l'assertion est fausse, c'est que la fonction ne retourne pas le résultat attendu, le test a échoué. (En pratique, un vrai test est un peu plus complexe, vous testerez plus de choses en même temps. Et comme vous ferez beaucoup de tests en même temps, un outil spécialisé se chargera de regrouper et présenter les résultats des tests, pour faciliter l'analyse des tests. Mais le principe de base est le meme). | ||
+ | |||
+ | Si le test échoue, cela va nécessiter une correction du code de votre part. La question est laquelle des deux tâches est incorrecte ? La premiere ? La seconde ? Les deux ? | ||
+ | |||
+ | En fait, ce test ne permet pas de répondre à ces questions, parce qu'il ne teste pas séparément les deux tâches. On dit que le test n'est pas "unitaire" (il ne teste pas une chose unique). Plus un test est unitaire, plus il sera facile d'identifier la source d'une erreur et corriger le code. | ||
+ | |||
+ | Il est facile de corriger le code précédent, en respectant le principe de responsabilité unique (SRP), c'est a dire en faisant une fonction pour chaque tâche. | ||
+ | |||
+ | <code cpp> | ||
+ | void task_1(int& value) { | ||
+ | // code pour la tâche 1 | ||
+ | ... | ||
+ | } | ||
+ | |||
+ | void task_2(int& value) { | ||
+ | // code pour la tâche 2 | ||
+ | ... | ||
+ | } | ||
+ | |||
+ | int do_something() { | ||
+ | int result { 0 }; | ||
+ | task_1(result); | ||
+ | task_2(result); | ||
+ | return result; | ||
+ | } | ||
+ | |||
+ | int main() { | ||
+ | // test de la tache 1 | ||
+ | int result_1 { 0 }; | ||
+ | assert(task_1(result_1) == expected_result_1); | ||
+ | |||
+ | // test de la tache 1 | ||
+ | int result_2 { 0 }; | ||
+ | assert(task_2(result_2) == expected_result_2); | ||
+ | |||
+ | // test de la tache 1 | ||
+ | const int result { do_something() }; | ||
+ | assert(result == expected_result); | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Vous voyez qu'avec ce code, selon quelle assertion échoue, vous pourrez retrouver facilement quelle tâche n'est pas correcte. | ||
+ | |||
+ | C'est le second critère de la testabilité : plus il sera facile d'écrire des tests unitaires, plus le code sera testable. | ||
+ | |||
+ | Un code peu testable sera un code qui demandera plus de travail pour vérifier qu'il est correct et le maintenir. Voire ca sera un code qui a plus de risque de contenir des erreurs. | ||
+ | |||
+ | Pour aller plus loin : [[https://en.wikipedia.org/wiki/Software_testability|Software testability]]. | ||
+ | |||
+ | |||
+ | ===== Classes, modules et bibliothèques logicielles ===== | ||
+ | |||
+ | Un dernier critère important est le découpage du code. Si vous écrivez un code d'une dizaine de lignes, vous (ou un autre développeur) n'aurez probablement pas de mal à relire et comprendre votre code. Si vous écrivez une centaine de lignes de code, cela sera plus difficile. Si vous écrivez plusieurs milliers de lignes de code, vous aurez du mal a comprendre votre code. | ||
+ | |||
+ | Les fonctions permettent de découper un code en partie plus courtes et plus simples a lire. En particulier, en donnant des noms aux fonctions et aux paramètres. Mais si votre code est conséquent, vous pourrez obtenir plusieurs milliers de fonctions et votre code redeviendra peu compréhensible. | ||
+ | |||
+ | De nos jours, les programmes sont de plus en plus important en taille, développés par des équipes nombreuses, maintenu sur des années. Le découpage en fonctions n'est alors plus suffisant, il faut des niveaux supérieurs d'organisation du code : | ||
- | plusieurs objectifs: fixer l'api, verifier que le code fait ce qu'il faut, eviter les regressions | + | * une classe regroupe plusieurs fonctions et structures de données ; |
+ | * un module regroupe plusieurs classes ayant une thématique commune (gestion des fichiers, réseaux, interface graphique, etc) ; | ||
+ | * une bibliothèque logicielle regroupe un ou plusieurs modules en projets, qui peuvent être développés de façon indépendante ; | ||
+ | * un framework regroupe plusieurs bibliothèques logicielles ; | ||
+ | * un programme va utiliser plusieurs bibliothèques logicielles pour remplir un ou plusieurs tâches spécifiques ; | ||
+ | L'application finale que vous proposerez aux utilisateurs pourra donc être un ensemble complexe d'applications qui interagissent en eux, de bibliothèques logicielles, de ressources (images, fichiers de données), etc. | ||
- | ===== libs et modules ===== | + | Ce qui implique qu'il faudra également gérer la création de //distribuables// (c'est-à-dire de "quelque chose" qui permettra aux utilisateurs d'accéder à vos applications : installation, mise à jour, fournir les sources, etc). |
- | la conception d'application vue comme la conception de libs | + | Pour terminer, en complément de cette organisation logique de votre code en fonctions, classes, modules, etc. il faudra également gérer l'organisation physique de votre code dans des fichiers et dans des répertoires. |