連載

次世代開発基盤技術“Software Factories”詳解

第6回 DSLによるモデル駆動型開発

マイクロソフト株式会社 萩原 正義
2005/09/03
Page1 Page2 Page3 Page4

DSLの構造

 DSLの構成要素は以下の3つである。

  1. メタモデル(抽象構文)
  2. モデルあるいは記法(具象構文)
  3. モデル・エディタ

 モデルを使いモデル駆動型開発を行う場合は、これに「コード・ジェネレータ」が追加となるが、必須ではない。さて、DSLのこの構成要素を分かりやすく説明するために、通常の開発言語を使って説明しよう。通常の開発言語では、モデルはUMLのような図形ではなく、ソース・コードの形をしたテキスト形式である。例えば、モデルとして、以下のコードを考える。

public interface Observer { void Update(object subject); }
public abstract class Subject {
  private ArrayList observers = new ArrayList();
  public void AddObserver(Observer observer) { observers.Add(observer); }
  public void RemoveObserver(Observer observer) { observers.Remove(observer); }
  public void Notify() {
    foreach(Observer observer in observers) { observer.Update(this); }
  }
}
通常の開発言語によるモデルの表現
通常の開発言語では、モデルはソース・コードの形をしたテキスト形式となる。

 このソース・コードの中で、class、interface、foreachなどは構文上の固有の意味を持った開発言語のキーワードである。これらをコンパイラが解釈し、ターゲットのマシン・コードへ変換する。ここでのソース・コードの記法は、構文の意味や概念を人間にとって分かりやすい言葉に置き換えたものである。

 classと同等の概念を例えばUMLのような箱の図形で表現しても、意味に違いはない。問題は編集作業、可読性の観点で、どの記述方法・表現方法が最良かの選択に依存する。

 コンパイラはclassの意味を理解しており、言語仕様で定められるclassの意味定義への参照を作る。コンパイラ自体が実際に参照を作るかどうかは実装に依存するが、通常構文は何らかの抽象データ型の木構造として表現される。この表現を「Abstract Syntax Tree」(AST:抽象構文木)と呼ぶ。すなわち、ソース・コードは、コンパイラ内部ではASTとして表現される。これをメタデータないし「抽象構文」と呼ぶ。

 抽象構文におけるclassの定義は、開発言語の具象構文におけるclassというテキスト形式でも、UMLの箱の図形形式でも、表現できる。すなわち、1つの抽象構文は、複数の具象構文を持つことが可能なのである。これは、例えば顧客データを、RDB(リレーショナル・データベース・システム)の表形式でも、XMLを使ったメッセージ形式でも表現可能なことと類似する。

●DSLにおけるモデルの表現方法と編集方法

 ソフトウェア開発は、テキスト形式のソース・コードが中心であるが、確かに開発対象の意味や設計の意図などを直感的に理解するうえでは図形の方が分かりやすい場合が多い。しかし、従来のCASEツールの多くが図形をベースとした開発を試みて失敗してきた歴史があるのは、図形が示す開発対象に汎用性を持たせすぎていたのが原因の1つである。DSLは、図形またはテキストが示す構文の開発対象領域を絞り、意味を明確化することを前提とする。この点が汎用CASEツールとは異なる。

 テキスト形式のソース・コードは、どのようなエディタでも編集が行える利点がある。IDE開発ツールが高度化しても、テキスト形式のソース・コードが依然として利用される理由は、編集、保存、交換、比較などでのテキスト形式の扱いやすさが最大の理由である。

 これに対応してDSLは、言語定義の中にメタモデルやモデルと並んで、モデル・エディタを自前で持つのが特徴である。モデル・エディタは、提供するDSLモデルのツール・ボックスを持つ。モデルの編集、保存、交換機能などを言語定義の一部として持つことで、テキスト形式のソース・コードの利点を継承する。

●DSLのコード・ジェネレータの特徴と実装方法

 図4はDSLの構成要素間の関係を示している。この図ではDSLによるモデル駆動型開発を行うためのコード・ジェネレータも含んでいる(なおDSLは、モデル駆動型開発における利用だけではなく、モデルの妥当性検証に利用することも可能であり、その場合はコード・ジェネレータが不要である)。

図4 DSLの構成要素
DSLコンパイラは、DSLモデルを解釈しメタモデルで定められる意味定義への参照を作り、抽象データ型の木構造「Abstract Syntax Tree」(AST:抽象構文木)で表現する。コード・ジェネレータは、AST表現、あるいは、ASTの木構造を汎用化したグラフ構造をした抽象データ型「Abstract Syntax Graph」(ASG:抽象構文グラフ)を入力モデルとして、プログラムを生成するための「テンプレート」というメタプログラムを用いて出力モデルやコードを生成する。これらは最終的にはアプリケーション・コードの一部となって、それをターゲット・プラットフォーム(フレームワークやオブジェクト・システム)が実行する。アプリケーション・コードのすべてがコード・ジェネレータにより生成されるのではなく、一部はカスタム開発など従来の手作業による開発を含むのが現実的である。

 コード・ジェネレータは、通常の開発言語のコンパイラでは、マシン・コードを生成する部分であり、ソース・コードを解釈したAST表現を、コード生成のための入力モデルとして用いる。DSLでは、モデルを解釈し、メタモデルの定義を使い、表現されるASTに代えて「Abstract Syntax Graph」(ASG:抽象構文グラフ)を入力モデルに使い、コード・ジェネレータがモデル変換する場合もある。なおASGとは、ASTの木構造を汎用化したグラフ構造をした抽象データ型のメタモデル表現である。

 DSLのコード・ジェネレータは、必ずしも実行可能コードだけを生成するのではなく、別のDSLへの入力モデルを生成し、最終的に出力モデルがターゲット・マシンでの実行可能形式のマシン・コードに変換されればよい。従ってコード・ジェネレータは、一般的にはモデル変換機能を行うプログラムである。例えば、図3のWebサービスDSLの例におけるモデルを変換するコード・ジェネレータが図5である。

図5 モデル変換を行うコード・ジェネレータの例
DSLのコード・ジェネレータは、必ずしも実行可能コードだけを生成するのではなく、別のDSLへの入力モデルをモデル変換して生成する。最終的には出力モデルがターゲット・マシンで実行可能コードになる。

 DSLのコード・ジェネレータの実装にはさまざまな方法があるが、典型的な方法は「テンプレート」というメタプログラムを使う方法である。メタプログラムとは「プログラムを生成するためのプログラム」の意味で、出力モデルを作るための変換ルーチンと考えてよい。

 例えば、出力モデルとして通常のC#のソース・コードを考えると、テンプレートはこのC#のソース・コードの原型となるような、いくつかのカスタマイズ個所をパラメータとして持つひな形である。これは、現在のダイナミック・コンテンツのWebアプリケーションの出力HTML形式を生成するためのスクリプト、ディレクティブを含むコンテンツのひな形と同じ考え方である。

 しかし、メタプログラムをターゲット開発言語ごとに用意すると煩雑になるので、ターゲット開発言語に依存しない中間形式で記述する方法や、大規模ソース・コードを生成する場合はテンプレートを分割する方法などを考慮する必要がある。テンプレートの分割では、DSLにならってドメインや関心による分離をしたり、メタプログラムの一部をさらに別のメタプログラムから生成したりする方法など、多くのバリエーションが存在するが、ここではこれ以上のコード・ジェネレータの実装法は触れないことにする。

 コード・ジェネレータにより生成された出力モデルやコードは、最終的にはアプリケーション・コードの一部となって、それをターゲット・プラットフォーム(フレームワークやオブジェクト・システム)が実行する。アプリケーション・コードのすべてがコード・ジェネレータにより生成されるのではなく、一部はカスタム開発など従来の手作業による開発を含むのが現実的である。(次のページへ続く)


 INDEX
  次世代開発基盤技術“Software Factories”詳解
  第6回 DSLによるモデル駆動型開発
    1.モデル駆動型開発によるEoD
    2.DSLとは
  3.DSLの構造
    4.Software FactoriesにおけるDSLの位置付け
 
インデックス・ページヘ  「次世代開発基盤技術“Software Factories”詳解」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間