I. RÉFLÉCHIR▲
I-A. Étude de faisabilité▲
Répondre aux questions suivantes :
- quelle est la fonctionnalité globale de mon application ?
Faire un croquis rapide :
Exemple pour une application de dessin :
- quelqu’un l’a-t-il déjà fait ?
- si oui quelle sera la valeur ajoutée de mon programme par rapport à l’existant ?
- pourquoi dois-je le faire ?
- suis-je prêt à passer beaucoup plus de temps que prévu pour son développement ?
I-B. Réflexion technique▲
I-B-1. Quels sont les acteurs ?▲
- Qui va pouvoir intervenir sur le déroulement du programme et comment ?
Exemples
Pour un programme de dessin : un utilisateur (dessine)
Pour un programme de gestion de bibliothèque :
- plusieurs membres (empruntent) ;
- plusieurs visiteurs (listent ;
- plusieurs bibliothécaires (mettent à jour) ;
- un administrateur (peut intervenir directement sur la base de données).
- Quelles sont les interactions avec le système ?
- gestion de configuration ? (.ini, base de registre)
- stockage sur le disque dur ?
- dialogue par le port série ?
- impression possible ?
- affichage textuel, graphique ?
- interaction par le clavier, par la souris ?
- …
- Quelles sont les technologies impliquées ?
- base de données ? XML ?
- technologie client/serveur ?
- base de registre ?
- directX ?
- …
- Se renseigner sur les technologies qui vont être utilisées afin de les maitriser.
I-C. Décrire plus précisément▲
- Regrouper les fonctionnalités dans des unités dédiées, refaire des schémas spécifiques.
Garder à l’esprit que toute unité puisse être réutilisée dans une autre application sans avoir à être obligé de la modifier. (Ce qui est tout le principe de la programmation objet.)
Exemple
Unité de gestion du port comm : « ne s’occupera que d’envoyer et recevoir des suites d’octets »
- Pour chaque unité passive, donner un nom commençant par UN (comme unité) et pour chaque unité active, donner un nom commençant par TH (comme thread). J’entends par unité active (exemple « THportComm »), les entités qui « tournent » continuellement en tâche de fond en attente de leur entrée.
- Décrire les actions réalisées en interne par cette entité et les actions qui pourront être effectuées par une autre entité chargée de la piloter.
Interne :
- initialisation
- désinitialisation
- réceptionner « attendre une réponse »
- envoyer réponse « c’est l’unité qui prend la décision de reporter la réponse reçue à une autre entité »
Externe :
- démarre
- arrêter
- envoyer
- déclarer emplacement réponse « déclare où la réponse reçue devra être envoyée par l’unité »
I-D. Établir les liens▲
- Établir une unité passive « UNmanager » qui sera le cerveau coordinateur de toutes les entités. Le décrire de la même façon que précédemment pour les unités spécifiques.
- Relier les unités entre elles avec des flèches symbolisant le mot « utilise » ou bien « pilote », exemple « UNmanager utilise THcommPort ». Les plus expérimentés utiliseront la méthode de description UML à ce stade.
II. CHERCHER▲
Pour chaque unité, chercher si quelqu’un ne l’a pas déjà faite (avec les sources ou juste une librairie). L’utiliser si possible le cas échéant.
III. IMPLÉMENTER▲
III-A. Les unités▲
- Pour chaque unité non importée de l’extérieur, la coder selon la méthode qui suit.
- Une unité = 1 fichier .h, un fichier .cpp du nom donné à l’unité :
Exemple : UNmanager.h et UNmanager.cpp
- J’écris dans le .h une classe du nom de l’unité sans le UN ou le TH devant et dont la première lettre est en majuscule.
class CommPort
{
}
;
-
J’écris toujours dans le .h les constructeurs et destructeurs par défaut…
- … Et le prototype des méthodes de la classe (je mets toujours bool quand je suis tenté de mettre void, et je mets toujours __fastcall).
Tout s’écrit en minuscules, hormis le deuxième mot qui prend une majuscule. Jamais de « _ » hormis pour les paramètres des fonctions qui commencent avec.
private :
bool __fastcall initialisation
(
) ;
bool __fastcall desinitialisation
(
) ;
protected :
bool __fastcall receptionner
(
byte *
_buffer) ;
bool __fastcall envoyerReponse
(
byte *
_response) ;
public :
bool __fastcall demarrer
(
);
bool __fastcall arreter
(
);
bool __fastcall envoyer
(
byte *
_toSend) ;
bool __fastcall declarerEmplacementReponse
(
void
*
_callBack) ;
- Je déclare les données que la classe va pouvoir utiliser pour passer d’une fonction à l’autre, elles commencent toujours par une minuscule.
private :
Byte buffer[4096
];
bool demarre;
void
*
callBack
(
);
-
Je me déplace dans le .cpp et dans le constructeur, je ne mets qu’un appel vers initilisation(), dans le destructeur un appel vers desinitilisation().
- Dans initialisation(), je commence par mettre le code suivant :
try {
…
return
true
;
}
catch
(
…) {}
return
false
;
puis j’initialise mes données members de classe à la place des « … »
try {
ZeroMemory
(
buffer, 4096
);
demarre =
false
;
callBack =
NULL
;
return
true
;
}
catch
(
…) {}
return
false
;
- Idem dans desinitialisation().
Règle d’or pour toutes les méthodes qui vont être écrites par la suite
• Toujours englober le corps de la fonction d’un bloc try catch.
• Toujours tester si les arguments de la méthode sont valides (notamment quand passés par pointeurs).
• Sortir le plus tôt possible les cas d’erreurs, par un return (permet d’avoir moins de niveau d’indentation dans son code).
• Par la suite n’avoir qu’un seul point de sortie pour la fonction.
• Les variables déclarées dans la fonction doivent être préfixées d’un « l_ » comme « local » (exemple : int l_variableTemp = 0), les autres sont supposées membres.
• Préférer les boucles for aux boucles while.
• Ne jamais mettre une boucle sans fin (« while(true) »), sauf dans le corps principal d’une unité active, il doit toujours y avoir une condition qui permette de sortir de la boucle.
• Chaque nom de fonction doit refléter ce qu’elle fait. Exemple : « bool __fastcall affichageTableau(int ** _tableau) ».
• Je code les setters et les getters, (ce sont les fonctions qui ne font que changer l’état d’une donnée membre privée ou d’en connaître l’état). Toujours commencer par mettre le bloc try catch, pour chaque fonction.
bool __fastcall Commport::declarerEmplacementReponse
(
void
*
_callBack)
{
try {
If (!
_callBack) return
false
;
callBack =
_callBack;
return
true
;
}
catch
(
…) {}
return
false
;
}
• Codage des autres fonctions selon le même principe.
III-B. L’interface▲
• Toujours se mettre à la place d'un utilisateur le plus idiot possible. L'application doit pouvoir faire le maximum des tâches à sa place, moins l'utilisateur doit faire, plus il est heureux.
• Et le plus feignant (moins il a à cliquer, plus il est heureux).
• La forme principale doit être nommée fmMain, son fichier FMmain.cpp et .h.
• Les formes destinées à être des fenêtres filles (au sens MDI du terme) doivent s'appeler ffQuelqueChose et le fichier associé FFquelqueChose.cpp et .h.
• Les autres fenêtres non MDI doivent être appelées fsQuelqueChose (FS pour fenêtre simple) et le fichier associé FSquelqueChose.cpp et .h.
• La forme principale doit être le propriétaire du Manager d'application.
• Les composants TEdit sont nommés EDquelqueChose, les composants Label LBquelqueChose, etc.
• Il faut toujours renommer un composant pouvant être modifié dynamiquement dans le code, et ne pas garder les noms donnés par C++ Builder par défaut.
• Les noms donnés à tous les objets graphiques ainsi créés avec l'EDI doivent refléter ce qu'ils font.
III-C. Liaison interface - unités▲
• Les méthodes de l'interface ne doivent pas exécuter directement du code spécifique, mais appeler une méthode de l'unité dont c'est la spécialité, de tester le résultat et de modifier l'affichage en conséquence.
Exemple : plutôt que de faire :
Void __fastcall fmMain : :BtgoClick
(
)
{
// initialisation
For (
int
i=
0
; i<
25
; i++
)
donnees[i] =
"
"
;
//affichage
SLaffichage->
Items->
Clear
(
) ;
For (
int
i=
0
; i<
25
; i++
)
SLaffichage->
Items->
Add
(
donnees[i] );
}
Faire :
Void __fastcall fmMain : :BtgoClick
(
)
{
donnees.initialize
(
) ;
//affichage
SLaffichage->
Items->
Clear
(
) ;
For (
int
i=
0
; i<
donnees.size
(
) ; i++
)
SLaffichage->
Items->
Add
(
donnees.at
(
i));
}
ou encore :
Void __fastcall fmMain : :BtgoClick
(
)
{
donnees.initialize
(
) ;
//affichage
SLaffichage->
Clear
(
) ;
donnees.toStringList
(
SLaffichage->
Items) ;
}
IV. TESTER▲
• Tester très régulièrement et s’assurer que ce qui marchait avant et que l’on pense ne pas avoir trop de rapport marche toujours.
• Tester les unités spécifiques en premier, et chercher à les valider entièrement (méthode publique par méthode publique) avant de les tester dans l’utilisation générale de l’application.
• Pour chaque problème, tester en mettant des lignes en commentaire jusqu'à trouver à partir de laquelle on a un fonctionnement de l’unité conforme à ce qu’on attend de lui, et rajouter les lignes mises en commentaire les unes après les autres, de façon à trouver celle qui doit être changée.
V. REFACTORISATION▲
Cette phase correspond à une implémentation qui marche, mais dont le code est lourd à lire. Il faut donc réorganiser la façon dont cela a été codé afin de réduire le nombre de lignes ou pour permettre une meilleure réutilisation d’une unité.
• Faire une fonction spécifique lorsqu’on voit qu’un morceau de code est dupliqué plus de deux fois.