事業成長に合わせた継続的なシステム改善

島谷宙伸氏(以下、島谷):では、発表させていただきます。よろしくお願いします。

(会場拍手)

簡単に自己紹介だけさせてください。島谷と申しまして、2012年にサイバーエージェントに新卒で入社して、4年間ぐらいソーシャルゲームのバックエンドサイドのエンジニアをしていました。

2年前ぐらいに、サイバーエージェントの子会社であるマッチングエージェントに出向しまして、現在は「タップル誕生」というプロダクトを担当してます。

タップル誕生について、簡単に説明させてください。タップル誕生は、趣味でつながるコンセプトのマッチングサービスでして、運用開始から5年ぐらいになってます。

ちなみにこのなかで「マッチングサービス使ったことあるよ」っていう方、いらっしゃいますか?

(会場挙手)

お、ありがとうございます。あと、率直に聞きたいんですけど、「マッチングサービス、あやしいんじゃね?」、「業者とかいるんでしょ?」とかお思いの方、いらっしゃいますか?

(会場挙手)

あ、ゼロということで、ありがとうございます。

(会場笑)

タップル誕生では不適切な投稿の監視や、不審な会員の取り締まりを24時間365日体制で実施しており、健全化への取り組みを徹底しておりますので、安心して使っていただければなと思います。

今日はリプレイスについてということで「リプレイスについて15分も話せることあるかな?」って思ってたんですけど。事業や組織のフェーズに合わせて繰り返してきていることを振り返って整理できたので、フェーズに合わせてどうやってシステムがリニューアルしていったのかというお話ができればいいなと思っています。

2年前のチームの状況

まず最初に、2年ぐらい前の僕がジョインしたてのチーム状況についてです。サービスリリース3年目というところで、事業としてはすごく成長していっている状態でしたが、もともとスモールチームで開発されていたので、エンジニアは10人規模で、バックエンドも2人ぐらいしかおらず、すべての技術領域で負債だらけな感じでした。

本当に負債が多すぎという感じでして、アラートメールもしょっちゅう飛んでくるし、「まともに開発できないじゃん!」という状態でした。

ただ、事業は伸び盛りということもあって、「成長させなきゃいけない。けど、負債も返さなきゃいけない」というジレンマにはさまれていました。

このフェーズでどのように進めていったのかというと、最初はゴール設計をちゃんとしました。

今回のゴールはクリティカルな状態からまずは脱出するということ。全部を一気に解消するのってなかなか難しいかなと思います。負債解消に使えるリソースも限られてるので、サービスが止まるといったクリティカルなものだけを注力して解消することが大事であると。そのため最初に負債を洗い出して、優先度をしっかり決め、取り組むべきポイントとどこまでやるかの線引きを決めた後で着手していきました。

検索システムの刷新

この流れで「検索システムがもっともヤバいだろう」という話になりました。メインのデータストアとしてMongoDBを使っていたのですが、ここでパフォーマンス問題が非常に多く発生していました。

マッチングにおいて検索ってどういう相性が良い人を出すかという点で大事な部分なんですが、この検索アルゴリズムまわりにもMongoDBを使っている状態で。もともとそれほど検索に強いDBではないので、ユーザーがどんどん増えていくにつれて負荷が増大し、全体に影響が及んでいるという状態でした。

ここで、検索システムとしてElasticsearchを導入することを考えたんですが、やっぱり施策開発もとても重要なので、システム刷新を並行して進めにくいという背景がありました。

このタイミングで、「ちゃんと改善を進めるための専任ラインを作らせてくれ」という話を、経営ボードのみなさんとトコトン話し合いました。結果的に専任ラインを作らせていただいたのですが、中長期で技術的な負債を返さなきゃいけない重要性をしっかり話し合って理解してもらうというのは大事だったのかなと思います。

しっかり専任ラインを作って、MongoDBからElasticsearchに検索部分を載せ替えたんですが、パフォーマンスとしては、……ちょっと上のグラフとか「ヤバすぎでしょ」みたいな感じなんですけど。

(会場笑)

ちゃんと(笑)、まともに利用できるぐらいまでにはなりました。全体のスループットとしても、良くなったというような感じです。

レガシーコードを改善する

こういったクリティカルな状況をなんとか脱せたので、次にどういうフェースに入ったかというと、「スタンダード化」って呼んでいました。「ちゃんと負債を返して、より良いプロダクトを作ることに集中できる状態に持っていきましょう」というのをゴール設計をして、また改善を進めていくというような流れです。

AndroidだったらKotlin化していくとか、iOSではSwift化していくという話でしたが、バックエンドのスタンダード化というのは、大きく分けて2つ考えています。「レガシーコードをちゃんと刷新していこう」という話と、もともとパブリックではなくプライベートクラウドを使っていたんですが、「それをちゃんとパブリッククラウドに載せていこう」という話をしてました。

それぞれどうやって進めていったかといいますと、レガシーコードの状態は、本当に信頼できるテストコードがありませんでした。コードアーキテクチャなどを改修して、開発効率を上げていきたいんですが「いや、これ、誰も触れないでしょ」みたいな、「勇気いりすぎでしょ」みたいなコードがけっこうたくさんあって、なかなか着手できない状態でした。

このときに一番課題だと思ったのが、そもそもテストを書くという文化が根付いていないとか、テストコードを書こうにも書くためのコード基盤が整っていないということでした。そこを解消しようということで一番有効に使えたのがこの2点かなと思います。

チームの文化を作るためにやったこと

まず、チームの文化をちゃんと作っていこうということで、テスト駆動開発の第一人者であるt-wadaさん、和田さんを講師として呼びまして、TDDについてワークショップを開いていただきました。

僕もそうなんですが、すごく影響力のある人に「大事でしょ」って言われると、「確かに!」というミーハー心というか、影響されることもあると思っているので、こうした文化を変えたいと思ったときに、自分の力でどうにもならないときは、外の人の力を借りるのも良い方法なのかなと思いました。

このワークショップ、1回やっただけでそんなにTDDがチームに根付いたわけではありませんでしたが、間違いなく「テストを書くぞ」という意識付けにはなったので、非常に良かったなと思います。

レガシーコードに立ち向かうために「テストを書くぞ」という、心に火がついた状態で開発合宿に行くっていうようなことをやりました。

もともとワークショップをやる前に、「開発合宿でちゃんとレガシーコードのアーキテクチャを変えようぜ」という話をしていた途中で、「じゃあ、t-wadaさんに講演してもらって火をつけてから行けばいいんじゃないか」という流れでした。

当日実践したこととしては、モブプログラミングをやって、「新しいアーキテクチャってこう書くべきだよね」とみんなで認識し合ったり、テスト基盤をちゃんと整備したりだとか、カバレッジを全員で上げたりだとか、そういったことをやっていました。

振り返ると、確実に解消されていっているなと思っています。

2年前はほぼゼロと言って差し支えなかったカバレッジですが、いま見ると60パーセントぐらいまで増えていて、確実に「けっこう書けてるな」という感触を持ってます。アーキテクチャも徐々にリファクタリングされていってて、誰も触れないコードも減っていってる状況です。

AWSへの移設

AWSへの移設の話をしたいと思います。移設は大きく分けて、アプリケーション層の移設とDB層の移設という、2つのフェーズに分けました。

分けた理由としては、全体を同時に進めるだけの人的にリソースを割くことが難しかったためです。「だったら、いっぺんにやるとそれだけ考慮事項も増えますし、段階的にやることでステップアップしてやっていけるんじゃないか」という話をしていました。

なぜDBから進めたのかというと、直近の最大のボトルネックがDBで、そこをまず解消したほうが心配がなくなるからという理由でした。プライベートクラウドとAWSクラウドで、どうやってハイブリッドな環境を実現したのかというと、AWSのDirect Connectという、プライベートクラウドとAWSの環境を専用回線でつなぐというサービスを利用しました。

どうやって進めたのか、ざっくりした図ですが、まずはDirect ConnectでAWS環境とつないで、レプリケーションで、オンラインでデータを同期させます。データの同期が終わって準備ができたタイミングで、アプリケーションの向き先をAWS環境の方に変えることで移設を完了させました。これによって通常のdump、restoreよりも早い移設が可能だったかなと思います。

この構成での注意事項としては、やはりネットワーク的に遠いのは間違いないので、レイテンシとか、大丈夫かは確認するべきだと思います。タップルの場合は、新しいDBに変えたことでパフォーマンス効果がすごく大きかったので、全体としてはレイテンシは改善されたかなと思います。

もう1つ大事なことですが、あくまでこれは、一時的な構成にしないとまずいということです。Direct ConnectというのはSLA、サービス・レベル・アグリーメントを定めてないので、ダウンしてもAWS側に文句言えません。なのでちゃんと「この構成は一時的なものだよ」ということを事前に話していました。

残るはアプリケーション層ですが、Route53のTraffic Flowを使って徐々に移設しました。

Traffic FLowは複雑なルーティングポリシーを、AWSの管理画面上でビジュアライズして設定できるものです。今回だと「99パーセントのトラフィックを旧環境に振り分けて、1パーセントを新しい環境に振り分ける」みたいなことを、このコンソールでポチポチやるだけで実現することができました。

リクエストを徐々に流していけるので、スケーリングの調整を本番のトラフィックを見ながらやれたり、予期せぬトラブルが発生したらすぐ切り戻せるという安心感を持って移設が進められました。もちろん事前に負荷試験もちゃんと実施していたのですが、こうした安心感があったのは心強かったかなと。

後にEC2からECSに載せ替えるんですが、ロードバランサーからロードバランサーへの振り分けも対応しているので、次の載せ替えのときもこれを使ったりしました。

マイナスを0へ、そしてその先へと進むために

こうしてスタンダード化をやってきましたが、これまではマイナスをなんとかゼロに戻していくフェーズだと考えていました。ですので、これからはより事業成長を加速させるようなシステムにしてかなきゃいけないと考え、マイクロサービス化を検討しています。

マイクロサービスと流行りに乗っかって言っていますが、要はちゃんと適切な機能やドメインにシステムを切り分けて、それ専用の構成や技術を使って作っていきたいということを考えています。

例えばマッチングアプリでは、メッセージ機能ってすごく大切です。以前ユーザ様から、「アプリ内のメッセージ機能で食事の約束をしていたが、当日サービスがダウンしていたせいで出会うことができなかった」というお問合せをいただいたことがありました。このお問合せには本当に落ち込みまして、あらためて大事な機能はダウンさせるわけにはいかないなと考えを強めました。そうしたシステムはちゃんと専用に作って守っていきたいと考えています。

その「マイクロサービスをやっていこうぜ」ということの先駆けで、現在ECSの環境にコンテナ化して載せ替えていて、APIや管理画面などのコンポーネントをコンテナ化しています。

コンテナ化へのハードルという点ですが、コードアーキテクチャの改修を実施する際に、今後コンテナ化することを視野に入れていたので、ECSへの載せ替えの際にあらためて大きく改修するということがなかったので、そこはうまく進められたかなと思います。

再掲になりますが、これからマイクロサービスを進めていくということで、適切にそれ専用のサービスを切り分けて、より事業を加速させるような単位でシステムを構成していきたい、と考えています。

焦らず「どこまでやるか?」を考える

最後にまとめです。

振り返ってみるとタップルではこの2年、いろんな改修をやってきました。2個目が今回で一番言いたかった内容なんですけど、リプレイスとかって、「いっぺんにやりたい!」って思うじゃないですか。僕もすごい思うんですけど。けど、まあ、できるわけ……、「できるわけない」じゃなくて(笑)。

(会場笑)

無理にやらなくていいかなと思っています。ちゃんといまのフェーズを考えたうえで、「どこまでやればいいんだっけ?」というのを焦らず考えていくのが大事なのかなと思います。

一番大事なのは、カイゼンをやめずにやっていくことだと思うので、みなさんも、……がんばりましょう(笑)。

(会場笑)

以上です。ご清聴ありがとうございました。

(会場拍手)