DSL / Model Ignorant Generation


DSL

モデルを意識しない生成

一言要約

コード生成では、全てのロジックが生成されたコードにハードコードされる。 そのため、セマンティックモデルの表現が不明確となる。

要約

仕組み

  • コード生成の有利な点の1つは、管理された方法で手作業で書くためには繰り返しが多くなるコードを作成することができること。
  • モデルを意識しない生成を使うためには、ターゲット環境で具体的なDSLスクリプトの実装を書くことを始めることである。ファウラーは非常にシンプルで最小限のスクリプトを起動する方を好んでいる。
  • 実装コードは明確にするべきだが、ジェネリックや特定のコードを自由に混在させることができ、特定の要素が生成されてから、特定の要素の繰り返しを心配する必要はない。
  • 賢いデータ構造や、よく好まれる手続き型言語は、単純な構造について考えなくてもいいことを意味する。

いつ使うか

  • モデルを意識しない生成を使用するための理由
    • ターゲットとする環境はたいていプログラムを構築し、良いモデルを組み立てるための限られた設備と言語とで影響がある。
  • この状況では、Model-Aware Generationを使うことはできないため、モデルを意識しない生成が、唯一の選択肢となる。
  • Model-Aware Generationを使用したとき、実行時にあまりに多くものリソース要求があるから。
  • 制御してロジックをエンコーディングすることは、必要となるメモリを減らす、もしくは、パフォーマンスを向上させることになる。もし十分クリティカルな状態なのであれば、モデルを意識しない生成は、良い方法となる。
  • しかし、全体的に見ると、ファウラーは可能であれば、Model-Aware Generationを見る方が好きと述べている。Model-Aware Generationの方が、理解したり、修正したりするためにより単純にプログラムを生成してくれるため。
  • コード生成するためのコードを書くことは難しいことだが、効果に影響するため、生成方法を理解しておくことでより簡単にすることができます。

例:ネストされた条件の秘密のパネルのステートマシン(C)

  • 入門の章で使用した秘密のパネルのステートマシンを例に紹介。
  • ミスグラントのコントローラのためにネストされた条件の実装を紹介。
  • ステートマシンの典型的な実装の1つが、現在の状態と受け取ったイベントに基づいて、次のステップが使用する条件式を評価するネストされた条件を使うこと。
  • ここでは、2つの条件(受信イベントと現在の状態)に対して評価を必要としている。この例の場合、現在の状態で開始する。
#define STATE_idle 1
#define STATE_active 0
#define STATE_waitingForDraw 3
#define STATE_unlockedPanel 2
#define STATE_waitingForLight 4

void handle_event(char *code) {
  switch(current_state_id) {
  case STATE_idle: {
   handle_event_while_idle (code);
   return;
 }
 case STATE_active: {
   handle_event_while_active (code);
   return;
 }
 case STATE_waitingForDraw: {
   handle_event_while_waitingForDraw (code);
   return;
 }
 case STATE_unlockedPanel: {
   handle_event_while_unlockedPanel (code);
   return;
 }
 case STATE_waitingForLight: {
   handle_event_while_waitingForLight (code);
   return;
 }
 default: {
   printf("in impossible state");
   exit(2);
 }
 }
}


  • 状態をテストするには、現在の状態を保持するstatic変数を含めます。
#define ERROR_STATE -99
static int current_state_id = ERROR_STATE;
void init_controller() {
  current_state_id = STATE_idle;
}


  • それぞれのサブ機能がより詳細な条件をチェックしており、受信するのはイベントに基づいている。以下は、アクティブな状態のケースになる。
#define EVENT_drawOpened "D2OP"
#define EVENT_lightOn "L1ON"
#define EVENT_doorOpened "D1OP"
#define COMMAND_lockPanel "PNLK"
#define COMMAND_unlockPanel "PNUL"

void handle_event_while_active (char *code) {
 if (0 == strcmp(code, EVENT_lightOn)) {
   current_state_id = STATE_waitingForDraw;
 }
 if (0 == strcmp(code, EVENT_drawOpened)) {
   current_state_id = STATE_waitingForLight;
 }
 if (0 == strcmp(code, EVENT_doorOpened)) {
   current_state_id = STATE_idle;
   send_command(COMMAND_unlockDoor);
   send_command(COMMAND_lockPanel);
 }
}
  • 他のサブ能は非常に似ているが、それらを自身が繰り返し書くことはしていない。
  • このコードは、心配になるくらい別のマシンのために手作業で書くコードが繰り返されるものの、コードが生成されるときにはフォローするのが非常に簡単なコードが提供されることになる。

ファウラーへのフィードバック

担当者のつぶやき

  • Model-Aware Generationをなるべく使えるようにね、ということと解釈しました。

みんなの突っ込み