サービスの拡大で「早くたくさん機能を作る」から目標を転換
コドモンは「子どもを取り巻く環境をテクノロジーの力でよりよいものに」をミッションに、主に保育・教育施設職員の業務を支援するWebアプリケーションを開発している。他にも保護者と施設のやりとりを支えるモバイルアプリケーション、施設職員向けモバイルアプリケーション、外部サービスと連携するAPIなども開発している。
2015年のリリース以来、加速的に利用者が増え、現在では1万4000以上の施設に利用されるほど成長した。継続利用率も高い。コドモン プロダクト開発チーム マネージャー 岡村謙杜氏は「リリース当初から2020年までは『早くたくさん機能を作る』を目標にしていました」と話す。これは安定してユーザーに価値を届け続けることが難しくなり得る側面を持つ。
結果として現在、安定稼働を最優先事項として技術負債に取り組んでいる。例えば「Aを修正したら、関係のないと考えていたBに影響が出た」「一箇所で問題が発生すると、システム全体に波及してしまう」「リリース後に1つ不具合が発見されると、全てロールバックする必要がある」など。そこでコドモンでは目標を「ユーザーに安定して素早く価値を届け続ける」へと転換した。
この目標を実現するための手段はいろいろ考えられるが、コドモンではこの機会にマイクロサービスアーキテクチャへと移行することに決めた。その理由として岡村氏は、独立してデプロイ可能、耐障害性向上、特定箇所のみスケール可能、副次的にチームの自律性向上、技術選定の機会を得られるなどを挙げる。マイクロサービスアーキテクチャを採用することにより起こりうるデメリットも存在するが、現在のコドモンではメリットの方が上回ると判断し、移行を決断した。
とはいえ、会社としてはマイクロサービスアーキテクチャの移行に取り組むのは初めての挑戦となる。社内にナレッジがあるわけではなく、経験者も少なく、どのくらい時間がかかるかも予想しづらい状態であり、最初に全体の戦略を立てるために不確実性を減らす必要があった。
移行対象の選択は「改修可能性を上げることで事業成長につながるか」というビジネス視点と、技術視点による「改修・移行難易度」の2つの視点を組み合わせて判断した。コンテキストマップを作成してドメインを整理したところ、「シフト」と「資料室」ドメインが候補に浮上した。他のサービスとの接続が少なく、リスクが少ないと考えられるためだ。「シフト」ドメイン自体は複雑性が高いものの、アプリとのつなぎ込みやデータ移行もなく、「シフト」の改修可能性を上げることで事業成長にも繋がるため最初の取り組みには良いと判断された。
![コンテキストマップを作成し、分割すべきドメインを特定した](http://cz-cdn.shoeisha.jp/static/images/article/17473/17473_p1.png)
実際の移行はXP(エクストリームプログラミング)を取り入れた。採用した理由について岡村氏は「テクニカルプラクティスが明確に定義されていることが大きな理由の1つ」と話す。数年前までのコドモンでは作業が属人化しており、ソースコードが読みにくいとか、改修が大変といった問題があり、XPで打破できると期待できたためだ。
XPの取り組みでは書籍『Clean Agile』を参考にした。岡村氏は「すべてのプラクティスを取り入れ、守破離の守を大切にすることを強く意識しました」と言う。プラクティスは1つだけ取り入れることもできるが、複数組み合わせることで相互作用が働き効果を増幅させることができるため、できるだけプラクティスを採り入れることにした。
例えばペアプロをしながらTDD(テスト駆動開発)をすることにより、開発にリズムが生まれ、属人化が減り、共同所有が促されていく。そしてそこに、継続的インテグレーションや受け入れテストを組み合わせることにより、小さなリリースがやりやすくなる。プラクティスに取り組むことにより、他のプラクティスに取り組みやすくなると共に、一つひとつの効果を大きくし、理想に近づくことができる。
実際の開発サイクルでは、最初に「ユーザーストーリーの受け入れ条件について認識を合わせる」ところからスタートし、受け入れテストを記述、ペアでTDDを実践しながら進める、ローカルでテストが通ることを確認、リモートリポジトリにプッシュ、CIでテスト実行、ステージング環境で確認、本番環境にデプロイというサイクルを回し続けた。
続いてブランチ戦略ではトランクベース開発を採用した。これは開発者が直接トランク(メインブランチ)に小さく頻繁にプッシュしていくというもの。これのメリットは継続的インテグレーションを実現でき、開発時の運用もシンプルになり、コンフリクトを早めに検知できて、修正も少なくてすむ。
岡村氏は「XPに取り組み、プラクティスを取り入れたからこそ、トランクベースがうまく回ったのかなと思っています」と話す。
マイクロサービスへの移行はStrangler patternで
ここからは「資料室」を例に、移行をどう進めたかを具体的に見ていこう。この「資料室」という機能は、保育・教育施設で取り扱うさまざまな資料を保護者が閲覧できるようにアプリ上に公開するためのサービスとなる。サービス自体は単純だが、既存アプリとの連携、特にこれまで蓄積されたデータも継続して扱えるようにするところが難点となる。
従来はモノリシックなシステムが同じリソースで稼働していた。またあらゆる機能が1つのデータベースに蓄積されるような形になっていた。新サービスでは、新しいリソース上で稼働させ、独自のデータベースを持たせ、新しいスタックを用いることにした。ただしデータは古いデータベースにあるものも扱えるようにしなくてはならないため、必要な情報を抜き取り、新しいサービスの形に変換するデータ同期バッチを中間に立てることにした。
![マイクロサービス移行後のシステム構成](http://cz-cdn.shoeisha.jp/static/images/article/17473/17473_p2.png)
技術スタックとしては、バックエンドはドメインを型で表現しやすく、nullチェックも厳格であり、メンバーに経験者がいたKotlinを選んだ。フロントエンドはNuxt.js、インフラはECS(コンテナ)、CI/CDはGitHub Actions、E2EテストはGaugeとPlaywrightとした。
リプレイスへのアプローチで最も重視したのは「安全にリリースすること」なので現行システムとできるだけ疎結合にした。ほかにもビッグバンリリースにしないこと(徐々にリリースする)、容易に運用できるようにテストに力を入れることも重視した。リリースから数年経ちユーザーが求めるものが見えてきたので、このタイミングでフロントもリプレイスできるように、フロントも切り出した。
モノリシックなシステムからマイクロサービスに切り離す時に参考にしたのが「Strangler pattern」で、これは新旧のサービスを並行稼働させながら徐々に切り替えていく方法だ。新しい機能を小さい単位で作り、トラフィックをコントロールすることでユーザーを徐々に新しい方へと誘導していく。コドモン プロダクト開発チーム エンジニア Dimitrov Chavdar氏は「本番環境に未完成の成果物をリリースできて、トラフィックを切り替えるまで何も影響がないのがうれしい」と話す。
![Strangler patternのメリット](http://cz-cdn.shoeisha.jp/static/images/article/17473/17473_p3.png)
新しいサービスを一部のユーザーから徐々にリリースすることをカナリアリリースと呼ぶ。何か問題が生じても影響範囲は少なく、安全な旧サービスにトラフィックを誘導すればいい。実際に新サービスでエラーになれば、自動的に旧サービスを利用するようにフェイルセーフする仕組みがあれば、ユーザーは「何かいま画面が遷移したかな?」くらいで大きな問題にはなりにくい。
新旧サービスのデータを同期する仕組みを導入
モノリシックからマイクロサービスへと移行するのに伴い、データのマイグレーション(移行)も発生する。新サービスで旧サービス時代のデータを使わなくていいのならいいが、今回の移行対象が資料管理システムなのでそうはいかない。先述したように、旧サービスと新サービスとの間にデータ同期バッチを配置し、旧サービスにあるデータを新サービスに同期するようにした。
今回はXPのプラクティスとしてTDDを導入していることもあり、このデータの同期バッチもTDDの対象とした。実際のテスト(検証)はGaugeで自動テストを行い、さらに手動テストも行い正確性を担保した。
Gaugeの自動テストではデータがストレージ(Amazon S3)やデータベースに入っているか、資料の状態などの確認、移行失敗時のロールバックの確認、手動テストではデータ移行前後で資料に表示崩れがないかの確認、移行バッチ実行時の負荷テスト、各種設定の確認などを行った。
![新旧サービスのデータの同期方法](http://cz-cdn.shoeisha.jp/static/images/article/17473/17473_p4.png)
こうしてデータを同期できる状態にできたことでChavdar氏は「モバイルアプリのリリースと施設側(PC側)のリリースを別々にできたのがうれしかったです。またシステムをメンテナンスモードにする必要がなく、ユーザーにもメリットがあったかと思います」と話す。
施設向けサービスのリリースはフィーチャーフラグを使い、新サービスが見えるユーザーを限定することでデプロイとリリースを分けることにした。データベースに新機能が表示か非表示かのフラグを持たせ、後は(Webサイトの)テンプレート側でどう見せるかを切り替えている。
保護者向けモバイルアプリもフィーチャーフラグを用いた。モバイルアプリで新しいものをリリースしようとするとストアに申請するなど手間がかかるが、フィーチャーフラグを使えば表示を切り替えることになるので不具合が発生してもロールバックしやすくて開発者としては安心材料になるのではないだろうか。またモバイルアプリでもエラーが発生したら旧画面に遷移するようにフェイルセーフの仕組みをいれておいた。
![フェイルセーフの仕組みを用意](http://cz-cdn.shoeisha.jp/static/images/article/17473/17473_p5.png)
最後にモノリシックからマイクロサービスへと移行することで、Chavdar氏は「資料室に限っては冒頭で挙げたようなさまざまな蓄積された問題が、かなり解消されていると感じています」と話す。
例えばシステム改修の影響は対象システム内に閉じていること、デグレが起きても他の全てが戻ることはなくなり、リリース調整のためのチーム間コミュニケーションは不要で独立してデプロイできるなど。マイクロサービスのメリットを享受できている。
岡村氏はXPを実践した感想と学びについて次のようにまとめた。
「XPのプラクティスを導入したことで安全に素早くリリースできる状態になりました。プラクティスはどれも効果を発揮したが、中でも特にペアプロが大きかったかなと思っていて、属人化がなくなり、知識がチームの中で流れ続け、メンバーそれぞれが得意分野を発揮しつつ他の分野でも成長できたと思います。あと自動テストを初期から入れたことで安全に開発を進めることができました。期限が迫ってくると『テスト書かないほうが早くすむのでは』と誘惑に駆られたりするが、そもそも何を実現したくてテストを書いているのか、一瞬だけ早さを出して本当に嬉しいのか等、本来の目的に立ち戻ることが大切です。また既存サービスとの関わりは難しいので、仕様や制約の調査をすることも大切です。
そして仕様の変更やXPの導入などは初めての取り組みでしたので、プロジェクト完了まで8カ月間を要しました。一番大変だったのは最初のチームがリズムに乗るまでの初動でした。この経験をもとに他のチームではこの難関をより早く乗り越えていきたいと思っています。今後はより複雑で他のサービスとの依存度が高いものでマイクロサービスへの移行に挑戦していきたいです」