はじめに
今回のテーマは「アーキテクチャ」です。
複雑なアプリを作る前に理解しておいた方が良い内容です。
アーキテクチャという言葉は、もともと「建物」や「建築物の構造」を表す用語です。
それがIT界隈では、もっぱら「構造」という意味で使われています。
データ・アーキテクチャとか、ビジネス・アーキテクチャだといった具合に別の言葉とセットで使われることが多く、混乱を招きやすい言葉だと思います。
ここではプログラムに関するアーキテクチャについて考えます。
紛らわしい言葉として「アプリケーション・アーキテクチャ」という用語がありますが、別の話です。
アプリケーション・アーキテクチャというは、業務を最適化するために「数多くのアプリをどのように選別し連携させようか」ということです。対して今回話題にしているアーキテクチャは「アプリの内部をどんな構造にすると良いだろうか」という話です。
つまり、1つのアプリの中の構造のことです。
アーキテクチャが必要な理由
アーキテクチャが語られる背景のひとつは「複雑なアプリを作るんだから、コードを整理整頓して、何がどこに置いてあるかをハッキリしといた方が良いよね。作りやすいし、後々のメンテナンスにも役立つはず。そのために収納場所と収納ルールを決めておこう!」からという考え方からでしょう。
ぶっちゃけると「コードの収納場所と収納ルール」がアーキテクチャのキモ。
では、なぜ、アーキテクチャが役立つのでしょうか?
収納ということなので部屋の片付けに例えて考えてみると、少し分かりやすくなります。
極端なミニマリストでもなければ、部屋の片付けをしておかないと、いろいろマズいことになります。
例えば、「出かけたいのにカギが見つからない!財布もどこへ行った?」とか、「床にメガネが落ちてたので踏んづけて壊してしまった。余計な出費だ!」とか、「これ、まだ残ってたのか、追加で買ってきちゃったよ。無駄になる!」など、など、、、
アプリも同じです。簡単なアプリならいいのですが、そうでなければ、「これはどこで処理してるんだ?改変したくても分からない!」とか、「メンテしたら思わぬ所にバグがでてしまった!」とか、「このロジック、ここにもあったのか!変更モレで障害だ!」とか、いろいろヤバそうです。
「コードの収納場所と収納ルール」がちゃんとしていれば、このような事態はかなり改善されそうですね。だから、アーキテクチャが必要なのです。
アーキテクチャのポイント
では、単純に「コードの収納場所と収納ルール」を決めればいいのか というと、そうではありません。考えた方が良いポイントがあります。
部屋のかたずけのキモは「物の置き場所を確保して定位置を決める」こと。定位置を決めるにあたっては、物の使用頻度や、使う際の人の動線などを考えますよね。
アーキテクチャもデータやロジックの置き場所を決めますが、置き場所を決めるにあたって「依存関係」を考えることがポイントになります。
では、依存関係というのは、どのようなものなのでしょうか?
依存関係について
依存関係は、あるクラスを生成したり、メソッドを呼び出したり、プロパティや変数を使ったり、継承したりすると、つまり参照すると発生します。
例えば、Aという処理が、Bという処理を呼び出している場合、依存関係が発生し、AはBに依存している状態に、BはAに依存されている状態になります。
図にするときは矢印で表現するのが普通です。上のようにAからBへ矢印を引きます。
この状態では、Bつまり依存先でコードが改訂されると、Aにも影響が出る可能性があります。また、Bの実行中にトラブルが発生すると、Aの所に火の粉が飛んでくることになります。
反対に、Aを改訂したり、Aがトラブっても、Bへの影響を受けません
まとめると次の表のようになります。
依存関係 | テスト容易性 | ドキュメント性 | 影響範囲 | 独立性 (安全性) | メモ (設計での配慮) |
---|---|---|---|---|---|
依存している | 小(困難) | 小(劣) | – | 小(弱) | その他部分へ配置 |
依存していない | 大(容易) | 大(優) | – | 大(強) | コア部分へ配置 |
依存されている | – | – | 大(広い) | – | – |
依存されていない | – | – | 小(狭い) | – | – |
テスト容易性というのは、他に依存していれば依存先の環境を用意する必要があるので困難になります。反対に依存していなければ単体でテストできるので容易です。
ドキュメント性というのは、該当部分のコードからどれだけアプリの対象範囲の知識や情報を読み取れるかということになります。
言い換えれば「そのコード、どこまで仕様書の代わりができる?」ということです。
他に依存していれば依存先のコードも読む必要が出てくるのでドキュメント性は落ちます。
影響範囲というのは、そのコードを改訂したり、そのコードでトラブルが発せするとどこまで影響がでるか?ということです。依存されていれば依存元にも影響を与える可能性があるので、影響範囲は大きくなります。
独立性というのは、他のコードをどれだけ必要としているか?と考えることもできます。他に依存していなければ、とうぜん独立性が強くなります。
ポイントは独立性です。
独立性が強ければ、つまり、他に依存していなければ、他から影響を受けないということ。他のコードが変更されても、他のコードでトラブルがあっても影響を受ないので、それだけ安全性が高まります。これは大きなメリットです。
それ以外にも、テストで他の環境の準備をしなくていいので単体テストが楽になる。
他の部分のコードを読まなくていいので処理内容を把握するのが楽。コードが分かりやすくなる などのメリットもあります。
対してデメリットはあまりありません。
なので、できるだけ他に依存しない状態にしたい。他に依存しない状態だけでアプリができれば最高!なのですが、、、
なかなかそんなアプリを作ることはできません。仕様を満たすためには何かしら他を参照しなければならない箇所が出るのが普通です。
そこで、「他に依存しない部分」と「(必要に迫られて)他に依存している部分を」を分けて、他に依存しない部分だけでも、メリットを享受しようということになります。
だから、依存するか依存しないかを整理して「置き場所」を決めるために、「参照」を考えることが重要になるのです。
さまざまなアーキテクチャ
部屋の片付けに正解がないように、アーキテクチャにも正解はありません。
ですが、部屋の片付けに、何かがときめく片付け法とか、人生以外は全部捨てるミニマリスト式とか、人気の方法があるように、アーキテクチャにも人気の方法が、いくつかあります。
ですが、基本的な考え方は似ています。
先に説明した「依存しない部分と、その他を分けよう」という発想です。
「依存しない部分」は、安全性が高く、テストが容易で、ドキュメント性が高く、メンテナンスが楽。
だったら、これをコアにして、アプリケーションの根本となるロジックを置こうという方針になるのが自然な流れですね。
あとは、コアを上に置いて階層のように区切って並べるか、コアを真ん中に置いて円陣を組むか、という違いになります。
あとがき
コアのことは「モデル」とか「ドメイン」と呼ばれることも多いですね。
階層型の具体的な実装は「【App. Design】Visual Studioでプロジェクトを分け階層型のアーキテクチャを実装する」で説明しています。
コアに配置するアプリケーションの根本となるロジックをどう決めるのかは、アーキテクチャではなく設計の話になるので、またの機会に、、、
コメント