新しいエンタープライズ アプリケーションを構築する会社で働き始めてから 6 か月が経ちました。私の新しいチームは、ペア プログラミングやテスト駆動開発 (TDD) などのアジャイル プラクティスに従っています。
よくほとんど。
この記事では、堅牢なエンタープライズ アプリケーションを構築するというトピックに関して、現在および過去の業界経験の両方で直面している問題がいくつかあります。
さらに、チームのコミュニケーションを強化し、高品質のコード配信をより迅速に促進するエンタープライズ アプリケーションを構築するための、シンプルなテスト ファースト ベースの方法論も提案します。
それでは、さっそく始めましょう。
アジャイル プラクティスは、ソフトウェアの迅速なプロトタイピングに非常に役立ちます。 TDD はそのようなプラクティスの中核に位置し、ソフトウェアに最も重要な特性である堅牢性を提供します。テストを前もって書くことで、開発者は自分が構築するソフトウェア コンポーネントの予想される例外的な動作について考える必要があり、コードの品質が向上し、機能要件が確実に満たされるようになります。
さらに、TDD は、開発者が機能要件の更新にコードを修正、クリーンアップ、および適応させることを恐れないようにする強力なプラクティスです。そして、それはすべて素晴らしいです。ただし、TDD を実践するのはそれほど簡単ではありません。
新しいエンタープライズ アプリケーションの構築の開始時に、私たち (開発者) はいくつかの機能要件を収集します。次に、そのような機能要件を満たす一連のユース ケースを導き出します。その後、最上位から最下位まで、さまざまなレイヤーに位置するソフトウェア コンポーネントを開発し、アプリケーションの核心、つまりドメイン モデルにドリルダウンします。それがトップダウンのソフトウェア開発プロセスの定義です。
ただし、ボトムアップのソフトウェア開発プロセスは、TDD に適しています。トップダウンの代替案と比較して、ボトムアップはより実用的なアプローチです。これにより、私たち開発者は、最も基本的なもの (つまり、ドメイン モデル) から始めて、徐々に上位層に移行するすべてのレベルの間接化を段階的にカバーすることができます。抽象化。これにより、より健全なアプリケーション コードの基盤を作成できるようになり、その結果、作業に大きな自信が持てるようになります。ただし、トップダウン アプローチで TDD を適用するには、まず上位層にあるソフトウェア コンポーネントのテストを作成する必要があります。このように、開発者は下位層のコンポーネントへの依存関係をモックする必要はありません。下位層のコンポーネントはまだ存在していないからです。
このような依存関係を作成する必要性は、すでに問題になっています。なぜなら、下位層のコンポーネントをモックすることは常に可能であるとは限らないか、最良のシナリオでは直観に反するように感じるからです。サービス コンポーネント テスト。
さらに、個人的には、中間コンポーネントの検証は、モックできる外部サービス (データベースなど) への依存関係を除くすべての依存関係を常に実行する必要があると考えているため、それがまったく価値をもたらすとは思えません。さらに重要なことは、重要な機能要件をコードとして実現することは本質的に複雑であるため、ドメイン モデルの実装中にそれらについて推論を開始するまで、特定の機能要件がドメイン モデルに与える技術的な意味を完全に理解することはできません。
繰り返しになりますが、中間ソフトウェア コンポーネントのテストを書き始めてもあまり価値がありません。下位層のソフトウェア アーティファクトが実際に実装されると、これらのテストの多く (すべてではないにしても) がゴミ箱に捨てられる可能性が高いからです。
さらに、ソフトウェア開発者 (特に若いチームメイト) が、検証ロジックをまったく記述せずに、目の前のユースケースの概念実証をあきらめて実装するのを見てきました。これは、TDD の目的を無効にするコード ファースト プラクティスを使用しています。また、適切な継続的デリバリーの実践に従わないと、検証されていないコードをバージョン管理リポジトリにプッシュすることになるリスクが高くなります。
では、一連の機能要件が与えられた場合、エンタープライズ アプリケーションの作成に TDD を効果的に適用するにはどうすればよいでしょうか?
ヘキサゴナル アーキテクチャに関する文献はインターネット上にたくさんあります。 Alistair Cockburn によって書かれたトピックに関するホワイト ペーパーを読むことを特にお勧めします。
この記事の目的のために、Hexagonal Architecture の動機と主な利点を簡単に説明することを目的とした実際の短い話をお話しさせてください:私も含めて)私たちの本当の使命ではなく、他のトピックに焦点を当てた新しいプロジェクトを開始しています。そのような使命は、私たちが働く企業に実際の価値を提供することです。その値は、アプリケーションのドメイン ロジックにあります。
ボブおじさんの著書「Clean Architecture」で言い換えると、他のすべては気を散らすものであり、理想的には開発の最後まで延期できる (そして延期すべきである) 実装の詳細です。実装の詳細の例としては、データベース テクノロジ、コントローラ ロジック、またはフロントエンド テクノロジがあります。バックエンド フレームワークでさえ実装の詳細であり、必要に応じて開発プロセスの後半で選択できます。 Ports and Adapters とも呼ばれる Hexagonal Architecture は、ソフトウェア アプリケーションのコア ロジックを外部実装の詳細から分離することを目的としたアーキテクチャ パターンです。
私たち開発者は、エンタープライズ アプリケーションのコア ロジックに集中し、外部サービスとの通信に必要なロジックの実装を延期する必要があります。その目標を達成するために本当に必要なことは、いくつかのインターフェース (いわゆるポート) を書き、実際に外部サービスと通信するコンポーネント (いわゆるアダプター) をモックすることだけです。したがって、アダプターの実装は、開発プロセスの後半に行うことができます。コア ロジックを生成する間に得たすべての洞察は、どのテクノロジを選択するかを決定する際に非常に役立つことが証明されているためです。
次の図は、六角形のアーキテクチャの多くの既存の図の 1 つです。
内側の六角形を構成する要素を考えてみましょう。ドメイン モデルとは別に、アプリケーション サービスのレイヤーもあります。これらのソフトウェア コンポーネントは、ドメイン ロジックを指定しません。代わりに、アダプターとドメイン モデル ロジックの単純なコーディネーターです。アプリケーション サービスは、エンタープライズ アプリケーションの機能要件のサブセットを処理するユース ケースを実現します。これは、次に来るもののために心に留めておくべき重要なデータです。
前述したように、TDD の適用は、ボトムアップのソフトウェア開発プロセスに従う方が簡単です。しかし、私たちの多くは、トップダウン アプローチに従ったシステム設計について推論する方が簡単だと感じています。利益相反が発生しているように見えますが、コードを 1 行も書かずにトップダウンでアプリケーション サービスの設計 (疑似コードまたは UML ダイアグラムのスケッチ) を開始できるため、問題ありません。ドメインモデルの実装が完了するまでは。
コーディングを開始する前に、アプリケーション サービスをソフトウェア設計ガイドラインとして解釈し、構築するエンタープライズ アプリケーションの垂直方向のスライスを実行することができます。各垂直スライスは、上流の外部サービスまたは UI 内のユーザーによって実行されるアクションから、下流の外部サービスで実行される操作まで、ユース ケースの実行パス全体を表します。アプリケーション サービスの設計が完了するまでに、実装する必要があるアダプタとドメイン コンポーネントを特定しています。ドメイン モデルを可視化したので、次に TDD を適用してその基本的なコンポーネントを実装できます。
次に、テスト優先のアプローチに従ってアプリケーション サービスを実装し、任意の外部サービス アダプターへのポートを作成して、その実際の実装をモックします。アプリケーション サービスと関連するドメイン モデルの実装が完了するまでに、そのような実装が有効であること、つまりバグがなく、その機能要件に適合していることを確認できます。最後に、アダプター ロジックを実装し、TDD も適用します。
この方法論により、エンタープライズ アプリケーションの迅速かつ段階的な実装が可能になり、開発者はテストを放棄することなく、作成したすべてのコンポーネントの有効性に自信を持てるようになります。さらに、機能要件の更新に制限を課しません。
次のフロー図は、1 つのユース ケースのロジックを記述する方法を示しています。これは非常に物議を醸すテーマであるため、特定のテストの種類については触れませんが、 The Practical Test Pyramid の記事で使用されている規則と用語に従うことをお勧めします。
提案された方法論は、単独で作業するかペアで作業するかに関係なく、チームのタスクの分散を簡素化します。そのステップの一部は並行して実行できます。たとえば、チームメイト/ペアは、外部依存関係への参照を模倣するコア ロジックを構築できますが、別のチームは、そのような外部依存関係を含む統合コードの開発に取り組むことができます。分離されているため、納期が短縮されます。それらが行う必要があるのは、ポートとして実現される外部依存関係の API を伝えることだけです。モックと実際の外部依存関係の両方で、前述のポート インターフェイスを実装する必要があります。同様に、別のチーム/チームメイト/ペアがユース ケースのフロントエンド部分を実装できます (それがエンタープライズ アプリケーションで必要な場合)。
一方、その構造化された性質により、具体的なユースケースの開発状況をピア間で簡単に伝達できます。ユースケースの開発を引き渡すとき、離脱するエンティティは、単に新しいものを、設計または実装している現在のアプリケーション サービスに向けることができます。新しいエンティティは、コード ベースのアダプタまたはドメイン ロジックで既に作成されているものを簡単にトレースできます。
実装の詳細に関する最後の注意: ドメイン モデルを更新して、データベース テクノロジの注釈/デコレータを記述し、アプリケーションの性質に最適に調整される基盤となるフレームワークからデータ検証リソースを入力することで、これらの詳細の一部を指定できます。ただし、実装の詳細とドメイン モデルはさまざまな理由と頻度で変更される傾向があるため、実装の詳細がドメイン モデルに漏れることになるため、これはベスト プラクティスではありません。一方、Vaughn Vernon が著書「Implementing Domain Driven Design (DDD)」で説明しているように、Hexagonal Architecture は DDD と密接に関連しています。ただし、Hexagonal Architecture に基づく複雑なエンタープライズ アプリケーションを構築するために、一連の DDD プラクティスとパターンに従う必要はありませんが、そうすることを強くお勧めします。しかし、結局のところ、これらの決定は完全にあなた次第です。
テスト駆動開発は、堅牢なエンタープライズ アプリケーションを構築するための強力な手法です。 TDD は、ボトムアップのソフトウェア開発プロセスに従って適用するのが最適です。ただし、開発者はトップダウン アプローチに従ってこのようなアプリケーションを推論することに慣れているため、実際に適用するのは困難です。この記事では、開発者がエンタープライズ アプリケーションの開発に TDD を効果的に適用するのに役立つ簡単な方法論を紹介します。