You are on page 1of 27

Plan Qualit v 1.

23

Page 1 sur 27

PLAN QUALITE pour les applications crites avec DELPHI


Release 1.23

1997 - Olivier Dahan Ingnieur Informaticien Intervenant officiel Borland (Delphi 16 et 32)
Email : odahan@cybercable.fr

rsentation

Le prsent document pour but de collecter une srie de conseils de dveloppement. Il sadresse donc en priorit une population professionnelle ayant dj de solides notions de programmation. Je nai pas eu ici la prtention ddicter une norme au sens acadmique du terme, ce qui serait la fois prsomptueux et hors de toute ralit. Ce document nest quune suite davis et conseils, parfois comments longuement car ce qui prime est la justification des choix, et, souvent, des digressions se mleront aux informations techniques. Une application professionnelle ne se conoit pas coup de recettes , cest avant tout un esprit, une rigueur, une attention de chaque instant, un attachement au dtail, une certaine noblesse. La mme que celle de lartisan qui corrige les moindres erreurs pourtant invisibles lil du profane. Comme pour un bel objet faonn, lutilisateur dun logiciel ne sait pas dire ce qui a t fait techniquement et qui cr son attachement ce dernier, il laime et lutilise. Cest tout. ... Mais pour en arriver un tel niveau de satisfaction il faut souvent beaucoup de travail dont les dtails chappent et chapperont toujours lil de celui qui nest pas initi. Un artisan est un magicien, il transforme linanim en objet de plaisir et de satisfaction, soyez-le aussi ... Les conseils proposs ici sont les fruits de rflexions longues, de nombreuses expriences, ou du simple bon sens. Ils contiendront parfois des interdictions voire des obligations. Pour dautres rubriques il sagira plutt de faire des choix entre diverses possibilits. Comme il faut bien se dcider jy propose alors une solution qui a lavantage, si elle est suivie, doffrir cohrence et homognit aux dveloppements. Tout ce que le lecteur trouvera ici doit tre vu sous langle dun travail en perptuelle volution. Cela implique quil a le pouvoir (le devoir ?) de proposer ses critiques, ses solutions. Toutefois, comme un tel document tire une partie de sa valeur de son unicit , il conviendra de me faire directement ces propositions afin que je puisse maintenir jour le Plan Qualit et qu une date donne il ny ait toujours quune seule version officielle en circulation. Les conseils ici prodigus le seront sous langle du dveloppement DELPHI. Lexistence de disparits entre la version 16 bits et la version 32 bits imposent aussi un nivellement sur une base commune. Ne seront donc pas abords ici les Threads, le Repository, les DataModules, lhritage de Tform et autres techniques propres lenvironnement 32 bits. Une notice complmentaire sera conu pour les dveloppements utilisant DELPHI 32 (2, 3,4) et les techniques qui lui sont propres.

I.

Ergonomie Gnrale

Il est en fait difficile de trancher sur ce qui est du pur ressort de lergonomie et de ce qui ne lest pas. Un bon logiciel nest quune suite de bonnes dcisions qui toutes influencent, directement ou non, lergonomie gnrale du produit. Toutefois nous nous limiterons dans ce chapitre ce qui concerne directement linterface.

A.

Les messages daide

DELPHI propose une gestion assez souple des messages daide notamment avec les bulles daide (HINTS). Il est trs important dutiliser ce systme qui peut souvent viter la cration dun systme daide contextuel plus lourd grer. Il convient ds lors de bien connatre le fonctionnement de ces HINTS et des astuces qui y sont relatives.

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 2 sur 27

1.

Les bulles daide

La norme est assez floue propos des bulles qui ne font pas partie du fonctionnement de base de Windows. Toutefois on peut affirmer que les textes doivent tre trs courts : une bulle daide ne doit pas tre un pav daide ! Le mot bulle , lui-mme, implique une certaine lgret, ne loubliez pas... On prfrera des bulles ne contenant quun seul mot ou expression avec le minimum darticles et de mots de liaison : QUITTER, MISE A JOUR, et non Quitter lapplication , Lancer la mise jour . Si la traduction franaise de HINT (bulle) insiste sur la lgret, le sens original de HINT insiste lui sur le caractre fugace de linformation donne et sur sa fonction premire qui est de donner une indication et non un cours complet. Pour information : HINT (1) Allusion, To drop a hint = faire une allusion ( noter drop , action rapide en gnral), (2) Conseil (piece of advise : morceau de conseil...), (3) Soupon... Une bulle, un soupon, un morceau de conseil... voici bien rsum ce que doit tre une bulle daide. Proscrivez laspect amateur et antinomique des bulles multi-lignes. Court et prcis ne signifie pas utiliser le style tlgraphique ou une sibylline notation hiroglyphique. Lergonomie est un mtier part entire, des gens y consacrent leur profession, des chercheurs leur vie. Si tout un chacun peut aujourdhui dvelopper sous Windows, cette dmocratisation saccompagne (comme toujours) dun nivellement par le bas et dun affaiblissement de la comprhension des concepts sousjacents. IBM et Microsoft ont publi leurs normes, il faut les lire et sen inspirer, ou au moins en connatre lexistence et le sens. Le choix dun texte pour une bulle est une dmarche de mme nature que celle du choix et du dessin dune icne, dune musique daccompagnement, dune squence vido. Le caractre multimdia de Windows impose des comptences artistiques tout concepteur. Ainsi, choisir un mot ou une expression qui rsumera bien une fonction est une tche parfois difficile qui rclame des qualits qui ne sont pas celles dun informaticien. Lhumilit, en partie, consiste connatre ses limites. Si vous ne trouvez pas, faites dans la simplicit et lvidence. Sil faut tre un informaticien ou un nouveau Champollion pour dcrypter vos bulles, mieux vaux ne pas en mettre du tout... Dans certains cas rares, il se peut que vous ne trouviez pas quelque chose de court et de sens. Ce nest pas trop grave, dans ce cas veillez ce que la bulle ne soit pas aussi large que lcran. Pour y remdier on peut alors admettre (et uniquement dans ce cas) de placer le texte sur deux lignes, pour ramasser lallure gnrale de la bulle. Lditeur de DELPHI ne permet pas de placer des changements de ligne dans le texte dune bulle. Ce dernier est considr comme une proprit STRING, le retour chariot met simplement fin la saisie en la validant. Cela ne doit pas vous dcourager, la fentre affichant les bulles utilise correctement les capacits de Windows et prvoit laffichage sur plusieurs lignes. Pour faire la jonction entre lditeur de proprit qui nautorise pas la saisie du caractre #13 et la classe de fentre des bulles qui, elle, le gre, vous avez deux mthodes : Saisir le texte par programmation (MonObject.Hint := 1re ligne+#13+seconde ligne), mthode qui vous poussera ne pas abuser de la chose, ou bien utiliser un diteur de proprit HINT spcialis. Il existe sur le Forum DELPHI un outil Freeware du nom de HINTEDIT qui assure cette fonction merveille. Il est important de prvoir, par un paramtre persistant de lapplication (donc stock dans un fichier INI -ou en REGISTRY- en gnral), la possibilit de dconnecter les bulles daide. Chaque objet TFORM dispose dune proprit SHOWHINT pour ce faire et tous les objets possdant une proprit HINT ont aussi une proprit PARENTSHOWHINT quon laisse TRUE (sauf cas particuliers).La visibilit globale pour la fiche est contrle par TFORM.SHOWHINT. Pour grer de faon habile cette option sans intervenir sur chaque fiche, programmez un gestionnaire de lvnement ONACTIVEFORMCHANGE de lobjet SCREEN. Systmatiquement vous placerez le SHOWHINT de la nouvelle fiche active la valeur de la fiche matre ou celle dune constante globale contenant le choix de lutilisateur propos de la visibilit des bulles.

2.

La ligne de statut (status line)

Si cette technique est plus ou moins vidente mettre en place dans des applications suivant le modle SDI ( moins quil ny ait quune seule fiche), le modle MDI se prdispose plus facilement son utilisation. Voyons tout dabord le cas le plus simple.

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 3 sur 27

a) Ligne de statut en mode MDI La ligne de statut est un espace gnralement plac en bas de la fentre mre dans lequel sont affiches des informations complmentaires sur lobjet en cours de slection (contrle ou lment de menu). En ce sens, la ligne de statut est une technique proche de la bulle daide. Plus simple techniquement que les HINTS (DELPHI vous offre une gestion des bulles daide dj programme mais cela nest pas trivial faire en partant de zro...), cette information contextuelle prcde historiquement ces dernires. Les bulles ne sont dailleurs quune amlioration de la ligne de statut visant disposer lcran linformation prs du contrle auquel elle se rattache pour renforcer lergonomie du procd. Une application suivant le modle MDI possde une fentre mre toujours visible, il est donc naturel de placer la ligne de statut en bas de celle-ci. Un TPANEL fera parfaitement laffaire (align ALBOTTOM). Il est possible de mettre en uvre ce procd dans le modle SDI mais comme il ny a pas de fentre mre assurment visible et non masque, il convient de placer la ligne de statut en bas de chaque fentre. La gestion en est plus technique comme nous allons le voir. La ligne de statut, par la place plus grande quelle offre au texte, est lendroit idal pour complter les explications des bulles daide. Une application bien conue possde ainsi 4 niveaux daide que sont les labels prcdant chaque contrle, les bulles daide, la ligne de statut et enfin laide contextuelle. DELPHI met votre disposition une gestion presque automatique de la ligne de statut, au prix dune petite ruse quil faut connatre. La proprit HINT de chaque contrle contient le texte de la bulle daide. Cest une chose. Nous avons vu que cette ligne peut tre segmente par linsertion du caractre #13, cen est une autre. Mais en ajoutant, la fin du texte de la bulle, un caractre pipe ALT-124, on peut placer, derrire celui-ci, un morceau de texte qui sera celui de la ligne de statut. Il ne doit pas contenir de retour chariot, bien que cela soit possible si le texte est affich par lintermdiaire dun TLABEL en mode WORDWRAP. Toutefois, ternel dbat, si cette ligne peut contenir plus de texte quune bulle, elle ne doit pas remplacer laide contextuelle, plus fournie. Son texte doit rester cours, mme si, ici, on peut utiliser une phrase complte. Dailleurs, il est bon de noter la granularit smantique conseille pour chaque niveau daide : Label prcdant les contrles et texte des bulles .......... mot ou expression Ligne de statut .............................................................. phrase Aide contextuelle .......................................................... page Comme DELPHI ne peut pas deviner le nom de lobjet qui contiendra la ligne de statut (alors quil fourni en interne un objet bien identifi pour afficher les bulles) ni mme le nom de la proprit de cet objet qui contiendra le texte lui-mme (CAPTION, TEXT, ...) et encore moins le procd que vous retiendrez pour laffichage (un simple conteneur de type TPANEL ou TLABEL, ou une gestion plus sophistique) il est ncessaire, pour afficher une ligne de statut de rpondre un vnement prcis : ONHINT de la variable APPLICATION. Cest au sein de ce gestionnaire que vous rcuprerez le texte afficher, fourni par DELPHI dans la proprit HINT de la variable APPLICATION, et que vous le dispatcherez o bon vous semble. La version la plus simple dun tel gestionnaire se limite une affectation du type MonPanel.Caption := Application.Hint ; . Vous comprenez maintenant pourquoi le modle MDI se prte mieux une telle gestion. Lvnement ONHINT tant unique pour toute lapplication, il est plus difficile, en SDI, de router le texte vers plusieurs lignes diffrentes selon la fiche qui est active. b) Ligne de statut en mode SDI Pour grer une ligne de statut sur plusieurs fiches (donc dans le modle SDI) il existe plusieurs mthodes, lune dentre elles a t dcrite par Borland dans le TI 2796. Elle consiste coder une rponse personnalise, dans chaque TFORM, lvnement APPLICATION.ONHINT. Chaque fiche aura ainsi son propre gestionnaire qui saura o et comment afficher le texte. Ces gestionnaires sont souvent trs simples et identiques (affectation de la variable APPLICATON.HINT au CAPTION dun TPANEL). Pour avertir DELPHI quune nouvelle fentre prend la focalisation et que cest celle-ci qui doit afficher la ligne de statut, il suffit, dans chaque fiche, de grer lvnement ONACTIVATE du TFORM qui se limitera affecter, la proprit APPLICATION.ONHINT, le nom du gestionnaire local. Ainsi, lorsquune fiche devient active, elle modifie le gestionnaire centralis afin de le faire pointer vers sa propre routine daffichage.

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 4 sur 27

Lun des nombreux avantages de la ligne de statut est que DELPHI gnre toujours lvnement APPLICATON.ONHINT, mme si les bulles sont dconnectes (TFORM.SHOWHINT :=FALSE). Lutilisateur aura ainsi le choix de voir ou non les bulles sans que la ligne de statut ne soit affecte par ce paramtre. Cela implique, en retour, que le texte de la bulle et celui de la ligne soient totalement indpendants. La ligne de statut ne peut pas faire rfrence, en le compltant, au texte de la bulle puisquil ny a aucune assurance que celle-ci soit affiche. Vous noterez, pour terminer, que le HINT dun objet peut fort bien ne contenir quun message pour la ligne de statut, sans message de bulle. Il suffit de ne mettre aucun texte devant le symbole pipe , donc de commencer la phrase par celui-ci (pratique pour les lments de menu naffichant jamais de bulle)... Comme nous avons pu le voir ici, DELPHI propose de nombreuses solutions pour aider lutilisateur, certaines se mettent en uvre automatiquement, dautres rclament un peu de code. Dans tous les cas vous devez porter une grande attention cet aspect de votre application, cest lun des points qui diffrencie une application professionnelle dun simple assemblage de boutons et de contrles.

3.

Les autres aides

Il est bien entendu possible de complter tous les systmes prcdemment tudis par des informations ponctuelles de nature diffrente et ce, selon le contexte de lapplication. Par exemple, il peut tre important pour lutilisateur, dans une application donne, davoir un indicateur des touches spciales de type Verrouillage numrique ou Majuscules . Dans dautres cas il faudra pouvoir afficher le rsultat ou la progression dactions en tche de fond, etc... Il ny a pas dautre emplacement (sauf le justifier) pour toutes ces donnes que dans lespace de la ligne de statut. La fin de celle-ci est alors segmentes en sous-panels contenant chacun un type dinformation prcis. Noubliez pas, enfin, que laide lutilisateur nest complte que si votre application intgre un fichier HLP. La conception de ce dernier dpend grandement de loutil de conception et il ne nous est pas possible ici de faire le tour de toutes les possibilits. Ce silence apparent ne doit pas vous faire penser que nous ny attachons pas une grande importance : une application Windows nest pas termine tant quelle ne dispose pas dun fichier daide contextuel intelligemment intgr et structur.

B.

Dialogues internes

Il est frquent quau sein dun projet il soit ncessaire de demander lutilisateur une chane de caractres, ventuellement initialise. En gnral le dveloppeur cr une fiche appele en mode MODAL pour assurer cette fonction. Noubliez pas que DELPHI met votre disposition des instructions rpondant dj ce besoin. Souvent ignores, elles ont pourtant lavantage dtre simples et de ne pas rclamer le moindre octet de plus dans votre excutable. Qui plus est, do la prsence de cette rubrique dans le chapitre traitant dergonomie, cela assurera une homognit salutaire votre application. Il sagit des fonctions INPUTBOX et INPUQUERY. La premire rclamant une chane, la seconde prenant en compte la possibilit dannulation (boutons OK / ANNULER). Paralllement, nous insisterons sur le fait quil faut toujours utiliser les dialogues standard de Windows partout o cela peut se faire. DELPHI propose des wrappers permettant daccder ces dialogues (OpenDialog, SaveDialog, etc).

C.

Traitement longs

il est indispensable que lutilisateur soit averti de la progression dun traitement qui risque dtre long. Le fait dinscrire un message du type Traitement en cours ne sert rien du tout. Un traitement en cours peut durer 5 secondes ou 5 heures. Dans ce dernier cas lutilisateur aura reboot sa machine bien avant, la croyant bloque ! Si votre application possde de tels traitements (dpassant une dizaine de secondes ou pouvant, en charge relle, les dpasser), crez une fiche simple possdant un message dattente ainsi quun barre de progression. Utilisez la technique de la procdure appelante pour cette fiche, technique que vous perfectionnerez pour loccasion. Nous vous conseillons dappeler la procdure douverture de cette fiche OPENWAIT(CONST MSG :STRING), MSG tant le message qui sera inscrit. Cette procdure aura pour tche de crer une instance de la fiche dattente, daffecter le message et mettre la barre de progression zro puis dappeler la fiche en mode SHOW non modal (sinon le traitement long en question serait bloqu jusquau retour de la fiche ...). La fiche dattente doit tre de type ALWAYSONTOP. Crez une procdure CLOSEWAIT dont la tche sera de dtruire la fiche dattente. Pour mettre jour la barre de progression crez enfin une procdure SENDWAIT(CONST NEWMSG :STRING ; GAUGEVALUE :INTEGER).

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 5 sur 27

Si le paramtre NEWMSG est vide, le message courant est conserv, sinon il est modifi pour prendre la valeur de NEWMSG. Le paramtre GAUGEVALUE sera une valeur entre 0 et 100 reprsentant le pourcentage davance du traitement. Cette procdure, aprs affectation des diffrents paramtres, se terminera par un appel APPLICATION.PROCESSMESSAGES afin dassurer le rafrachissement de limage. Dailleurs, au sein de votre traitement long, placez au moins un appel cette procdure afin dassurer la lecture frquente de la pile des messages de Windows. Cela est indispensable sous Windows 3.1 pour simuler le multitche coopratif (justement). Certains dveloppeurs pensent que le multitche des environnements 32 bits (W95 et NT) rend cet appel caduque. Ils se trompent. Si la commutation de tche nest plus assure par la coopration des tches entre elles, la lecture de la pile des messages Windows par lapplication reste conditionne lappel de PROCESSMESSAGES qui reprend alors tout son sens premier (traiter les messages). Certains traitement rellement longs doivent toujours pouvoir tre interrompus par lutilisateur. Il est indispensable de prvoir cette possibilit. Cela se fera en ajoutant un bouton ANNULER dans la fiche dattente. Lappui sur ce bouton positionnera une proprit de la fiche dattente, ANNULATION_DEMANDEE :=TRUE, proprit initialise FALSE par la procdure OPENWAIT. Le traitement long, en plus de faire des appels rguliers SENDWAIT, testera aprs ces derniers la valeur de la proprit ANNULATION_DEMANDEE qui sera lisible travers une fonction ISCANCELREQUESTED :BOOLEAN qui, toujours dans lesprit dune isolation totale entre les fiches sera la seule savoir lire la vritable proprit de la fiche dattente. Si aucun appel PROCESSMESSAGES nest effectu dans la boucle du traitement long, cette variable ne sera jamais positionne correctement. Charge votre application dannuler le traitement en cours proprement en rtablissement la situation prcdente ou en interdisant certaines oprations tant que le dit traitement na pas t relanc. Si vous devez lancer un traitement rellement long qui ne peut vraiment pas tre annul, en plus de la barre de progression nous vous conseillons dafficher une estimation du temps restant, la manire des copies de fichiers de Windows 95 (mais en mieux...). Ce temps sanalyse simplement en fonction du pourcentage davance, et du nombre de pas rellement raliss et de ceux restants. Laffichage devra tre effectu sous la forme Heure, Minute, Seconde.

D.

La gestion du Presse-papiers

Le presse-papiers est un outil essentiel pour lutilisateur, il est le mcanisme le plus simple qui illustre la coopration entre diverses applications et reste le symbole mme des environnements graphiques comme celui du Mac dApple ou Windows. Avant mme linvention du DDE ou de lOLE, la seule relle coopration qui faisait la diffrence entre ces environnements et les autres tait justement de pouvoir copier des informations dune fentre vers une autre. Les oprations sur le presse-papiers sont ainsi essentielles dans une application professionnelle et elles doivent faire lobjet dune attention toute particulire.

1.

Quand copier nest pas suffisant

DELPHI, pour les contrles de sa VCL, automatise la gestion du Couper/Copier/Coller. Mais le sens de ces oprations est orient contrle alors quun humain travaille plutt sur des concepts, ce que, bien entendu, le meilleur des environnements de dveloppement ne sait absolument pas grer... Prenons lexemple dune fiche individuelle client au sein dune gestion commerciale. Elle contiendra certainement ladresse du client. Techniquement celle-ci sera matrialise selon toute vraisemblance par les contrles : adresse 1 et 2, code postal et ville. Les fonctions presse-papiers automatiques de DELPHI concerneront chaque contrle mais pas la totalit du groupe de contrles formant ladresse qui nest quun concept. Si lutilisateur souhaite copier ladresse pour crire un courrier avec WORD, la gestion de base sera trs lourde (plusieurs va et vient entre WORD et lapplication pour copier/coller chacun des contrles). Pour offrir un plus grand confort, il est ncessaire de proposer au minimum une fonction copier qui copiera toute ladresse en une seule opration. Ce traitement peut tre automatique (selon le contexte de votre application) ou bien tre matrialis par un bouton ou une entre dans le menu EDITION. Techniquement, vous devrez piloter lopration de copie par code en utilisant lunit CLIPBRD. Pour grouper plusieurs informations dans un mme copier , il suffit de les mettre bout bout, spares par un caractre 1310 (retour chariot) dans un PCHAR puis de copier ce dernier dans le presse-papiers avec le format texte (voir les identifiants de type de donnes du presse-papiers). Cette technique peut largement tre exploite dans vos applications qui nen seront que plus conviviales.

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 6 sur 27

Paralllement, il est bon de constater que nous navons trait ici quun seul sens : le copiage. Pour le collage lopration est plus complexe, notamment lorsque celle-ci est ralise entre plusieurs applications diffrentes. Par exemple, pour rcuprer une suite de ligne copies depuis WORD dans la srie de contrle formant ladresse dans votre application, il faudrait dcouper le buffer du presse-papiers puis appliquer tous les contrles de saisie avant daccepter ou refuser le collage (par exemple tester la numricit de la zone qui devra remplir le contrle grant le code postal). Ces difficults, assorties de la ncessit de dtourner les messages Windows entrant de type coller pour les traiter de faon spcifique, font que les applications ne grent presque jamais ce type de collage multicontrle. Par contre, il est tout fait possible dexploiter le copier/coller multi-lment au sein dune mme application qui, elle, peut reconnatre les constituants du groupe coller. DELPHI, pour les besoins de son IDE, enregistre un format spcial dans le presse-papiers pour les objets. Cest ce qui permet de copier/coller des composants sur une fiche en mode conception. Ainsi, votre application peut dfinir des descendants de TPERSISTENT qui contiennent des informations fortement types (des proprits de lobjet) servant aux oprations de presse-papiers complexes entre les divers modules du logiciel (structures dynamiques, objets, ... ). Gnralement, les oprations de collage acceptant des formats non habituels (texte ou image) font lobjet dun menu spcifique. Ce dernier est souvent appel coller / spcial . La possibilit de pouvoir manipuler des objets persistants dans le presse-papiers est une formidable ouverture qui peut simplifier le codage de vos applications tout en amliorant lergonomie (par exemple copier une fiche client entire qui peut tre rcupr, mme partiellement, par tous les modules de lapplication). Lutilisateur reste matre des instants et des lieux et le code, objet, peut tre centralis.

2.

La gestion centralise du presse-papiers

La gestion de des fonctions de base de Windows est assure, dans DELPHI, par chaque contrle. Il sagit des fonctions Couper, Copier et Coller. Toutefois, il est courant davoir lenvie de proposer des boutons pour les commander, voire un menu Edition afin de se conformer lergonomie standard de Windows. Si tout bon dveloppeur sait que les boutons doivent tre de type TSPEEDBUTTON car ils ne prennent pas le focus, il est frquent de voir des morceaux de code qui sont soit indigents, et ne fonctionnant pas dans tous les cas, soit trop complexes. On peut effectivement tre tent de tester le type de contrle actif (ACTIVECONTROL) pour assurer un traitement personnalis. Le plus courant est le test IF ACTIVECONTROL IS TCUSTOMEDIT THEN TCUSTOMEDIT(ACTIVECONTOL).COPYTOCLIPBOARD rpt pour les trois commandes lidentique en dehors de lordre final. Cette solution, bien que valide, ne gre quune toute petite partie des possibilits des contrles de DELPHI en ne sintressant quaux type drivs de TCUSTOMEDIT (TEDIT et TMEMO). Que se passe-t-il si le contrle est un TDBIMAGE ? Rien ! Et cest dommage... La direction gnralement prise par ceux qui se sont aperus de la faiblesse de la technique ci-dessus voque est celle dune sophistication accrue de la squence de code grant chacune des fonctions. Cette voie nest pas la bonne. En fait, la gestion du presse-papiers nous donne ici loccasion de vous conseiller de vous intresser lOS sous lequel tournent vos applications : Windows. En ignorer les concepts fondamentaux, en nier les API est un comportement damateur. Sans connatre les moindre mandres de Windows, faites leffort de mieux lapprhender car le code que vous crirez sera la fois plus court, plus rapide, moins bugg, plus lgant et moins amateur ... Ainsi, en sappuyant sur une connaissance somme toute fort modeste de Windows, comment grer le problme du presse-papiers ici pos ? En utilisant les messages appropris, simplement : SendMessage(ActiveControl.Handle, WM_CUT, 0, 0); Cest tout ! La constante du message est la seule chose variable selon la fonction (WM_PASTE et WM_COPY pour les 2 autres possibilits la place de WM_CUT). Si votre application est de type MDI, vous utiliserez ACTIVEMDICHILD.ACTIVECONTROL.HANDLE et les trois boutons seront placs dans une speedbar en haut de la fiche mre, en copie des commandes du menu EDITION. Vous complterez linstruction par un test contrlant si la forme MDI active est diffrente de NIL afin dviter tout problme (IF ACTIVEMDICHILD<>NIL THEN ...). En fait ce test est redondant si vous avez dcid dtre encore plus soucieux de lergonomie de votre application. Dans ce cas, vous dsactiverez les boutons concerns sur lvnement SCREEN.ONACTIVECHANGE o vous testerez le MIDCHILDCOUNT pour savoir sil est suprieur zro. Dans la ngative les entres du menu et les boutons grant les fonctions du presse-papiers sont dconnectes en modifiant leur proprit ENABLED FALSE.

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 7 sur 27

La technique ici utilise, celle du simple message Windows, consiste donner lordre au contrle actif de grer la fonction dsire. Sil nen a pas la capacit, le message sera ignor. Mais dans le cas contraire, il ny aucun besoin de contrler le type de lobjet concern, il saura comment traiter le message. Rptons une fois encore le conseil de cette rubrique, il est trop important : apprenez connatre la philosophie de Windows afin dcrire des applications qui la respecte. Votre code sera plus performant et plus compact.

E.

Ergonomie des fiches

Il y a beaucoup de choses dire sur lergonomie des fiches, et pour cause, ce sont, in fine, les parties les plus prsentes de linterface dune application. Nous aborderons ici les diffrents thmes qui semblent, le plus souvent, tre oublis, mal compris ou dont les mises en uvre sont trop disparates. Le reste sera laiss lapprciation de chacun...

1.

Le focus dentre

Il nest pas concevable qu son premier affichage une fiche ne positionne pas correctement le focus sur le premier champ ayant le plus dintrt. DELPHI met la disposition du dveloppeur, dans lobjet TFORM, la proprit ACTIVECONTROL. Cette proprit permet, durant lexcution, de connatre le contrle ayant le focus et, au premier affichage dindiquer quel contrle recevra le focus. Cest ici dans ce dernier sens quon lexploitera systmatiquement. Noubliez pas, non plus, de repositionner le focus dans certains cas. Par exemple, sur une fiche de type Donnes, lorsque lutilisateur dclenche (par quelque moyen) la cration dune nouvelle fiche, le focus doit tre transfr au premier contrle de celle-ci automatiquement...

2.

La dynamique du focus

Il nest pas normal que le curseur puisse se balader un peu partout et, le pire, dans nimporte quel ordre. Il est essentiel de veiller lordre des tabulations, ce qui peut se faire simplement depuis lEDI en mode conception. De mme, si certains boutons nont pas un intrt vital dans loptique dune saisie manuelle, il nest pas ncessaire de les inclure dans la chane de tabulation (proprit TABSTOP) ce qui est le cas par dfaut. Et mme dans le cas o leur activation depuis le clavier a un sens, il sera prfrable de programmer un acclrateur plutt que de voir le curseur, lors dune saisie, tre oblig de faire le tour de tous les boutons pour revenir au premier contrle (un acclrateur de bouton se programme en ajoutant le symbole & devant une lettre de son texte). Bien entendu, dans certains cas, il sera prfrable de laisser les boutons dans le circuit de tabulation. Rptons-le encore une fois : ce document sadresse des professionnels qui doivent toujours utiliser leur bon sens, seule instance capable, in fine et pour une application donne, de trancher...

3.

Les grilles et le focus

Si une grille (DBGRID, STRINGGRID ou autre) est place sur une fiche et si elle ne sert pas directement la saisie, il est indispensable de positionner sa proprit DGTABS FALSE. Ainsi, la touche de tabulation permet de sortir de la grille au lieu que le curseur reste coinc lintrieur de celle-ci passant de champ en champ.

4.

Elaborer un circuit de saisie

Toute fiche se doit de proposer un circuit de tabulation rapide suivant la logique et lordre de saisie des informations. Les contrles nentrant pas directement dans le processus de saisie ne doit appartenir au circuit dfini. a) Simulation de la touche Tabulation Il est souvent ncessaire, lorsque les utilisateurs migrent depuis des environnements console vers Windows, de proposer une quivalence entre la touche ENTREE et la touche TABULATION afin de mimer la logique du mode console. De plus, les claviers ont t conu pour que la touche ENTREE soit naturellement port des doigts, sa grande taille en atteste. Ce nest pas le cas de la touche de tabulation. Pour ces diverses raisons (et dautres) on peut admettre, dans la majorit des applications, de proposer une quivalence ENTREE = TABULATION. Noubliez toutefois pas que cela ne respecte pas du tout lergonomie de Windows et que, dans certains cas, cette quivalence risque de poser des problmes cornliens. La mise en uvre de ce procd se fait enbasculant la proprit KEYPREVIEW de lobjet TFORM TRUE et en programmant un gestionnaire pour lvnement ONKEYPRESS :

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 8 sur 27

if Key = #13 then begin Key := #0; PostMessage(Handle, WM_NEXTDLGCTL, 0, 0); end; Vous noterez, ici encore, que nous nutilisons pas dinstruction VCL pour accomplir cette tche, mais, la place, une API Windows directe. Lorsque cela est possible, rappelez-vous que poster un message est toujours une solution de meilleure qualit que tout autre bricolage plus ou moins savant avec la VCL. Ici nous postons le message WM_NEXTDLGCTL (Next Dialog Control = Prochain contrle du dialogue). b) Mise jour automatique des donnes Si une fiche utilise des donnes passant par le BDE, il est important de prvoir un mcanisme clair et vident pour leur validation, notamment lors de la fermeture de la fiche. Le problme stend souvent aux changements de page lorsque la fiche propose un talement des donnes sur plusieurs pages dun NOTEBOOK ( onglet ou non). Selon si la validation des donnes entrane ou non des consquences dimportance, vous opterez pour lune ou lautre des mthodes suivantes : (1) Validation automatique Normalement, la fermeture de tous les DATASET est regroupe dans lvnement ONDESTROY des objets TFORM. Juste avant la fermeture de chacun de ces DATASET vous contrlerez leur proprit STATE (IF STATE IN [DSEDIT,DSINSERT]) et effectuerez un POST (ou un CANCEL suivant la stratgie adopte). (2) Validation semi-automatique Lorsque la validation de certaines donnes est lourde de consquences il est normal de sassurer que lutilisateur souhaite rellement abandonner la fiche (ou lapplication) sans validation explicite de sa part. Il existe un vnement de TFORM pour grer de telles situations : ONCLOSEQUERY dont le but est de vous donner la main avant que la demande de fermeture de lutilisateur naboutisse rellement. Dans le gestionnaire de cet vnement vous utiliserez un dialogue (par exemple la fonction MESSAGEBOX de lobjet APPLICATION) pour demander une confirmation dabandon. Dans laffirme vous navez rien faire. Dans la ngative vous avez loption soit de faire un POST sur chaque table en cours de modification, soit dinterdire la sortie de lapplication (ou de la FORM). Les deux mthodes se valent et seul le contexte vous permettra de trancher (sans oublier votre bon sens). La mthode totalement silencieuse consiste refuser la sortie tant que des tables sont en modifications et ce, sans message particulier. Cela ne peut sappliquer qu des fiches sur lesquelles la visualisation de ltat des tables et vident.

F.

Gris ou invisible ?

Lune des questions qui rongent le dveloppeur est celle du choix Gris ou Invisible pour les boutons, items de menus et autres lments dinterface. Rappelons quelques rgles de bon sens en accord avec lesprit de Windows. Un lment dinterface est gris (ENABLED=FALSE) lorsquil est indisponible mais reste tout de mme visible. Lorsquil est invisible, lutilisateur ne peut pas se poser la question de savoir sil est disponible ou non. Quil est bon denfoncer les portes ouvertes... On en conclue que : Linvisibilit (VISIBLE=FALSE) supprime une fonction que lutilisateur na pas mme connatre. Linvisibilit ne donne aucune information, au contraire elle soustrait du champ visuel une fonction inutile. Lindisponibilit (ENABLED=FALSE) dconnecte une fonction de faon temporaire car le contexte limpose. Cette indisponibilit visible renseigne lutilisateur sur ltat de lapplication. De l, on peut dire que : Si une fonction nest pas disponible pour des raisons externes (lies lutilisateur, ltat dun priphrique, etc), les lments dinterface la reprsentant doivent tre griss (ENABLED=FALSE).

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 9 sur 27

Cest le cas dun bouton Calculer si aucune formule na t saisie, dune entre de menu Coller si le presse papier est vide, dun bouton de fermeture dun cran de dtail si celui-ci na pas t ouvert, etc. Si une fonction nest pas disponible pour des raisons internes (fonction non autorise pour le profil de lutilisateur, fonction dconnectes car nayant pas de sens dans le contexte, etc), les lments dinterface la reprsentant doivent tre invisibles (VISIBLE=FALSE). Cest le cas dun bouton Cration sur une fiche permettant la cration mais utilise dans un contexte o cette cration nest pas autorise, dun item de menu non accessible lutilisateur car celui-ci na pas les droits daccs ncessaires, etc...

II.

La gestion des donnes

Nous pourrions utiliser ici la mme introduction que celle du chapitre sur lergonomie. En effet, il est trs difficile de sparer le traitement des donnes, leur stockage, leur utilisation du reste dune application. Rappelons la formule de Wirth : Algorithme + Structure de donnes = Programme. Toutefois nous nous limiterons dans le prsent chapitre tout ce qui concerne les donnes stockes sur support permanent, quil sagisse de fichiers texte ou de tables dune base de donnes SQL.

A.

Amliorer les performances du BDE

Afin que vos applications fonctionnent au plus vite il est ncessaire de bien configurer le BDE (si vous utilisez des tables, bien entendu). Vous noterez que certains des conseils ci-dessous sont gnriques alors que dautres peuvent varis selon la base cible choisie. Le plus important est ici de porter lattention sur certains paramtres plutt que doffrir un plan de rglage universel. Voici quelques conseils importants : 1. Maintenez toujours un nombre dindex secondaires trs bas et rappelez-vous quil est souvent plus rapide de crer un index lexcution le temps de son utilisation puis de le dtruire plutt que de surcharger en permanence lapplication avec des index surnumraires. 2. Si possible, augmentez la taille du buffer du BDE ainsi que le nombre de HANDLES qui lui sont attribus (programme de configuration du BDE). Noubliez, surtout sous Windows 3.1 naugmenter aussi le nombre de HANDLES de votre applications (API Windows SETHANDLECOUNT). 3. Quand cela est possible, ouvrez les tables en mode exclusif (non partag). 4. Regroupez, si possible, le maximum doprations, notamment par lutilisation de la fonction BDE DBIBATCHMOVE (un composant BATCHMOVE existe dans la palette de DELPHI). Si vous traitez directement les donnes, pensez utilisez les API du BDE telles que DBIWRITEBLOCK et DBIREADBLOCK et essayez de travailler sur des buffers de taille multiple du buffer du BDE (cest dire 2 ou 4ko en gnral). 5. Si vous tes amen ouvrir et fermer de faon rptitive une ou plusieurs tables, songez utiliser lAPI du BDE DBIACQPERSISTTABLELOCK en lappliquant, une premire fois, sur un fichier non existant. Cela forcera le BDE crer le fichier LCK qui ne sera pas cr puis dtruit chaque fermeture de table. Cela ne sapplique bien entendu quaux donnes de type PARADOX. Noubliez pas dappeler en fin de traitement lordre de relchement du fichier LCK par lAPI BDE DBIRELPERSISTTABLELOCK.

B.

Maintenance des tables

Le menu Administration (voir la rubrique concernant cet aspect) de votre application devra contenir une option de rgnration des index et de compactage des donnes si elle travaille sur des tables dBase ou Paradox. Pour Rafrachir les index dune table, placez les units DBITYPES, DBIPROCS et DBIERRS dans la clause USES du module puis appelez lAPI du BDE DBIRegenIndexes(Table1.Handle); La table doit tre ouverte en mode exclusif et les index doivent effectivement exister. Pour compacter les donnes, utilisez lappel suivant (dans les mmes conditions) : Check(DbiPackTable(Table1.DbHandle, Table1.Handle, Nil, szPARADOX, TRUE));

C.

Connatre le nom rseau de lutilisateur

Plusieurs mthodes existent, selon quon souhaite obtenir ce nom depuis lOS ou le BDE. Laccs lOS est trs spcifique et ncessite des squences de code ventuellement diffrentes suivant la version de Windows et, ventuellement, selon le driver rseau. Pour utiliser la fonction interne du BDE, et aprs avoir plac DBIPROCS, DBIERRS, DBITYPES dans la clause USES de votre module : Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 10 sur 27

function ID: String ; var rslt: DBIResult ; szErrMsg: DBIMSG ; pszUserName: PChar ; begin try Result := '' ; pszUserName := nil ; GetMem(pszUserName, SizeOf(Char) * DBIMAXXBUSERNAMELEN) ; rslt := DbiGetNetUserName(pszUserName); if rslt = DBIERR_NONE then Result := StrPas(pszUserName) else begin DbiGetErrorString(rslt, szErrMsg); raise Exception.Create(StrPas(szErrMsg)); end ; FreeMem(pszUserName, SizeOf(Char) * DBIMAXXBUSERNAMELEN) ; pszUserName := nil ; except on E: EOutOfMemory do ShowMessage('ID failed. ' + E.Message); on E: Exception do ShowMessage(E.Message); end ; if pszUserName <> nil then FreeMem(pszUserName, SizeOf(Char) * DBIMAXXBUSERNAMELEN) ; end ;

D.

La gestion des tables

Toute application grant des donnes via le BDE se doit davoir un objet TDATABASE pour chaque base de donnes ouverte. Le TDATABASE doit tre reli lALIAS BDE et propose lapplication un ALIAS local auquel seront connects tous les TDATASET de lapplication. Le TDATABASE est plac sur la fiche mre (modle MDI) ou sur la fiche principale (modle SDI). Cest dans le gestionnaire dvnement ONCREATE de cette fiche que la connexion est gnralement ouverte. En tout cas, il ne faut jamais laisser la connexion ouverte depuis le mode design de lIDE. Paralllement, toute fiche manipulant des donnes doit effectuer les ouvertures soit au moment du besoin (mais attention au temps de connexion), soit en rpondant lvnement ONCREATE de lobjet fiche TFORM. La fermeture doit tre effectue en respectant lordre des dpendances (gnralement linverse des ouvertures pour viter des resynchronisations inutiles) en rpondant lvnement ONDESTROY de lobjet fiche. En aucun cas les tables ne doivent tre ouvertes en mode design et laisses dans cet tat.

E.

Grer simplement des sous-requtes SQL

Il est parfois ncessaire dextraire ou de traiter des donnes partir du rsultat dune autre requte. Si vous utilisez des SGBD-R puissants (voire mme Local Interbase), la syntaxe de ces moteurs supporte les sousrequtes. Par contre, le BDE ne supporte pas ces dernires sur les donnes locales. La mthode la plus efficace et la plus simple consiste en lappel dune procdure de lAPI du BDE qui rend persistante une requte et ce, sous un nom de fichier choisi par vous. Lexemple suivant vous clairera : with GeneralQuery do begin SQL.Clear; SQL.Add(.... inner SQL); SQL.Open; DbiMakePermanent(handle, 'temp.db',true); SQL.Clear; SQL.Add(SELECT ... From 'temp.db'....) SQL.Open; Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 11 sur 27

end; Le seul problme grer est celui de la collision des noms si votre application fonctionne en mode rseau. Il vous faudra aussi dtruire le fichier temporaire une fois le traitement termin. Pour cette tche utilisez un TQUERY avec un ordre DELETE TABLE, le BDE se dbrouillant pour faire le mnage notamment lorsque les donnes sont de type PARADOX (o le fichier principale est souvent accompagn de trs nombreux fichiers auxiliaires - index, checks... ). Cette solution a aussi lavantage dtre portable sans modification.

III.

Mise en uvre

La mise en uvre (traduction de IMPLEMENTATION) cest le passage lacte , la transposition dans le monde de laction dune laboration de la pense. Pour tre fidle cette pense, son esprit, la mise en uvre doit elle-mme tre intgre un processus de dveloppement de pense plus vaste. La cohrence est ce prix. Trop souvent on simagine quil y a dun ct des penseurs (en informatique on dirait des analystes) et de lautres des ouvriers spcialiss (des programmeurs). Cest oublier que mettre en uvre cest raliser et que Ralisateur est mtier noble part entire qui ne peut exister sans une philosophie, sans une mthodologie propre. Dailleurs, ce nest pas pour rien si, dans le milieu du cinma, la promotion est faite presque exclusivement avec le nom du Ralisateur, celui de lauteur tant en tout petit quelque part en bas de laffiche. Il ny a pas dOS dans le cinma, ou bien pour les petits bouleaux annexes (aller chercher les sandwiches ou perchman) tous les mtiers sont uniques et rclament un haut niveau de savoirfaire : du maquilleur aux effets spciaux, il ny a pas douvriers spcialiss mais des spcialistes (nuance...). Linformatique, dans sa mise en uvre, est bien plus proche des mtiers de lesprit que de lindustrie. Dailleurs, les logiciels sont protgs en France par les mmes lois que les oeuvres des auteurs et compositeurs et non pas celles des concepteurs de moteurs ou dimmeubles. Lerreur de beaucoup de socits est de vouloir industrialiser linformatique en la traitant comme on traite la construction dun stade ou la fabrication en srie de savonnettes parfumes. Si on veut industrialiser le logiciel il faut le faire dans le respect de sa spcificit qui est celle dune uvre de lesprit et sinspirer des mthodes industrielles appliques la production musicale ou cinmatographique. Rsoudre une analyse informatique au plan dun architecte, rsoudre la programmation au mtier de maon, et aussi nobles que soient ces mtiers qui mritent respect, est un fantasme dargentier, de spculateur et de boursicoteur nayant rien compris lessence mme de linformatique. Il est donc essentiel de comprendre quil ne peut y avoir de recettes ni de pense unique lorsquon aborde la mise en uvre du code dune application. Cest un acte tout aussi pens, tout aussi sophistiqu que celui de la conception. Il se place sur un autre registre, cest tout. Pour terminer avec les mtaphores cinmatographiques, disons que conception et ralisation sont deux camras qui prennent la mme scne (lapplication) sous deux angles de vues diffrents avec des objectifs diffrents. Cette longue introduction na pas forcment grand rapport avec les rubriques du prsent chapitre qui sont, par force ici, trs orientes vers les aspects bas niveau. Mais justement, elle tait ncessaire pour bien replacer le code qui suivra dans son vrai contexte qui nest pas technique mais philisophique.

A.

La lisibilit du code

Le fait de pouvoir facilement lire (et comprendre !) le code source quon a crit il y a longtemps ou crit par dautres est essentiel. Il est tellement important que nous avons mme dj vu des appels doffres pour des dveloppements en C accompagns de restrictions dcriture qui transformaient presque le C en Pascal ! Aujourdhui, Object Pascal comporte des astuces de notation et des ajouts importants qui lloignent de sa puret originelle. Certain mots cls sont mme ambigus, ce qui est en contradiction avec lesprit mme du Pascal (DEFAULT, par exemple, dfini soit la valeur par dfaut dune PROPERY, soit une PROPERTY de type ARRAY par dfaut pour lobjet, tout dpend du point virgule qui le prcde ou non...). De fait, il convient dadopter une conduite claire face une syntaxe qui devient permissive et (trop ?) subtile. Le premier conseil sera ici ne pas tomber dans le pige que les psychologues nomment la pense magique . Pour viter un dbat psychanalytique qui naurait pas sa place ici donnons immdiatement un exemple en rapport avec le sujet : Le C (par exemple et sans lutte de classe - jeu de mot trs subtil vous en conviendrez) est souvent utilis par des gens victimes du syndrome de la pense magique qui consiste croire que puisque le code quon crit est hyper compact et ultra sibyllin, le programme qui sera gnr par le compilateur et lditeur de lien sera, par force, tout aussi efficace et compact. Grave erreur... Lefficacit en programmation na rien voir avec laspect de ce quon tape mais avec linfluence des mots quon utilise et de lordre de ceux-ci. Ces points peuvent mme varier dune version lautre dun mme compilateur et sont loin dtre toujours comments. Ainsi, remplacer le trs clair BEGIN END par { } en C, ninfluence en rien le code gnr. Prenons linstruction CASE comme exemple. Jusquau BP7 lordre le meilleur des constantes de cas pour un code plus efficace devait tre celui de lordre dcroissant de la frquence dutilisation. Le cas le plus Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 12 sur 27

frquent tant en premier, le moins frquent en dernier. Cela tait li au code machine gnr par le PASCAL (une suite de comparaisons et de JUMP de cas en cas, du premier au dernier). Le PASCAL de DELPHI gnre un code trs diffrent, et, ici, le moyen doptimiser lefficacit est de placer les constantes de cas dans lordre numrique croissant (qui est celui de lordre de la dclaration dans le type si le slecteur de CASE est de type numr). Donc, inutile dcrire du code sotrique et difficilement lisible uniquement dans le vain espoir que le code gnr sera meilleur. Il ne faut pas confondre exercice de style et programmation efficace. Toute subtilit dcriture devra se justifier par une argumentation technique sans faille (voir le cas du WITH tudi plus haut). En dehors de ces cas parfaitement identifis, aucune astuce ne sera acceptable dans un logiciel professionnel qui doit tre maintenu, donc relu et compris. Dans le mme sens, on pourra tendre encore plus le champ du premier conseil : entre efficacit de code et lisibilit, et sauf cas critique ou la vitesse de traitement est rellement cruciale, on choisira toujours la lisibilit du code. De cet conseil tendu on pourra par exemple affirmer que : Bien que jug avec mpris par les Pascaliens , lordre GOTO (et LABEL) peut et doit tre utilis en place et lieu de structure IF THEN ELSE imbriques si le niveau dimbrication rend la comprhension de lalgorithme difficile. Bien que nous ayons dmontr la puissance de linstruction WITH, il sera parfois plus clair de rpter un nom de variable si les sous-champs de celle-ci ont trop dhomonymes avec les variables de la porte et / ou que ces dernires doivent tre exploites lintrieur du WITH. Concernant les objets, il est prfrable dcrire : MonObjet.Var1 := Var1 que WITH MonObjet do Var1 :=Self.Var1 . Bien entendu il faut viter, tant que faire se peut, de dclarer des variables portant des noms entranant ce type de problme. Par exemple, on tentera de ne jamais utiliser de variables ayant le mme nom que certaines proprits dobjet. Une variable FONT entrera immdiatement en conflit au sein dun WITH portant sur un objet visible de la VCL (possdant une proprit FONT en gnral). On choisira quelque chose comme FONTLocale ou TmpFONT, ou tout autre prfixe ou suffixe permettant de crer une diffrence.

B.

Le choix du modle, la stratgie mono-instance.

Windows offre deux stratgies : le modle MDI1 et le modle SDI2. La norme dicte par Microsoft est trs claire quant au choix faire. Si votre application manipule des fentres ayant une structure diffrente (donnes de structures diffrentes), le modle SDI simpose. Si votre application utilise plusieurs instances du mme type de fentre (mme cadre avec des donnes diffrentes mais de mme structure) alors il faut choisir le modle MDI. Pour rappel voici quelques exemples : Le gestionnaire de fichier de Windows 3.1 est de type MDI, on peut ouvrir plusieurs vues sur diffrents lecteurs mais la structure de chaque fentre est rigoureusement identique. LEDI de DELPHI est un exemple du modle SDI : une fentre mre (le bandeau suprieur avec la palette) est accompagne de plusieurs fentres filles de nature trs diffrente (Inspecteur dobjets, diteur de source, ...). Dans le modle MDI, les fiches filles sont poses sur lespace de la fentre mre qui simule ainsi un bureau local . Dans le modle SDI, les fentres filles sont poses sur le bureau de Windows. En dehors des diffrences cosmtiques entre ces deux modles il est important de noter que le choix nest pas innocent. En effet, lorsquon utilise le modle MDI, seule la fentre mre peut crer des filles. Ainsi, si une fille doit dboucher sur laffichage dune autre fille, elle sera oblige dappeler une commande de la fentre mre pour le faire, la nouvelle fiche tant alors une sur. Le modle SDI autorise lui la filiation multiple et toute fiche peut tre la mre (propritaire) de toute autre fiche. Cette simple nuance entre les deux modles impose le choix du SDI lorsque des fentres filles doivent tre relies entre elles par un lien de subordination fonctionnelle (de type synchronisation, par exemple). La synchronisation dune fentre liste et dune fentre dtail est trs dlicat grer avec le modle MDI absolument pas tudi pour ce type de dveloppement. Malgr tout, et bien que lindustrie informatique ait pay fort cher la pression des utilisateurs layant oblig adopter le standard Windows, il convient de constater que la trs grande majorit de ces mmes utilisateurs na pas investi un temps suffisant la comprhension de Windows, que cela soit volontaire ou par contrainte du milieu. De fait, bien peu de ces gens savent utiliser la combinaison ALT-TAB pour passer dune application lautre, par exemple. Pire, nous avons tous en mmoire des exemples dapplications lances 10, 20 fois, voire plus, sur le mme poste. Un simple clic sur le Gestionnaire de Programme de Windows 3.1 ou sur une autre application fait disparatre celle qui avait la focalisation. Lutilisateur de Windows rflchi comme un nouveau-n (ce qui se comprend puisquil aborde une nouvelle ralit): tout objet
1 2

MDI : Multiple Document Interface SDI : Single Document Interface Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 13 sur 27

quittant son champ de vision nexiste plus dans la ralit. Pour cette raison, nombreux sont les dveloppeurs prudents qui prfrent adopter le modle MDI en format maximis. Bien que gnralement en totale contradiction avec la norme et avec les besoins techniques de lapplication, ce choix se justifie ici par la simplification de linterface : un seul espace, celui de le fentre mre de lapplication, contient toutes les fentres filles. La mre occupant tout lespace cran, les chances de cliquer sur une autre application deviennent proches de zro. En tout tat de cause, MDI ou SDI, une application doit absolument comporter un mcanisme interdisant plusieurs instances (sauf si cette possibilit est justifie par un besoin fonctionnel qui a t clairement dcid avec le client). Noubliez pas quun contrle mono-instance doit pouvoir aujourdhui fonctionner aussi bien sous Windows 3.1 que sous Windows 95 ou NT. De ce fait, mme en DELPHI 1 il ne faut plus utiliser le pointeur PrevInstance disponible en 16 bits qui renvoie toujours NIL sous Windows 32 bits (chaque application ayant son propre environnement et non plus un environnement commun permettant de voir les autres instances). Il existe toutefois une technique portable fonctionnant pour toutes les combinaisons (compilateurs 16/32 et environnements 16/32). Elle consiste a chercher la fentre principale de lapplication (FINDWINDOW) et annuler lexcution en cours aprs avoir redonn lavant-plan la premire si elle existe dj. Attention, lactivation par un simple SHOW nest pas suffisante, il faut exploiter le mode RESTORE pour tre certain que linstance appele passe rellement en avant-plan. Pour conclure le conseil de cette rubrique sera le suivant : Si votre application est utilise par une population assez grande et mal forme, prfrez le modle MDI, si votre application contient beaucoup de liens de subordination fonctionnelle entre plusieurs fentres, prfrer le modle SDI. Bien entendu de trs nombreuses applications mlanges ces deux impratifs. A vous de faire un choix intelligent...

C.

Traitements gnriques et variables globales

Les diverses fiches qui constituent une application ont souvent besoin de partager du code, des types, des constantes ou des variables globales. On constate que les dveloppeurs placent souvent ces globales au sein mme des objets TFORM, ou, au mieux, dans la fiche principale, parfois dans le corps de plusieurs fiches. Le code est ainsi maill de rfrences croises ce qui comporte des risques certains notamment pour la maintenance. Sil est possible de faire rfrence une proprit ou un champ dun objet fiche depuis un autre objet, cette technique doit tre proscrite sauf lorsquelle repose sur un fondement mthodologique, comme la dlgation par exemple. Il y a de nombreuses bonnes raison cela, et sil nest pas question ici dentrer dans la thorie, on retiendra de la programmation Objet le principe dEncapsulation qui impose quun objet ne doit pas avoir connatre la structure dun autre objet en dehors des proprits et mthodes publiques, sauf cas exceptionnels bien cerns. Certaines structures de donnes sont parfois volumineuses et, sous Windows, la taille du segment de donnes tant trs petite, une bonne habitude consiste dynamiser ces variables. Comme une application DELPHI bien crite ne comporte gnralement que des fentres dynamiques, il semble logique de placer ces variables au sein des objets TFORM. Cette vision simpliste a les travers que nous avons noncs plus haut. Les variables globales de grandes taille doivent tre gres de faon dynamique, mais selon un processus propre et de faon isole. Elles ne doivent en aucun cas dpendre de lexistence dune fiche ou dune autre, ce qui, nonc ainsi, dmontre bien quil ne sagit alors plus de Globales mais de Locales partages... Toute application qui doit grer des objets (au sens le plus large) partags, se doit de possder dune unit de code (UNIT) ddie cette mission. Nous vous conseillons de crer une unit portant le nom COMMON. Les types, les variables, les constantes, les objets, les procdures et fonctions devant tre partags se trouveront dclars dans la partie INTERFACE de cette unit. La partie IMPLEMENTATION ne contenant que le code des ventuels procdures, fonctions et objets, ce qui implique que, dans certains projets, cette section pourra tre totalement vide. Toute fiche devant accder aux donnes partages fera rfrence lunit commune dans la clause USES de sa partie IMPLEMENTATION. Toutefois, ce type de dclaration se justifie par le seul fait qu cet endroit DELPHI ne gre par les rfrences croises. Certaines Globales peuvent toutefois tre utilises au sein du code de certaines fiches (des TYPES par exemple). Ds lors, et seulement pour lunit COMMON qui ne doit poser, par sa structure, aucun problme de rfrence croise, il est possible den faire la dclaration dans la clause USES de la partie INTERFACE de lunit en ayant besoin.

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 14 sur 27

1.

Linitialisation des Globales

En dehors des constantes types, le seul moyen dtre sr du contenu dune variable, par dfaut, est de linitialiser par code. O et quand initialiser les Globales de lunit COMMON ? Certains dveloppeurs place ce code dans le gestionnaire de lvnement ONCREATE de la fiche principale. Que dire de cette pratique sinon quencore une fois elle consiste localiser des Globales, ce qui est proscrire. La structure des units en Object Pascal offre une solution bien plus lgante : la section INITIALIZATION. Ce mot cl remplace le mot BEGIN de lunit elle-mme. Elle se termine par le END finale de lunit. Le code qui sy trouve est excut au chargement de lexcutable, ce qui en assure le traitement prcoce avant mme quune seule fiche (normalement) nexiste. Le code dinitialisation sera ainsi plac dans cette section qui lui est destine.

2.

Le traitement des structures dynamiques

Lorsque que des structures globales sont consommatrices de mmoire dans le segment de donnes (cest dire, en principe, ds quune Globale dpasse quelques octets...) il convient de les rendre dynamiques. Le code qui les crera en mmoire trouve naturellement sa place dans la partie INITIALIZATION dcrite plus haut. Cette technique est rendue obligatoire pour les Globales, mme de faible volume, fonde sur le modle TOBJECT puisque celui-ci est dynamique par essence. Le code source de la VCL de DELPHI dmontre parfaitement ce mcanisme lors de la cration dobjets systmatiquement prsents comme APPLICATION, SCREEN, PRINTER ou CLIPBOARD. Ainsi, linitialisation -1 dune variable LONGINT ou la cration dun objet de type TLIST global seront des actions codes dans la partie INITIALIZATION. Toutefois, un problme se pose, celui de la destruction des donnes dynamiques. DELPHI 2 offre une solution rationnelle par lajout du mot cl FINALIZATION ayant la fonction inverse de INITIALIZATION. Ce code est excut quand lexcutable se termine. Les parties dinitialisation et de terminaison de toutes les units en possdant sont excuts dans lordre inverse ce qui assure une gestion rationnelle de ces codes particuliers. Ce que fait le mot cl FINALIZATION de DELPHI doit tre simul par programmation en DELPHI 1 qui offre la procdure ADDEXITPROC laquelle on passe en paramtre le nom de la procdure assurant la fonction de terminaison. Cette dernire centralisera le code de dallocation des blocs mmoires rservs lors de la phase dinitialisation.

D.

Astuce de linstruction WITH

Linstruction WITH permet au compilateur de gnrer un code plus efficace, il est donc conseill de ce servir de cette instruction lorsque plusieurs affectations qui se suivent concernent le mme objet. Lune des particularits de WITH, dans le code machine gnr sa place, est quun pointeur vers lobjet dfrenc est allou durant sa porte. Ainsi, WITH autorise la syntaxe suivante, un peu trange lorsquon la voit la premire fois : WITH TMYFORM.CREATE(SELF) DO TRY SHOWMODAL ; FINALLY RELEASE ; END ; Linstruction SHOWMODAL ci-dessus porte sur la variable de type TMYFORM cre dans linstruction WITH. Mais il ny a pas de variable ... On utilise ici la zone de stockage pointeur temporaire alloue par WITH. Une telle construction doit obligatoirement tre utilise conjointement un bloc de protection de ressource TRY...FINALLY. Entre ces deux instructions on a tout loisir de placer le code quon dsire. Pour lappel de fiches, lexcution dune requte SQL ou tout autre processus ncessitant la cration temporaire dune variable objet il est toujours prfrable dutiliser cette astuce de linstruction WITH qui vite la dclaration dune variable et rend le code plus efficace. Voici un autre exemple dmontrant une requte nutilisant aucune variable TQUERY: WITH TQUERY.CREATE(SELF) DO TRY DATABASENAME :=DBDEMOS ; SQL.ADD(SELECT MAX (TOTALAMOUTPAID) AS TOTAL FROM ORDERS) ; ACTIVE :=TRUE ; MaVariableTotal :=FIELDBYNAME(TOTAL).AsFloat ; ACTIVE :=FALSE ; FINALLY FREE ; END ; A noter : Il est clair que limbrication de nombreux niveaux de WITH est nuisible la lecture du code source, tout comme le sont les structures IF THEN ELSE qui se suivent. Face un choix entre criture acadmique et lisibilit des sources on choisira toujours cette dernire.

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 15 sur 27

E.

Utilisation des PROPERTIES dans les fiches

Le modle objet de DELPHI dfini les proprits dun objet comme des variables fantmes remplaces la compilation par des appels aux champs internes ou aux procdures et fonctions dclares dans les sections READ et WRITE. Cette mthode, trs utilise dans la conception des composants, peut tre mise profit dans bien dautres cadres, notamment au sein des objets TFORM sous-classs que sont les fiches que vous manipulez dans vos applications. Il ne faut jamais perdre de vue que la conception dune fiche dans DELPHI nest ni plus ni moins quune criture guide dun sous-classement de lobjet TFORM (ou de lun de ses descendants avec DELPHI 2). Ds lors, il ny a aucune raison de ne pas utiliser le mot cl PROPERTY pour dfinir des proprits ayant des comportements complexes. Notre conseil est ici dutiliser au maximum cette technique pour simplifier linterface des fiches lorsque celles-ci doivent communiquer avec dautres fiches. Prenons un exemple simple ; dans un projet vous disposez dune fiche liste des clients et vous ajoutez une fiche dtail dun client . Vous souhaitez naturellement pouvoir appeler une fiche dtail en doublecliquant dans la liste des clients. Plusieurs techniques de synchronisation existent, suivant si cette dernire doit tre persistante ou non. Nous supposerons une synchronisation non persistante dans cet exemple (donc lentre uniquement). La mthode quon voit le plus gnralement employe consiste, dans la fiche liste et en rponse au double-clic de la grille de donnes, crer une fiche dtail puis la synchroniser par code en appelant par exemple la mthode Findkey dune de ses tables. Une telle approche nest pas conforme au conseil disolation donn dans une rubrique prcdente. Toutefois, dans ce cas prcis (quoi doit tre gnralis de nombreuses circonstances quivalentes) il nest pas toujours possible dopter pour la solution de la fonction appelante tel que nous le dcrivions. Dans un tel cas, et dans dautres ou une fiche doit effectuer des traitements pilots par une autre fiche (ou objet, ou code quelconque) il convient dexploiter les capacits des proprits dfinies par PROPERTY. Pour continuer notre exemple, nous rsoudrons ici le problme en crant, dans la fiche dtail, une proprit PROPERTY CODECLIENT du type du code client (supposons un LONGINT). En lecture cette proprit fera rfrence un champs priv du TFORM dtail, en criture une procdure prive dont la tche sera deffectuer la synchronisation. Ainsi, la proprit (dans la partie PUBLIC de lobjet TFORM de la fiche dtail) ressemblera : PROPERTY CODECLIENT :LONGINT READ FCODECLIENT WRITE SETCODECLIENT ; La procdure SETCODECLIENT prendra un LONGINT en paramtre qui servira synchroniser la fiche. Ainsi, depuis la fiche Liste des clients, il suffira dcrire : MaficheDetail.CodeClient :=26 ; pour que la fiche dtail soit immdiatement synchronise sur ce code client sans avoir, du ct de lappelant, connatre le moindre morceau de la logique de cette action ni aucun champ de la fiche dtail. Nous ne rpterons pas les avantages dune telle isolation et insisterons ici sur le fait que, demain, vous pourrez modifier le code effectuant la synchronisation (peut-tre par une mthode plus rapide ou plus sophistique) sans que cela ninfluence la moindre autre fiche de votre application. Notre conseil sera ici dinsister sur la ncessit dexploiter cette technique lorsque celle de la fonction appelante nest pas approprie afin de conserver le mme degr disolation dans toute lapplication.

F.

Les Traitements en tche de fond

Certaines application ncessitent la cration de tches de fond. Parmi ceux-ci on rencontre souvent laffichage dune horloge (exemple stupide mais gnrique). Pour grer de telles tche il existe plusieurs mthodes qui dpendent beaucoup de lOS choisi et du compilateur natif quon utilise. Malgr tout, on constate que la majorit des dveloppeurs utilise un TIMER comme dclencheur. Si cette mthode est acceptable dans certains cas, il savre quil existe, aussi bien sous Windows 3.1 que sous Windows 95 / NT, dautres techniques plus efficaces. Sous Windows 3.1, et avec DELPHI 1, la meilleure dentre elles consiste programmer lvnement ONIDLE de APPLICATION. Aucune ressource TIMER nest utilise, et on a lassurance que la tche nest appele que lorsque lapplication ne fait rien dautre quattendre. En cas de traitement long il ny a pas de messages TIMER qui viennent encombrer la mmoire non plus. La frquence de cet vnement est assez grande. Sous Windows 95 et NT, et avec DELPHI 2, nous conseillons la cration dune tche THREAD dont la priorit sera IDLE, ce qui recr un quivalent de la technique 16 bits tout en tirant avantage de la technologie 32 bits.

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 16 sur 27

On peut alors se demander quand utiliser des timers ? ... Uniquement lorsque vous avez besoin de mesurer un laps de temps peu prs constant. Les timers peuvent tre utiliser pour distinguer des vnements entre eux, selon un seuil programm. Les timers sont en fait rellement utiles lorsquil faut quun certain temps minimum espace deux vnements. Avec ONIDLE votre tche peut tre appele 10 fois ou 1000 fois par seconde, vous ne matrisez pas la temporisation. En utilisant un timer programm sur 10000 ms vous aurez la certitude que le gestionnaire dvnement ne sera pas appel plus de 6 fois par minute. On peut donc accepter lutilisation dun timer lorsque le gestionnaire dvnement appel effectue des tches qui doivent tre espaces dans le temps par un intervalle minimum. Noubliez pas que Windows garanti un espace minimum et non un espace maximum. En dehors des horloges affiches, dautres traitement (plus essentiels) peuvent tre placs en tche de fond. Les impressions lourdes, et les requtes sur donnes en font partie. Si vous utilisez un gnrateur de document de type ReportSmith ou un outil comme QUICKREPORT, vous ne pourrez pas matriser limpression en tche de fond. Si vous optez pour une programmation intgrale (ce qui se justifie dans certains cas) vous pourrez concevoir une squence interruptible que vous placerez dans la gestion de lvnement (ou de la tche) IDLE. Pour les requtes sur donnes, tout dpendra de la mthode retenue et de lOS. Sous Windows 95 / NT, toutes les techniques sont possibles, notamment la cration dun THREAD dans lequel une requte SQL est envoye au BDE. Cette technique permet dinterroger des donnes sans bloquer lapplication, ce qui est trs intressant pour les traitements statistiques longs. En environnement 16 bits une telle possibilit nest pas offerte, mais vous pouvez fort bien la simuler. Si un traitement de donnes est trs long, vous avez la possibilit, plutt que dutiliser une requte SQL, deffectuer le traitement vous-mmes en balayant les tables. Bien entendu cela est moins efficace, mais ici, ce qui est intressant cest que cette tche ne soit pas bloquante, peu importe quelle dure 10 minutes de plus. Vous pourrez ainsi concevoir une routine interruptible que vous placerez dans un gestionnaire de ONIDLE.

G.

La dynamique des donnes

Lorsquune application utilise plusieurs fiches, ce qui est donc le cas le plus souvent, et que ces fiches font rfrences des donnes communes, il convient de rafrachir ces dernires afin quun changement intervenu dans une fiche soit immdiatement visible dans une autre. Prenons un exemple fort simple : Au milieu de la saisie dune commande lutilisateur dcide de crer un nouvel article en appelant la fiche de maintenance de la table des articles. Lorsquil revient la commande en cours, il sattend naturellement ce que larticle frachement cr soit accessible dans le DBLOOKUP servant au choix de larticle. Si vous navez rien programm en ce sens, larticle cr ne sera pas visible ! Comme il serait trs vite fatigant de programmer les vnements ONSHOW ou autre de toutes les fiches de lapplication pour y crire des suites de MaTable.Refresh ; , et ce, pour chaque table sans en oublier une, nous proposons ici une mthode plus rapide. Elle consiste programmer un seul vnement, ONACTIVEFORMCHANGE de lobjet SCREEN, et dy placer un code gnrique qui soccupera de rafrachir tous les objets TTABLE automatiquement. Au passage on en profitera pour traiter les TQUERY qui ncessite une fermeture suivie dune ouverture pour obtenir le mme effet. Ce code balaye tous les composants de la TFORM qui devient active (ACTIVEMDICHILD pour le modle MDI) et teste leur type par une instruction du type IF .... IS TTABLE THEN ... . En rponse positive ce test il conviendra de transtyper le composant en un TTABLE pour atteindre sa mthode REFRESH. Pour les TQUERY on enchanera CLOSE et OPEN. Cette solution lavantage de la simplicit, de la compacit, de llgance le tout en tant totalement indpendante du nombre de fiches de lapplication et de la structure de ces dernires dans lesquelles, cerise sur le gteau, il ny a rien programmer... Ouf ! Autant davantages pour si peu de code, que demander de plus... ... En fait il y a un petit problme (ctait trop beau !) : effectuer un REFRESH sur un TDATASET arrte les modes EDIT et INSERT. Dans la squence propose, on testera la proprit STATE du TDATASET et on effectuera le REFRESH que si STATE=DSBROWSE.

H.

Localisation des interface des fiches

La plupart des projets possdent des fiches servant la saisie dinformations ponctuelles (mot de passe par exemple) ou la slection de donnes (liste des clients par exemple). Trs souvent les dveloppeurs arrtent leur rflexion la conception de telles fiches sans penser leur utilisation. Ds lors, il nest pas rare de rencontrer dans une application la rptition du mme code dappel dune mme fiche. La squence est gnralement du type (dans le meilleur des cas): Procedure ButtonPassWordClick1(Sender :Tobject) ; Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 17 sur 27

Var F :TFInputPassWord ; begin F := TFInputPassword.Create(self) ; F.Edit1.text := ; If F.Showmodal=MrOK then motdepasse :=F.Edit1.text.... else .... F.Release ; end, Ainsi, si plusieurs modules ont besoin de saisir un mot de passe (ou doffrir une slection dun client, dun article...), on retrouve le mme code, avec parfois des variantes, un peu partout. Une telle pratique est proscrire pour de nombreuses raisons videntes. Lun des plus importantes est que chaque module appelant doit avoir connaissance de la classe de lappel, de sa structure, du nom de ses champs et proprits. Toute amlioration de la fiche appele se traduira par une maintenance lourde et des risques de bugs pour avoir oubli de modifier lun des appels. Lune des rgles de la programmation qui se trouve renforce dans le modle Objet est que lAppel ne doit pas connatre lAppelant. On peut tendre ce prdicat son inverse, ce qui, nous lavons prouv, a un sens bien concret notamment en ce qui concerne la maintenabilit de lapplication. De fait, notre conseil ici est que toute fiche doit contenir dans lunit qui la dclare une procdure ou une fonction isole (hors de lobjet fiche) dclare dans la partie INTERFACE de lunit dont la fonction premire sera de rsoudre les problmes dappel la fiche sous-jacente. Seule cette procdure ou fonction sera utilise par le projet. Elle seule connat certains dtails de la fiche appele, et comme elle se trouve dclare dans la mme unit de code, sa modification, dans le cas de la modification de la fiche elle-mme, sera la fois intuitive, directe et centralise. En fait, ce que nous dcrivons ici est lun des principes des mthodes de classe. Il est donc tout fait licite de mettre en uvre ce mcanisme en dclarant une mthode de classe dans la fiche elle-mme. Ce jeu dclaratif rclame une trs bonne connaissance du modle Objet de DELPHI, toutefois sa mise en uvre est extrmement simple ce qui force a adopter ce modle pour les fonctions appelantes. Lexemple qui suit va dmontrer cette simplicit. Supposons un projet o il existe une fiche (TFORM) appele TFInputText possdant en tout et pour tout quun champ EDIT (EDIT1) et un bouton de validation renvoyant un code modal MROK. Nous voulons utiliser cette fiche chaque fois quun morceau de texte devra tre saisi. Le champ EDIT devra tre initialis lentre et la fonction appelante devra retourner le texte tap par lutilisateur. Pour mettre en uvre cette fonction, nous allons, dans TFinputText, dclarer une mthode de classe dans la partie PUBLIC de lobjet TFORM : PUBLIC CLASS FUNCTION ASKTEXT(CONST S :STRING) :STRING ; Dans la partie IMPLEMENTATION nous crirons : CLASS FUNCTION TFInputText.AskText(Const S :String) :String ; Begin Result := ; With Create(Application) do try Edit1.text :=s ; Showmodal ; Result :=edit1.text ; Finally release ; end ; end ; Le code ci-dessus utilise lastuce de notation de linstruction WITH (tudie dans le prsent document) vitant la cration dune variable temporaire. En dehors de cela, le code est trs simple : il cre une instance de la classe, initialise le champ EDIT, appelle la fiche en mode modal, renvoie le rsultat de la fonction puis supprime linstance de la fiche. On peut bien entendu faire voluer cette squence vers quelque chose de plus sophistiqu selon les besoins. NDLA : A lheure actuelle mon avis reste partag entre lutilisation dune vritable fonction autonome et celle dune mthode de classe. Cette dernire solution me sduit par sa beaut trs Objet, toutefois il faut connatre le nom de la classe pour appeler la fonction, nom qui nest pas toujours trs significatif et alors mme quon pourrait vouloir changer la Classe appele. La fonction autonome lavantage dencapsuler la Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 18 sur 27

complexit et de transformer la stratgie Objet sous-jacente en un simple mot ressemblant toutes les fonctions de service de lenvironnement. Cette banalisation me semble intressante aussi. A dfaut pour linstant dun plus grand retour sur mes propositions, chacun aura le choix entre les deux mises en uvre de la Fonction Appelante prsentes ici.

1.

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 19 sur 27

ALLOWCREATE FALSE. Il va sans dire que laffichage du bouton permettant la cration (et de tous les lments visuels relatifs cette fonction) doit tre grer convenablement selon la valeur de ALLOWCREATE. Une fonction peut aussi renvoyer une rponse plus riche de sens quun simple Boolen. Par exemple, une fiche de slection peut autoriser la cration (cas prcdant) mais ne pas tre mme deffectuer elle-mme une telle cration. Dans ce cas, il faut que lappelant puisse savoir si lutilisateur a slectionn un enregistrement, a annul son choix ou bien a fait une demande de cration. Il serait en fait prfrable quune telle fiche gouverne elle-mme la cration. Dans le cas de son annulation elle se placerait nouveau en slection, dans le cas de sa validation est retournerait la cl exactement comme si lenregistrement avait t seulement slectionn. Cette possibilit pose un problme li la nature mme de lenregistrement crer. Dans certains cas il sagit juste de crer une cl primaire. Si elle est automatique il ny a mme rien demander de plus lutilisateur. Si elle ne lest pas, un simple champ TEDIT est ncessaire. Dans la plupart des cas on ne peut malheureusement pas se contenter de crer uniquement la cl primaire. Certaines informations hors cl sont obligatoires (le nom et le prnom dun client alors que seul le code client fait partie de la cl par exemple). Ces informations obligatoires imposent alors la cration une mini fiche de saisie. Cette dernire peut devenir assez vite complexe si des business rules particulires sappliquent, si des tables de rfrences sont utilises, etc. Dans un tel cas, la fiche de cration peut ressembler normment la fiche de saisie / modification normale . Il serait stupide davoir la dupliquer. Autant dire quune telle redondance de code est plus que prohibe ! La re-exploitation de la fiche de saisie en mode MODAL peut poser un problme si lapplication est en mode MDI. En effet, la fiche a t cre avec le style fsMDIChild et on ne peut pas ouvrir une telle fiche avec SHOWMODAL. Nous testons en ce moment des mcanismes permettant une telle adaptation automatique (ce qui nest pas simple du tout). Lorsquune solution aura t valide, elle sera intgre au Plan Qualit. Pour en revenir la fonction appelante, il existe donc des cas o la cration est possible mais o la fiche de slection ne peut pas grer elle-mme cette cration. Il faut que lappelant puisse dtecter cette situation puisque faute dune solution totalement intgre (Cf. paragraphe prcdent) il aura la charge de cette cration. On admettra ainsi que le rsultat de la fonction appelante ne soit pas Boolen mais de type numr. Le type lui-mme sera dclar dans lunit des Globales de la faon suivante : TYPE TENHANCEDCREATE = (tec_cancel, tec_Select, tec_Create, tec_user1, tec_user2) ; Les trois valeurs correspondent respectivement lannulation de la demande, la validation de la slectio n et la demande de cration. Les deux premiers cas sont quivalents au rsultat Boolen FALSE / TRUE du mode non tendu. La valeur de CANCEL est en premire position pour que dun point vue de la reprsentation interne elle soit quivalente FALSE, et que toute initialisation zro corresponde, par dfaut, une annulation. Les valeurs tec_user1 et tec_user2 permettent de grer deux modes de sorties supplmentaires (en dehors de ceux de base et du mode Cration). Cela permet davoir une seule dclaration de type valable tout au long dune application. On pourra fixer des valeurs plus explicites, en relation avec lapplication tout autant qutendre le nombre de ces valeurs. La raison oblige conseiller de restreindre ce nombre mais vous restez matre de cette dcision dans votre application du moment que votre choix est motiv et quil suit la prsente convention. Un fonction appelante retournant un type numr la place dun type Boolen se signalera par le prfixe ENHANCED ajout aux autres prfixes. On pourra ainsi trouver des fonctions GETCREATEENHANCED, GETINITCREATEENHANCED par exemple. Toutefois, il sera la charge du dveloppeur de proposer systmatiquement une fonction GET ou GETINIT de base. Celle-ci se chargera dappeler la fonction tendue et dinterprter la valeur de retour en la limitant la signification Slection / Non Slection. c) Francisation Si vous dsirez tout prix franciser les prfixes, utilisez : GET GETINIT GETCREATE GETINITCREATE GETENHANCED etc... CHOIX CHOIXINIT CHOIXCREATION CHOIXINITCREATION CHOIXENTENDU

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 20 sur 27

I.

Externalisation des traitements

Nous avons vu (Traitements gnriques et variables globales, page 13), comment grer les globales et certains traitements par lintermdiaire dune unit commune appele COMMON. Dans le mme esprit, nous allons voir ici quon peut pousser assez loin la sparation entre les traitements et la gestion de linterface. Fonctionnellement, une fiche (TFORM), na dintrt que celui de permettre de coder une interface utilisateur propre trs rapidement. Est-il donc logique dintgrer des traitements dans lunit de gestion dune fiche ? Comment faire la diffrence entre un traitement qui doit tre effectu cette dernire et un autre qui mriterait dtre externalis ? O placer le code ainsi extrait des fiches ? La localisation de ces traitements particuliers tombe sous le sens, ils doivent se trouver dans une unit commune. COMMON semble ainsi tre une bonne place. En fait ce choix est plus dlicat quil ny parait, mais, pour simplifier, on admettra que les petits projets utiliserons lunit COMMON comme zone de stockage des traitements externaliss. Il faudra tout de mme bien les identifier dans la partie interface. Pour les autres projets il conviendra de crer une nouvelle unit que nous nommerons EXCODE (EXternal CODE). Attention, le code plac dans lunit de gestion dune fiche a lavantage de ntre charg que lorsquil existe une instance de lobjet fiche alors que le code plac dans une unit commune augmentera la taille minimale utilise par lapplication. En ce qui concerne lunit COMMON cela se justifie pleinement, pour lunit EXCODE il faudra trancher si la taille de cette dernire devenait trop importante. En gnral on ne tient plus compte aujourdhui de la taille des logiciels et 100, voire 500 Ko, de plus ou moins ne gnent personne. Pour certains projets il faudra tout de mme garder prsent lesprit les consquences ventuelles dun tel choix. Nous savons maintenant o placer le code dlocalis, reste savoir quel code mrite ce traitement et quel avantage tirer de cette technique. Stricto sensu tout code qui ne gre pas explicitement de linterface devrait, dans la logique ici propose, se trouver dans EXCODE. Comme nous lavons vu il faudra parfois tre moins catgorique. Le meilleure compromis consiste externaliser uniquement le code dont on peut pressentir une ventuelle rutilisation. Cette mthode permet un tri efficace mais nest pas absolue, il faut ainsi en admettre les limites. Prenons un exemple concret : Dans une application donne on trouve une fiche permettant de manipuler des entits fournisseurs , or, il se trouve que chaque fournisseur possde une cl daccs (primaire) calcule la cration de tout nouveau enregistrement. La cl utilise les 4 premiers caractres du nom de la socit du fournisseur plus le mois et lanne de cration de la fiche sur 4 chiffres. Si le nom de la socit fait moins de 4 caractres, des espaces compltent celui-ci. Comme cette cl peut ne pas tre unique (deux enregistrements fournisseurs crs le mme mois dont le nom de socit commence par les 4 mmes lettres), un caractre supplmentaire est ajout en fin de cl. Il sagit du zro. En cas de doublon ce dernier chiffre sera incrment. Ainsi, la socit DUFOUR dont lenregistrement est cr le 10 avril 97 aura pour cl DUFO04970, la socit KTH saisie le 15 mai 1997 aura pour cl KTH 0597 et la socit DUFOIX cre dans le systme le 25 avril 1997 aura pour cl DUFO04971 (le 1 final gre le doublon avec le premier exemple). Grer la constitution dune telle cl rclame un peu de code, ne serait-ce que pour chercher les doublons et les grer par incrmentation du caractre final. Placer le code dans la fiche de gestion des fournisseurs semble, de prime abord, assez raisonnable puisquil ny a pas dautres fiches permettant la cration dun enregistrement fournisseur. Toutefois un tel cas nest pas carter. Les besoins de lutilisateur pourront voluer, il sera peut-tre aussi dcid dimporter des enregistrements depuis un autre systme (ou danciennes tables), etc. Lorsquun tel besoin se fera sentir il sera peut-tre difficile dextraire le code de son contexte, ce qui demandera de toute faon du travail alors que le placer ailleurs dambl vite tous les problmes (ce code resservira-t-il ? ce code sera-t-il facile extraire de son contexte ? O ce code sera-t-il alors dplac ? Dailleurs, sera-t-il dupliqu ou rellement dplac ? etc.). La solution consistera ici crer une fonction laquelle on passera en paramtre le nom de socit du fournisseur et qui retournera la cl. La date de cration ne parat pas indispensable puisque la fonction peut fort bien interroger lhorloge. Mais que ce passe-t-il sil faut un jour recrer les cls de certaines fiches ? Si le modle conceptuel na pas prvu de conserver la date de cration des enregistrements il ny a plus se poser la question, si cette date est conserve, il faudra alors prvoir de la passer en paramtre la fonction. La fonction sera localise dans lunit EXCODE. Au travers de cet exemple nous avons pu dgager une certaine logique quil conviendra dappliquer convenablement, cest dire en faisant grand usage de son libre arbitre qui, pour sexercer, ncessite une bonne comprhension du mcanisme. La prsentation un peu longue dun contexte particulier, comme souvent dans le prsent document, permet de vivre de lintrieur le cheminement des penses, il est donc essentiel doublier le ct anecdotique pour en extraire la logique sous-jacente.

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 21 sur 27

IV.

Techniques particulires

La structure du prsent document est encore balbutiante et, il faut lavouer, loin dtre parfaite. Ds lors, comme il fallait bien classer ce qui va suivre quelque part, un chapitre au nom aussi flou que techniques particulires semblaient simposer...

A.

Lorganisation du dossier

Si les dtails techniques dimplmentation ont leur importance, la tenue du dossier, notamment son organisation, peut tre un lment dcisif lors de futures maintenances, quelles soient correctives ou volutives. Ainsi, il est souhaitable dadopter une certaine rigueur dans le stockage de tous les lments affrents au dossier. Si nous ninterviendrons pas ici sur le stockage des lments physiques (cahier des charges, analyse, courriers en provenance de lutilisateur...), nous conseillerons ici un modle de classement des informations gnres par le dveloppement. Bien videmment, il sagit toujours ici de conseil que nous vous enjoignons de suivre, et non dune dmarche acadmique qui, alors, pourrait tre ridicule. Voici un exemple darborescence de classement dun dossier DELPHI :

Organisation disque d'un dossier


Rpertoire ddi

COURRIER courriers relatifs au projet

DOC Documentation relative au projet

SOURCES Sources du projet

INTERNE Documentation usage interne (quipe dv.)

APPLICATION Descriptions techniques pouvant devenir la doc technique

PROJET Totalit du projet

COMPO Tout composant non non standard utilis (sources obligatoires)

EXTERNE Documentation usage externe (vers le client)

HIERARCHIQUE Documentation interne entre le Chef Projet et sa hirarchie

AIDE Fichiers relatifs au systme d'aide intgr

BMP/ICO images utilises (logo, icones...)

DOCUSER Documentation destination des utilisateurs

B.

Ladministration de lapplication

La plupart des applications ncessitent la mise en place de certaines maintenances rserves son administration. Pour exemple citons celle des utilisateurs notamment. Certains dveloppeurs font le choix de crer un module excutable spar regroupant lensemble de ces fonctions. Dans certains cas cela est justifi. Dans tous les autres il sagit l dune complication non justifie et dune perte de temps qui lest encore moins (cration dun nouveau cadre dapplication, etc). De plus, la sparation de ces fonctions est peu pratique : sur un poste donn on ne sera jamais certain davoir accs lexcutable dadministration ce qui complique la maintenance oprationnelle. Plus loin, la dsynchronisation physique des deux excutables (application et administration) ajoute une contrainte au suivi du projet (cohrence, changement de certaines constantes, ...). Pire, il ny a pas de moyen simple dempcher ladministrateur dutiliser une version prime de loutils dadministration. Pour toutes ces raisons, le conseil de cette rubrique sera dintgrer le module dadministration directement au menu principal de lapplication. Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 22 sur 27

Bien entendu il ne sagit pas de laisser ces outils en libre-service ! La technique la plus simple qui offre, au minimum, les mmes garanties que celles dun excutable spar, consiste grer les choses de la faon suivante : Mise en place 1. Crez une entre ADMINISTRATION dans le menu principal de lapplication. 2. Ajoutez sous celle-ci les items de ce menu. 3. Ajoutez un item Activer / Dsactiver auquel vous associerez un acclrateur (par exemple MAJ-CTRL-F12) 4. Revenez sur lentre principale de ce menu et placez sa proprit VISIBLE FALSE. Mise en uvre Windows est un environnement subtil, et non visible (VISIBLE=FALSE)ne signifie pas non actif , ce qui se gre avec un autre paramtre (ENABLED=FALSE). De fait, les acclrateurs connects des entres de menu non visibles mais actives restent fonctionnels. Lorsque lutilisateur active lacclrateur Activer/Dsactiver votre application ragira de cette faon : si la proprit VISIBLE du menu administration est TRUE, il suffira de la basculer FALSE (en ayant ventuellement pris soin de fermer automatiquement toutes les fentres relatives restant ouvertes), si la proprit VISIBLE est FALSE, lapplication affichera un dialogue mot de passe . Si le mot de passe administrateur est correct la proprit VISIBLE du menu sera bascule TRUE, sinon, rien de se passera. Le risque quun utilisateur, mme sans le vouloir, puisse activer le dialogue mot de passe est, statistiquement le mme que celui quil dcouvre lexcutable dadministration sur une disquette qui trane ou sur un rpertoire du rseau. Discuter du risque relatif de ces deux probabilits semble proche du clbre dbat sur le sexe des anges. Dans tous les cas lutilisateur sera arrt par un mot de passe administration ce qui revient donc strictement au mme, in fine. La scurit nest donc ni meilleure ni moins bonne ct utilisateur, par contre celle de lapplication ainsi que sa maintenabilit sen trouvent renforces. Vous vous apercevrez vite que ce menu administration intgr lapplication vous incitera a ajouter ponctuellement certaines informations, certains paramtres que vous nauriez jamais eu lenvie daller crer dans une seconde application ddie. Ce qui, incidemment favorise une meilleure approche de ladministration de lapplication. Parmi ces petites choses qui peuvent trouver place dans le menu dadministration notons la gestion centralise des erreurs dexcution et des Logs (technique dcrite dans le prsent document).

C.

La gestion centralise des Logs et erreurs dexcution

Si une telle gestion nest que rarement rclame elle nen a pas moins dimportance pour autant. La maintenance dune application peut se trouver simplifie sil existe un moyen de tracer les erreurs dexcution ainsi que les connexions et dconnexions des utilisateurs. La majorit des applications sont sensibles une fin brutale : certaines donnes ne sont pas mises jour (dstabilisation des informations), certains fichiers peuvent tre endommags, etc. Les utilisateurs (encore eux...) nont que rarement conscience de ces problmes techniques et, malgr les conseils, certains sont de dangereux rcidivistes qui ne connaissent dautres faons de mettre fin une cession de travail quen teignant lordinateur. Sous Windows il faut aussi penser que dautres applications peuvent tre lances durant lexcution de la vtre. Ces applications peuvent planter le systme (avec blocage ou retour au niveau console) sans pour autant que votre application nait eut la moindre de chance de se terminer proprement. Dans un environnement rseau il devient vite impossible de savoir ce quil sest pass. Par contre, en cas de problme dans votre application (erreurs louverture de certaines fiches, perte de donnes,etc) au bout du fil un seul coupable, vous (le dveloppeur), un seul responsable, votre programme. Il est donc important de pouvoir sassurer quil ny a pas eu de dysfonctionnement au sein de votre application (trace des erreurs dexcution) afin de dtecter un ventuel bug, et quil ny a pas eu de sortie suspecte dun ou plusieurs utilisateurs (trace des Logs). Les deux aspects se grent diffremment, mais on utilisera une table centralise pour leur mise en uvre. Il ne peut sagir dun fichier ASCII car il vous faudrait grer le partage en rseau sur ce dernier ce qui nest pas forcment simple. Une table fera donc laffaire. Elle fera partie de celles de lapplication et sera gre selon les mmes mthodes (sur le serveur en modle C/S par exemple).

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Page 23

27

La gestion des Logs


table des Logs et inscrirez Date, Heure, Code utilisateur et un code de LogIn. Vous pourrez aussi ajouter localiser la machine et lutilisateur de faon spare (noubliez pas, en effet, quun problme peut-tre li une installation donne et quun mme utilisateur peut changer parfois de machine, donnant ainsi au bug un Pour la sortie, le mieux est de vous brancher sur lvnement ONDESTROY de la fentre mre. Vous ouvrirez le fichier de Logs et inscrirez les mmes informations en utilisant, cette fois, le code de Une simple interrogation SQL (de type GROUP BY) sur cette table vous permettra de savoir, pour chaque machine ou pour chaque utilisateur si le nombre des entres correspond celui des sorties. Une analyse

2.
Certaines erreurs ne peuvent malheureusement pas tre interceptes lorsque, notamment, Windows se bloque ou retourne en mode DOS. Ces problmes peuvent toutefois tre dtects par la gestion des Logs procds prsents conjointement). Pour toutes les autres erreurs non gres par votre application (TRY EXCEPT) il peut tre essentiel de savoir ce quil sest pass. Rares sont les utilisateurs capables de noter jusqu' nier le problme, de peur quon le leur reproche. Ainsi, dans certains cas, votre application pourra souffrir dun rel problme dont vous ne serez pas tenu au courant, problme pouvant avoir des

DELPHI offre une mthode assez simple pour centraliser les erreurs, lvnement ONEXCEPTION de lobjet APPLICATION. En programmant un gestionnaire pour cet vnement, il vous sera possible douvrir machine et lutilisateur. La colonne contenant les codes LOGIN et LOGOUT sera utilise avec un troisime code EXCEPTION, ce qui autorisera le filtrage des donnes pour leur affichage ou pour toute requte SQL. connaissance des ventuels problmes. Le menu ADMINSITRATION (voir autre rubrique du prsent document) pourra parfaitement contenir une fiche de visualisation de cette table. Elle peut tre trs simple statistiques voques ici (couples LOGIN/LOGOUT par exemple) et comporter un bouton de RESET. Concernant ce dernier point, chacun grera en son me et conscience. Faut-il dsactiver la fonction RESET Log contient une erreur ou sil ny a pas parit des LOGIN et LOGOUT autoriser le RESET mais en garder une trace (avec les informations statistiques) sur un fichier ASCII ou une autre table inaccessible exigences du clients et du temps disponible pour coder ces options gnralement non incluses dans le prix de vente du logiciel.

Cryptage
(la cl tant fournie aux procdure sous la forme dun WORD) const C1 = 52845; function Encrypt(const S: String; Key: Word): String; var begin Result[0] := S[0]; Result[I] := char(byte(S[I]) xor (Key shr 8)); Key := (byte(Result[I]) + Key) * C1 + C2; end;

Copyright Olivier

odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 24 sur 27

function Decrypt(const S: String; Key: Word): String; var I: byte; begin Result[0] := S[0]; for I := 1 to Length(S) do begin Result[I] := char(byte(S[I]) xor (Key shr 8)); Key := (byte(S[I]) + Key) * C1 + C2; end; end;

E.

Lutilisateur Application

La majorit des applications en rseau (ou client / serveur) ncessitent une gestion des utilisateurs, souvent pour les droits daccs, frquemment pour stocker qui a modifi / cr quoi et quand. Dans ce dernier cas, qui nous intresse ici, il est important de prvoir un identifiant spcifique pour lapplication elle-mme, voire une plage didentifiants rservs lapplication. En effet, lensemble des traitements agissant sur les donnes nest pas toujours intgralement sous le contrle de lutilisateur. Certaines mises jour automatiques ou intgrations de donnes (transferts inter plate-formes par exemple) peuvent tre dclenchs par lapplication en fonction de son tat. Ds lors que des oprations de ce type ne sont pas explicitement lances par un utilisateur, il convient de prvoir un code utilisateur pour lapplication puisque celle-ci se comporte, fonctionnellement, comme un utilisateur qui prend la dcision dagir sur les donnes. On peut aussi opter pour un code utilisateur constitu du code de lutilisateur humain auquel est un ajout le code utilisateur de lapplication ou du process.

F.

Grer les accs lapplication

Lorsquune application doit grer des droits daccs, en rseau ou en client / serveur, il est prfrable (sauf cas particuliers) de ne pas utiliser directement les options de la base de donnes pour ce faire. En effet, une telle gestion implique de manipuler sans cesse la base pour prendre en compte les dparts et arrives des utilisateurs (utilisateurs nayant plus accs lapplication, nouveaux utilisateurs, mutation de droits de certains utilisateurs). Au-del de la lourdeur de cette gestion, chaque utilisateur dispose dun mot de passe donnant rellement accs aux donnes de la base. Il peut ainsi utiliser ce mot de passe depuis un outil interactif. Il possde ainsi une vrai cl. Il est plus intelligent de ne pas distribuer de cls relles en utilisant une indirection. Le systme fonctionne alors comme cela : La base possde un fichier des utilisateurs protg (mot de passe Paradox, Grant SQL,...). Seule lapplication connat le mot de passe qui nest connu de personne. Lorsquun utilisateur entre dans lapplication il fournit son identifiant qui nest autre que la cl daccs la table des utilisateurs. Il fournit aussi sont mot de passe. Lapplication cherche lutilisateur dans la table et vrifie la fois son existence et la validit de son mot de passe. Une fois lidentification passe avec succs, lapplication note le groupe auquel lutilisateur appartient (information stocke par le superviseur dans la table des utilisateurs). Le code du groupe renvoie une table des groupes qui contient au minimum le vritable mot de passe pour accder la base de donnes. Ce mot de passe correspond une utilisateur imaginaire qui reprsente en fait les droits de tout un groupe. Enfin, lapplication ouvre la base en lui fournissant, automatiquement et de faon transparente, le vritable mot de passe. On peut fournir lutilisateur un utilitaire lui permettant de changer volont son mot de passe qui nest quun champ dans la table des utilisateurs sans aucune signification relle. En dehors de lapplication, lidentifiant et le mot de passe dun utilisateur ne lui permettent pas daccs la base de donnes. La protection est ainsi totale et cette indirection simplifie lextrme la gestion des droits de la base elle-mme qui ne connat que quelques utilisateurs dont la dfinition claire ne varie pas dans le temps (ou trs peu). Si daventure il savre ncessaire quun utilisateur accde la base par dautres outils que votre application, il faut soit revoir la stratgie (et grer les droits directement avec le SGBD-R) soit se contenter de donner le mot de passe du groupe (ce qui noffre que certains droits et qui peut tre changer rgulirement).

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page

sur 27

G.
Lexprience prouve quil savre souvent ncessaire dajouter ou de modifier des comportements concernant des fiches dune application. Ces comportements peuvent intervenir, soit au moment de linstance (donc, soit en dbut, soit en fin de vie dune instance de la classe). Delphi, dans son modle objet, et au travers de la VCL, propose, pour les fiches, deux vnements : OnCreate OnDestroy . Ces vnements se situent dans une logique de peut supposer ici que les vnements en questions sont gnrs depuis ces mthodes particulires de lobjet Tform). approprie pour atteindre son but. Pour mieux fixer la problmatique, prenons un exemple de comportement de dbut de vie dinstance, et un (ce ne sont que des exemples qui pourraient, ponctuellement, tre rsolus autrement): On peut vouloir ajouter une application un paramtre global permettant dafficher ou non les bulles daide, en compte les droits daccs de lutilisateur en cours, notamment en plaant les ensembles de donnes en mode read only ou non. dj beaucoup de fiches dans lapplication, soit parce quil faudra ajouter une contrainte supplmentaire la indiquant les oprations minimales coder sur chaque nouvelle fiche. Que dire alors si les comportements en questions sont supprims ou modifis grandement dans le futur Chaque fiche devra tre revrife. Et chacune de ces interventions viendra alourdir le cycle de maintenance corrective tout autant que celui de la maintenance volutive. Sans parler des invitables bugs logiciel cr par la dcentralisation de ces traitements porte, pourtant, gnrique. Pour linstant nous nous sommes limit un exemple dajout, en cours de conception dune application, de nouvelles instances de la classe. Nous aborderons plus tard le problme des comportement devant intervenir sur la fin de vie des instances.

ou de complter son vnement OnCreate Traitements gnriques et variables globales 13) indiquant si les bulles daide doivent ou non tre affiches et den ensemble de donnes, sa proprit grant les droits en criture. Concernant les bulles daide, il suffira de lire une variable globale de type , de type boolen, et den affecter le rsultat la proprit de lobjet TFORM courant. Toutefois, on voit bien que, pour chaque fiche de lapplication, il faudra rpter ce mme code lidentique, Pour les ensembles de donnes, chaque fiche reprsente un cas particulier. Telle fiche possdera un objet , telle autre un couple tClient, tFactures n, ncessitera peut-tre de mettre jour une quinzaine dobjet ayant tous des noms diffrents. ! ...Surtout quil faudra le rpter sur chaque fiche, sans rien oublier. Loubli dune seule table dans la liste ci-dessus pourra causer des effets inattendus (on appel des aussi...). Cette mthode nest pas la bonne, nous en arrterons la description ici.

environnement il suffit de crer un TFORM de base pour toute application et den faire descendre toute fiche. De ce fait, lorsquil faudra ajouter des traitements gnriques il suffira de modifier lobjet TFORM matre et de recompiler lapplication. Cest l toute la magie des objets mise au service de lhritage des Cette solution est de loin la meilleure mais elle a un inconvnient majeur : si Delphi 1, au niveau du fiche ne sait pas travailler sur de telles classes drives. Si on modifie lentte dun objet TFORM pour indiquer une autre classe parente, il nest pas possible de la modifier librement en mode conception.

Par contre, ce qui marche en Delphi 1 fonctionne gnralement bien en Delphi 32 bits, il existe alors une solution gnrique qui sadapte aux deux types denvironnement.

Dahan odahan@cybercable.fr

Plan Qualit v 1.23

Page 26 sur 27

Elle consiste crer dans lunit COMMON (voir Traitements gnriques et variables globales, page 13) une procdure pour grer les traitements de dbut de vie et une autre pour ceux de fin de vie dune instance de TFORM. Il sagit de traitements gnriques qui devront sadapter tous les cas de figure, nous verrons comment dans quelques lignes. La seule contrainte, mais qui reste fort lgre et qui, de surcrot est systmatique, consistera appeler lune et lautre de ces procdures dans le OnCreate et le OnDestroy de toutes les fiches de lapplication. Si ces vnements existent dj, on considrera toujours que ces appels sont effectus en premier. Comment grer la personnalisation des traitements ? Les procdures ici tudies, que nous appellerons INITCHECKPOINT et EXITCHECKPOINT, ne prennent quun seul paramtre de type TFORM. Leurs enttes respectifs sont ainsi : Procedure InitCheckPoint(Sender : Tform) ; Procedure ExitCheckPoint(Sender : Tform) ; Grce au paramtre SENDER, mais aussi aux proprits et mthodes de base de la classe TFORM, il va tre possible de globaliser la plupart des traitements. Et si les contraintes de dveloppement imposaient un moment donn dappliquer un traitement rellement spcifique certaines fiches, toujours grce au SENDER, il serait possible (en utilisant loprateur IS) de connatre la classe de lappelant (ce qui permettrait de traiter les cas particuliers). Lappel des procdures CHECKPOINT se fera ainsi en passant comme paramtre lidentificateur SELF qui rfrencera linstance en cours de la fiche appelante. Voici un exemple dappel de INITCHECKPOINT dans une fiche TFORM1 : Procedure TFORM1.FormCreate(Sender: TObject); Begin InitCheckPoint(Self) ; ... autres traitements ventuels du OnCreate de la fiche ... End ; Reprenons notre exemple de traitement de dbut de vie dinstance. Sagissant des bulles daide, la procdure INITCHECKPOINT positionnera la proprit SHOWHINT de lappelant en faisant rfrence une variable globale de lunit COMMON (qui sera, selon toute vidence, lue et sauvegarde depuis et sur un fichier de type INI). Concernant les droits daccs aux tables, second point de notre exemple, nous supposerons aussi quune variable de mme nature existe et quelle contient une indication claire quant aux droits de lutilisateur en cours. Le code de INITCHECKPOINT pourrait alors tre le suivant : Procedure InitCheckPoint(Sender : Tform) ; Var i : Integer ; Begin Sender.ShowHint := GLOBAL_SHOWHINT ; For i :=0 to Sender.ComponentCount -1 do Try If (Sender.Components[i] is TDataSet) and (Sender.Components[i].Tag<>K_NOINITCHECKPOINT) then (Sender.Components[i] as TDataSet).ReadOnly := GLOBAL_READONLY ; Except End ; End ; Explications : La variable GLOBAL_SHOWHINT est de type BOOLEAN, elle se trouve dans lunit COMMON du projet et indique ltat de la visibilit des bulles daide. La boucle FOR balaye tous les composants appartenant au SENDER (donc la fiche faisant lappel). Comme le OWNER des TDATASET est systmatiquement le TFORM lui-mme, tous les composants grant des donnes seront trouvs dans la liste COMPONENTS de lappelant. Le fait de tester le type TDATASET permet denglober en un seul traitement tous les descendants de cette classe, donc le TTABLE, le TQUERY et le TSTOREDPROC. Il serait possible de ne tester que lun de ces types ou bien dappliquer un traitement diffrent en les testant tous sparment.

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

Plan Qualit v 1.23

Page 27 sur 27

limite comme MAXLONGINT dfinie par DELPHI). Tout composant de type driv TDATASET qui possdera un TAG ayant cette valeur chappera aux traitements de la procdure. Cela est trs utile pour Chacun a, bien entendu, la possibilit de sophistiquer souhait en dclarant une tendue de valeurs qui permettrait de grer des cas exceptionnels de nature diffrente. tout moment dans la procdure INITCHECKPOINT, do lintrt norme de cette technique. La procdure EXITCHECKPOINT sera, de toute vidence, gre de la mme faon. Lexemple dune telle : Il est gnralement intressant de proposer lutilisateur (ou, au minimum, ladministrateur de oprations non valides sur les tables. A noter que certaines applications possdent des systmes de saisie compliqus auxquels la prsente solution ne convient gure. Mais dans tous les autres cas (nombreux) il : Procedure ExitCheckPoint(Sender ; Var i ; Begin :=0 to Sender.ComponentCount -1 do Try If (Sender.Components[i] is TDataSet) and (Sender.Components[i].Tag<>K_NOEXITCHECKPOINT) then if GLOBAL_CANCEL then (Sender.Components[i] as TDataSet).Cancel else (Sender.Components[i] as TDataSet).POST

Except End ; ;

Explications La constante K_NOEXITCHECKPOINT joue un rle identique que celui de K_NOINITCHECKPOINT. La variable GLOBAL_CANCEL est un boolen qui contient VRAI si la fermeture des fiches entrane une Ici aussi on peut sophistiquer les traitements souhait selon les exigences de lapplication.

Copyright Olivier Dahan odahan@cybercable.fr - reproduction interdite sans l'accord de l'auteur

You might also like