Fourth World Logo Fourth World Media Corporation
  Embassy Services Products Resources   About Fourth World Contact  
logo

Le Guide de l'écriture en xTalk

Trucs et astuces pour xTalk, Lingo et
autres L4G (langages de 4° génération)

Richard Gaskin
Fourth World Media Corporation

Adapté de: The Michael and Richard Style Guide
Présenté à la conférence des développeurs SuperCard de San Francisco, Californie, USA, janvier 1996.
6° révision, en date du 18 septembre 2001
Copyright © 1994-2002 Fourth World
Portions Copyright © 1994-1996 Michael Silver et Barnacle Software
Traduction: Didier Gross
1° version, en date du 19 février 2002
dg_xtalk@club-internet.fr
avec l'aimable autorisation de Richard Gaskin,
Fourth World Media Corporation

Adapted from The Michael and Richard Style Guide,
presented at the SuperCard Developer Conference in San Francisco, California, January 1996.
With six revisions since then, it was last revised 18 September, 2001.

Copyright © 1994-2001 Fourth World
Portions Copyright © 1994-1996 Michael Silver and Barnacle Software

Ce document peut-être librement reproduit et diffusé, sous réserve qu'il ne soit pas modifié et que la reproduction soit intégrale, y compris cette introduction et le copyright.



Résumé
Les langages de script permettent en général un apprentissage plus rapide que des langages formels tels que le C++, mais cette séduisante facilité peut conduire à une écriture moins structurée du code, le rendant ainsi difficile à lire et coûteux à maintenir.
En adoptant quelques unes des meilleures pratiques des langages formels, les programmeurs peuvent réduire le risque d'erreurs et raccourcir les cycles de développement.

Mots clé: script, L4G, programmation, style de code, HyperTalk, Transcript, MetaTalk, SuperTalk, Lingo, notation hongroise, conventions de dénomination.

Contenu:

Introduction

Techniques générales d'écriture de scripts

Clarifier le flux de traitement
Rédiger des commentaires efficaces
Écrire du code réutilisable
Écrire du code rapide

Conventions de dénomination

Variables et arguments
Handlers et fonctions


Introduction

À un moment ou à un autre de notre carrière, nous avons tous commis du code exécrable (excepté mon ami Mark Lucas, mais c'est un être à part!). Vous voyez le tableau: vous replongez dans votre code six mois après l'avoir écrit pour ajouter de nouvelles fonctionnalités ou améliorer le traitement des erreurs, et vous n'avez plus la moindre idée de ce que les lignes que vous contemplez sont censées faire... C'est ce qu'on appelle la "programmation spaghetti": tout s'emmêle, et mettre au point la moindre modification constitue un défi qui mobilise toute votre énergie et votre temps. Sans compter la correction des bogues qu'elle a générés! C'est là où intervient ce document.

Quelques saines pratiques peuvent concourir à rendre votre code plus fiable et le cycle de développement plus court. Même si elles requièrent un peu d'auto-discipline au début, l'adoption de ces pratiques, si vous les trouvez utiles, vous facilitera tellement votre travail quotidien qu'elles deviendront vite naturelles et ne vous demanderont plus aucun effort.

Parmi les nombreuses raisons qui plaident pour ces bonnes pratiques d'écriture du code, citons celles-ci:

  • le code obtenu est plus lisible et plus compréhensible
  • elles apportent une cohérence indispensable dans le cas d'un travail de groupe
  • les évolutions du code sont facilitées
  • si vous souhaitez le partager, vous pourrez être fier de votre code
  • ça impressionne les nanas (ou les mecs, selon le cas)
    NDT: je laisse la paternité de cette remarque à Richard ;-)

Les trucs présentés ici reflètent les pratiques de programmeurs parmi les meilleurs au monde, et je voudrais prendre le temps de les saluer ici :
Michael Silver, Ken Ray, Mark Lucas et Mark Hanrek sont parmi les meilleurs auteurs SuperCard que je connaisse, et c'est en mettant notre code en commun que nous avons découvert que nous avions chacun développé indépendamment des techniques d'écriture très proches.
NDT: Mark Lucas est devenu depuis un des piliers de l'équipe de développement de SuperCard et Ken Ray a écrit en SuperTalk le Project Editor, c'est à dire l'éditeur de projets livré avec SuperCard.
Le premier jet de ce document reflétait notre intérêt commun pour SuperTalk, et se trouvait ainsi plus limité. Il faisait partie du compte rendu d'un débat sur les techniques de script lors de la Conférence des Développeurs SuperCard en 1996, l'année ou SuperCard 2.5 a reçu l'Eddy Award du Best New Multimedia Authoring Tool (Meilleur Nouvel Outil Auteur Multimedia).

Ce document a vu son horizon s'élargir au fil des révisions, en incluant de nouveaux trucs pour d'autres langages de script similaires. Au cours de cette évolution, nous avons intégré des trucs très intéressants de programmeurs de talent, dont Scott Raney, Kevin Miller, Steven McConnel, Jad Santos et Alex Bronstein. Grâce à l'ensemble de ces contributions, ce document pourra être mis à profit avec bonheur par les utilisateurs de dialectes de type HyperTalk, et par quelques autres.
NDT: c'est à Scott Raney qu'on doit MetaCard et à Kevin Miller, Revolution.

En parcourant ces lignes, vous trouverez peut-être que votre façon de programmer vous convient mieux que nos suggestions. Qu'à cela ne tienne! Si votre code vous sied, il n'a pas besoin d'être modifié.

Il ne s'agit que de lignes guide. Mais plus elles seront utilisées, plus les programmeurs pourront échanger leur code facilement, régler leurs problèmes rapidement, passer plus de temps avec leurs familles, et créer un monde toujours meilleur.
NDT: la tournure typiquement américaine de cette phrase a été volontairement conservée.

Ceci étant dit, cela ne vaut jamais la peine de ré-écrire du code déjà existant pour se conformer à ces suggestions. De même qu'il ne faut pas se contraindre à suivre ces lignes guide si leur application compromet l'efficacité du programme. La frontière entre code aisément maintenable et code efficace est floue et mouvante. C'est à vous qu'il appartient de déterminer où elle se situe dans votre code.

Ce document est en perpétuelle évolution. Nous l'utilisons chez Fourth World pour la formation de nos programmeurs et comme base de travail. De ce fait, il est complété et amélioré autant que l'expérience l'exige et que le temps le permet. Si vous avez des idées ou suggestions que vous aimeriez y voir figurer, merci de me les faire parvenir à scripts@fourthworld.com (en anglais).
NDT: les suggestions en français peuvent être adressées à dg_xtalk@club-internet.fr avec pour objet "guide xTalk"

Après ces digressions, nous vous proposons d'attaquer le plat de résistance:


Techniques générales d'écriture de scripts

Quelques techniques pour éviter l'envahissement de votre code par les spaghetti...

Clarifier le flux de traitement

Une des meilleures techniques pour éviter le code spaghetti est de s'assurer que la logique de programmation est implicite. Par exemple, si vous avez un long handler qui réalise toute une série d'actions d'initialisation, vous pouvez le morceler en plusieurs handlers qui traitent chacun des tâches de même nature. Si vous leur donnez des noms parlants, vous n'aurez pas de difficultés à retrouver le principe de votre handler:

on InitialisationProgramme
   InitialisationMenus
   InitialisationFenêtres
   InitialisationPréférences
end InitialisationProgramme

Le temps perdu par l'interpréteur pour traiter ces 3 appels est négligeable. En revanche, ce découpage vous aidera à pister les erreurs en phase de débogage.

Une bonne technique pour assurer que le flux de traitement est clair consiste à commencer par la rédaction des commentaires. Décrivez le squelette de votre programme sous forme de commentaires, puis reprenez depuis le début en intercalant les lignes de code. Cette méthode peut également s'avérer utile pour mettre au point un handler présentant des difficultés particulières.

Beaucoup de mots des langages de script possèdent une abréviation. N'hésitez pas à l'utiliser: cela réduit la taille du code et cela fait ressortir les noms de vos variables et de vos handlers. En plus, vous économiserez de la frappe.

Il est recommandé d'utiliser des parenthèses pour regrouper les expressions logiques ou arithmétiques, ou pour clarifier le code:

if (the vis of wd "myWindow") then

est plus lisible que:

if the vis of wd "myWindow" = true then

L'utilisation du signe égal "=" dans les comparaisons plutôt que "is" permet de mieux les repérer visuellement.

Rédiger des commentaires efficaces

De façon générale, il s'avère judicieux de commenter tout bloc de code dont la fonctionnalité n'est pas implicite et d'éviter les commentaires superflus.

Un commentaire de ce type ne vous sera pas d'une grande utilité:

-- choix du curseur "montre"
set the cursor to watch

NDT: comme le xTalk est très proche de l'anglais naturel, la phrase de commentaire et la ligne de code sont rigoureusement identiques dans le document d'origine

En revanche, une brève explication comme celle-ci est la bienvenue pour expliciter des blocs plus complexes:

--- mise à jour de toutes les cartes avec la date courante
set the cursor to watch
put the short date into tDateCourante
repeat with i=1 to the number of cds
   put tDateCourante into fld "Date" of cd i
end repeat

Les commentaires peuvent aussi être utilisés comme des repères visuels, séparant les différentes sections du code. Voici un exemple de regroupement visuel de handlers grâce à des lignes de commentaires:

--======================================================--
-- HANDLERS DE GESTION DES FENETRES
--
--
-- RectDefautFenetre()
--
-- Retourne le "rect" par défaut des fenêtres des nouveaux documents
-- en fonction de la taille de l'écran
--
function RectDefautFenetre
   put the screenRect into rRect
   add 4 to item 1 of rRect
   add 4 to item 2 of rRect
   subtract 4 from item 3 of rRect
   subtract 4 from item 4 of rRect
   return rRect
end RectDefautFenetre
--
-- MajToutesFenetres
--
-- permet le rafraîchissement de toutes les fenêtres ouvertes
--
function MajToutesFenetres
   put windows() into tListeFenetres
   repeat for each line tFenetreCourante in tListeFenetres
      send "majFenetre" to tFenetreCourante
   end repeat
end MajToutesFenetres
--======================================================--

On notera que l'exemple ci-dessus inclut une brève description de chacun des handlers, ce qui rappelle brièvement leur rôle, mais les met également en relief et permet de les situer rapidement lorsqu'on parcourt le code.

Il est également bienvenu de séparer les différents blocs logiques d'un handler par des commentaires:

on MonHandler
   global gMaVariableGlobale
   --
   QuelquesInstructionsConcernantUnePhaseDuTraitement
   --
   LesInstructionsConcernantUneAutrePhase
end MonHandler

Afin que votre code puisse être parcouru très rapidement, mettez en Ïuvre ces deux principes simples:

  • découpez le code en blocs fonctionnels délimités par des commentaires, ceci permet aux différentes phases du traitement de se détacher visuellement.
  • n'utilisez pas de lignes vides à l'intérieur des handlers, mais seulement entre ceux-ci

Ne craignez pas de commenter abondamment si vous n'êtes pas limités par la taille des scripts. SuperCard, HyperCard, et quelques autres environnements sont limités à des tailles de script de 32ko, ce qui peut vous contraindre à vous limiter aux commentaires les plus importants et à restreindre les séparateurs visuels, dans le cas où vous atteignez cette limite.

Écrire du code réutilisable

Lorsque vous développez, posez vous la question de savoir si vous allez réutiliser le code que vous êtes en train d'écrire. Si c'est le cas, écrivez le sous forme d'une routine afin de pouvoir l'appeler à tout moment. De même, si vous vous rendez compte que ce que vous écrivez a un air de déjà vu, il y a sûrement une opportunité de créer un handler commun.

Lorsque vous écrivez vos handlers, prenez soin de les rendre aussi universels que possible. Si vous pouvez éviter les variables globales, faites-le: les possibilités d'utilisation ultérieure de tout élément dépendant d'autres portions de code se verront réduites. Si vous avez simplement besoin de lire la valeur d'une variable globale, passez la plutôt à votre handler sous forme d'argument.

Un autre moyen de garantir la portabilité du code est de ne pas utiliser de référence à des objets spécifiques. La version non portable d'un handler calculant la somme de deux champs ressemblerait à ceci:

put SommeChamps()
 
function SommeChamps()
   return fld "Num1" + fld "Num2" + fld "Num3"
end SommeChamps

Ce handler ne fonctionnera que dans les situations où vous désirerez additionner le contenu de trois champs, sous réserve que vous leur ayez donné ces noms spécifiques.

En revanche, le handler suivant sera beaucoup plus universel, car non seulement le nom et le type des objets ne constituent pas une contrainte, mais il effectuera la somme d'un nombre quelconque d'objets:

function SommeObjets()
   put 0 into rSomme
   repeat with i = 1 to paramcount()
      add param(i) to rSomme
   end repeat
   return rSomme
end SommeObjets

et

put SommeObjets (fld "Num1", fld "Num2", fld "Num3")

donnera le résultat escompté dans notre cas particulier.

Lorsque vous faites référence à des objets, utilisez autant que possible leur nom. Si le nom n'est pas connu, ou est susceptible de changer, utilisez le numéro d'ID de l'objet. Évitez d'utiliser la numérotation ordinale des objets (par exemple: "button 4"), car toute modification de disposition des objets peut entraîner un changement de "layer" (plan). Le numéro de l'objet changera et le script ne présentera pas le fonctionnement attendu. Un nom descriptif de l'objet facilitera la compréhension.

Nommez tous les objets auxquels vous pouvez faire référence par script: fenêtres, champs, graphiques, etc. Abstenez-vous d'utiliser des nombres, sauf si votre script nécessite de recourir à cette technique. Même dans ce cas, utilisez des noms. J'utilise souvent pour ma part des noms tels que "Signet1", "Signet2", etc.

Écrire du code rapide

La vitesse est un problème sensible pour les langages interprétés, qui sont généralement plus lents que les langages compilés. Voici quelques trucs qui faciliteront le travail de l'interpréteur et lui permettront de gagner en rapidité:

  • utilisez les appellations littérales comme "comma" et "colon" lorsque le langage le permet. Elles sont traitées plus rapidement par l'interpréteur
  • placez toujours les chaînes littérales entre guillemets, même si elles ne comportent qu'un mot. Par exemple :
    background button "Suivant"
    et non:
    background button Suivant
    Ne placez jamais entre guillemets les valeurs littérales, sauf si le langage l'exige. S'il n'y a pas de guillemets, l'interpréteur doit balayer la liste des variables avant de conclure que la chaîne doit être utilisée sous sa forme littérale.
  • utilisez des nombres plutôt que des constantes numériques textuelles. Par exemple :
    put tMaVariable - 10 into cd fld "monChamp"
    et non:
    put tMaVariable - ten into cd fld "monChamp"
  • réalisez les opérations répétitives sur des variables et non sur des champs. Quand l'interpréteur accède à un champ, il effectue un grand nombre d'opérations complémentaires pour préparer le texte, le modifier et l'afficher. Le transfert des données dans une variable accélérera souvent le traitement de plusieurs ordres de grandeur.

Conventions de dénomination

Nous allons préconiser dans ce paragraphe l'utilisation intensive de ce qu'on appelle communément la notation Hongroise, en hommage au fameux programmeur de Microsoft Charles Simonyi, qui, dit-on, suit religieusement cette pratique. Cette méthode consiste à utiliser une notation méthodique et cohérente permettant d'identifier l'utilisation et la nature d'un contenant (container) simplement par son nom. Le but est d'éviter de devoir rechercher dans le code pour identifier son origine, s'il s'agit d'une variable globale, d'un argument, ... Cette méthode a été adoptée à des degrés divers par beaucoup de programmeurs ces dernières années, comme on peut le constater dans les documentations de Revolution, SuperCard, et d'autres produits.

NDT: Si votre langue maternelle comprend des caractères spécifiques (en français: les caractères accentués par exemple) et que vous souhaitez partager votre code, il est recommandé de les éviter. Un utilisateur exploitant un autre jeu de caractères pourrait avoir des problèmes avec ces caractères: limitez vous à l'utilisation des caractères internationaux.

 

Variables et arguments

Vous pouvez identifier instantanément si une variable est locale ou globale, ou si elle a été passée comme argument, en faisant précéder son nom descriptif par une minuscule indiquant son type.

Préfixe

Signification

Exemple

g

Variable globale

gMaGlobale

t

Variable locale (temporaire)

tMaVariable

p

Paramètre (encore appelé argument)

pMonParametre

s

Variable statique (MetaCard & Visual Basic seulement)

sMaVariable

k

Constante (MetaCard & Visual Basic seulement)

kMonNombre

u

Propriété définie par l'utilisateur (user property)

uMaPropriete

r

Valeur de retour d'une fonction

rValeurDeRetour

NDT: la dernière ligne est une suggestion personnelle qui s'avère utile pour les fonctions qui nécessitent un code complexe

Notes

  • à propos du préfixe "p": quelques lecteurs m'ont signalé que "p" ne devrait plus être utilisé pour les paramètres, et que les scripteurs qui utilisent Lingo et AppleScript l'utilisent conventionnellement pour désigner les propriétés. J'ai passé quelque temps à rechercher en vain du code publié qui utilisait cette convention. Si vous en trouvez, merci de m'en faire part à scriptstyle@fourthworld.com (en anglais). Ce document est vivant, et toute opportunité de le faire évoluer en fonction des nouvelles pratiques qui se font jour sera la bienvenue.
    NDT: les suggestions en français peuvent être adressées à dg_xtalk@club-internet.fr avec pour objet "guide xTalk"
  • à propos du préfixe "k": même si votre langage ne gère pas les constantes, il est bien sûr recommandé d'identifier une variable globale que vous utilisez comme telle avec ce préfixe

Quelques conseils d'ordre général pour nommer vos variables et arguments:

  • déclarez toutes les variables globales dans la (les) première(s) ligne(s) de votre code
  • si votre langage gère les variables locales, déclarez-les également au début de votre code, avant les instructions exécutables
  • usez modérément des variables globales. Comme elles peuvent être modifiées à des endroits multiples de votre code, cela rend généralement les problèmes complexes à déboguer. Ceci dit, si vous avez besoin d'une variable globale, il n'y a guère d'autre solution que d'en utiliser une...
  • utilisez des noms de variables significatifs. Gardez-vous d'appellations telles que "tempo", "var1", et autres dénominations sans signification. Utilisez plutôt des noms comme "tCheminProjet".
  • cette dernière règle comporte une exception: les compteurs qui n'ont d'autre fonction que de servir d'index dans une boucle. On utilise traditionnellement les lettres de l'alphabet à partir du "i" pour les dénommer. On utilisera ainsi successivement "i" puis "j", "k", "l", ... Vous n'êtes pas censé utiliser le "j" et les lettres suivantes tant que vous ne construisez pas de boucles imbriquées.

Voici un exemple qui utilise plusieurs de ces principes:

on EnregistrementNoms pNombrePersonnes, pNoms
   global gCheminFichier
   -- constantes (disponibles pour certains langages seulement,
   -- sinon utiliser une globale initialisée au lancement)
   global kMaxPersonnes, kMinPersonnes
   if pNombrePersonnes > kMaxPersonnes then exit EnregistrementNoms
   if pNombrePersonnes < kMinPersonnes then exit EnregistrementNoms
   repeat with i = 1 to the num of items in pNoms
      put item i of pNoms & cr after tDonneesFichier
   end repeat
   open file gCheminFichier
   write tDonneesFichier to file gCheminFichier
   close file gCheminFichier
end EnregistrementNoms

Handlers et fonctions

  • utilisez toujours des minuscules, sauf exceptions ci-après
  • mettez en majuscule la première lettre de chaque mot d'un nom composé, sauf la toute première (exemple: amortissementMensuelLineaire). Ceci s'applique à l'ensemble des mots du langage que vous utilisez: noms de handlers, de fonctions, de variables, ...
  • mettez en majuscule la première lettre de vos propres handlers et fonctions
  • évitez d'utiliser le caractère souligné pour séparer les mots (exemple: quel_nom_de_handler_horrible): vous ne pourriez pas sélectionner le nom par un double-clic, ce qui ne manquera pas de vous compliquer la vie lors de l'écriture des scripts

Exemple:

on MonHandler
   global gCheminFichier
   put cd fld "Noms" into tNoms
   set the directory to pCheminFichier
   put the files into tListeFichiers
   put ConversionRepertoire (tFileList) into tRepertoire
   if tNoms = tRepertoire then pass MonHandler
end MonHandler


Fin du document de Fourth World Media Corporation

 

Quelques liens utiles

Retrouvez le document d'origine (en anglais) sur le site de Fourth World Media Corporation:

www.fourthworld.com/embassy/articles/ScriptStyle.html

ainsi qu'un document plus général sur les outils RAD (Rapid Application Development),
paru dans MacTech Magazine:

www.fourthworld.com/embassy/articles/MacTechEd.html