はじめに
大多数の開発者は階層化アーキテクチャアプローチの価値を理解しています。階層化アーキテクチャの中核的な考え方は「責任の分割」です。各層はそれぞれ限定的な量の仕事について責任を負います。ある特定の層で遂行すべきでない仕事は、それを処理するのにふさわしい層に委任されます。
しかし残念ながら、階層化アーキテクチャを支持している人でも、階層間に必要以上の結合を持ち込んでしまうことがよくあります。階層間の結合度が高くなると、アーキテクチャの変更や拡張が難しくなり、結果として脆弱なアプリケーションになりがちです。
本稿では、堅牢性やテスト容易性(testability)という点で問題のある手法を使って構築されたプロジェクトを例にとり、アプリケーションの柔軟性とテスト容易性を高めるのに役立つ原則とテクニックとリファクタリング方法をいくつか適用します。
本稿の最初の部分では、階層化アーキテクチャをもっとスマートなやり方で利用できるようにするための設計原則について説明します。さらに、このプロジェクトに依存性注入を取り入れてプラグ可能なアプリケーションアーキテクチャを実現する方法を具体的に示します。
手近な事例
まずは手近な例で考えてみましょう。私は自分の会社の従業員情報を表示するために、図1のような画面を開発するよう頼まれました。これはごく「単純な」画面なので、私はすぐにリスト1のようなコードを書き上げました(念のため言っておきますが、これが現実の例であれば、私は決してこんなコードは書きません)。
public partial class ViewEmployeesTightlyCoupled : Page { private const string ConnectionString = "data source=(local);Integrated Security=SSPI;" + "Initital Catalog=NorthWind"; private SqlConnection connection; protected void Page_Load(object sender, EventArgs e) { if (! IsPostBack) { PopulateGridFrom(MapFrom(GetAllEmployees())); } } private DataTable GetAllEmployees() { using (connection = new SqlConnection(ConnectionString)) { SqlCommand command = connection.CreateCommand(); command.CommandText = "SELECT * FROM Employees"; command.CommandType = CommandType.Text; connection.Open(); using (SqlDataReader reader = command.ExecuteReader( CommandBehavior.CloseConnection)) { DataTable results = new DataTable(); results.Load(reader); return results; } } } private List<Employee> MapFrom(DataTable employeeData) { List<Employee> employees = new List<Employee>(); foreach (DataRow employeeRow in employeeData.Rows) { employees.Add(MapFrom(employeeRow)); } return employees; } private void PopulateGridFrom(List<Employee> employees) { this.employeesRepeater.DataSource = employees; this.employeesRepeater.DataBind(); } private Employee MapFrom(DataRow row) { return new Employee(Convert.ToInt32( row["EmployeeId"]), row["LastName"].ToString(), row["FirstName"].ToString(), row["Title"].ToString(), Convert.ToDateTime(row["BirthDate"]), Convert.ToDateTime(row["HireDate"])); } }
リスト1は、私がわざと問題のある方法で記述したコードです。コードの内容をよく読んでみると、いろいろな問題が見えてくるのではないでしょうか? このコードはアプリケーションアーキテクチャのいくつかのルールに違反しています。
- 接続文字列がハードコーディングされている
- ユーザーインターフェイス側がデータベーステーブルの詳細を知らなければならない
- ユーザーインターフェイス側がデータベースデータをドメインオブジェクトにマップしなければならない
- 抽象ではなく実装にコーディングしている
最後の項目のことはしばらく忘れてください。まずは最初の3つの項目について、階層化アーキテクチャによる改善に取り組みます。