こんにちは。Sansan Engineering Unitで副部長を務めている笹川 裕人です。新たにスタートする、この「Sansan Tech Talk」。Sansan技術本部のテックリードたちが取り組んでいる技術的な取り組みやチャレンジを対談形式で深掘りします。初回となる今回はEight Engineering Unitで部長を務める大熊 秀治にインタビューしました。
笹川:それではよろしくおねがいします。まずは私の自己紹介をしますね。私はコンピューターサイエンスの博士号を持っています。学生時代の友人や研究者の同僚と飲み会でアルゴリズムの話をするのが好きで、ときどき白熱してきたところを店員さんに聞かれて困惑されてしまうことがあります(笑)現在は営業DXサービス「Sansan」を楽しく開発しています。よろしくお願いします。
それでは大熊さんも自己紹介をお願いします。
大熊:名刺アプリ「Eight」の開発責任者を務めている大熊 秀治です。2014年にSansan株式会社へ中途入社しました。
もともと日本のオフィス機器メーカーで、ソフトウェアエンジニアとして、機器とクラウドサービスを連携させるためのJavaScriptライブラリを作っていました。
Sansanへ入社した当時、モバイルのウェブアプリケーションでデータ化をやろうというプロジェクトがあり、そこでプロトタイプを作りました。以降は、Eight開発のために奔走してきました。
笹川:そのコードは使われ続けたのですか?
大熊:結局プロトタイプだったので、私のコードはほとんど消えました。 改めてプロダクションコードとしてチームで作り直したと聞きましたが、私が作ったプロトタイプは検証用として役割を果たしたと思っています。
私がMVP(Minimum Viable Productの略。顧客に価値を提供できる最小限のプロダクトのこと)を作って、それを動かすためにチームで改めて作り直す流れでした。 実現性の検証を、jQueryを使ってやりました。 懐かしいですね。
笹川:それはPC版もあったのですか?
大熊: PC版もありましたね。それのモバイルウェブ版を作ろうというプロジェクトでした。実際作って触ってみないと実現可能なのかが分からない状況だったため、APIを使って作りました。
笹川: バックエンドに追加開発が発生しないように作ったのですか?
大熊:当時は、バックエンドのことはあまり考えず、体験としてどうなのか検証できる環境を作りました。PCブラウザだけでできることがあるので、 モバイルでやったらこんな感じになるだろうなとプロトタイプを作りました。これがSansanに入社して最初の仕事で、その後はずっとEightの開発に携わっています。
笹川:ありがとうございます。 それでは直近、Eightの開発で取り組んでいる技術的なチャレンジについて聞かせてください。
大熊:はい。最近、私たちはSRE(Site Reliability Engineering)に取り組んでいて、ここ半年は、その取り組みに力を入れています。具体的には、CUJ(Critical User Journeyの略。ターゲットユーザーがゴールに到達するために達成しなければならないタスクのこと)を定義し、それに基づいて監視を行い、問題を発見して改善していくことに焦点を当てています。
以前は、システム全体のレスポンスタイムやエラーレートを単純に監視していましたが、例えば、レスポンスタイムに関しては、ユーザからのアクセスのみではなく、ポーリングなどのアクセスもあるため、これによってかなりの割合が生まれていました。特定のAPIではエラーや遅延が発生していることがありましたが、数値だけを見ると問題がなさそうに見えることもあり、違和感を抱いていました。そのため、SREチームからCUJを定義し、ユーザーの体験に着目した可視化を提案されたので、それに取り組むことにしました。
笹川:エンジニアからの発案だったのですね。 普段はビジネスサイドからの提案が多いのかなと思っていました。
大熊:ビジネスサイドからの問題提起は特にありませんでしたが、開発サイドが全体的には良さそうな数値でも、個別に見ると遅い箇所もあることに気付きました。そのため、SREグループからPdMと協力してCUJを設定し、それを基に改善することを提案されました。私自身はこの手法に詳しくなかったのですが、全体平均で見るよりも詳細に見られて、ユーザーの体験に焦点を当てて進めることがビジネスサイドにとっても有益だと判断し、了承しました。現在、最優先のCUJが1つ設定され、具体的な数値を収集し、仮の閾値を設定し、アラートを設定しています。アラートを見ながら調整し、現状を把握するための運用を開始しました。今後は、設定した閾値や運用を微調整しながら、拡大していく予定です。
笹川:今はあえて、本質的ではないしきい値を決めて運用しているのですかね。
大熊:負担が大きくなりすぎないように、最初は緩めに設定し、運用しながらPdMと相談しながら調整していく予定です。
笹川:PdMとの相談はこれからなんですね。
大熊:感覚値としてどうか、といった相談は既に始めています。ようやく可視化できて準備が整ったフェーズのため、PdMと実際の結果を踏まえての具体的な相談はこれからです。
笹川:これは本質的な改善につながる重要な取り組みですね。
大熊:平均だけを見て満足するのではなく、ユーザーがどこで困っているのかに焦点を移したことが大きなポイントだと思っています。
笹川:ありがとうございます。今月来月あたりの近い将来の話を聞きましたが、さらに中長期的な未来でやりたいことはありますか。
大熊:2つあります。1つはEC2からの脱却であり、もう1つはモジュラーモノリスの導入です。まず、EC2からの脱却についてです。名刺アプリ「Eight」は2012年に提供が開始され、12年の歴史があります。長い間、AWSを利用しており、基本的にはEC2インスタンス上にWebサーバーを立ててバッチジョブの仕組みなどを運用してきました。しかし、EC2を使用することで、EC2内で動作するミドルウェアのメンテナンスや、EC2に依存したアプリケーション設計に関する課題が生じていました。例えば、非同期でワーカーとして動作させたい仕組みをローカルで試そうとしてもうまくいかないといった状況がありました。
笹川:ローカル開発もなかなか難しい状況ですか?
大熊:EC2の仕組みに合わせて全体を構築しているので、便利な面もありますが、ローカル環境ではかなり難しいです。実際の運用の場面ではEC2インスタンスのメンテナンスや、自動スケーリングの仕組みが必要ですが、それらが自動で行われているわけではなく、手動で設定しなければなりません。そのため、仕組み自体を見直す必要があります。ちなみに、WebサーバーはEC2ではなくコンテナで動いています。
笹川:一番外側は簡単ですからね。
大熊:簡単なのはいいんですけどね。バッチの部分を単純にコンテナ化するのではなく、独自の要件に合わせて細かく作り込んでいるため、何を残すべきか、捨てるべきかを整理し、再構築を検討しています。
笹川:進め方もいろいろありそうですね。
大熊:そうですね。どうやって進めるかから考えないといけません。
現在、EightではRailsの非同期ジョブを独自のEC2上の仕組みで動かしており、これが複雑さの一因となっています。そのため、Railsの非同期ジョブの仕組みを使いつつ、EC2ベースからコンテナに移行するか、あるいは別のサーバーレスのアプローチを検討しています。Railsの標準的な仕組みを素直に使えるように、SREグループのメンバーと協力して、次のバッチのアーキテクチャを検討したいと思っています。
笹川:現状、動作可能なサーバーをスケールさせる方法は難しいですか?
大熊:あらかじめ台数を確保している中で、どこで動かすかを調整していくイメージです。
そのため、突然バッチがどのサーバーよりも大量のメモリを必要とする状況になると、対応が難しくなります。
過去にそのようなバグが発生し、1つのインスタンス内で複数のプロセスが動作している中で、1つのプロセスがメモリを食いつぶしてしまい、他のプロセスも全て停止してしまいました。これにより、本来影響を受けるべきでないプロセスにも影響が及び、復旧が困難になることがありました。リソースの有効活用は重要ですが、このような事態は避けたいと感じています。ただ、1つのインスタンスで1つのプロセスを動かすのは非効率だとも思います。
実際、バッチのプロセスは常に忙しいわけではなく、時間帯によってはアクティブなジョブがないこともあります。そのため、無駄なリソースが発生している可能性があります。
笹川:この問題を解決するとクラウドコストを削減できそうですね。
大熊:金銭的な面での削減につながるかはわかりませんが、現状では深夜などのアクティビティの低い時間帯でも、リソースを確保したままジョブを実行しています。現在の方法では柔軟性や効率が不足しているので、改善が必要です。
笹川:この改善はかなり大変そうですが、やりがいがありそうですね(笑)
大熊:やるならただ単純に仕組みをモダナイズするだけではなく、コスト効率を調整して実現できると事業の利益にもつながるので、金銭面と日常的な運用の無駄をなくして効率よくしていきたいです。
笹川:新しい仕組みにするにしても、現在の仕組みで残すべきところと残さなくていいところを整理した上でバランスよく最適化していきたいですね。
大熊:そうですね。
そして、もう1つのモジュラーモノリス化の検討の話になりますが、現在は1つのRailsアプリケーションで構築されています。名前空間は一応区切られていますが、機能間の依存関係が複雑であり、範囲外に影響が及ぶことがあります。
笹川:縦横無尽に見ようと思えば見えてしまいますね。
大熊:コードを書く際に入り口は明確ですが、時には外に広がってしまったり、逆に内側に侵入したりすることもあります。入社から10年経ち、機能のドメインが複雑に絡み合ってきてしまいました。MVPを作成する際はうまくいきましたが、想定外な範囲へ影響が及ぶケースが徐々に目立ってきています。
笹川:整理して、綺麗な状態にしていきたいですね。
大熊:またがるときはルールを定めたり、依存関係を見極めたりすることが必要です。そのために議論を始めています。
笹川:Railsのモジュラーモノリスで有名なShopifyのPackwerkのように、超えてはいけない範囲を明確にするイメージですかね。
大熊:実際にお試しで、ある名前空間で区切って導入していますが、Packwerkを導入してもすぐに解決するわけではなく、自分たちで違反や許容範囲を定めなければならないので、段階的に導入しています。
これも1カ月、2カ月でできることではありませんが、中長期的に向き合おうとしています。
笹川:機能を維持しつつ内部構造を改善するのは、うまい進め方とセットでないといけなかったり、新規の開発とのコンフリクトをどうするかを考えるのが難しかったりしますよね。
大熊:現在はあまり触れられない範囲から取り組んでいますが、ガンガン開発する部分はどうリファクタリングしていくか考えていく必要がありますね。
また、新しい依存関係を増やさないようにバランスを取る必要があります。
笹川:この辺りはまだプロジェクト化の段階ではありませんか?
大熊:もう何人かメンバーを当て始めています。それぞれが主に担当している機能開発がありますが、技術課題に一定の時間割いて議論したり、実際に手を動かす時間を取ったりしています。
ある程度イメージが固まったら、プロジェクト化する予定ですが、現時点ではまだ探っている状況です。
笹川:全体像を把握してから動くのですね。 ちなみに、Eightのコードベースの規模はどのくらいですか?
大熊:数十万行ぐらいですね。
笹川:数十万行ですか。確かにテストもかなりありますよね。フルでテストを実行することもありますか?
大熊:すべてのマージ前に実行しています。フロントエンドの変更だけの場合は、フロント以外のテストをスキップすることはあります。
バックエンドの変更があった場合は、バックエンドのテストはすべて走らせるようにしています。また、プルリクのマージやブランチに変更がある時は、必ずテストを実行しますが、何もスキップせずフルでテストすると約20分かかりますね。
笹川:結構時間がかかりますね。20分もかかると、コーヒーを取りに行ってもまだ終わっていないくらいですね。
大熊:現在はプルリクを投げた後、他の作業をして待機していますが、もっと早く終わらせたいと思っています。
一応、みんな手元でスペックとか動かしていますが、どうしても依存関係があって悩むケースもあるのでもう少し早くしたいです。とはいえ明確に境界が別れているわけではないので難しいですよね。
笹川:それが実現できるとスムーズに進みそうですね。
大熊:確かに、依存関係が明確で、パッケージ内だけのテストで済むような運用なら、4、5分で終わるかもしれません。ただ、依存関係がある場合は、仕方ないのですべてのテストを実行することになりますけどね。
笹川:それでも、2、3個ぐらいはスキップできますよね。
大熊:そうしたやり方も実現可能になるかもしれません。
笹川:CIは特に迅速化したいですね。リファクタリング系の話は、ビジネスサイドには進んでいないように見えてしまうので、メリットを用意しておかないと進めづらそうです。
大熊:そうですね。EightではCircleCIを利用していますが、使用した分だけクレジットが消費されるサービスなので、早く終われば終わるほどコストを抑えられます。そういった意味では、消すことも意識してますね 。
笹川:大事ですね。社内で一貫して消すことを意識した仕組みがあるのは良いと思います。Sansanも機能廃止のプロセスが決まっていて、事前にアナウンスをして問題なければ進められる仕組みになっています。使われていないのに増えてしまったり、いらないタイミングで問題が発生したりしますから。
大熊:Eightの場合は、Sansanほど明確なプロセスはないですが、リファクタリングやミドルウェアのバージョンアップ、Railsやライブラリのバージョンアップなどを行う際、影響を受ける部分と使われている機能が明確でないことがあります。
使われていない機能であれば、開発サイドから消すことを提案し、その分の工数を他の作業に充てるよう心がけています。使われなくなったものを削除しないと、増える一方になってしまいます。この考え方は、テスト時間の短縮にも通じるものがあります。メンテナンスが必要なものを減らし、その時間を新しい取り組みに費やすようにしています。
笹川:プロダクトマネジャーや他のビジネスサイドの人とフラットに相談できるんですね。
大熊:はい、ログやファクトは調べて伝えますが、フラットに相談できます。プロダクトとして残すべきものは一定はあると思うので、最終的にはPdMに判断してもらっていますが、メンテナンスの際に都度相談するケースもあります。
笹川:それは大事ですね。脱EC2とモジュラーモノリス化、つまりモノリスの境界分割に向き合っているんですね。
大熊:そうですね。モジュラーモノリスですが、きちんとメンテナンスをして見通しの良い状態を保ちながら作れる状態を目指しています。
笹川:最近は流行りの漸進的型付けでしたっけ。RubyだとSorbetとか使っていますか?
大熊:型に関してはまだ具体的な議論をしていませんが、境界を切った場合にその境界間で何か依存する場合、何らかのインターフェースで対応すると思います。型を入れるのはもしかすると良いかもしれませんが、現状はまだ全然見えていないので、具体的に進んだら一度試してみようかという段階です。
笹川:流行ってはいるけれど、入れるとまた複雑になるところもあるし、メリデメもあると思うので見極めていきたいところですね。
大熊:はい、入れどころを見つけて、適切に使っていくのがよさそうだと思っています。
境界の部分はありだなと想定しています。マイクロサービスに切った場合でも、その隙間を定義して運用するので、 もし同じモノリスの中でも境界を切るのであれば、境界の部分がハマりそうな気がしています。実際、そこでのインターフェースの齟齬は、割といろんなところでありがちなバグだったりします。
笹川:インターフェースが明確になっていれば、うっかりミスしても型エラーで気付けるし、作る側もこのインターフェース上でこういう風に定義しているからこう守らないとといった感じで矯正できそうです。
大熊:人数が増えている中で、Eightとしてもドメインがある程度固まってあっちこっち行かなくていい状況にできると、先ほどのインターフェースの齟齬によるバグはなくせると思います。その中の改善も担当チームで同じ空間内でできるようになるので、将来的には実現可能ではないかと感じています。
まずは今の見通しの悪い状況を改善していきたいです。
機能変更などで新しいジョブを追加した時に、別のところにもジョブが副次的に溜まってしまうこともあるので、そこを綺麗にしてEightを伸ばしていきます。
笹川:頑張ってください!ありがとうございました!