効果的なTDD
ClimatePartnerで新しいエンタープライズアプリケーションを開発し始めてから6ヶ月が経ちました。私の新しいチームは、ペアプログラミングやテスト駆動開発(TDD)などのアジャイルプラクティスを採用しており、私たちには太陽が輝いていると正直な気持ちです!
まあ、ほとんどですが。
今、そして過去の産業経験で直面していた企業アプリケーションを構築する上でのいくつかの問題があるのですが、その問題点についてこの記事でお話ししたいと思います。
さらに、チームコミュニケーションを強化し、高品質のコードを素早く提供するための、シンプルなテストファーストベースの方法論を提案したいと思います。
そういうわけで、始めましょう!
TDDの光と影
アジャイルプラクティスはソフトウェアの迅速なプロトタイピングに非常に有益です。TDDはその核心であり、ソフトウェアに非常に重要な特性を提供します:堅牢性。テストを前もって書くことにより、開発者は構築するソフトウェアコンポーネントの期待される動作と例外的な動作について考えることを強いられ、コードの品質が向上し、機能要件の達成が保証されます。
TDDが万能というわけではないので、SOLID原則などの良い実践に従う必要がありますが、機能要件の更新にコードを修正、清掃、適応させることを恐れないようにするための強力な実践です。しかし、効果的にTDDを適用するのは簡単ではありません。
新しいエンタープライズアプリケーションの構築を開始する際、私たち開発者はいくつかの機能要件を集めます。次に、これらの機能要件を満たす一連のユースケースを導き出します。その後、最上位から最下位に至るまで、アプリケーションの心臓部であるドメインモデルに至るまで、様々なレイヤーに座っているソフトウェアコンポーネントを開発します。これが トップダウン ソフトウェア開発プロセスの定義です。
しかし、TDDにより適合するのは ボトムアップ ソフトウェア開発プロセスです。トップダウンの代替手段と比較して、ボトムアップはより実用的なアプローチであり、最も基本的な(つまり、ドメインモデル)から始めて段階的に抽象化の高いレイヤーに移行するすべての間接レベルを徐々にカバーすることができます。それにより、より確かなアプリケーションコードの基盤を生産することができ、それによって私たちは私たちの仕事に対する大きな自信を得ることができます。一方で、トップダウンアプローチでTDDを適用するには、高いレイヤーにあるソフトウェアコンポーネントに対して最初にテストを書かなければなりません。こうすることで、開発者はまだ存在しない低レイヤーコンポーネントへの依存をモックする必要がありません。
必要な依存関係を作成すること自体がすでに問題です。なぜなら、低いレイヤーのコンポーネントをモックすることは常に可能ではないか、ベストケースシナリオでは直感に反すると感じられるからです。例えば、サービスコンポーネントのテストを作成するためにドメインオブジェクトのロジックをモックする必要があることを自分に想像してみてください。
さらに、こうした依存関係を解消することは何の価値ももたらさないと個人的には疑問に思います。というのも、私は中間コンポーネントの検証は外部サービス(例えば、データベース)への依存を除いて、すべての依存関係を試すべきだと考えているからです。より重要なことに、技術的な複雑さから非自明な機能要件をコードとして実現するには、ドメインモデルの実装中にそれらについて推理し始めるまで、一部の機能要件がドメインモデルに与える技術的な影響を完全には理解できません。
もう一度言いますが、中間ソフトウェアコンポーネントのテストを書き始めることはあまり価値がありません。なぜなら、これらのテストの多く(すべてではないにせよ)は、実際に低層ソフトウェアアーティファクトが実装されると、ゴミ箱に捨てられる可能性が高いからです。
さらに、ソフトウェア開発者(特に新人チームメンバー)がケースを作るためのいくつかのコンセプトを実装することを諦め、検証ロジックなしでコードを書いてしまうことがあります。これはコードファーストの実践であり、TDDの目的を敗北させます。また、適切な継続的インテグレーションの実践に従わなければ、検証されていないコードをバージョン管理リポジトリにプッシュする高いリスクがあります。
では、どのようにして機能要件があるエンタープライズアプリケーションの生産にTDDを効果的に適用することができるでしょうか?
救世主としての六角形アーキテクチャ
インターネット上には六角形アーキテクチャに関する豊富な文献があります。特に、Alistair Cockburnによって書かれたホワイトペーパーを読むことをお勧めします。
この記事の目的のために、六角形アーキテクチャの動機と主要な利点を簡単に説明するために実際の話を少し聞かせてください:私は多年にわたってエンタープライズアプリケーションの開発に関わってきましたが、多くの人々(私を含む)が本当の使命とは別のトピックに焦点を当てて新しいプロジェクトを開始するのを見てきました。そのような使命とは、私たちが働いている会社に実際の価値を提供することであります。その価値は、私たちのアプリケーションのドメインロジックにあります。
Uncle Bobの本「クリーンアーキテクチャ」で述べたように、他のすべては気を散らすものであり、実装の詳細であり、アイデアとしては開発の終わりに延期されるべきです。実装の詳細の例としては、データベース技術、コントローラのロジック、またはフロントエンドの技術があります。バックエンドフレームワークでさえ、開発プロセスの後半で本当に選びたい場合には、実装の詳細です。六角形アーキテクチャ、別名 ポートとアダプター としても知られている、ソフトウェアアプリケーションのコアロジックを外部の実装の詳細から切り離すことを目的としたアーキテクチャパターンです。
私たち開発者は、エンタープライズアプリケーションのコアロジックに集中し、外部サービスとの通信に必要なロジックの実装を延期するべきです。それを達成するために、本当に必要なのは、いくつかのインターフェース(いわゆる_ポート_)を書いて、実際に外部サービスと通信するコンポーネント(いわゆる_アダプター_)をモックすることです。そのため、アダプターの実装は開発プロセスの後の方で行うことができます。そして、それが後の方に来るほど良い。なぜなら、コアロジックを作成しながら得られるすべてのインサイトが、どの技術を選ぶかの意思決定にとても役立つからです。
内側の六角形を構成する要素を考えてみましょう。ドメインモデル以外に、_アプリケーションサービス_のレイヤーもあります。これらのソフトウェアコンポーネントはドメインロジックを指定していません。代わりに、アダプターとドメインモデルのロジックの単純な調整者です。アプリケーションサービスは、エンタープライズアプリケーションの機能要件のサブセットを担当するユースケースを実現します。これは、これから来ることを念頭に置いておく重要なデータです。
六角形アーキテクチャに基づくエンタープライズアプリケーションでTDDを効果的に使用する方法
先に述べたように、TDDの適用はボトムアップソフトウェア開発プロセスに従う方が簡単です。しかし、多くの開発者はシステム設計についてトップダウンアプローチで推論する方が簡単に感じます。そして、私たちが利益相反に陥るように見えるが、それは問題ない。なぜなら、そのドメインモデルの実装を完了するまで、私たちはアプリケーションサービスを設計することを始めることができます(つまり、疑似コードやいくつかのUMLダイアグラムでスケッチすることです)が、コードの単一行も書くことなく。
コードを書き始める前に、私たちはアプリケーションサービスを、構築されるエンタープライズアプリケーションの垂直スライスを実行するためのソフトウェア設計ガイドラインとして解釈することができます。各垂直スライスは、UI内のユーザーまたは上流外部サービスによって実行されるアクションから、下流外部サービスで実行される任意の操作まで、ユースケースの全実行パスを表します。アプリケーションサービスの設計を完了する頃には、実装する必要があるアダプターとドメインコンポーネントが特定されています。今や我々はドメインモデルに視界を持っているので、次にTDDを適用してその基本コンポーネントを実装することができます。その後、テストファーストアプローチに従ってアプリケーションサービスを実装し、外部サービスアダプターにポートを作成し、その実際の実装をモックします。アプリケーションサービスと関連ドメインモデルの実装が完了するまでに、その実装が有効であると判断できます。最後に、TDDも適用してアダプターロジックを実装できます。
この方法論は、エンタープライズアプリケーションの迅速かつ段階的な実装を可能にし、作成したすべてのコンポーネントの妥当性に自信を持つことができ、テストを捨てる必要がありません。さらに、機能要件の更新に対する制限は課されません。
![TDDベースのエンタープライズアプリケ
こちらの記事はdev.toの良い記事を日本人向けに翻訳しています。
https://dev.to/josuto/effective-tdd-3hii