Jiemamyのアーキテクチャに関する悩み。
みなさん、今日はどうか私の悩みを聞いてください。m(__)m
現在、Jiemamyのアーキテクチャをどの様に構成するか、大いに悩んでいます。こういった状況は、どう対応するのがベストなのか、みなさんのご意見をお聞きしたいです。超長文になりますが、順を追って分かりやすく説明したいと思いますので、宜しくお付き合い下さい。
Jiemamyの概略とプロダクト構成
まず始めに、Jiemamyについて簡単にご説明します。
Jiemamyは、データベース(DB)のモデリングツールです。DBのスキーマをモデル化し、そのモデル(Jiemamyモデル)を、ER図を介して作成・編集することができます。作成したJiemamyモデルは、主にSQLとして出力*1することができます。
つまり、大きく分けて「ER図(Jiemamyモデル)を作成・編集する機能(A)」と「JiemamyモデルをSQLとして出力する機能(B)」で構成されています。
次にプロダクト構成ですが、Jiemamyのプロダクトは以下の2つに分かれます。
- Jiemamy Eclipse Plugin
- 上記A,B(Jiemamyの全機能)を、Eclipseのプラグインとして実装したプログラムです。
- maven-jiemamy-plugin
- 上記Bだけ(JiemamyモデルをSQLとして出力する機能)を、Maven2のプラグインとして実装したプログラムです。
これらのプロダクトは、機能Bが重複していますので、共通部分(JiemamyCORE, JiemamyDIALECT, JiemamyPORTER)を切り出して、処理を共有するようになっています。
- JiemamyCORE
- Jiemamyのコア部分です。主にデータモデル(Jiemamyモデル)を定義しています。
- JiemamyDIALECT
- RDBMSによって異なるSQLの小さな違い(SQL方言)を定義しています。
- JiemamyPORTER
- JiemamyモデルをSQLに変換する為のロジックを定義しています*2。
- JiemamyECLIPSE
- Jiemamy Eclipse Pluginの本体です。Jiemamyモデルの編集機能と、PORTERを呼び出す事によりJiemamyモデルを加工する機能が実装されています。
- Jiemamy Maven2 Plugin
- maven-jiemamy-pluginの本体です。Maven2からPORTERを呼び出すことによりJiemamyモデルを加工する機能が実装されています。
Jiemamyは、以上の5コンポーネントで構成されています。そして、
- Jiemamy Eclipse Plugin = JiemamyCORE + JiemamyDIALECT + JiemamyPORTER + JiemamyECLIPSE
- maven-jiemamy-plugin = JiemamyCORE + JiemamyDIALECT + JiemamyPORTER + Jiemamy Maven2 Plugin
という形で動いています。
Jiemamyの現在のアーキテクチャ
アーキテクチャ図を描くのも初めてなので、正確に表現出来ているか自信がありませんが…。もう少し細かく依存関係図を描いてみます。
Jiemamyの5コンポーネントは、以上のような依存関係になっています。(図が左右非対称で気持ち悪いですね…)
複雑ですね。ちょっとこのままでは理解の妨げにもなると思いますので、今回の悩みのテーマと関係が薄いコンポーネントを省いてみることにします。というわけで、以下、JiemamyCOREとJiemamyDIALECTに関しては、忘れてしまって下さい。
スッキリしました:-) (でも、図が左右非対称で気持ち悪いですね…)
依存関係の解説
- JiemamyECLIPSEは、EclipseAPIに依存します。EclipseプラグインのUI部分ですので、必然的に大きく依存しています。
- JiemamyMaven2Pluginは、Maven2APIに依存します。これも、Jiemamyの機能をMaven2に提供するコンポーネントなので、当然です。
- JiemamyECLIPSEとJiemamyMaven2Pluginは、JiemamyPORTERに依存します。両者とも、Porterを呼び出す立場になりますので。
- JiemamyPORTERは、EclipseAPIに依存します。ここが大きな問題になっています。詳細は後述。
そうです。図を左右非対称にしている張本人です…。
JiemamyPORTERの中身
先ほども述べました通り、JiemamyPORTERは「JiemamyモデルをSQLに変換する為のロジック」、もっと広く言えば
が定義されています。このロジックは、「Jiemamyモデル」と「何か別のデータ形式」の一方が「入力」となり、他方が「出力」となる訳ですが、ロジックによっては、その他の「パラメータ」が必要になることがあります。
- 「Jiemamyモデル」+「パラメータ」 ----(Exporterロジック)----> 「何か別のデータ形式」
- 「何か別のデータ形式」+「パラメータ」 ----(Importerロジック)----> 「Jiemamyモデル」
こんな感じですね。例えば、SQLExporter(JiemamyモデルをSQLファイルに変換する)とDBImporter(RDBMSのスキーマを読み込んでJiemamyモデルに変換する)で言えば、
- 「Jiemamyモデル」+「DROP文,スキーマ名は出力するか? 等」 ----(SQLExporter)----> 「SQLファイル」
- 「RDBMS」+「ドライバ情報, 接続URI, ユーザ名 等」 ----(DBImporter)----> 「Jiemamyモデル」
このようになります。
JiemamyPORTERがEclipseAPIに依存してしまう理由
先ほど、せっかく簡略化された依存関係図ですが、少し分解・加筆をします。
- EclipseAPIを「SWT」と「SWT以外」に分解します。
- JiemamyPORTERを「JiemamyPORTER-LOGIC」と「JiemamyPORTER-UI」に分解します。
- Maven2の「pom.xml」を図中に加筆します。
最初に出てきたSWTについて、詳細は下の記事等をご参考に。簡単に言えば、ボタン,テキスト入力フィールド,コンボボックス,ラジオボタン等の、GUIを作成するためのライブラリです。Eclipse上で「何かの入力画面などを作る場合に必要になります」。(←今日のテーマの重要ポイント)
SWT(Standard Widget ToolKit)とは、Eclipseプロジェクトから提供されているGUI作成用ツールキットです。
http://www.atmarkit.co.jp/fjava/rensai2/eclipse2_07/eclipse07_1.html
さて、こんな感じになった依存関係図。左右対称になりましたね〜。気持ちが良いですね:-)
新しく出てきたコンポーネントの解説です。
- JiemamyPORTER-LOGIC
- 先ほど書いた通り、「Jiemamyモデル」と「何か別のデータ形式」の相互変換ロジックが定義されたコンポーネントです。ロジックなので、UI等のEclipseAPIには依存しません。(依存してしまったら、Maven2上で動きません。)
- JiemamyPORTER-UI
- ユーザに、前節の「パラメータ」を入力してもらう為のUIが定義されたコンポーネントです。UIを定義する為には、SWTに依存する必要があります。
- pom.xml
- Maven2にGUIはありませんので、「パラメータ」はpom.xml中に記述されます。Maven2上でPorterを走らせる時、JiemamyPORTER-UIの代役を果たします。
以上で、Jiemamyの主要部分の動作を結構ディープに理解して頂けたかと思います。
JiemamyPORTERは、Jiemamyに対するプラグイン
ここでちょっと軽い話を。
先ほどから書いている通り、JiemamyPORTERは、「Jiemamyモデル」と「何か」の相互変換ロジックです。
- 「Jiemamyモデル」→「SQLファイル」(SQLExporter)
- 「Jiemamyモデル」→「DTO(Data Transfer Object)ソースファイル」(DTOExporter)
- 「Jiemamyモデル」→「DB仕様書HTML」(SpecificationExporter)
- 「Jiemamyモデル」→「ER図画像ファイル」(GraphicExporter)
- 「既存DBのスキーマ」→「Jiemamyモデル」(DBImporter)
- 「Jiemamyのテストに使う組み込みモデル」→「Jiemamyモデル」(SampleModelImporter)
現在、標準で以上のようなPorterが用意されていますが、ユーザによっては、他の「何か」との相互変換を望む可能性もあると思います。そういった状況に対処する為、Porterを各ユーザが自作できるように設計してあります。つまり、JiemamyPORTERは、Jiemamyに対するプラグインであると考えられます*3。
そこで、上に挙げた6つのPorterは、ユーザが独自Porterを実装する際の「サンプルコード」としての役割も担っています。
悩み1
長かった…。やっと私の「悩み」を説明できる段階にやって来ました。
先ほど、JiemamyPORTERを「JiemamyPORTER-LOGIC」と「JiemamyPORTER-UI」に分解しました。が、現状のJiemamyは、実はこのように分解されておらず、1つのコンポーネントとして存在しています。
そこで、以下の選択肢で迷っています。
- JiemamyPORTERは、プラグインの「サンプルコード」としての役割があるので、分かりやすいように、PorterのLogicとUIは、JiemamyPORTERコンポーネントにまとめて置いておくべきである。ただ、JiemamyPORTERはMaven2からも利用されるので(実際使用しないにもかかわらず)Maven2上で動作する際にEclipseAPI関係の依存コンポーネントを解決する必要がある、という欠点がある。
- 先ほど説明した様に、PorterのLogicとUIは、コンポーネントを分けるべきである。そうすれば、Maven2からはJiemamyPORTER-LOGICを利用するだけなので、EclipseAPI関係の依存は発生しない。ただ、「サンプルコード」が分散してしまい、分かりづらくなってしまう。さらに、1コンポーネントにつき1クラスしか存在しない、大袈裟な実装になってしまう。
- JiemamyPORTERの「UI」部分を切り出して、JiemamyECLIPSEに統合すべきである。見た目はすっきりする。ただ、ユーザが独自Porterを実装する際の指針、という役割が(果たせないってことは無いけれど)非常に弱くなる。
- その他、上手な設計がある。(私の頭では、今のところ浮かびませんT^T)
ベストな選択肢はどれでしょうか?
悩み2
「JiemamyECLIPSE と JiemamyPORTER 両者から使用したい、SWTに依存したクラス」というものが出てきてしまいました。このクラスを、どのコンポーネントに置くべきかを考えました。
- JiemamyPORTER … PORTERはあくまでも「プラグイン」なので、存在しなくても動かなくてはいけないので、ここには置きたくない。
- JiemamyECLIPSE … ここに置くと、JiemamyPORTERはJiemamyECLIPSEに依存していないので、参照することができない。
- JiemamyCORE … 元々SWTに依存していないクラスなので、ここには置きたくない。COREはSWTに依存させたくない。
- JiemamyDIALECT … UIとは関係ないコンポーネント。論外(笑)
- Jiemamy Maven2 Plugin … もっと関係ない(笑)
- JiemamyUTILS … 新たなコンポーネントを作って、そこに配置する。(下図)
どうするべきでしょうか?
〆
長い間、お付き合い頂き、どうもありがとうございました。
どなたか、指針を頂ければ幸いです。m(__)m
*1:SQLの他に、DB仕様書HTMLや、ER図画像ファイル等として出力する事も可能です。この場では、SQL出力を主に考えていきます。
*2:DB仕様書HTMLや、ER図画像ファイル等として出力する為のロジックも定義されています。また、RDBMSからスキーマを読み込む為の(データ入力)ロジックも定義されています。前者をImporter、後者をExporterと呼び、併せてPorterと表現しています。
*3:実際、Jiemamy Eclipse Plugin の「ER図(Jiemamyモデル)を作成・編集する機能(A)」は、JiemamyPORTERが存在しなくても動作するようになっています。