カスタム ブロック: スタイルガイド

長年にわたり、Blockly と Blockly のゲームチームは、新しいブロックを開発する場合に役立つ多くの教訓を学んできました。ここでは、Google が犯した誤りと、他の人が犯しがちな誤りの集まりを示します。

これらは Blockly のビジュアル スタイルを使用して習得した一般的な教訓であり、すべてのユースケースやデザインに当てはまるわけではありません。他のソリューションも存在します。また、ユーザーが直面する可能性のある問題とその回避方法を網羅的に列挙しているわけではありません。すべてのケースは若干異なり、独自のトレードオフがあります。

1. 条件とループ

新規ユーザーにとって最も難しいブロックは、条件とループです。多くのブロックベースの環境では、これらのブロックが同じ「コントロール」カテゴリにグループ化され、両方のブロックが同じ形状と色を使用します。これは、新規ユーザーが 2 つのブロックを混同するため、しばしば不満につながります。Blockly では、条件とループを異なる色で別々の「ロジック」カテゴリと「ループ」カテゴリに移動させることをおすすめします。これにより、形状が似ていても、異なる動作である明確なアイデアであることが明確になります。

おすすめの方法: 条件とループを分離します。

2. 1 ベースのリスト

初心者のプログラマーは、ゼロベースのリストに初めて遭遇するとうまく対応できません。そのため、Blockly は Lua と Lambda Moo のように、リストと文字列のインデックスを 1 から始まるようにします。

Blockly のより高度な使い方のために、ゼロベースのリストがサポートされており、テキストへの移行が簡単になります。若年層や初心者でも 1 ベースインデックスが推奨されます

おすすめの方法: 最初の数字は「1」です。

3. ユーザー入力

ユーザーからパラメータを取得する方法は 3 つあります。プルダウンは最も制限の厳しいもので、シンプルなチュートリアルや演習に適しています。入力フィールドは自由度が高く、よりクリエイティブなアクティビティに適しています。値ブロックの入力(通常はシャドウ ブロック)を使用すると、単なる静的な値ではなく、値を計算できます(ランダム ジェネレータなど)。

おすすめの方法: ユーザーに適した入力方法を選択します。

4. ライブ ブロックの画像

ブロックのドキュメントには、参照しているブロックのイメージを含める必要があります。スクリーンショットの撮影は簡単です。しかし、そのような画像が 50 個あり、アプリを 50 の言語に翻訳すると、1 つが 2,500 枚の静止画像を保持することになります。カラーパターンが変わると 2,500 枚の画像がまた更新されます

こうしたメンテナンスの悪夢から脱却するため、Blockly Games はすべてのスクリーンショットを、読み取り専用モードで実行されている Blockly のインスタンスに置き換えました。結果は画像と同じように見えますが、常に最新のものであることが保証されます。読み取り専用モードにより、多言語化が可能になりました。

おすすめの方法: 複数の言語に対応する場合は、読み取り専用モードを使用します。

5. もう 1 つは左

米国の子どもたちからのフィードバックにより(興味深いことに、他の国々からはそう思わない)、左と右の間で混乱が広がることが明らかになりました。これは、矢印を追加することで解決されました。方向が相対的(アバターなど)の場合は、矢印のスタイルが重要です。A → 直線矢印または ↱右向き矢印は、アバターが反対方向を向いていると混乱します。回転する角度が矢印よりも小さい場合でも、⟳ の丸い矢印を使うと便利です。

おすすめの方法: 可能な場合は Unicode のアイコンでテキストを補完します。

6. 上位レベルのブロック

実行パフォーマンスや柔軟性が低下する場合でも、可能な限り上位のアプローチを採用する必要があります。次の Apps Script 式を考えてみます。

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

可能なすべての機能を保持する 1 対 1 のマッピングでは、上記の式は 4 つのブロックを使用して作成されます。Blockly は高レベルを目指しており、式全体をカプセル化する 1 つのブロックを提供します。目標は、残りの 5% がより困難になる場合でも、95% のケース向けに最適化することです。Blockly はテキストベースの言語に代わるものではなく、ユーザーが最初の学習曲線を乗り越えてテキストベースの言語を使用できるようにすることを目的としています。

おすすめの方法: API 全体をやみくもにブロックに変換しないでください。

7. オプションの戻り値

テキストベース プログラミングの多くの関数は、アクションを実行してから値を返します。この戻り値は、使用される場合もあります。スタックの pop() 関数などがこれに該当します。ポップは、最後の要素を取得して削除するために呼び出すか、戻り値を無視して最後の要素を削除するためだけに呼び出すことができます。

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

ブロックベースの言語は通常、戻り値を無視することは得意ではありません。値ブロックは、その値を受け取るものを挿入する必要があります。この問題には、いくつかの方法で対処できます。

a)問題を回避する。ほとんどのブロックベースの言語では、このようなケースを回避するように言語が設計されています。たとえば、Scratch には副作用と戻り値の両方を持つブロックはありません。

b)ブロックを 2 つ指定してください。ツールボックスのスペースが問題にならない場合は、このタイプのブロックを 2 つずつ(1 つは戻り値なしブロック、もう 1 つは返値なし)提供することで簡単に解決できます。欠点は、ほぼ同一のブロックが大量にある、混乱を招くツールボックスが増える可能性があることです。

c)ブロックを 1 つ変更します。プルダウン、チェックボックス、またはその他のコントロールを使用して、戻り値があるかどうかをユーザーが選択できるようにします。ブロックはオプションに応じて形状が変更されます。この例は、Blockly のリストアクセス ブロックで確認できます。

d)価値を食べる。App Inventor の最初のバージョンでは、接続された値を取得する特別なパイプブロックを作成しました。ユーザーがコンセプトを理解できなかったため、App Inventor の 2 番目のバージョンではパイプブロックを削除し、代わりに使い捨て変数に値を代入することを推奨しました。

推奨事項: どの戦略にも長所と短所があります。ユーザーに適した方法を選択してください。

8. 増え続けるブロック

ブロックによっては、入力に必要な数が異なる場合があります。任意の数のセットを合計する追加ブロック、任意の数の elseif 句を含む if/elseif/else ブロック、任意の数の初期化された要素を持つリスト コンストラクタなどがこれに該当します。いくつかの戦略があり それぞれに長所と短所があります

a)最も単純なアプローチは、ユーザーに小さなブロックからブロックを組み立ててもらうことです。たとえば、2 つの数値の加算ブロックを 2 つネストして、3 つの数値を加算します。別の例としては、if/else ブロックのみを提供し、ユーザーがそれらをネストして elseif 条件を作成する場合があります。

このアプローチの利点は、初期が(ユーザーとデベロッパーの両方にとって)簡素であることです。デメリットは、ネストが多数ある場合に、コードが非常に扱いにくく、ユーザーが読み取ってメンテナンスするのが困難になることです。

b)代替方法として、ブロックを動的に拡張して、末尾に空いている入力が常に 1 つになるようにします。同様に、最後に空入力が 2 つある場合、ブロックは最後の入力を削除します。これは、App Inventor の最初のバージョンで使用されたアプローチです。

自動的に増加するブロックは、いくつかの理由から App Inventor のユーザーに好まれませんでした。1 つ目の理由は、常に自由回答があり、プログラムが「完了」することはないからです。次に、スタックの途中に要素を挿入すると、編集下のすべての要素との接続が解除されて再接続されるため、ストレスが伴います。とはいえ、順序が重要ではなく、ユーザーがプログラムの穴を許容できる場合は、非常に便利なオプションです。

c)穴の問題を解決するために、手動で入力を追加または削除する +/- ボタンをブロックに追加するデベロッパーもあります。Open Roberta では、このような 2 つのボタンを使用して、下部での入力を追加または削除しています。他のデベロッパーは、スタックの中央からの挿入と削除に対応するために、各行に 2 つのボタンを追加します。また、スタックの並べ替えに対応するために、各行に 2 つの上下ボタンを追加するものもあります。

1 ブロックあたり 2 ボタンから 1 行 4 ボタンまで、さまざまなオプションがあります。一方の端では、ユーザーが必要なアクションを実行できないという危険があります。もう一方の端では、UI がボタンでいっぱいになっていて、宇宙船エンタープライズの橋のように見えるのです。

d)最も柔軟なアプローチは、ブロックにミューテータ バブルを追加することです。これは、そのブロックの構成ダイアログを開く 1 つのボタンとして表示されます。要素は自由に追加、削除、再配置できます。

この方法の欠点は、初心者にとってミューテータを直感的に利用できないことです。ミューテータを導入するには、なんらかの形式の指示が必要です。年齢の低い子供を対象とするブロックベースのアプリでは、ミューテータを使用しないでください。一度学んだとしても、パワーユーザーにとっては貴重なものです。

推奨事項: どの戦略にも長所と短所があります。ユーザーに適した方法を選択してください。

9. クリーンなコード生成

高度な Blockly ユーザーは、生成されたコード(JavaScript、Python、PHP、Lua、Dart など)を見て、自分で作成したプログラムをすぐに認識できるようにする必要があります。つまり、この機械生成されたコードを読みやすくするには特別な労力が必要です。余分な括弧、数値変数、破棄された空白文字、冗長なコード テンプレートはすべて、洗練されたコードの生成の妨げとなります。生成されるコードにはコメントが含まれ、Google のスタイルガイドに準拠している必要があります。

推奨事項: 生成されたコードを自慢しましょう。ユーザーに提示してください。

10. 言語の依存関係

コードをクリーンにすることを求める副作用は、Blockly の動作が、クロスコンパイルされた言語の動作に関して大部分が定義されていることです。最も一般的な出力言語は JavaScript ですが、Blockly が別の言語にクロスコンパイルする場合、両方の言語で正確な動作を維持するために、合理的な理由なしに試行しないでください。たとえば、JavaScript では空の文字列は false ですが、Lua では true です。ターゲット言語に関係なく実行できるように Blockly のコードが単一の動作パターンを定義すると、GWT コンパイラから送信されたように見える、保守ができないコードになります。

おすすめの方法: Blockly は言語ではないため、既存の言語が動作に影響しないようにしてください。