Blocchi personalizzati: guida di stile

Nel corso degli anni il team di Blockly e Blockly Games ha imparato molte lezioni che sono applicabili a chi sviluppa nuovi blocchi. Di seguito sono riportati una raccolta di errori che abbiamo commesso o di errori comunemente commessi da altri.

Queste sono lezioni generali che abbiamo imparato utilizzando lo stile visivo di Blockly e potrebbero non essere applicabili a tutti i casi d'uso o a tutti i progetti. Esistono altre soluzioni. Inoltre, non si tratta di un elenco esaustivo dei problemi che gli utenti potrebbero riscontrare e di come evitarli. Ogni caso è leggermente diverso e ha i propri compromessi.

1. Condizionali e loop

I blocchi più difficili per i nuovi utenti sono i condizionali e i loop. Molti ambienti basati su blocchi raggruppano entrambi questi blocchi nella stessa categoria "Controlli", in cui entrambi i blocchi hanno la stessa forma e lo stesso colore. Questo genera spesso frustrazione, in quanto nuovi utenti confondono i due blocchi. Blockly consiglia di spostare condizionali e loop in categorie "Logica" e "Loop" separate, ciascuna con un colore diverso. Ciò chiarisce che si tratta di idee distinte che si comportano in modo diverso pur avendo forme simili.

Consiglio: tieni separati le condizionali e i loop.

2. Elenchi in base una sola

I programmatori principianti reagiscono male quando trovano per la prima volta elenchi basati su zero. Di conseguenza, Blockly segue l'esempio di Lua e Lambda Moo definendo un'unica base per l'indicizzazione di elenchi e stringhe.

Per usi più avanzati di Blockly, sono supportati elenchi in base zero per semplificare la transizione al testo. Per i giovani o per i principianti, è comunque consigliata l'indicizzazione con un'unica posizione.

Consiglio: uno è il primo numero.

3. Input utente

Esistono tre modi per ottenere un parametro dall'utente. Un menu a discesa è quello più restrittivo ed è ideale per tutorial ed esercizi semplici. Un campo di immissione consente maggiore libertà ed è ideale per attività più creative. Un input di blocco di valore (di solito con un blocco shadow) offre l'opportunità di calcolare un valore (ad es. un generatore casuale) anziché essere solo un valore statico.

Consiglio: scegli un metodo di inserimento appropriato per i tuoi utenti.

4. Blocca immagini live

La documentazione relativa ai blocchi deve includere immagini dei blocchi a cui fa riferimento. Acquisire screenshot è facile. Ma se ci sono 50 immagini di questo tipo e l'applicazione viene tradotta in 50 lingue, all'improvviso si riesce a mantenere 2500 immagini statiche. Poi la combinazione di colori cambia e 2500 immagini devono essere aggiornate.

Per riprenderci da questo incubo di manutenzione, Blockly Games ha sostituito tutti gli screenshot con istanze di Blockly in esecuzione in modalità di sola lettura. Il risultato è identico a un'immagine, ma è garantito che sia aggiornato. la modalità di sola lettura ha reso possibile l'internazionalizzazione.

Consiglio: se supporti più lingue, utilizza la modalità di sola lettura.

5. L'altro lato sinistro

I feedback dei bambini negli Stati Uniti (anche se interessante non provenienti da altre nazioni) hanno rivelato una dilagante confusione tra destra e sinistra. Questo problema si è risolto con l'aggiunta di frecce. Se la direzione è relativa (ad esempio, rispetto a un avatar), lo stile della freccia è importante. Una freccia dritta → o una freccia di svolta ↱ crea confusione quando l'avatar è rivolto nella direzione opposta. La più utile è una freccia circolare ⟳, anche nei casi in cui l'angolo ruotato è più piccolo di quello indicato dalla freccia.

Consiglio: se possibile, integra il testo con icone Unicode.

6. Blocchi di alto livello

Ove possibile, si dovrebbe adottare un approccio di livello superiore, anche se riduce le prestazioni o la flessibilità dell'esecuzione. Considera questa espressione Apps Script:

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

In una mappatura 1:1 che conserva tutte le potenziali funzionalità, l'espressione sopra riportata viene creata utilizzando quattro blocchi. Tuttavia, Blockly punta a un livello superiore e fornirebbe un blocco che incapsula l'intera espressione. L'obiettivo è eseguire l'ottimizzazione per il caso del 95%, anche se ciò rende più difficile il restante 5%. Blockly non è pensato per sostituire le lingue basate su testo, ma è destinata ad aiutare gli utenti a superare la curva di apprendimento iniziale in modo da poter utilizzare le lingue basate su testo.

Consiglio: non convertire alla cieca l'intera API in blocchi.

7. Valori di ritorno facoltativi

Molte funzioni nella programmazione basata su testo eseguono un'azione, quindi restituiscono un valore. Questo valore restituito può essere utilizzato o meno. Un esempio è la funzione pop() di uno stack. Pop potrebbe essere chiamato per recuperare e rimuovere l'ultimo elemento oppure per rimuovere solo l'ultimo elemento con il valore restituito ignorato.

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

Le lingue basate su blocchi in genere non sono adatte a ignorare un valore restituito. Un blocco di valore deve essere collegato a un elemento che accetta il valore. Esistono varie strategie per affrontare questo problema.

a) Concentrati sul problema. La maggior parte dei linguaggi basati su blocchi progetta il linguaggio in modo da evitare questi casi. Ad esempio, Scratch non ha blocchi con effetti collaterali e valore restituito.

b) Prevedi due blocchi. Se lo spazio nella toolbox non è un problema, una soluzione semplice è fornire due di ciascuno di questo tipo di blocco, uno con e uno senza un valore restituito. Lo svantaggio è che questo può creare strumenti confusi con molti blocchi quasi identici.

c) Modifica di un blocco. Utilizza un menu a discesa, una casella di controllo o un altro controllo che consenta all'utente di scegliere se deve essere restituito o meno un valore. Il blocco cambia forma in base alle opzioni. Un esempio può essere visto nel blocco di accesso all'elenco di Blockly.

d) Mangiare il valore. La prima versione di App Inventor creava un blocco pipe speciale che conteneva qualsiasi valore collegato. Gli utenti non comprendevano il concetto e la seconda versione di App Inventor ha rimosso il blocco barra verticale, consigliando invece agli utenti di assegnare semplicemente il valore a una variabile usa e getta.

Consiglio: ogni strategia ha pro e contro, scegli quella più adatta per i tuoi utenti.

8. Blocchi in crescita

Alcuni blocchi potrebbero richiedere un numero variabile di input. Alcuni esempi sono un blocco di addizione che somma un insieme arbitrario di numeri, un blocco if/elseif/else con un insieme arbitrario di clausole otherif oppure un costruttore di elenchi con un numero arbitrario di elementi inizializzati. Esistono diverse strategie, ognuna con vantaggi e svantaggi.

a) L'approccio più semplice consiste nel fare in modo che l'utente componga il blocco di blocchi più piccoli. Un esempio potrebbe essere l'aggiunta di tre numeri, mediante la nidificazione di due blocchi aggiuntivi di due numeri. Un altro esempio potrebbe essere fornire solo i blocchi if/else e fare in modo che l'utente li nidifica per creare condizioni otherif.

Il vantaggio di questo approccio è la sua semplicità iniziale (sia per l'utente che per lo sviluppatore). Lo svantaggio è che, in caso di elevato numero di annidamento, il codice diventa molto ingombrante e difficile da leggere e gestire per l'utente.

b) Un'alternativa è espandere dinamicamente il blocco in modo che ci sia sempre un input libero alla fine. Allo stesso modo, il blocco elimina l'ultimo input se ci sono due input liberi alla fine. Questo è l'approccio utilizzato dalla prima versione di App Inventor.

Gli utenti di App Inventor non hanno apprezzato i blocchi che crescevano automaticamente per un paio di motivi. Innanzitutto, c'era sempre un input senza costi e il programma non era mai "completo". In secondo luogo, inserire un elemento al centro dello stack era frustrante, poiché comportava la disconnessione di tutti gli elementi al di sotto della modifica e il loro collegamento. Detto questo, se l'ordine non è importante e gli utenti possono sentirsi a proprio agio con le lacune nel programma, si tratta di un'opzione molto comoda.

c) Per risolvere il problema delle interruzioni, alcuni sviluppatori aggiungono pulsanti +/- per i blocchi che aggiungono o rimuovono manualmente gli input. Apri Roberta usa due di questi pulsanti per aggiungere o rimuovere input dal basso. Altri sviluppatori aggiungono due pulsanti in ogni riga per agevolare l'inserimento e l'eliminazione dal centro dello stack. Altre aggiungono due pulsanti Su/Giù in ogni riga in modo che il riordinamento dello stack possa essere ridotto.

Questa strategia prevede una gamma di opzioni che vanno dai soli due pulsanti per blocco a quattro pulsanti per riga. Da un lato c'è il pericolo che gli utenti non siano in grado di eseguire le azioni di cui hanno bisogno, dall'altro l'interfaccia utente è così piena di pulsanti che sembra il ponte dell'astronave Enterprise.

d) L'approccio più flessibile consiste nell'aggiungere una bolla mutatore al blocco. Viene rappresentato come un singolo pulsante che apre una finestra di dialogo di configurazione per il blocco in questione. Gli elementi possono essere aggiunti, eliminati o riorganizzati a piacimento.

Lo svantaggio di questo approccio è che i mutatori non sono intuitivi per gli utenti alle prime armi. Per presentare i mutatori è necessario un qualche tipo di istruzione. Le applicazioni basate su blocchi rivolte ai bambini più piccoli non devono utilizzare mutatori. Anche se una volta appresi, sono inestimabili per gli utenti esperti.

Consiglio: ogni strategia ha pro e contro, scegli quella più adatta per i tuoi utenti.

9. Generazione di codice puro

Gli utenti Blockly avanzati devono essere in grado di esaminare il codice generato (JavaScript, Python, PHP, Lua, Dart e così via) e riconoscere immediatamente il programma che hanno scritto. Ciò significa che è necessario fare ulteriori sforzi per mantenere leggibile il codice generato automaticamente. Parentesi superflue, variabili numeriche, spazi vuoti schiacciati e modelli di codice dettagliati compromettono la produzione di codice elegante. Il codice generato deve includere commenti e deve essere conforme alle guide di stile di Google.

Consiglio: vai orgoglioso del codice che hai generato. Mostralo all'utente.

10. Dipendenza dalla lingua

Un effetto collaterale del desiderio di un codice pulito è che il comportamento di Blockly è in gran parte definito in termini di comportamento del linguaggio cross-compilato. Il linguaggio di output più comune è JavaScript, ma se Blockly eseguisse la cross-compilazione in una lingua diversa, non dovrebbero essere fatti tentativi irragionevoli per preservare il comportamento esatto in entrambe le lingue. Ad esempio, in JavaScript una stringa vuota è falsa, mentre in Lua è vera. La definizione di un singolo pattern di comportamento per l'esecuzione del codice di Blockly indipendentemente dalla lingua di destinazione comporterebbe un codice non gestibile che sembra essere uscito dal compilatore GWT.

Consiglio: Blockly non è una lingua, consenti al linguaggio esistente di influire sul comportamento.