API構築の基礎を学んだ。QConは、開発者コミュニティにおける知識とイノベーションの普及を促進することで、ソフトウェア開発に力を与える。実務者主導のカンファレンスであるQConは、チーム内のイノベーションに影響を与える技術チームのリーダー、アーキテクト、エンジニアリングディレクター、プロジェクトマネージャー向けにデザインされている。Sheehy氏は、人工知能ハイプ時代における責任ある開発者としてのあり方について、洞察に富んだ開会基調講演をした。Grizzanti氏が、「スタッフ・プラス」への道と、それを「科学」というより「芸術」としてとらえ、芸術を創作することとソフトウェアを創作すること、そして組織のダイナミクスに対処することの類似性について語っている。Codeを採用する:確認するべき6つの適性LCNC(ローコード/ノーコード)プラットフォームは、プログラマーだけでなくプログラマーでなくても、最小限のコーディングとワンクリックのデプロイメントで、アプリケーションソフトウェアを開発できるよう設計されている。ドラッグ&ドロップ方式のインターフェースなどを利用することで、開発・デプロイメントプロセスを簡素化し、効率的なアプリケーション開発とデプロイメントを実現する。[1][2])はもはや業界の非主流派ではない。大成功してより多くのソフトウェアプロジェクトで適用されている。この記事では、過去数年間に集めた経験に基づきベストプラクティスへの私たちの貢献を伝えたいと思う。コードジェネレータがでてきてからしばらく経っているので、必然的に、この記事はこの分野でベストプラクティスに関して解説する最初の記事ではないこれらの以前に述べられたプラクティスのいくつかはしっかりと定着したが、一方では、関連がなくなったり、すでに廃れてしまったりしたプラクティスさえある。この記事の最初の部分では「時の試練に耐えた」これらの原則を扱う。他の新しいベストプラクティスはまだはっきりしていないが、時間をかけて明らかになってきている。これらについてはこの記事の二番目の部分で解説する。重大な基本的提案から始めよう。生成したコードと手書きのコードをお互いに分離する関連スポンサーコンテンツ重大な点ではあるけれども何度も繰り返して無視されることがある。すべての成果物はそれが生成されたものであるか、開発者によって操作されたものであるか、はっきりと明白でなければならない。これは、ユーザが後で追加したり変更したりするコードにコードジェネレータを使うべきではないという意味ではない。これは明示的にしなければならず、とりわけこのコードは一度だけ生成すべきである。(『用語解説』を参照)100%生成したコードは、変更したり、リポジトリにチェックインしたりすべきではない。それは使い捨てにできるものであり、重要な成果物はモデルなのだ。受動的なコード生成、つまり「ウィザード」型の1回限りの生成は最近とても人気がある。フレームワークで新しいプロジェクトの最初の段階は可能な限り簡単なものになっている。これは、最初はとても役に立ち、フレームワークの受け入れをかなり促進できる。これらの最初の段階はプロジェクトのライフサイクルのほんの少しの部分を構成するものであり、ユーザに短期間の支援を提供するにすぎない。このベストプラクティスに反して相対的に広まっていることは、保護されたリージョンを使うことである。これは、ジェネレータが上書きしない生成したコードのテキストリージョンを指す。保護されたリージョン内で開発者は手書きで変更でき、ジェネレータがそのギャップを埋める。することにより生成したコードはファーストクラスのコードのレベルに上がり、例えば、チェックインしなければならなくなるのだ。(追加の作業も発生する)さらに開発者が書き込んだ保護されたリージョンはアクティベートされなければならない。なければ保護されていない状態になる。プロジェクトの熱い戦いの最中にこれは簡単に見過ごされるので、コードが失われ、長い時間エラーを調査して大きな苛立ちを感じることになる。それでは、実際のベストプラクティスはどのようなものか?2つのバリエーションがあって、うまい具合に一緒に使うこともできる。生成したコードに別のディレクトリを準備すべきである。src-gen)こうすれば生成したコードと生成していないコードの物理的な分離ができる。MODIFY」のようなコメントで始めるべきである。完璧主義の人は、そのコードがどのテンプレートで生成したかを追記してこれを補うかもしれない。どちらのオプションも、IDEの中で生成したファイルと生成していないファイルを区別するのに使うことができる。生成したコードをチェックインしない生成したコードはチェックインすべきではない。それはJavaのバイトコードや他の派生した成果物をチェックインすべきではないのと同じ理由である。派生した成果物は100%冗長であり、それらは再生可能ではない情報は含んでいない。そのような成果物をチェックインすることは、管理するデータのボリュームを増加させ、同期化するたびにコンフリクトが発生する。それらのコンフリクトは、OverrideとCommitを使うときは無視するほうがよいのだ。一方で、すべてチェックインすれば、あなたはもう一杯コーヒーを取りに行けるかもしれないが......保護されたリージョンでこの問題はさらに大きくなる。そのような場合、すべてを単に上書きすることができないからだ。同時に他の開発者が保護されたリージョンを変更していることもありえるだろう。生成したコードをチェックインする意味があるのは、唯一なんらかの理由でビルドプロセス中に実行するジェネレータを統合することができない場合である。ジェネレータをビルドプロセスに統合するビルドプロセスの自動化は、開発チームの生産性を大いに改善する方法である。これに関して重大な点は、プロセスを実際に完全に自動化し、手動の作業をなくすことである。(必要な場所で)、テストプラットフォームの配置とユニットテストの実行で構成される。MDSDプロジェクトでは、生成フェーズはコンパイルフェーズの前に追加されなければならない。ビルドプロセスはローカルだけでなくこの目的のために設置されたサーバー上でも実行されることは言うまでもない。ターゲットプラットフォームのリソースを使うターゲットフラットフォームの概念はさまざまなタスクに役立つ。わずかに表現される部分から成る。DSLが一般的に役に立つ分野はドメインモデルやサービスレイヤーなどのスキーマ情報を扱う。これらのレイヤーにも含まれているロジックはいかなるプログラミング言語でもうまい具合に定義できる。保護されたリージョンを使って生成したコードにロジックを統合する代わりに、ターゲット言語の構造を使い、異なるファイルにさまざまなアスペクトを置くオプションがある。一方は生成され、他方は不足している情報を追加しながら開発者によって提供されるのである。Javaでは継承が使える。その価値が証明されている。一般的フレームワークによって提供され、その属性や振る舞いは生成された同様な抽象クラスによって継承される。具象クラスはこの生成されたクラスから継承する。三段階の継承もちろん、継承やデリゲーションの組み合わせのようにさらに数多くのバリエーションがある。他のターゲット言語で、Includesのように他の概念は適切な場所で使わなければならない。クリーンなコードを生成する単にコードを自動的に生成したからといって、二度と再び人間の目で読まれないという意味ではない。生成したコードはそれ故に手書きのコードに適用するのと同じ品質の要求を満たすべきである。同質のコードベースは、後の理解とエラー箇所の発見をずっと容易にする。生成プロセスと直接連動してコードフォーマッターを使うことによって、コードの挿入とフォーマットはテンプレートの複雑さを増すことなく自動化できる。生成したコードは適切なコードスタイルに従い、きちんと確立されたデザインパターンを使うべきである。コンパイラを使うターゲットプラットフォームを使う別の機会は、ターゲット言語のコンパイラを通して開発者とコミュニケーションすることである。上述した3段階の継承が使われた場合、それぞれのメソッドを実装するために抽象メソッドが生成されるだろう。コンパイラは、開発者が具象クラスにこのメソッドを実装するように要求するだろう。自分自身へのもっと複雑な依存関係では、開発者がまだ作成していないコードを使ってダミーのコードを生成することをコンパイラは可能にするだろう。Recipeは、各ジェネレータを実行した後、ある状態になるかどうか開発者に確認するよう指示する。特定のクラスを手動で作成し、それが生成されたクラスから継承しているかどうかといったことである。その状態にならない場合、開発者は随時通知を受ける。中でユビキタス言語の概念を記述している。このアイデアの最重要ポイントは、プロジェクトで技術的、または、専門的な概念を定義し、それに関してすべての参加者がコミュニケーションできる1つの同一言語を開発することである。このようにして、複雑な概念がはっきりと明示的に扱われる。その結果として、プロジェクトの重要で「生きている」コンポーネントになることができる。これらの概念とそこで使われる言葉は、プロジェクトのすべての段階に相互に関連がある。このモデルがメタモデルに関連する概念に使われる場合、技術的な概念にも明白な名前と意味を与えるべきである。専門用語と意味を一貫して用いることにより、例えば、チームミーティングで重要なアスペクトがさらにはっきりと説明できる。決定された概念がもはや要求に合っていないとき、それもすぐに明らかになる。そのような場合、DSLは変更されたフレームワークの状態に適応させなければならない。繰り返しDSLを開発するDSLは前もって準備された方法を使って開発されるのではなく、理想で言えば、APIと同じで徐々に増やしていくものである。明らかな核となる抽象化を定義する。記述されたドメインを理解しながら、個々の要素を追加したり、削除したりする。DSLは公開されたインタフェースで、API開発の原則もこの分野に当てはまる。インタフェースのライフサイクルに関してはすでに合意したものであり、既存の規約を将来の開発プロセスの中で破ってはいけない。どのような場合であっても、DSLの中心にある技術は移行機能に大きな影響を持つ。新しく導入された概念ではもはや利用できないものを置き換えるために、手動でモデルを移行するには、エディタに古いモデルを読み込まなければならない。XMIやデータベースを使ったオブジェクトベースの保存は、しばしばメタモデルへの変更がそれらの互換性をなくすため、使えなくなることが多い。そのような場合、古いシステムから新しいメタモデルへのモデル変換を使ったプログラムで移行が行われなければならない。なければ、保存フォーマットレベルに落として古いデータを互換性のあるものにしなければならないのだ。場合は、移行はもちろんずっと簡単である。繰り返しモデル検証を開発するすでに強調されているように、モデル駆動開発プロセスは処理されているモデルがマシンで読むことができる正式な形式で利用できることを前提にしている。モデルが持つ形式は、そのメタモデルで決まっていて、同時にモデリングツールの土台を形作る。(実際のところ、メタモデルとは関係なく動くモデリングツールがあり、その結果としてMDSDのモデルチェーンで深刻な問題を引き起こしている。)さて、正当なモデリングツールは形式的に正しいモデルのみを作成すると仮定できるはずだ。すれば、モデルはジェネレータで問題なく処理できる。これは残念ながら間違っている。メタモデルは、作成されたモデルの静的な面を記述しているに過ぎない。セマンティクスはこの静的情報で表現することはできない。例として、「限定されたステートマシンで、各ステートは一度だけ出現できる」という条件がある。この条件は普通のメタモデル言語で表現できない。この問題をうまく避けるためにOCLやoAWのCheckのような制約言語が作られたのである。これにより先程述べたような(「すべてのマシーンステートの中で名前が重複してはいけない」)条件が表現できる。「限定されたステートマシンで、各ステートが他のステートに遷移によって接続されていなければならない」という条件は、直接メタモデルの中でも実装できる。(1...nという多重度によって)このような場合、制約がそれでもなお好まれることが多い。ひとつはメタモデルが結果としてよりはっきりと簡単になるからであり、もうひとつはモデル設計中にできる中間ステートが全体的なスキーマに従うからである。それは多くのツールにとって保存時の基本的な前提条件である。制約は繰り返し開発されるべきである。第一に、明らかに正しいと思われる制約が定義される。プロジェクトの最中に生成エラーが発生するとすぐに、制約がこの問題を解決するのに使われる。そのエラーは、モデルのチェックが不完全であることが原因で起こったものである。このように、モデルの妥当性チェックはだんだん完成してギャップがなくなっていく。レファレンスモデルを使ってジェネレータをテストする。できれば自動テストスイートを使ってコードジェネレータ自身もテストされるべきである。やってこれを実現するのか?よく知られている選択肢は、ソースのテキストを予想されるソースコードと単に比較することである。この構成はとても脆弱で、ジェネレータの非常に小さな変更でさえテストを無効にする。実際のところ、生成したコードが要求にあう方法でターゲットプラットフォームの中で動くことを確認することが目的である。これは、生成したコードをテストするのにユニットテストを使ってとても簡単に実現できる。ほとんどのターゲット言語には対応するフレームワークがある。このプロセスで、レファレンスモデルは特徴的な方法を用いてDSLの概念を使って生成される。この場合、特徴的という意味は、例のドメインが「発明されて」使われたのではなく、表されているDSLの概念によってモデル要素の名前がつけられることである。ドメインモデルDSLのレファレンスモデルは、例えば、以下のようになる。etc...理想を言えば、テストスイートはそのようないくつかのレファレンスモデルと関連するテストで構成される。そのテストは異なるアスペクトと組み合わせを記述するだろう。次のイテレーションで、新しいレファレンスモデルは、取り除く前に不具合を見つけるために利用できる。既存のレファレンスモデルとそれぞれのテストはこのプロセスで妥協することはない。ちなみに、モデル検証とモデル変換は同じようにこの方法でテストでき、また、そうすべきでもあるのだ。適切な技術を選択するモデルを表現し編集する多数の異なる方法がある。どの技術やシンタックスが適切であるかは、一般的な要求やプロジェクトの文化によるであろう。この点は、決め手となるドメインの型だけでなく他の選択肢と比べてどれだけ技術の適応性があるか、そして、開発プロセスでどれだけ尽力が要求されるかという問題でもある。考慮すべき点は、技術がアプリケーション開発者の開発プロセスと既存のツール群に統合されるときの容易さである。統合は今日ではほぼ必要条件である。理想を言えば、シンタックスはコアな抽象化をはっきりと識別し、それほど問題なく拡張できるとよい。記述的で素早い編集に対応できるとよい。完璧な技術というものは、残念ながらまだ存在しない。UMLでのモデリングは、言語を定義すること、つまり、プロファイルの定義で時間と労力を使う小さな初期投資を意味することが多い。一方で、ほとんどの場合、結果を得るまでの時間はとても長い。DSLでもツールでもそれほど簡単には拡張できず、モデルを処理しながらとても大きく複雑なメタモデルを受け入れなければならない。私たちの経験から言うと、「本物の」DSLを使うプロジェクトの大部分はその価値がある。それぞれのドメインの要求がぴったりとはまり、重いものを何も持たないように調整してありさえすれば。(他の複雑なメタモデルも)技術を選ぶとするとすべての警告にもかかわらず、結局UMLになる。ドメインでさらに簡単なメタモデルへと処理する前にUMLモデルを変換することになるのだ。これで後に続く下流のプロセス段階は、より簡単でエラーが起こりにくくなるだろう。モデルの検証は変換の後で行われるべきである。これによって、制約も簡単にドメインに特化して定式化できるようになる。この非干渉化により、ジェネレータを変更しなくても後の段階で「本物の」DSLに移行するさらなる可能性が出てくる。グラフィカルなシンタックスを正しく使うグラフィカルなモデリングは大きな強みがある。それは、はっきりとした簡単な方法で重要な要素間の関係を表現する。詳細が書かれているからではなく視覚的に表現されているため、多くの情報がずっと早くまとめられる。グラフィカルなモデルを使うとき、視覚化によって得られる可能性を活用することができる。視覚的な方法でモデル要素のもっとも重要な特徴を表現するシンタックスを見つけるようにしよう。UMLは、これに関してとても役に立つロールモデルである。この場合について例を挙げると、抽象クラスはイタリック体の名前によって識別される。オペレータを使ったアノテーションは、グラフィカルなDSLでもテキストのDSLでも両方使える。気をつけて!シンタックスはあっという間に情報でいっぱいになる。図がごちゃごちゃしていたり、散らかったりしていてはいけない。例を挙げれば、テキストをあらゆる種類のフォントとフォーマットで表してはいけない。これは正しいバランスを崩すような問題である。画面設計の基本的原則はこの方面で役に立つヒントを与えてくれる。テキストのシンタックスを正しく使うテキストのシンタックスを定義しているときに、簡潔であることと包括的であることの間のちょうどよい妥協点にたどり着くことが重要である。モデラーがどれほどの専門性を持っていると期待されるかによって、解説のキーワードを省略することができるかもしれない。以下でJavaの見慣れたシンタックスを比較する。それは、架空ではあるが、可能性のある代案として抽象クラスの定義のシンタックスを表わす。abstract=trueJavaのシンタックスが架空のものより読みやすいことはおそらく疑問の余地はない。それは自己表現的ではない。架空のシンタックスでは、どの属性にどの値を割り当てるかが明確になっている。ユーザはメタモデルを知っていればよいだけで、シンタックスは明らかである。XMLはちょうどこの方法で機能する。私たちの意見では、このことは明らかになっていないけれども、シンタックスが明白で簡単に理解できることは、実際にはXMLの小さな利点である。表現力と明示性の適切なバランスは重要である。シンタックスをたくさんのシンタックスシュガーを使って表現できるかどうかはDSLのユーザ次第である。彼らがスマートでDSLをたくさん使う場合、さらに表現力が豊かになる。ない場合は、シンタックスは明示性を強化すべきである。例外による設定を使うさらに重要な点は、設定に関して正しく選択し、よく考えたアプリケーションを使うことである。すべての情報が示されるグラフィカルなシンタックスとは対照的に、通常、ある種のプロパティビューやテキストのモデリングの中で情報がデフォルトである場合、その情報が簡単に除かれることがある。一度、これをJavaで見てみよう。以下に別に作成した架空のシンタックスを示す。abstract=false非常に簡単にわかるように、設定を正しく選択することで読みやすさは大いに改善できる。それは、最初から絶対はっきりさせておくべきであるが、これらの設定はAPIの一部でもある。デフォルトは、既存のAPIの規約を破らずに過去にさかのぼって変更できない。する前に二度考えよう。チームワークはテキストのDSLが好き古典的なモデリングツールはチームワークに関して問題がある。この理由は、モデルが保存される方法にある。UMLツールは、通常1つの大きなXMIファイルにモデルを保存する。技術的かつ一般的形式である。基本となるXMIモデルのコンフリクトをすでに解決しようとした人は、これがどのような問題を引き起こすのか知っている。長く不可解なUUIDを使って参照することは、私たち開発者にとって単に手に余ることなのだ。そのような場合にはコンフリクトを避けようとする。モデルに排他的な書き込みアクセス権限だけを与えたり、モデルに非常に細かい粒度のパーティション構造を使ったりする。この問題の本質を探るために、読みやすく簡単にメンテナンスできるフォーマットでモデルを保存することも考えるべきである。今日、1つのDSLで複数のシンタックスを持つのは全く可能であり、例えば、テキストのDSLにグラフィカルなエディタを使うことさえできる。多くの専門的なUMLツールは、チームサーバがあり、チームは異なった方法でモデリングできる。残念ながら、これはツールチェーンを壊すことにもなる。2つの別々なツールと2つの別々なリポジトリを使わなければならないのである。これは、統合ビルドなどに関して、さらにマイナスの影響がある。この複雑さを扱う1つの方法は、ジェネレータを2つの部分に分けることである。(「分断攻略」)このプロセスで、生成するコードにできるかぎり近くなるようにモデルは設計される。モデル変換はこの入力モデルを新しいメタモデルとして同じタイプの一時モデルに変換する。コードジェネレータは一時メタモデルからターゲットプラットフォームにマップするだけである。この手順には、メタモデルを通して明らかなインタフェースを作成するといううれしい副作用がある。各部分は異なるチームで開発され、他のシナリオでお互いに独立して再利用できる。そのような一時的段階は、必要なだけコードジェネレータに統合できる。モデル変換を使う場合、MDAでは多くのカスケードレイヤーを推奨する。これは、さまざまなプラットフォームを分離するためである。著者の控えめな意見では、これは実際のところ実行可能ではない。:-)広範囲のプラットフォームのために生成するモデルからコードへの変換をできる限り小さくして、ジェネレータの複雑さを最小限にするもう1つの重要な方法がある。それは、できる限り遠いところでジェネレータに対応するプラットフォームを開発することである。