28 ポイント 投稿者 GN⁺ 2025-05-10 | 10件のコメント | WhatsAppで共有
  • 初期のスタートアップでコードを性急にマイクロサービスへ分割すると、チームの生産性の深刻な低下と複雑性の増大を招く
  • モノリシック(単一)アーキテクチャは、シンプルなデプロイ、高速な新機能リリース、効率的な協業を通じて生存に最適化されている
  • マイクロサービスは、大規模なスケーラビリティ、多様なワークロード、または別個のランタイム要件がある場合にのみ、分離の利点を発揮する
  • 過度なサービス分割、リポジトリの乱立、不安定なローカル開発環境、技術スタックの不一致などが、速度低下とチーム士気の低下につながる
  • スタートアップはモノリスから始めて、明確なボトルネックが生じた時だけ分離する慎重なアプローチが最適である

序論と背景

  • スタートアップの生存は、高速な反復、新機能の提供、ユーザー価値の創出によって決まる
  • プロジェクトの基本アーキテクチャ、技術スタック、プログラミング言語の選択がチームの速度に影響する
  • 早期のマイクロサービス導入は表向きには洗練されて見えるが、実際には生産性低下、未完成サービス、過剰な複雑性を招く
  • データ: サービスオーケストレーション、Docker/スクリプトの問題、重複したCI/CD、サービス間結合、可観測性コスト、テストの分散など、さまざまな開発コストが発生する
  • むやみに複雑なアーキテクチャへ進むのではなく、実利的なアーキテクチャの重要性を強調している

モノリスの強み

  • SaaSであれ単純なデータベースラッパーであれ、時間とともにアプリは複雑になるが、モノリスアーキテクチャはシンプルかつ柔軟に保ちやすい
  • デプロイが容易で、人気フレームワーク(Django, ASP.Net, Nest.js など)の支援やオープンソースコミュニティの恩恵が大きい
  • 実例: ある不動産スタートアップでは Laravel モノリスを使い、多数のサードパーティ統合や機能拡張を容易に実現した
  • 複雑なインフラ導入やマイクロサービスへの分割を行わず、ビジネス要件と期待値の充足に集中できた
  • 教訓: アーキテクチャの簡潔さはチームがデプロイに集中する助けとなり、内部のモジュール化の失敗さえ避ければ十分にスケール可能である

マイクロサービスは常に最善か?

  • 多くのエンジニアはマイクロサービスが模範解答だと考えるが、実際にはスケールなど特別な理由がある時にだけ真価を発揮する
  • 少人数・小規模・高速変化の段階では、むしろ重複インフラ、遅いローカル開発、遅い反復サイクルという逆効果を生む
  • Segment のような企業も、非効率な構造による転換を経験している
  • 教訓: マイクロサービスはボトルネック解消のためのツールであり、初期テンプレートではない

マイクロサービスが特に初期段階で失敗する理由

1. 恣意的なサービス境界

  • ドメイン駆動設計やクリーンアーキテクチャ理論を借用し、ビジネスロジックごとにサービス分割を試みても、実際のロジックとサービス境界がうまく一致しない
  • 例: ユーザー、認証、権限の分離により、デプロイの複雑性や API 開発の難度が上がる
  • 実際のボトルネックが発生していない段階での分離は、システムを不安定かつ低速にする
  • 内部フラグやトグルで将来の分離をシミュレーションし、急ぎのインフラ作業よりも有機的な境界探索を行う方が効果的である
  • 教訓: 理論ではなく実際のボトルネックに基づいて分離を決めるべきである

2. リポジトリ/インフラの過剰化

  • コードスタイル、テスト、設定、ドキュメント、CI/CD など、あらゆる要素がサービス数に比例して増える
  • モノレポ構造を使えば、すべての構成を一か所で管理し、コードの一貫性と協業効率を高められる
  • Node.js の場合、nxturborepo のようなツールで、内部サービス間の依存関係やビルド管理を容易にできる
  • 欠点としては、複雑な依存関係、CI 性能のチューニングの必要性、より高速なビルドツールの必要性などがある
  • Go エコシステムでも、初期は単一 workspace で管理し、規模が大きくなればモジュール分割を検討できる
  • 教訓: 小さなチームはモノレポと共有インフラによって時間を確保できる

3. 不安定なローカル開発環境

  • ローカル実行に過度な時間がかかる、スクリプトが複雑、システム依存が多いなど、オンボーディングの遅延と生産性低下が発生する
  • 文書化不足、互換性問題、OS 固有のハック(例: macOS 専用スクリプト)などが障害となる
  • あるプロジェクトでは、Node.js プロキシによって Docker の複雑性を緩和し、開発者のオンボーディング時間を短縮した
  • 教訓: アプリが一つの OS でしか動かないなら、チームの生産性は結局一台のラップトップの信頼性に左右される

4. 技術スタックの不一致

  • Node.jsPython は高速な反復には向いているが、マイクロサービス環境ではビルド/ランタイムの不一致問題が頻発する
  • Go は静的バイナリ、高速ビルド、運用の単純さで利点がある
  • 初期の技術スタック選定は慎重に行うべきで、必要であれば gRPC などのプロトコルで言語混在も可能である
  • ML・ETL などの特別な要件がないなら、スタック混在はむしろ複雑性を増すだけである
  • 教訓: 理想ではなくチームの現実に合ったスタックを選ぶべきである

5. 隠れた複雑性: 通信と監視

  • マイクロサービスでは、サービスディスカバリ、API バージョニング、分散トレーシング、集中ログ管理などが必須となる
  • バグや障害の追跡は、モノリスではスタックトレース一つで済んでも、分散環境でははるかに複雑になる
  • きちんとやるには、OpenTelemetry などの専門ツール導入と可観測性スタックの構築が必要である
  • 分散システムは、追加のエンジニアリング課題に対する義務的投資だと認識しなければならない

マイクロサービスが有効な状況

  • ワークロード分離: 画像処理、OCR など特定の非同期処理を分離すると効率的である
  • スケーリング必要性の不均衡: Web API と ML ワークロードでハードウェア・運用要件が異なる場合、それぞれ別に分離する
  • 別のランタイムが必要: レガシー C++ コードなど、主要アプリとランタイム互換のない構成要素は分離サービスとして維持する
  • 大規模なエンジニアリング組織(例: Uber)の事例から見ても、明白な組織的必要と成熟した運用能力がある場合にのみ適している
  • 小規模チームでも、外部分析サービスのように管理が単純な場合には、まれに分離が実用的である
  • 教訓: 実質的に分離の利点が明確なワークロードでのみ採用すべきである

スタートアップ実践ガイド

  • 最初はモノリスで始め、実証済みのフレームワークで開発に集中するべきである
  • シングルリポジトリは、運用・管理効率やセキュリティの観点から初期チームにより有益である
  • ローカル開発環境の簡素化が重要であり、難しい場合は詳細な案内文書や動画の提供が必須である
  • CI/CD への早期投資により、反復作業の自動化とチームの心理的負担の軽減が必要である
  • 明確なボトルネックが現れた時だけ選択的に分離し、それまではモノリス内のモジュール化とテスト強化に集中する
  • 最優先目標は開発速度の維持である
  • 教訓: シンプルさから始め、分離の必要性に応じてスケールすべきである

マイクロサービスをどうしても使うなら

  • 技術スタック評価と開発者体験ツールへの投資: サービスごとの自動化、明確なスクリプト、統合デプロイ管理ツールの整備が必要である
  • 信頼できるサービス間通信プロトコルと標準化: メッセージスキーマの一貫性、文書化、エラー処理など、追加実装事項を把握する必要がある
  • テストインフラの安定化: 単体・統合・E2E テストがサービス分離に合わせて拡張されるべきである
  • 共通ライブラリの検討: 可観測性・通信の共通コードは最小範囲に保ち、全サービスの頻繁な再ビルドを防ぐ
  • 可観測性は早期導入: 構造化 JSON ログ、コリレーション ID など基本的なロギングツールから整備するべきである
  • 結論として、複雑性を受け入れるなら、全力で管理可能な体制を設計することが重要である

結論

  • 性急なマイクロサービス導入は負担だけを残すため、シンプルさを最優先に選ぶべきである
  • 明確な痛点なしに分離せず、生き残り成長するために必要な最小限の複雑性だけを追加するという視点が重要である
  • 生き残ることが先、スケールはその後である

10件のコメント

 
kuil09 2025-05-12

元の話には全体的に同意します。
組織の経験の問題だと思います。
フードトラックで料理を売っていて、やがてレストランへと成長していくことを想像するとよいでしょう。
最初から分業化や専門化を考えるには、利害関係者の経験が絶対的に不足しています。

 
dhlee0305 2025-05-12

スタートアップは生存期間を延ばすために、コストの低い方法を選ぶべきだと思います。マイクロサービスは決して安くありません。実際に現場へ適用すると、かなりのコストを発生させます。できるだけ自社サービスに合ったアーキテクチャを設計することが、より少ないコストで同様の効果を得られる方法だと考えます。
マイクロサービスが悪いというわけではありません。多くのコストを必要とするモデルです。

 
mhj5730 2025-05-12

同期専用モノリスと非同期専用モノリスの2つだけでも十分だと思いますし……。マイクロサービスの導入は、結局のところDBで管理すべきテーブルの規模次第だと考えています。テーブルが常識外れに多くて複雑ならMSAを検討すべきですし、単純ならモノリスが最適でしょう。

 
roxie 2025-05-12

このすべての波が過ぎ去ったとき、後世はこの時代をどのように記憶するでしょうか

 
n1ghtc4t 2025-05-12

あの時はまたあの時の波が…

 
bungker 2025-05-11

スタートアップでも、マイクロサービスには多くの利点があると思います。まず、モノレポを使う利点は本当におすすめです。

  • プロダクトの方向性が修正されたとき、マイクロサービスはモノリシックよりも修正すべき箇所が明確で少ないです。私はこれが本当に大きいと思います。
  • AI開発の時代において、マイクロサービスの小さな単位はAIを使って開発しやすいです。(モノリシックではできないという意味ではありません)
  • CI/CDの負担は認めますが、方向性を固める段階で整理されるサービスもあります。最終的に方向性が固まった段階で構築しても、ほぼコピペレベルなので1週間以内に構築可能です。
  • 言語ごとに強みのあるオープンソースは明確です。SecurityとビジネスロジックはJavaで、AIはPythonで、という形で、マイクロサービス構成ではできるだけ多くのオープンソースを活用できます。
 
andone 2025-05-11

大規模AI開発時代に合わせて、小さな単位で単一責任として実装することが必須だという点には同意します

 
bus710 2025-05-10

意見欄でも少し出ていましたが、beam/otp 系はこういうかなり柔軟で良い感じですね。Gleam の場合は、go と rust 両方の良い文法に beam の安定性が加わって、かなり印象的な言語になっています。小規模プロジェクトでそろそろ使ってみたいですね。

 
ndrgrd 2025-05-10

チームをやたらと細かく分けると、集まって意見を交わすことさえ非常に大きな業務になってしまいます。

 
GN⁺ 2025-05-10
Hacker Newsの意見
  • 本当にスケーリングの問題や大規模チーム、独立して発展すべきドメインがないなら、マイクロサービスはコストばかりかかって利益は得られないと気づいた。実際、Segmentもこの理由でマイクロサービス分割を巻き戻した。これは技術ではなく組織パターンだという点。普通は単一のモノリスを運用しつつ、フロント、バックエンド、時間のかかる処理(例: PDF生成)だけを別サービスに切り出す。その後サービスが増えてきたら標準化やアーキテクチャを考え始める。エンジニアが200人未満では、むしろ生産性の損失が大きい。マイクロサービスのおかげで生き残るのではなく、それにもかかわらず生き残っているのだと思う
    • 一部の開発者には、将来の大企業向けの職務経歴のためにマイクロサービスを導入したがる傾向がある。実際のスタートアップにはあまり役立たない。こうしたことを防ぐには本当に賢い技術リーダーシップが必要だ
    • エンジニア50人規模のスタートアップで、数十のサービスに分割した事例を見た。新規参加者がシステムを把握するのに最低6か月、ユーザーは数百人しかいないのにものすごい複雑さだった。VC資金5,000万ドルを燃やし、結局つぶれた。製品は革新的でよく設計されていたが意味はなかった
    • サービス分割時にコードは分けず、一般的なモノリスをロールフラグだけで分離デプロイする方法もある。バックグラウンドワーカーもWebサーバーと同じように運用しつつ、ヘルスチェックやメトリクスを活用し、ロードバランサーがロール別にトラフィックを振り分ける
    • Khan Academyの事例のように、モノリスを十分にスケールさせた後なら、経験をもとにサービス境界を判断できるようになる。そのときはマイクロサービス導入が適切だ
    • 技術的に分離すべき理由は挙げられるが、サービスというものは元々難しい仕事だ。ただし必要なら習熟度を高めようとする姿勢が重要だ。流行っているからといって無条件に拒否せず、トレードオフを見極めるべきだ
    • 単に「複数チーム」があるからといって組織を分ける必要はないのに、実際には小規模なSquadが2つできただけで、すぐモノリスを分割しようとするディレクターがいる。チームは頻繁に再編される(9か月ごと)ので、アーキテクチャ境界を早く決めすぎるとかえって災厄になる。少なくとも18か月ほど安定して1チームとして運営する価値があるか確認してからでないと、アーキテクチャ境界にはしにくい
    • マイクロサービスの定義はもともと「独立して発展できるドメイン」に関するものなので、目新しいことではないように感じる
    • ある非常に特殊なURLだけトラフィックやメモリ要件が違っていて、PHPサーバーでは適さなかったため、別言語のサーバーを1つだけ追加した。1000倍の性能・コスト改善を経験した。Java/Spring/Guava流に、サービスという概念を「プロセス外」で実装するか「中」で実装するか見直してみる必要もある。技術スタック、バージョン、シリアライズの標準化がしっかりできれば生産性はむしろ上がるかもしれないが、標準化が欠けるとコミュニケーションミスや互換性問題などの混乱を招く
    • Conway's law(コード構造は組織構造を反映する)は実際にその通りだ
    • サービスとは人が提供するもの、マイクロサービスは企業内経済におけるサービスだと強調している
    • 15年前の体験談として、小さなチームの単一ソリューションは簡単に運用できていたのに、マイクロサービス導入後は各サービスの起動や調整まで必要になって苦労した。YAGNI(必要になるまで作らない)を実践する重要性を身をもって学んだ
    • トラフィックが高い経路や重要な経路だけ分離するなど、技術的に分離すべき理由は多い。小さな組織では通常望ましくないが、高負荷の経路だけ切り出せばスタートアップでも大きな効果があるかもしれない
    • 実際、マイクロサービスの主な利点は、小さなグループが互いに干渉せず独立して働けるようにすることにある。しかし複数チームがそれぞれマイクロサービスを所有するようになると、標準化会議が延々と続き、外部サービスに口を挟まれて、協力よりも「他人の仕事には口を出すな」という外交術のほうが重要になる
  • 開発者2〜3人のチームで、かっこよく見えるからとマイクロサービス導入を勧められ、助言にもかかわらず実施した。2年後になってようやく既存コードを再構築し、3年経った今もデプロイやその他の問題を解決できていない。初期の助言を無視せずモジュラーモノリスを選んでいれば、こんな問題はなかったはずだ。この文章に共感する
    • 派手な技術やプロジェクトの経歴だけ残してすぐ転職してしまえば、後始末は他人に回る
    • マイクロサービスは、各サービスごとに1チームずつ担当するときにだけ本当に使いものになる。1チームが複数サービスの面倒を見る形でうまくいった例は見たことがない
    • 問題のかなりの部分は、チームメンバーがマイクロサービスを1つのシステム(モノリス)のように考え続けることから生じる。設計からデプロイまであらゆる工程で摩擦が生じる。組織全体が十分に腹落ちしていてこそ成功できる。既存システムをマイクロサービス化すると内部抵抗も大きい
    • 結局、スタートアップでは皆が似たような苦労をたどる感じがする
    • 8〜12個のマイクロサービスで構成された社内UIプロジェクトでも、実際のユーザーは5〜10人で、不要に複雑さだけが増した。理由がわからない
    • Thoughtworksのコンサルティングでマイクロサービス+Javaを導入した経験がある。コンサル会社は金だけ稼いで去ったが、組織のほうは機能豊富なモノリスを分散マイクロサービスとして再実装するのに迷走した。プロジェクトは結局失敗し、会社も消えた。それ以来、大手コンサル会社を信用していない
  • grug脳スタイルで言えば、なぜわざわざシステムを分割してネットワーク呼び出しまで追加する難しい方法を選ぶのか疑問だ
    • まるでPythonのように言語に「モンキーパッチ」機能がないところへ、それを追加するのと同じだと感じる
    • ネットワーク呼び出しは、ルールを法則に変える役割を果たすという意見だ
    • grugユーモアとして、grug脳を持つgrugが増えると、上位グループが9人のgrugで1か月で赤ちゃんgrugを作れると錯覚する、という意見
  • マイクロサービスは大規模組織で人的問題を解決し、官僚的なハードルを取り除き、開発者に自律性を与えるのに効果的だ。小規模スタートアップでは実際の利益は大きくない。ただし特定ドメインで技術スタックが混在するなら(例: ElixirとPython/Go)、こうした分離が必要になることはある
    • アプリ内で負荷やリソース要件が異なる部分があれば、小さなスタートアップでも別サービスを作る利点はある。大半のビジネスロジックはモノリスのままにし、GPUのような特殊な作業だけ分離する。ただしこうしたパターンが100個のサービス維持にまで広がるのは避けるべきで、基本的にはモノリスを好み、必要な瞬間にだけ分離する
    • マイクロサービスはむしろ組織的依存や調整の必要性を新たに生む。例えば「どのサービスでも持ってきて使ってよい」という方針は保守負担を大きく増やし、誰もが何でも学ばないと回らなくなる。結局、人探しに時間を費やすことになる
    • 互いに対立したり重複したりするチームがあると非効率が大きくなる
  • マイクロサービスはソフトウェアアーキテクチャにおけるConway's Law(組織構造がコード構造に影響する)に近い。チーム境界ごとに越えるべき境界が生まれ、内部で大きなアーキテクチャ境界を人為的に作るのはたいてい非生産的だ。その代わり、依存性注入やモジュール境界設計、アクターモデル活用などでモジュラーモノリスとして管理し、後で本当に必要になればサービス分離もしやすくなる。この方法はコスト対効果が高かった。実際にモノリスを3〜4回切り出した経験がある
    • Conway's Lawはコミュニケーション、つまり意思疎通の境界に関する法則だ。チーム境界ごとに手を入れる必要まではない。むしろ組織をソフトウェアに合わせて再編することが必須で、つまりアーキテクチャを変えるたびに会社のリオーグが必要になる。こうしたやり方はチームとビジネス目標の断絶を深めるだけで、Amazon流をむやみに信奉するなという意見だ
  • 技術的にスタートアップでマイクロサービスが適しているのは、(1) コアアプリと別言語が必須なとき(例: Rails+R)、(2) 一部のサービスだけスケールが桁違いなとき、(3) 特定データだけ異なるセキュリティやライフサイクル要件があるとき(医療情報など)で、それ以外では細分化する理由はほとんどない。小さな組織ではむしろ損だ
    • いくつかの新規サービス分割は本当のマイクロサービスとは違う。実際のマイクロサービスは、普通のアプリならモジュールにしておくようなものまで全部分ける
    • スケールだけでなく、信頼性や可用性の要求が極端に異なるなら、別サービスに分けるのは合理的だ。SLA維持のために関心事を分離することで、リスク低減やデプロイ速度向上が期待できる
    • こうした場合ですら、DBサーバーだけ別運用するのと大差ないという見方もある
  • マイクロサービスの本当の成果は組織面にある。問題を分割し、各チームが1つの断片を完全所有し、エンドツーエンドの提供まで責任を持つことで専門化できる。変更は基本的に段階的に行われ、APIが唯一の相互作用経路になる。単一DB、ファイルシステム、APIの共有はない。その代わり、標準化と管理ツール群(モニタリング、テスト、CI/CDを含む)が重要になる。モノリスであれ何であれ、ある程度は必要な部分だ
    • インフラ、ロギング、認証などはパッケージ化するか、gRPC・メッセージキューなどで管理する。新しいサービスを素早く作れ、チーム内のマージリクエストも小さくなって衝突が減り、生産性が上がる。5〜10人規模のときはモノリスで衝突、デプロイ、リリース問題が頻発していたが、マイクロサービス移行後は生産性と協業のリードタイムが改善した。ただしテスト、ドキュメント、エンドポイントなどのルールは重要だった
    • DB分離など、性能面で技術的に分離すべき場合もあるが、一般的なスタートアップではまれかもしれない
  • BEAM/OTP(Erlang, Elixir)エコシステムの強みは、モノリスを維持しながら「マイクロサービス的」設計を練習し、本当に分離が必要になったときに簡単に移行できることだ。規模が小さいうちはモノリスの利点を享受し、大きくなれば同時にスケーリングと独立性を確保できる。ただし不変オブジェクト、並行コミュニケーション、障害管理などの学習は必要で、人材採用も難しいかもしれない
  • 大筋では同意する。スタートアップ環境ではサービス境界を引くのはほぼ不可能だ。ただし小さなチームでも、外部APIや複雑な依存関係の問題のためにマイクロサービス化が有利な場合はある。この場合、ネットワーク境界が必須なので別サービスにしても複雑性の増加は大きくない。あるいはビルドやデプロイの複雑性がある場合も、分離すればモノリスを単純化する効果がある
  • マイクロサービスは大規模なスケーリングやチームのマイクロマネジメントが必要なときにだけ適している。明確なモジュール境界を放棄してはならない。メッセージパッシング型のオブジェクト指向で、モノリス内でもマイクロサービスの利点を活かせる。DBを直接触らない訓練が必要だ。Javaのような言語ではモジュール化、DBスキーマのネームスペース化、最小限のインターフェースだけ公開し、独立したテストやモニタリングを可能にし、複数サービスの同時デプロイも容易になる
    • 論理的境界を十分に理解していれば、ArchUnitのようなツールで強制する方法もある