Blocs personnalisés: Guide de style

Au fil des ans, les équipes Blockly et Blockly Games ont appris de nombreuses leçons applicables au développement de nouveaux blocs. Vous trouverez ci-dessous un ensemble d'erreurs que nous avons commises ou des erreurs couramment commises par d'autres.

Il s'agit de leçons générales que nous avons apprises à l'aide du style visuel de Blockly. Il est possible qu'elles ne s'appliquent pas à tous les cas d'utilisation ou à tous les conceptions. Il existe d'autres solutions. Il ne s'agit pas non plus d'une liste exhaustive des problèmes que les utilisateurs peuvent rencontrer et de la manière de les éviter. Chaque cas est un peu différent et présente ses propres compromis.

1. Expressions conditionnelles et boucles

Les blocs les plus difficiles pour les nouveaux utilisateurs sont les expressions conditionnelles et les boucles. De nombreux environnements basés sur des blocs regroupent ces deux blocs dans la même catégorie "Controls" (Commandes), car ils ont la même forme et la même couleur. Cela entraîne souvent de la frustration, car les nouveaux utilisateurs confondent les deux blocs. Blockly recommande de déplacer les conditions et les boucles dans des catégories "Logique" et "Boucles" distinctes, chacune ayant une couleur différente. Cela indique clairement qu'il s'agit d'idées distinctes qui se comportent différemment, bien qu'elles présentent des formes similaires.

Recommandation: Séparez les conditions et les boucles.

2. Listes à base unique

Les programmeurs débutants réagissent mal lorsqu'ils rencontrent des listes basées sur zéro pour la première fois. Par conséquent, Blockly suit l'exemple de Lua et Lambda Moo en faisant une indexation des listes et des chaînes sur une base unique.

Pour des utilisations plus avancées de Blockly, les listes basées sur zéro sont compatibles afin de faciliter la transition vers du texte. Pour les audiences plus jeunes ou plus novices, l'indexation unique est recommandée.

Recommandation: Le premier chiffre est le premier.

3. Entrées utilisateur

Il existe trois façons d'obtenir un paramètre auprès de l'utilisateur. Un menu déroulant est le plus restrictif et convient aux tutoriels et exercices simples. Un champ de saisie offre plus de liberté et convient aux activités plus créatives. Une entrée de bloc de valeurs (généralement avec un bloc fantôme) permet de calculer une valeur (par exemple, un générateur aléatoire) au lieu d'être simplement une valeur statique.

Recommandation: Choisissez une méthode d'importation adaptée à vos utilisateurs.

4. Images bloquées

La documentation des blocs doit inclure des images des blocs auxquels il fait référence. Faire des captures d'écran est un jeu d'enfant. Toutefois, s'il existe 50 images de ce type et que l'application est traduite dans 50 langues, on conserve soudainement 2 500 images statiques. Ensuite, le jeu de couleurs change,et 2 500 images doivent de nouveau être mises à jour.

Pour éliminer ce cauchemar de maintenance, Blockly Games a remplacé toutes les captures d'écran par des instances de Blockly s'exécutant en mode lecture seule. Le résultat ressemble à une image, mais est forcément à jour. Le mode lecture seule a rendu possible l'internationalisation.

Recommandation: Si plusieurs langues sont acceptées, utilisez le mode lecture seule.

5. D'autre part

Les commentaires d'enfants aux États-Unis (même s'il ne s'agit pas d'autres pays) ont révélé une confusion générale entre la gauche et la droite. Ce problème a été résolu grâce à l'ajout de flèches. Si la direction est relative (pour un avatar, par exemple), le style de flèche est important. Une flèche droite → ou une flèche de rotation ↱ est déroutante lorsque l'avatar est orienté dans la direction opposée. La plus utile est la flèche circulaire ⟳, même dans les cas où l'angle de rotation est plus petit que l'indique la flèche.

Recommandation: Dans la mesure du possible, ajoutez des icônes Unicode au texte.

6. Blocages généraux

Dans la mesure du possible, une approche de niveau supérieur doit être adoptée, même si cela réduit les performances d'exécution ou la flexibilité. Prenons l'exemple de cette expression Apps Script:

SpreadsheetApp.getActiveSheet().getDataRange().getValues()

Avec un mappage 1:1 qui préserve toutes les capacités potentielles, l'expression ci-dessus serait créée à l'aide de quatre blocs. Toutefois, Blockly vise un niveau supérieur et fournirait un bloc qui encapsule l'intégralité de l'expression. L'objectif est d'optimiser les 95 %, même si cela complique les 5% restants. Blockly n'a pas vocation à remplacer les langues textuelles. Il est destiné à aider les utilisateurs à franchir la phase d'apprentissage initiale afin de pouvoir utiliser des langues textuelles.

Recommandation: Ne convertissez pas aveuglément toute votre API en blocs.

7. Valeurs de retour facultatives

Dans la programmation textuelle, de nombreuses fonctions effectuent une action, puis renvoient une valeur. Cette valeur renvoyée peut être utilisée ou non. La fonction pop() d'une pile en est un exemple. La fonction "Pop" peut être appelée pour obtenir et supprimer le dernier élément, ou simplement supprimer le dernier élément dont la valeur renvoyée est ignorée.

var last = stack.pop();  // Get and remove last element.
stack.pop();  // Just remove last element.

Les langages basés sur des blocs ne sont généralement pas efficaces pour ignorer une valeur renvoyée. Un bloc de valeur doit se connecter à un élément qui accepte la valeur. Il existe plusieurs stratégies pour résoudre ce problème.

a) Orienter le problème La plupart des langages basés sur des blocs conçoivent afin d'éviter ces cas de figure. Par exemple, Scratch ne dispose d'aucun bloc ayant à la fois des effets secondaires et une valeur renvoyée.

b) Créez deux blocs. Si l'espace dans la boîte à outils n'est pas un problème, une solution simple consiste à fournir deux blocs de chaque type, un avec une valeur renvoyée et l'autre sans valeur renvoyée. L'inconvénient est que cela peut entraîner une boîte à outils déroutante, contenant de nombreux blocs presque identiques.

c) Modifier un bloc Utilisez un menu déroulant, une case à cocher ou une autre commande permettant à l'utilisateur de choisir s'il existe une valeur renvoyée ou non. Le volume change ensuite de forme en fonction de ses options. Vous pouvez en voir un exemple dans le bloc d'accès à la liste de Blockly.

d) Prenez la valeur. La première version d'App Inventor a créé un bloc de tuyau spécial qui mangeait n'importe quelle valeur connectée. Les utilisateurs n'ayant pas compris le concept, la deuxième version d'App Inventor a supprimé le bloc pipe et leur recommandait d'attribuer simplement la valeur à une variable non pertinente.

Recommandation: Chaque stratégie a ses avantages et ses inconvénients. Choisissez celle qui convient le mieux à vos utilisateurs.

8. Blocs qui grossissent

Certains blocs peuvent nécessiter un nombre variable d'entrées. Il peut s'agir d'un bloc d'addition qui additionne un ensemble arbitraire de nombres, d'un bloc if/elseif/else avec un ensemble arbitraire de clauses elseif, ou d'un constructeur de liste avec un nombre arbitraire d'éléments initialisés. Il existe plusieurs stratégies, chacune avec ses avantages et ses inconvénients.

a) L'approche la plus simple consiste à faire en sorte que l'utilisateur compose le bloc à partir de blocs plus petits. Exemple : ajouter trois nombres en imbriquant deux blocs d'addition à deux chiffres. Un autre exemple consisterait à ne fournir que des blocs if/else et à faire en sorte que l'utilisateur les imbrique pour créer des conditions elseif.

L'avantage de cette approche est sa simplicité initiale (tant pour l'utilisateur que pour le développeur). L'inconvénient est que, dans les cas où le nombre d'imbrications est important, le code devient très fastidieux et difficile à lire et à gérer pour l'utilisateur.

b) Une alternative consiste à développer dynamiquement le bloc afin qu'il y ait toujours une entrée libre à la fin. De même, le bloc supprime la dernière entrée s'il y a deux entrées libres à la fin. C'est l'approche utilisée par la première version d'App Inventor.

Les blocs qui se développaient automatiquement n'étaient pas appréciés par les utilisateurs d'App Inventor pour plusieurs raisons. Premièrement, l'entrée était toujours libre et le programme n'était jamais "terminé". Deuxièmement, l'insertion d'un élément au milieu de la pile était frustrante, car cela impliquait de déconnecter tous les éléments sous la modification et de les reconnecter. Cela dit, si l'ordre n'est pas important et que les utilisateurs peuvent se sentir à l'aise avec des trous dans leur programme, il s'agit d'une option très pratique.

c) Pour résoudre le problème de trou, certains développeurs ajoutent des boutons +/- pour des blocs qui ajoutent ou suppriment manuellement des entrées. Ouvrir Roberta utilise deux de ces boutons pour ajouter ou supprimer des entrées au bas de l'écran. D'autres développeurs ajoutent deux boutons à chaque ligne pour permettre l'insertion et la suppression à partir du milieu de la pile. D'autres ajoutent deux boutons haut/bas à chaque ligne afin de permettre la réorganisation de la pile.

Cette stratégie est un éventail d'options allant de seulement deux boutons par bloc à quatre boutons par ligne. D'un côté, le risque est que les utilisateurs ne puissent pas effectuer les actions dont ils ont besoin. À l'autre extrémité, l'interface utilisateur est si remplie de boutons qu'elle ressemble à la passerelle du vaisseau spatial Enterprise.

d) L'approche la plus flexible consiste à ajouter une bulle de mutateur au bloc. Il est représenté par un bouton unique qui ouvre une boîte de dialogue de configuration pour ce bloc. Les éléments peuvent être ajoutés, supprimés ou réorganisés à sa guise.

L'inconvénient de cette approche est que les mutateurs ne sont pas intuitifs pour les utilisateurs novices. L'introduction de mutateurs nécessite une certaine forme d'instruction. Les applications basées sur les blocs ciblant les jeunes enfants ne doivent pas utiliser de mutateurs. Bien qu'une fois apprises, elles sont inestimables pour les utilisateurs expérimentés.

Recommandation: Chaque stratégie a ses avantages et ses inconvénients. Choisissez celle qui convient le mieux à vos utilisateurs.

9. Génération de code propre

Les utilisateurs d'Advanced Blockly doivent pouvoir regarder le code généré (JavaScript, Python, PHP, Lua, Dart, etc.) et reconnaître immédiatement le programme qu'ils ont écrit. Un effort supplémentaire est donc nécessaire pour que ce code généré par machine reste lisible. Les parenthèses superflues, les variables numériques, les espaces blancs écrasés et les modèles de code détaillés empêchent tous de produire du code élégant. Le code généré doit inclure des commentaires et être conforme aux guides de style Google.

Recommandation: Soyez fier du code généré. Montrez-le à l'utilisateur.

10. Dépendance linguistique

L'un des effets secondaires de l'intérêt d'un code propre est que le comportement de Blockly est largement défini en termes de comportement du langage de compilation croisée. Le langage de sortie le plus courant est JavaScript. Toutefois, si Blockly effectue une compilation croisée dans un autre langage, aucune tentative déraisonnable ne doit être effectuée pour préserver le comportement exact dans les deux langages. Par exemple, en JavaScript, une chaîne vide est "false", tandis que dans Lua, c'est "true". Définir un modèle de comportement unique pour que le code de Blockly s'exécute quelle que soit la langue cible entraînait la création d'un code difficile à gérer qui semble provenir du compilateur GWT.

Recommandation: Blockly n'est pas un langage. Utilisez le langage existant pour affecter le comportement.