# Shoprocketのマイクロサービスへの道、第1回：モノリス分割で私が間違えたこと

> Shoprocket創業初期のエンジニアリングチームによる記事。PHPのモノリスからサービスを切り出した最初の試みについて。最初のサービス選びを間違えた理由、密結合から学んだこと、もっと早く従うべきだったNewmanの助言を紹介します。

Winston Berty  - 2016年3月17日 - 読了目安 5 分

Shoprocketで働き始めて数か月がたつころ、私はいら立ちを募らせていました。私たちは、世界中に散らばる少人数の優秀な開発者たちが手がけるPHPアプリケーションを抱えていました。私の目には、バグを直すと別のバグが生まれ、新機能の統合は本来あるべき簡単さではなく、デプロイは頻度が低くて神経をすり減らすものに映りました。原因は、強く結合したコードです。

私たちのアプリケーションはモノリスで、ほぼすべてが1つのGitHubリポジトリに入っていました。ある機能の更新や修正に、複数の箇所の変更が必要になることがよくありました。テストについては、ブランチをmasterにマージしてデプロイするには、少なくとも2人の他の開発者の承認が必要という、ピアレビューのプロセスがありました。そのため、バグが紛れ込んだとき、問題を起こした変更の特定が難しいことがよくありました。見つかったとしても、修正も同じプロセスをたどり、アプリケーション全体を再デプロイする必要がありました。

新しいものをいつも探している意欲的な若手開発者だった私は、マイクロサービスに出会ったとき、これで私たちの問題がすべて解決すると思いました。

## 私がマイクロサービスだと思っていたもの

マイクロサービスに正式な定義はありませんが、調べた結果、私はこう理解しました。マイクロサービスアーキテクチャとは、ソフトウェアアプリケーションを、独立したサービスの分散システムとして設計する手法です。各サービスは高度に専門化されており、それぞれ独自のライフサイクルを持ちます。詳しい入門としては、Martin Fowlerの[記事](https://martinfowler.com/articles/microservices.html)が秀逸です。

私が夢中になった点は2つあります。1つ目は、アプリケーションを厳格な境界を持つサービスに分割するという発想です。境界をまたぐインターフェースを慎重に設計しなければならないため、特定のビジネス上の文脈に固有のロジックが、コンポーネント間に漏れ出す可能性が下がります。ローカルの関数を呼び出すほど単純ではありません。2つ目は、各コンポーネントが独立したライフサイクルを持てることです。チームは自分たちのコードを所有し、そのサービスに最適なスタックを使えます。変更は1サービスずつデプロイでき、ほかに影響を与えずにロールバックもできます。

私はすっかり乗り気でした。Shoprocketはモノリスを分割するのだ、と。これは、その道のりを追う短いシリーズの第1回です。同じような移行を計画中、あるいは進行中の読者が、私たちの成功と失敗から学べることを願っています。

## 最初の課題は、技術ではなく人だった

チームのほかの人たちに、このアイデアを売り込む必要がありました。彼らは興味は示したものの、私ほどの熱意はなく、プロダクトのこの初期段階で開発時間を割くことには消極的でした。幸い、CTOが私にセッション管理を調べてほしいと考えていたので、この機会をつかみました。セッションサービスを切り出せると、彼を説得したのです。

振り返れば、最初のサービスとしては悪い選択でした。私たちのプロダクトには、[どんなウェブサイトでもECを可能にする](https://v3.shoprocket.io/ja/features/sell-on-any-website.md)JavaScriptウィジェットが含まれています。私たちはセッションをリソースとして扱い、カート放棄などのKPIを分析するために、セッション情報をデータベースに永続化していました。しかし、このリソースは、注文や明細行のような具体的なものほど実体がなく、しかもアプリケーションの状態が変わるほぼすべての場面でセッションを使っていました。つまり、このサービスはアプリケーションのほかの部分と、避けられないほどやり取りが多くなります。私はそれを予見しておらず、そのせいで作業はいっそう難しくなりました。

## 実際に作ってみて学んだこと

私は調査を強化しました。Fowlerに加えて、Sam Newmanの**『Building Microservices』**が、欠かせない資料になりました。

Newmanの助言は、今にして思えば、私が従うべき助言そのものでした。まず既存のアプリケーションを、ドメインの境界づけられたコンテキストを反映したモジュールに再構成すること。開発者たちが境界に納得したら、*そのときに*モジュールを独自のサービスに切り出すこと。理由は、境界が悪いモジュールを分解して書き直すほうが、余分な配管コードや永続リソースをすべて抱えたサービス全体を分解して書き直すより、はるかに簡単だからです。

私はその助言に従いませんでした。自分のコンポーネントを作りたくてたまらず、セッションサービスを先に進めてしまったのです。

私は、モノリスとほんのわずかしか違わないスタックを選び、作り始めました。サービス自体は素早く形になり、REST APIを持つ単独のアプリケーションが数週間でできあがりました。難しかったのはそこではありません。難しかったのは、サービスをモノリスと連携させることでした。

セッション管理は、コードベースのほかの部分と密に結合していることがわかりました。関数呼び出しをAPI呼び出しに置き換える作業は、遅々として進みませんでした。セッションサービスとモノリスのデータベーススキーマが別だったため、モノリス内で古いデータベースのセッションリソースを使っているロジックはすべて、書き直さなければなりませんでした。JavaScriptウィジェットのようなクライアントとの互換性を保つため、アプリケーションの境界でデータ構造を組み替えました。

統合には、構築よりも時間がかかりました。しかも、それにはマイクロサービスが通常もたらすオーバーヘッドの大半（サービスディスカバリ、ロギング、モニタリング、分散トレーシング）がまだ含まれていません。さらに悪いことに、密結合のせいで、変更はコードの多くの領域に広がりました。その間もチームは並行して作業を続けていたため、マージしてセッションサービスを本番に出すには、私が見積もっていたよりずっと多くの調整が必要だったはずです。

## 正直な評価

このサービスは、もうすぐ本番に入るかもしれません。ただ今では、Newmanの助言に従い、まず既存のアプリケーションのモジュール化に力を注ぐべきだったと感じています。1つのサービスだけが単独で存在することの利点は、わずかです。本当の利点は、全体を分割したときに、少なくとも互いのやり取りが可能な限り少ない、粒度の粗いサービスに分けたときに生まれます。そのためには、よく考え抜かれたコンポーネントの境界が必要で、私たちはまだそこに達していませんでした。

私は、アイデアとしてのマイクロサービスには、今も賛成です。この試みは、有益な実験だったと考えています。アプリケーションアーキテクチャ、ドメインモデリング、RESTの原則について多くを学び、その教訓は私たちのコードのほかの部分にも波及しました。

同じような移行を考えている人への、私の正直な推奨は次の通りです。

- 踏み切る前に、このテーマについてできるだけ調べる
- 既存のコードベースとドメインモデルに本当に自信が持てるまで、作業を先送りにする
- モノリスに安定性と回復力をもたらす方法は、ほかにもあることを忘れない。自動化されたユニットテストと機能テストは、非常に役立ちます。テスト駆動開発はリグレッションを減らします。水平スケーリングは、デプロイの苦痛を和らげます
- サービスを切り出す前に、まずモノリスのモジュール化から始める

Shoprocketの旅は続きます。第2回から、もっと面白くなります。

---

*PHPのモノリスからの脱却というShoprocket初期の移行を記録した短いシリーズの第1回として、最初に公開されました。後の改良で正されたミスを含む旅の全体は、その後のプラットフォームの大規模な書き直しのたびに続いてきました。*

---

- HTML version: https://v3.shoprocket.io/ja/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith
- Language: 日本語 (ja)
- Also in: [العربية](https://v3.shoprocket.io/ar/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [Deutsch](https://v3.shoprocket.io/de/blog/shoprocket-microservices-teil-1-monolith-zerlegen-fehler.md), [Ελληνικά](https://v3.shoprocket.io/el/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [English](https://v3.shoprocket.io/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [Español](https://v3.shoprocket.io/es/blog/shoprocket-microservicios-parte-1-lo-que-hice-mal-monolito.md), [Français](https://v3.shoprocket.io/fr/blog/shoprocket-vers-les-microservices-partie-1-decouper-le-monolithe.md), [עברית](https://v3.shoprocket.io/he/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [हिन्दी](https://v3.shoprocket.io/hi/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [Bahasa Indonesia](https://v3.shoprocket.io/id/blog/perjalanan-shoprocket-menuju-microservices-bagian-1-salah-memecah-monolit.md), [Italiano](https://v3.shoprocket.io/it/blog/viaggio-di-shoprocket-verso-i-microservizi-parte-1-cosa-ho-sbagliato-sul-monolite.md), [Lietuvių](https://v3.shoprocket.io/lt/tinklarastis/shoprocket-kelione-i-mikropaslaugas-1-dalis.md), [Norsk](https://v3.shoprocket.io/nb/blogg/shoprockets-vei-mot-mikrotjenester-del-1-hva-jeg-tok-feil-av.md), [Nederlands](https://v3.shoprocket.io/nl/blog/shoprocket-microservices-deel-1-monoliet-opknippen.md), [Polski](https://v3.shoprocket.io/pl/blog/droga-shoprocket-do-mikroserwisow-czesc-1-rozbijanie-monolitu.md), [Português](https://v3.shoprocket.io/pt/blog/jornada-do-shoprocket-para-microsservicos-parte-1-o-que-errei-ao-quebrar-o-monolito.md), [Română](https://v3.shoprocket.io/ro/blog/drumul-shoprocket-spre-microservicii-partea-1-ce-am-gresit-cu-monolitul.md), [Русский](https://v3.shoprocket.io/ru/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [ไทย](https://v3.shoprocket.io/th/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md), [Türkçe](https://v3.shoprocket.io/tr/blog/shoprocket-mikroservis-yolculugu-1-monoliti-parcalarken-yanlis-yaptiklarim.md), [中文](https://v3.shoprocket.io/zh/blog/shoprockets-journey-to-microservices-part-1-what-i-got-wrong-about-breaking-up-the-monolith.md)
