はじめに
こんにちは、サーバーサイドエンジニアの池垣です。
この前にGoとクリーンアーキテクチャでAPI実装する機会があったので
本記事ではクリーンアーキテクチャ+GoでREST APIを実装した際に、受けた具体的な恩恵を3つご紹介したいと思います。
どのようにクリーンアーキテクチャで実装していくかについての記事はたくさんあります。
ですが、実際にその実装をして受けられた具体的な嬉しいことについて書かれている記事は意外と少ないのかも、と思いその路線で書くに至りました。
クリーンアーキテクチャ導入の2つの目的
そもそも今回の開発は3週間でSNSサービスを作り切るというものでした。
フロント3人、サーバー3人、ML/DS2人の計8人のチームでの共同開発です。
3週間後に成果発表があるということで、それまでにSNSの必須機能要件を満たさなければいけないという状況でした。
それも踏まえて今回のプロジェクトにクリーンアーキテクチャを導入した主な理由は以下の2つです。
- 急いでぐちゃぐちゃに書いてカオスにならないようにするため
- コード設計の議論をしやすくするため
1. ぐちゃぐちゃに書いてカオスにならないようにするため
3週間後に成果発表が控える開発ということで、それに間に合わすため、終盤にかけてコード品質が落ちていき、やがて見るに堪えないソースコードが出来上がることは、ある程度経験からも予想できていたからです。
あと要件の変更や追加が短い期間でどんどんくる可能性が高い、というのも一つありました。
そのため予め変更可用性の高いアーキテクチャを選定し、そのレールに沿って開発することでバタバタしてもある程度品質をたもてるようにしたいというのが一つ目の理由です。
2. メンバー間でのコード設計の議論をしやすくするため
メンバー全員がAWSを触るのが初めてだったりML推論システムを組み込んだことがなかったりで、プロジェクト走り出しの時点での不確実性がとても高い状態でした。
それに加えて、これまでの開発経験も、使用技術も異なる完全初めましての3人で開発していくのでコードを書く際の共通認識を図る必要がありました。
そこで事前に、クリーンアーキテクチャに沿って実装することを決めておくことでコード設計の議論や質問が発散しないようにしたい、というのが二つ目の主な理由です。
実際のコード
4つの層
各ディレクトリとレイヤーの関係性は次のように対応しています。
ディレクトリ名 | レイヤー |
---|---|
domain | Entities |
infrastructure | Frameworks & Drivers |
interfaces | Interface |
usecase | Use cases |
具体的に嬉しかった3つのこと
では、本題である具体的にどんな現象が起きて何が嬉しかったかを3つお話ししていきます。
1. プロジェクト後半にかけてどんどん開発スピードが上がっていった
3週間後が締め切りなので、基本急ぎめのスピード開発になっていました。
そんな中でクリーンアーキテクチャは登場人物が多いのもあって、走り出しの時は、1つの機能を実装するだけでもかなり多くのファイルにコードを書く必要があります。
MVCより実装する際のコード量が増えるので邪魔くさくなる時もありましたが、ボブおじさんの言うことを信じてアーキテクチャを守り続けました。
動くものを作るというのが大目標のプロジェクトでは、短期的なスピードを優先してしまいコードの品質が落ちて後から読めたもんじゃないソースコードになるのがオチなのですが、そんな状態でもクリーンアーキテクチャに沿って実装していたため、どの層がどの責務を持つのかが明確になっていて、メンバーそれぞれが迷うことなく実装し続けることができました。
すると実装が進むにつれ、メンバーはクリーンアーキテクチャに慣れてきて、かつソースコードの煩雑さは増加しないので自然と開発スピードが上がっていきました。
最終的には1つのAPI実装が1時間半程度で終わるようになっていました。
「スピードと品質はトレードオフか?」の記事にもあるように品質を守ることで自然とスピードも上がっていくのだということを初めて身をもって体感した瞬間でした。
この記事では品質とはそもそも何か?から丁寧に説明してくれているのでとても分かりやすかったです。
2. メンバー間でのコード設計の議論がものすごくスムーズ
サーバーのメンバーのこれまでの開発歴や開発の仕方、考え方は三者三様でした。
そんな中でコード設計の議論をするにも、それぞれ過去に先輩から教えてもらったことや成功体験が異なるので、何が正義かが分からなくなり無駄な議論が続いてしまいます。
その点クリーンアーキテクチャという指針を用意することでチーム内の議論が散らばることなく収束させることができました。
例えば、
「ここの処理はビジネスロジックに影響してはいけないから外側のインフラ層に書こうと思ってるんだけど問題ない?」という風に質問してくれると、ある処理をどの層に置くのが適切か、依存性は内側に向いているかに着目すればいいのでお互い議論がとてもスムーズです。
また、議論の中で文脈がズレてしまうということもほとんどなかったです。
今どこの何について議論しているのかがクリーンアーキテクチャ内の用語を用いて進められるので話に齟齬が生まれにくくなります。
これはチーム内にひとつの指針を設けたことによる恩恵だと思っています。
それにクリーンアーキテクチャは開発者をガチガチに縛るようなものではなく、無秩序なところへ指針を示してくれるようなイメージなので、そこから逸れたとしても依存性の方向やおおよそのレイヤー構成が守れていれば変更可用性や保守性は高く保持されます。
その点でも、ある場面において適切に許容したりカスタマイズしたりして融通が効きました。
それも体験として良かったです。
3. 外部都合の修正に対して迅速に対応できる
これ割と1番体験として良かったです。
レスポンスデータをUIが求める形に変換する層を外側においておくことでUIからの修正依頼に迅速に対応できました。
チームのOpenAPIの運用が良くなく、フロントが求める型とサーバーが返す型がずれたときなどもPresenter層を修正するだけでいいので修正コストは最小で済みました。
また、ユーザに対して最適なお店をレコメンドする推論サーバーとの接続に関しても、インフラ層が責務を持つことで内側へ影響を及ぼさないようにできました。
そして、各レイヤーが独立しているので既存のリポジトリやインタラクターを再利用すれば良いという実装も多く、インタフェースに依存するプログラミングの強さを生で実感しました。
このように外部の不確実性が高い状態でも、もっとも重要なドメイン層・ユースケース層だけでアプリケーションを組み立てていける点でやはり扱いやすかったと言えます。
受けれるはずだった恩恵たち
単体テストのしやすさ
今回APIの要件を満たすというのが大目標だったのでテストを書かないという英断(迷断?)をしたので単体テストがしやすいという恩恵を受けれなかったです。
これは書いていないだけなのでちゃんと書けば疎結合が保たれているので単体テストは書きやすいのだと思っています。
あとテストは時間がかかると言えど、テストがない状態の開発はありえないくらい大変だったのでこれからは絶対に書きます。教訓になりました。
各レイヤーの実装を並行で進めれる
レイヤー間の独立性が高いので、インタフェースさえ正しく定義できれば、メンバーそれぞれが各レイヤーの実装を同時並行で進めることができます。
そうすることで自分の作業が誰かの作業に依存してしまうなどの制約スラックが解消され、よりスムーズな開発になったのだと思います。
また、同じようなインタフェースをそれぞれが定義してコンフリクトを起こすという非効率なこともあったのでそういうのをなくすようなタスクの切り方もレイヤー間の独立性ゆえできたのでしょう。
最後に
長期的に見るとメリットがたくさんあると言われているクリーンアーキテクチャですが、3週間という短い期間でも十分良い開発体験にすることができたと言えます。
初めてクリーンアーキテクチャで一つの動くプロダクトを作れたというのは大きな収穫ですし、それによって具体的な恩恵を得られたのも大きな経験でした。
ですが、まだボブおじさんに産毛が生えた程度なのでもっとちゃんと理解していきたいと思います。
ある友達が言っていて衝撃だった言葉があります。
「アーキテクチャとかはよく知らんが、綺麗なコードを書いていけば自然とクリーンアーキテクチャに近づいていくよ」
はい。クリーンアーキテクチャを掟のようなものと捉えていた僕はハッとさせられました。
SOLID原則を突き詰めると理想の形になる、それがクリーンアーキテクチャだ、という言葉を思い出しました。
クリーンアーキテクチャの細かいルールを覚えるのではなく、クリーンなコードとは何かということをもう少し突き詰める必要がありそうです。
ばり参考になった記事