【第3章】 外部サービスとの連携 - マイクロサービスを見越した実装
※ この記事は「Railsのリファクタリングに立ち向かうための教科書」シリーズの第3章になります(4/5)
【序章】 問題はどうして起こるのか ~ 方針とアーキテクチャについて
【第1章】 ModelとServiceを紐解く
【第2章】 ApplicationServiceの導入
★【第3章】 マイクロサービスを見越した実装
【最終章】 リファクタリングを通してチームを強化していく
前回までで、おおよそ価値のあるリファクタリングが行えるだけの知識は習得できたものと思います。この章ではさらにそれを発展させ、ヘキサゴナルアーキテクチャからport/adapterという概念を用いて、マイクロサービスなどの外部サービスとの連携を行う際の実装手法を見ていきたいと思います。
※ ヘキサゴナルアーキテクチャについてはこちらを参照ください blog.tai2.net
重要なのはやはり責務
例えば、キャッシュ機構を実装することを考えてみましょう。アプリケーションからすれば、キャッシュを保持することがドメインの関心であって、キャッシュの保存先が何であるか、どうやってそこに接続する必要があるかは関心外です。なので、アプリケーションからはインターフェースだけを参照すれば十分というような設計にすることで、そうした外部性を疎結合に実装したくなります。この実現をするための設計がport/adapterです。外部サービスとの連携は、すべてport/adapterを通して行うようにします。そうすることによって、例えば保存先をmemcachedからredisに変えようという際に、アプリケーション側では一切コードを変更する必要がなくなります。他にもテスト時だけadapterを付け替えることが可能になるなどのメリットがあります。基本的にadapterは外部との連携なので、接続自体はテストで担保する必要がなく、mock化することがほとんどなので、大きなメリットを享受できます。
では、実際のディレクトリ構造を見てみましょう。例として下記のようなものが考えられます。
port/adapter/ persistence/ cache_store.rb microservices/ config.rb grpc.rb service/ service_A.rb service_B.rb ...
ここでは永続化用のadapterとmicroserviceへの接続用adapterを例として取り上げています。実装は、汎用的な名前(接続先に依存しないような名前。redisではなくcache_storeのような形)を選ぶようにすれば、あとは単純に接続を実装していけば問題ないかと思います。
port/adapterを実装すると、さらにServiceの責務がきれいになり(おそらくport/adapterがなければServiceに実装することになるので)、また、先述したように外部サービスとの接続周りの実装が扱いやすくなるので、非常におすすめです。
いかがでしたでしょうか?これでコアとなるリファクタリングの説明はおしまいです。次章「【最終章】 リファクタリングを通してチームを強化していく」では、まとめとしてこうしたリファクタリングを通して開発チームがどうなっていくか、ということを書きたいと思います。
それでは!