見出し画像

フレームワーク

本ドキュメントの利用は、https://github.com/kae-made/kae-made/blob/main/contents-license.md に記載のライセンスに従ってご利用ください。

GUI や Web サービス、メッセージ駆動による状態機械など、様々なアプリケーションで共通に使われる制御を一般化して制御の骨格を抽出し、特定のプログラミング言語で利用可能にしたものを、フレームワークと呼びます。フレームワークは、個々のアプリケーションに特化しない共通の制御の流れを実現するためのデータ構造とロジックを実装したライブラリと、個々のアプリケーションがそのフレームを使うための決まり事から構成されます。ライブラリは“フレームワークライブラリ”とも呼ばれます。フレームワークライブラリは、個々のアプリケーション要件に関するコードは含まれていないので、単体での実行はできません。半完成品のライブラリとも言えます。個々のアプリケーションがフレームワークを使うための決まりごとは、使用するプログラミング言語の特徴や、そのフレームワークが解決しようとしている問題領域ごとに様々な形式で提供されます。
以降、いくつかのフレームワークを参考までに紹介していきます。

Windows Presentation Foundation

GUI フレームワークの例として WPF(Windows Presentation Framework)を紹介します。WPF は、2006年に Windows Vista がリリースされた時に、.NET Framework上でアプリケーションの GUI(Graphical User Interface)アプリケーションを構築する為の基盤技術として投入されたフレームワークです。WPF 以前は、Windows 32 API をベースにした MFC(Microsoft Foundation Class)や、.NET Framework 上でGUIを構築する WinForms(Windows Form)というフレームワークを使って Windows アプリケーションの GUI を開発していました。この二つのフレームワークも歴史的経緯を詳しく調べると非常に興味深いのですが、ここでは割愛します。また、何故、MFC やWinForms があるのにもかかわらず、WPF が出現したか、その背景も非常に興味深いですが、そちらも割愛します。
WPF は、アプリケーションの画面で使う、ウィンドウやボタン、テキストボックス、コンボボックスなどの GUI 部品や GUI を持つアプリケーションに必要な基本制御構造のライブラリと、GUI 画面のデザイン方法、アプリケーション作成にあたって必要になる定型コードの自動生成、Visual Studio による開発支援ツールから構成されています。GUI画面は、XML(Extended Markup Language)でGUI部品の配置とスタイルを定義し、デザインします。Visual Studio では、XMLエディタと実際の配置を表示するエディタが並列表示され、直感的な配置と微調整を支援します。WPFのアプリケーションは、MVVM(Model-View-ViewModel)という、一種のレイヤー型のアーキテクチャを前提としています。WPF を使いこなすには、この MVVM の理解が欠かせません。ちなみに MFC もそうですが、一般的な GUI フレームワークは、MVC(Model-View-Controller)というアーキテクチャを元にしてデザインされたものがほとんどです。
WPF のアプリケーションは、Visual Studio が提供するプロジェクトテンプレートを使って作成します。プロジェクトテンプレートを使う事により、.NET Framework が規定するプログラムのエントリポイントや、一枚のウィンドウを表示するのに必要なプログラムコードを自動生成してくれます。また、XML で定義された GUI デザインは、Visual Studio により、C#(Visual Basicを使っている場合はVisual Basic)のコードに自動変換されます。XML による GUI のデザインは宣言的であるのに対して、生成される C# コードは手続き的で、例えば、「ボタンを(32、200)の位置に配置する」は、「ボタンクラスのインスタンスを一つ生成し、指定の位置に設定するメソッドをコールする」といったような形式で変換されていきます。XML や Visual なエディタで記述を更新すると、都度都度生成コードの中身が変わるので、自動生成されるソースファイルと、ボタンがクリックされた時に何を処理するかという開発者が記述するファイルは、別のファイルになっています。MainWindow という名前のウィンドウ(それぞれ表示されるウィンドウは WPF が提供する Window クラスを継承したクラスとして定義される)があった場合、GUI 部品の配置を行うコードと、GUI 上のイベントを処理するユーザーロジックコードは、それぞれ同一のウィンドウクラスのメソッドとして定義されるのですが、それぞれの別のファイルに記述されるわけです。後者を“コードビハインド”と呼びます。また、C# には、一つのクラスのメソッドは、一つのファイル内で記述するのが基本ですが、前述の partial キーワードを使う事により、同一クラスのメソッド群を別々のソースファイルで記述できるようなプログラミング言語のセマンティクスが用意されています。
Windows 8 以降の GUI アプリケーションでは、更に、UWP(Universal Windows Platform:プロレスかよw)という WPF と同系統の GUI フレームワークが提供されています。WPF は、そのアプリケーションプログラムを実行するハードウェアと密結合しているデスクトップアプリケーションであるのに対して、UWP は、アプリケーションマーケットプレースからダウンロードしてインストールされるようなサンドボックスで動くアプリケーションという違いがあります。IoTの制御機器が Windows OS を採用している場合は、そのWindows のバージョンにもよりますが、GUI 付きの制御アプリを開発する場合は、WPF と UWP のどちらかを選択する必要があります。

ASP.NET

Webアプリ開発用のフレームワークです。
https://docs.microsoft.com/ja-jp/aspnet/overview
Web ページ作成用の ASP.NET Web Form、ASP.NET MVC、ASP.NET Web Page や、Web API の定義と実装、ルーティング、Microsoft Account、Google ID、Facebook ID、をはじめとする OAuth2.0 を基盤とした認証とユーザーの区別、データベースアクセスを容易にする Entity Framework、インターネット上の同報通信機能を提供する SignalR 等から構成されています。

WPF と同様、プロジェクト作成用のプロジェクトテンプレートによる、基本ソースセットの自動生成、C#による記述からのデータベース定義生成など、ASP.NET プロジェクト開発を支援する様々な便利機能が Visual Studio から提供されています。

Web アプリ開発向けには、他にも、Facebook 由来の React、Java の Struts、Ruby on Rails 等々、様々なフレームワークが実際の開発で活用されています。

フレームワークの設計

一般的なアプリケーションソフトウェア開発では、フレームワークを活用することにより、コードの記述量を大幅に減らすことができ、また、フレームワークがカバーする機能はテスト済みなので、テストの規模も小さくなります。「概念モデリング教本」で解説している開発方法においても事情は同じです。
アプリケーションドメインやサービスドメインのモデル群のプログラムコードへの変換方法を決めていく過程では、インフラストラクチャドメインで選択された実行プラットフォーム上で動作させるために必要な基本ロジックの定義と、その定義に基づいた概念モデル要素のコードへの置き換えルールの定義を行います。この二つの作業は、フレームワークの設計でやらなければならない作業と基本的に同じです。概念モデルと、サービスドメインのドメインそれぞれに対して、この二つの作業を行います。この時、GUI 等、既に世の中で一般的に使われているフレームワークがあるなら、それを率先して採用します。

モジュールの固定部分と可変ポイント

フレームワークは、下図に示すように、フレームワークライブラリのロジックが制御の骨格を形作り、アプリケーション固有の処理の部分だけ、フレームワークを利用する側のロジックに、処理を委譲しながら処理を進めます。

画像1

この図は、フレームワーク側のロジックから利用側のロジックをコールしているので、一見、フレームワークが利用側に依存しているように見えます。フレームワークは制御の骨格だけでなく、例えば GUI ならボタンやテキストボックスを使うためのライブラリが提供されているなど、利用側のロジックが利用する基本部品もフレームワークライブラリに含まれています。結果として、フレームワークと利用側は双方向の依存関係が生じているように見ます。
実際のフレームワークでは、C++ の virtual class、C# や Java の interface を使ってこの双方向依存問題を解決し、フレームワークライブラリは、一切、利用する側のデータ構造やロジックには依存せず、利用側からの依存になるように構築されています。
本稿では既に一般的な用語として“インターフェイス”という用語を使ってしまっているので、区別するために、C++ の virtual class や C# や Java の interface を、まとめて、“Interface”と書くことにします。Interface は、そのフレームワークライブラリが利用側のロジックをコールするのに必要なメソッド群のシグネチャを宣言したものです。Interface の宣言をフレームワーク側で行い、フレームワークの制御の骨格を処理するロジック内で、その Interface に定義されたメソッドをコールするコードを書くことにより、利用される側のロジックに一切依存することなくフレームワークライブラリを作成することができます。

画像2

利用する側は、フレームワークが定義した Interface を実装する class を作成し、それぞれのメソッドのロジックを実装します。利用する側のデータ構造とロジックが記述されたソースコードは、コンパイルされ、フレームワークライブラリとリンクされて、実行ファイルが完成します。実行ファイルが実行プラットフォーム上で処理されるときには、フレームワークが定義した Interface の各メソッドは実装を持つため、処理が滞りなく進んでいくわけです。
この依存関係を図に示すと、依存方向は一方向であることが判ります。

※ ちなみに、C言語の場合は、関数ポインタを使えば同様な仕組みを用意することができます。

Interface を使った依存方向の逆転のことを Dependency Inversion と呼び、実行時に実装を挿入することを Dependency Injection と呼びます。これらは、フレームワークを定義する時の常套テクニックなので覚えておいてください。
また、フレームワークの設計では、利用者のフレームワークへの正しい理解を促進するために、利用する側が実装するべき Interface や、提供するユーティリティメソッドに関する説明だけでなく、フレームワークの起動から、利用側のロジックコールを含む処理の流れを、シーケンス図を使って明確にしておくことを推奨します。

フレームワーク側のロジックが、Interfaceの変数を複数同時に処理する場合に、利用する側のロジックをコールした時に、利用する側のロジックが、フレームワークから提供しているメソッドをコールするようなフレームワークの場合、コールしてきた利用側のロジックが複数ある中からどの Interfaceの変数からのコールなのかを区別して処理を変えたい場合があります。そのような場合は、コンテキスト(Context、文脈)を表現するデータ型を定義して、Interface のメソッドの引数にコンテキスト変数を追加することによって解決します。

画像3

このテクニックもよく使われるものです。実際に Context というキーワードを含むデータ型を受け渡しているフレームワークはよく見かけます。

フレームワーク設計の要諦は、フレームワークの内部に利用側の意味や概念を含まずに、利用側にとって有用な仕組みを提供する事につきます。基本的な考え方は、「概念モデリング教本」で解説したサービスドメインとアプリケーションドメインの分割と同等です。

参考までに、Interface 以外で利用側のロジック実装を規定する仕掛けをいくつか紹介しておきます。

先ず、C# の Event です。event キーワードを使う事により、ある事象が発生したことを複数のクライアントに通知する時のコールバックを、より少ないコード量でエレガントに記述できます。

次は、C# の attributeJava の annotation)です。この仕組みを使って、利用する側のコードのフラグメントにマーキングを行えるようにしておき、コンパイル時や実行時にマークされたフラグメントに対して、フレームワークが想定する処理を追加できます。

次に紹介するのは、C#の拡張メソッドです。これは、フレームワークを利用する側のロジックで、フレームワークで定義されていない、第三者が公開しているデータ型を使う場合に、そのデータ型に、フレームワークの制御で必要なメソッドを、追加できる仕組みです。

他にも、プログラミング言語ごとに、フレームワーク設計で使えるテクニックは様々あるので、調べてみてください。
マニアックな二つを紹介しましたが、もっと一般的な機能としては、C言語ではマクロ、C++ では template、C# や Java では総称型なども、フレームワークの独立性を高めつつ、利用する側の自由度を高める仕組みとして、活用できます。

フレームワーク設計のサンプルとして、「概念モデリング教本」で紹介した“状態モデル”について、「フレームワークの設計と実装」を公開しているので、参考にしてみてください。
加えて、「Azure IoT Hubに接続する機器側のIoTアプリケーション向けフレームワークの設計と実装」も公開しているので、そちらも参考にしてください。

以上、フレームワーク設計に関する基本的な考え方を解説してきました。フレームワークに利用側の文脈を一切入れずに独立性を高くするということを、利用するアプリケーション側から見ると、そのアプリケーション専用のライブラリではないものを利用するということになります。専用ライブラリではないので、利用側の要件からすると不必要な機能が含まれていたり、求めている実行パフォーマンスが達成できないといった不具合が生じる場合があります。小型組込み機器の様な HW リソース制約が厳しい実行プラットフォームの場合は、リッチなフレームワークを採用するのが難しいので、設計中の評価でその事実が分かった時点で、利用をあきらめた方が賢明です。

設計時のフレームワーク選択においては、当たり前のことですが、候補のフレームワークが実用上問題ないことを評価する作業が必要です。評価に当たっては、フレームワークの概念モデルを作って、そのフレームワークが実装しているドメインを明確化するとよいでしょう。概念モデリング中に、そのフレームワークが前提としている、インフラストラクチャドメインの切り出しも行えば、機能の過不足だけでなく、必要な HW リソースやパフォーマンスなど大まかな非機能要件の見積もりも行えます。

フレームワークの中には、セキュリティ標準をはじめとする様々な標準や業界の法律を満たすための仕組みを持っている場合もあり、それらも明確になります。代替候補の選定や、自前開発をした場合のコストの見積もりのベースにもなります。トータルコスト算定の結果、利用する実行プラットフォームを変えるという選択もあり得ます。加えて、フレームワークの概念モデルが出来上がったら、フレームワーク側に存在する意味や概念が、アプリケーション側のドメインに混在していないかチェックをしてみましょう。もし両方にあれば、同じ要件に対する処理を二重に行うことになるので、HW リソースやパフォーマンスに影響を与えます。見つけた場合は、利用する側の概念モデルから重複する概念を排除するなど、設計の見直しを行うのも一つの手段です。

一般的に広く使われている今時のフレームワークのほとんどは、Apache ライセンスや MIT、GPL などのオープンソースライセンスで提供されており、GitHub 等でソースコードも公開されています。障害報告や機能改善要求も大抵の場合可能です。機能追加やパフォーマンス改善に関するコードを書いて、Pull & Request で、フレームワークを開発している組織側で入れ込んでもらうよう要求も可能です。この様なフィードバックは、オープンソースを利用する場合に推奨される作法なので、積極的に行いましょう。

次の章では、「モジュールのビルドと配置」について解説します。


この記事が気に入ったらサポートをしてみませんか?