マイクロサービスでチームを分離したくないマン
コンウェイの法則とかで、マイクロサービス=組織 という話になることが多いなと感じる。
正解の場合もあるし、不正解の場合もあると思っていて、個人的には小さいチームでもマイクロサービスをやるメリットは技術的にも組織的にもあると思う。 そのメリットを無視してすぐ組織の話に持っていきたくないので、基本分離したくないマンとしての主張を書いておく
技術観点でのメリット
いまさら語るまでもないけど、
- ドメイン境界の分離
- デプロイ独立性
- リソースの最適配分
- 障害の局所化(サーキットブレーカー等)
このうち、ドメイン境界の分離だけはモジュラモノリスで対応可能だが、あとの3つにはマイクロサービスが必須。(もっとあるかも)
この3つが必要なのにモノリス or モジュラモノリス で進める判断をするということはシステムの表現力を落とすことに直結する。
もちろん、複雑度は増すし難易度も増す。熟練のサーバーサイドエンジニアとインフラエンジニアは必須。
※別の記事でも言及してますが分散モノリスにならないようアーキテクチャ側で制約をもっている。チームが分かれてなくても分散モノリスの回避は可能。
※モジュラモノリスはどこまでも分離を前提として設計しています(アプリ側はDI差し替えたら分離完了する)。そうしないとあまり意味がなさそう。
組織、チーム観点でのメリット
開発を進めていき、コードベースが大きくなっていくと「全てを把握してコードを書く」ことがどんどん難しくなる。
ここで安易に人数を投入して把握すべき単位を小さくするアプローチは、個人的にはかなりコスパの悪いアプローチだと思っている。
具体的には以下のようなことが考えられるからである。
- エンジニアは把握すべき単位を超えた部分に対する理解や責任が浅くなり、開発の速度や機能開発の質が悪くなる
- 案件をすすめるにあたり、コミュニケーションを取る対象が増え、アジリティが低くなる
- 開発チーム内でサイロ化が始まり、やるべき破壊的な変更に対し実行する判断を下せなくなる(めんどくさくてやらなくなる)
この辺はラストマンシップをもった人で構成されているチームであればある程度解消できるが、そもそもラストマンシップをもっている人にとってはこの垣根は邪魔なものでしかない。
個人的には適切に関心事が分離されているコードベースであれば、1プロダクトであればかなりの規模のコードでも少人数で回せると思っている。(少人数の定義はむずいが、1つのプロダクトに100~1000人のエンジニアは絶対要らないはず。もちろん場合にもよると思うけど)
理由は
- 適切に関心事が分離されていれば、全てを把握してなくても「今触りたい機能に関係する部分」だけ知識のアップデートをして開発に取りかかれる
- 誰がどの機能に詳しいなどの偏りは出るが、むしろそれによってアサインが明確になりレビューが捗る(その機能に詳しい人+そうでもない人をレビュワーとしてアサインする等)し、チームメンバーのコミュニケーションも円滑になる(経験則)
- 複数の機能に詳しい人が育ちやすく、それによって案件を一人で遂行できる能力がつき、ラストマンシップが身につく といった流れができる。
上記のようなメリットを享受しつつ開発時のコミュニケーションも最小で済ませることができる。
単機能を担当するような組織だと担当機能の変更を好まない性質が出やすい。
- 変更しないほうが障害リスクもないし対外的に見て得なことが多い。スケジュールの握りも過剰に安全性に倒しまくったほうが得になる。
- 常にシステム全体の利害関係者であるべきだが、その状態が維持しにくい。維持できないと適切な機能開発は難しく、歪になっていく。
- ○○チームがあまり要望聞いてくれないから勝手に○○機能実装しました。みたいな例も聞いたことがある・・・。馬力のあるやつの無駄遣いすぎる。
以上のようなことを考えないで済むのはかなりのメリットだと思っている。
まとめ
現職では、19のマイクロサービス(Scalaで76万clocほど)は15人ほどのサーバーチームと、5人のSREチームで管理している。(マイクロサービス化した頃は、7つのサービスにサーバー3人、インフラ兼サーバー1人だった) それらは案件ベースで協力して動くが、組織的観点では同じチームだし、案件に必要ならどのマイクロサービスも触る。(クレイグ・ラーマンの法則に近い動き方なのかな?あんまり詳しくないのでわからないけど)
普通に事業的にも、開発的にも上手く回ってるし、分割したら上手く回らない未来しか見えない。(少なくとも自分のチームでは)
これからチームがどんどん大きくなっていっても、少なくとも1サービス-1チームの分割はしないんじゃないかなーと思っている。
ただ、上手く回ってるのは、以下の要素も大きいのかなーと思うので、どこでも適用できる話ではないのかもしれない。
- Scala+Effによるシステムの表現力
- CleanArchitectureによる分散モノリスを防ぐ制約(例えば👇)
- 内部通信用アダプタ(gRPC)と外部通信用アダプタ(http)を分けている
- ドメインに他サービスの関心事が入ってこないようRepositoryとは別で出力OnlyのDIPをしている再考 - ドメインサービス - まっちゅーのチラ裏
- sbtプロジェクトによる、コードを直接参照できない強固な縦横の境界付と、依存方向を単方向に強制する制約
- 開発が普通にできるレベルのエンジニアリング力がありつつ、PM力もすごい強いPMが複数いる
- インフラもk8sで運用が楽。
- CIも工夫して手間なく複数サービスのデプロイができる
とはいえ、ECSやk8sだったり、CIの仕組みだったり、マネージドサービスだったりでマイクロサービスもどんどん運用が楽になってきているし、これからもなっていくだろう。
その時流の中、チームが小さくて組織とマッピングできないからといって検討もせずにコンテキスト分離のメリットを捨ててしまうのはもったいないと思う。
小さいチームでもマイクロサービスは十分有効で、組織分割は必須ではないという意見でした。
※マイクロサービスの前にモジュラモノリスを考えるべきではある。デプロイ独立性等は不要で、縦のコンテキスト分離だけ必要ならそれで十分なので。
※組織を分割する必要のない小さいチームでもコンテキスト分離を試みるメリットについて書いたのは👇 認証と認可と課金とコアドメインを分離したシステムは勝てるという話 - まっちゅーのチラ裏
※追記 コンウェイってより逆コンウェイじゃね?と教えてもらって、たしかにそうっぽい。と思ったので逆コンウェイの引用も貼っておく。 逆コーンウェイ戦略とDevOps, Microservices, Agile | an Agile Way
ざっくり👇のように理解した。
※追記 マイクロサービス化 -> 組織分割の間にはグラデーションがあると思っているだけで、組織分割自体を否定したいわけではありません。すぐそっちに話を持っていくのが違うなーという。特に「コアドメインのコンテキスト分離の境界をどこにするのか」は、めちゃくちゃ難しいので組織分割を先にしてコンテキスト分離すると意味不明な単位になるし、組織を専任で当てるほどでもない小さい単位でも、分離すると有用なケースも往々にしてあると思う。