会員数急増によるパフォーマンス劣化の危険性

今井雄太氏(以下、今井):ちょうど今横路さんの話にもありましたが、まずリリースすることが重要。特にシード・アーリー期ってスピードを持ってサービスを開発してリリースして行くことが重要です。非常に当然のお話だと思うんですが、いくつか整理しなければいけないものって出てくると思うんですよね。

作って運用してみて、今の環境への不満とか改善したい点、いわゆる技術的負債とかいろいろたまってくると思うんですね。そのへんについてどんなものがあって、どんな付き合い方をしているのかっていうのを教えてください。今村さんからお願いしていいですか?

今村雅幸氏(以下、今村):さっきのQAセッションでちらっと言ったんですけど、みんな大好きMongoDBというのを使っていまして、そのパフォーマンスの劣化がちょっと激しすぎてヤバイというのがあって。MongoDBって、ご存知だと思うんですけどインデックスがメモリにのらなくなるとすごいパフォーマンスが落ちていくんですよ。

ちょうどCMプロモーションを先月かけて、会員数が200万人ってなった瞬間に、一気にデータがメモリーに乗らなくなりましたみたいな事件がありました。そうなるとすごいパフォーマンスが劣化して。

でも「じゃあそれを防ぐぞ」ていうことになると、AWSさんにとてつもなく高いメモリーの、これは誰が使うんだっていうようなインスタンスを使わなきゃいけなくなるんでそうなってくると、そもそもアーキテクチャから変えないといけなくなったり。

多分、結構ソーシャル系のサービスを運用する方だとタイムラインって作らないといけないと思うんですけど、ああいうのを作るときのアーキテクチャを変えたいっていうので、僕らが考えたのは、今Rails使って全部作り直すということをしています。

今井:ありがとうございます。ちなみにMongoを選ばれた理由って何だったんですかね?

今村:3、4年くらい前ですかね、当時の流行りというか1番よく使われていたはずです。結構物議をかもしていたんですけれども、でもすごい便利は便利で、データ容量が少ないうちは便利でした。あと意地でもシャーディングをしないという。事故るんで。

そういうのがあって普通に使ってるぶんには便利だったんですけど、やっぱりサービスが増えてくるとスケーラビリティー的に結構厳しいなって。その当時はよかったっていう理由です。

今井:ありがとうございます。非常にいいキーワード、意地でもシャーディングをしないっていうの最近よく聞くすごく重要な設計のポリシーのひとつなのかなと思ったりしています。ありがとうございます。

「書き直し」もひとつのドラスティックな対策

今井:高橋さんお願いしていいですか?

高橋三徳氏(以下、高橋):うちの、さっきちらっと言ったサーバサイドをAWSに選ばなかったのはちょっと今、後悔してるっていうのがあるんですが、それにはいい点と悪い点があるので、いいんですけども。

サーバサイドはアーキテクチャ設計から、中身のコードの書き方はけっこうきちんとやっていたと思っていて、あんまり不満はないかなと思っています。

今書き直してやろうとはしてるんですけど、それも別に想定内で順調に進んでるなと思って不満はあんまりないんですね。

ただうち、アプリとかもあるんですけど、アプリサイドって結構アプリのエンジニアのスキルによっちゃってて。そのへんがちゃんと見きれるのにな、ってところがあります。アプリの中の最初のコーディングというか、レガシーコード具合にちょっと今悩んでいるなというのがあります。

今井:アプリ側が見きれないというのは、高橋さんもしくはその人手が足りないのか、そもそも見る側の経験が必要なのか?

高橋:最初はアプリ担当って1人とかなんで、結局その人に任せきっちゃってとか。あとベストがわかりにくかったっていうのがあって、最近何かMatzさんがいろいろ出してたりもするんですけど、それに今自分も乗っかってたりするんですが。

サーバサイドは上手く、いろいろ過去の経験とかたくさんあるんですけど、アプリは何か試行錯誤するのが多かったかなと思っていて、そこを上手く動いてたんで停止していたら今大変だなというところです。

今井:リファクターとか今後の付き合い方みたいなところで、打ってる施策とか考えてることとかありますか?

高橋:例えばiPhoneアプリってFat View Controllerになりやすくて、その状態で規模がでっかくなってくると、どこから手を出していいかわかんないような状況になってきちゃうんですね。

そうするとほとんど1から作り直しじゃないかみたいなところがあって。ほぼ書き直しに近い状態で進めてます。

今井:ありがとうございます。ちょっと負債がたまってきたところ。さっきのQAセッションでもありましたが、いくつか書き直しという声も上がっていましたね。ひとつのドラスティックな対策だと思います。

サービスのコアである初期のコードは書き直しが難しい

今井:椎名さんお願いできますか?

椎名アマド氏(以下、椎名):正直、今日いる高橋さんがおっしゃったことと結構似てきてしまうんですけど、弊社では現在CIが一部しかできてないんです。特にネイティブアプリのほうは、たとえCIを多少導入したとしても、カバレッジが全然足りないと思ってるんですよね。

その理由としてはやっぱり、そもそもネイティブアプリってbehavior driven developmentでテストで書くんだったらいいんですけど、きちんとユニットテストを書きたい場合は、そもそもテストだけじゃなく設計をやってないとダメなんですよね。

弊社のiOSアプリは僕が1人の頃から書き始めてて、まさにビューコントローラがでっかくなってる部分が多いんでそうするとちゃんとテスタブルな状態じゃないということで、まずレガシーなネイティブアプリケーションのコードをテスタブルにする。

それはちゃんとモデルとビューと、あと弊社としてはビューモデルっていうのちゃんと間に挟もう、ビューモデルっていうレイヤーをちゃんとテストしてあげようっていうことを言ってるんですね。

モデルだけでテストしても、結局たいていのアプリが落ちるのってUIのところでデータとの整合性取れてないみたいな、そういう系で落ちたりするんで。そこはちゃんとビューモデル挟んでやりたいねっていうとこで、そういう設計をし直したりするとかなりコストが大きなものなんです。

新機能に関しては結構新しい設計思想で書けてるんですけど、古いところってまさに僕らのアプリでいう会員登録だったり、カップルがペアリングするというそういうコアな部分なんで。そこをやらなきゃいけないなあと結構悩んでるとこですね。

今井:ありがとうございます。

どうやってテスタブルな状態にするのかが課題

今井:Fat Controllerからモデルをキレイに切り離すとかって、わりとそのそれぞれのクラスの役割を変えて、インターフェースを変えていくことになるじゃないですか? リファクタするときってやっぱり先にテストがあって、それからリファクタしたいって話になると思うんですけど。

インターフェースを切り替えていくとなると、多分テストがない状態で、わりとこうガガガッて変えていかなきゃいけないっていう感じだと思うんですけど、そのへんってどうやったとか、どういう苦労をしたかとか、もしあれば。

椎名:まさに悩んでるとこです。それは今の環境への不満(笑)。どうやってきれいにテスタブルな状態にするのか? あるいは本当に、気合いで人力で頑張っちゃうのか? っていう選択肢も、決してなくはないなと思ってたりするんですよね。

今井:なるほど、ありがとうございます。ちなみに最初は1人で作られてたということなんですけど、今はiPhoneアプリのチームになってたりするんですか?

椎名:そうですね、今はちゃんとiPhoneアプリのエキスパートがいて、Androidアプリもちゃんとエキスパートの方が、非常に優秀な人たちがいるんでその人たちにちゃんと設計を考えてもらってます。

設計するときにはやっぱり、iPhoneとAndroidとサーバサイド、皆で「テスタブルなネイティブのアプリってどんなもんだろう」っていう、そういうことをガツガツ議論しながら、今まさにいろいろ悩んで進めているところです。

今井:ありがとうございます。

テストにかかる時間や1日にできるデプロイの回数が減ってきている

今井:横路さんお願いできますでしょうか?

横路隆氏(以下、横路):うちはこの1年で20人くらいエンジニアが増えて、CIプロセス自体は3、4人のときからあったんですけど、それでテストにかかる時間とか1日にできるデプロイの回数とかが減ってきて、それが大きな問題だなと思ってます。

freeeでは1,800くらいの銀行やクレジットカードのWeb口座とスクレイピングで同期しているんですけど、そのコードも会計のWebアプリも、すべてひとつのモノリシックなコードベースでやってたんですね。

そこに新しく入ってきた人がコードを書いて、全てのコミットが同一のCIプロセスでデプロイされるので、どんどんリリースが遅くなっていったんです。freeeが他のチームと違うかなと思うのは、うち、複数のマスタデータに依存するようなテストケースっていうのがすごく多くて。

大量のマスタデータをDBに突っ込んでからテストかけなきゃいけないケースがたくさんあって、それでテストにすごく時間がかかってしまってるというのもあります。

それで最近はチームのアーキテクチャをちょっとずつ分けるっていうのを、新サービスとして給与計算ソフトが出たあたりから少しずつ実践してますね。最初は認証と課金サービスを独立させるところをやってます。

今井:ありがとうございます。そのサービスとか機能間の独立っていうのは、さっきちょっと個人的にもおっしゃっていただきましたけど、そのサービス間でのRPCみたいなインターフェースを作ってやっているっていう感じなんですかね?

横路:RPCではなくて、普通のWeb API形式でやってるんですけども、そうするとやっぱりインターフェース間の齟齬というか、コメントをきちんと書かなきゃいけないとか、そういったところで結構コストがかかるなというのを今感じています。

今後もっとサービスができてきたときには、もう少しきちんとデータ構造やバリデーション情報が定義できるような仕組みが必要かなと考えています。

今井:そのへんはチーム間ではAPIの仕様だけをお互いに見せ合って、そこから進めていってるという感じですか?

横路:そうですね、あとはモバイルとかWebフロントエンドの開発に関しては、APIエンドポイントも呼びたい人が自分で作ってもらうっていうのを結構やっていて。

ビジネスロジックをもつドメインモデルを複数組み合わせたサービスがたくさんあるので、それを組み合わせてユースケース毎に使いやすいAPIを自分で作ってもらって。ユーザの体感速度とか考えると、RESTじゃなくて全然いいんで、速くて使いやすいものを作ろう、というふうにやったりしてますね。

今井:ありがとうございます。

機能ごとにチーム分けをすることで、開発がスムーズになる

今井:もう1個だけ。それって結構すごいキレイなチームの体制になってるなと思うんですが、その仕組みで仕事というか、開発を進めようっていう最初の仕組み作りはなかなか。

それ専用の開発、タスクコースみたいな人がいたのか、それとも誰かが……? どんな感じでその体制づくりを進めていったんでしょうか?

横路:ちょうど給与計算ソフトを作りはじめるときにエンジニアが10人くらいになっていて、それまでチームという概念はなかったんですけど、そろそろ限界だねということで基盤チームとか会計チーム、給与チームというように、機能毎にチームをわけて。

あとはちょくちょく出てくる皆で課題に感じていることに対して、ワークグループをチーム横断で作って問題をつぶしたりとかしてます。

今井:ありがとうございました。ちょうどこのイベント、CTO Night & Dayの前日、はてなさんのオフィスで「Netflix Meetup in Kyoto」というイベントがあって、私とうちのメンバーもう1人とで参加させてもらったんですけど。

Netflixもやっぱりサービス・各機能ごとに開発チームで、それぞれの間は厳密に定義されたJSONベースのプロトコルを使ってやりとりするという、疎結合なアーキテクチャを使っているっていう話をしていました。

制作協力:VoXT