マイクロサービス化もScalaで行うことを決意
Scalaの採用を決めたとはいえ、ほとんどの開発者がScalaについてよく知らない状態だっため、まずはScalaのことを知ろうと社内で勉強会が開かれました。技術フェロー(当時)による勉強会を皮切りに、Scalaの紹介や、Haskellで関数型言語に触れるといったことが行われました。また、同年5〜6月にかけては「Scalaもくもく会[2]」も開催し、業務に先立ってScalaに触れる機会を増やしていきました。
この時点での短期目標は「意欲的なメンバーをぐんぐん伸ばす」でした。それ以外のメンバーに関しては、Scalaを書くまではいかなくても、「弊社はScalaを導入するんだ」と意識をもってもらえれば十分だと考えていました。
またこの時期、Scala導入とは別に、Applivをマイクロサービス化するプロジェクトが進んでいたのですが、「それもScalaでやってみないか?」という話が同年4月に持ち上がりました。Appilvのマイクロサービス化は、PHP(Symfonyフレームワーク)を使ってすでに進められていたのですが、どうせ近い将来Scalaに乗り換えるならと、いくらかの検証の後、マイクロサービス化もScalaで行うことが決定されました。
それまでの作業を捨ててしまうようですが、実装を始めたばかりであったことや、設計でScalaやそのライブラリを参考にしている部分もあったことで、「Scalaで実装したほうが、むしろ実装量を減らせるだろう」と踏んでの決定でした。
Actor同士のやりとりがそのままマイクロサービス同士のやりとりに
Scalaでサービスを構築しようとして最初に驚いたのが、PHPではApacheにmod_phpを入れて……のような動かし方だったものが、Scalaにおいては直接HTTPリクエストを処理できるという点でした。
また、必要なリソースが違ったり、そもそもPHPでの実装より細かく分けて実装していったほうが効率がよかったりして、当初使いまわせると思っていた設計にも変更を加える必要がありました。
設計に変更を加えるといっても、かえってすっきりした部分もあります。たとえば、マイクロサービスの基礎部分に「Akka Actor」を使うことで、「Actor同士がメッセージをやりとりして動作する」という動きを、そのままマイクロサービス同士の動き方へ拡張することができます。これを踏まえて設計を、協調して動作するActorを複数まとめて1つのマイクロサービスを構築し、このマイクロサービスをまとめてドメインを構築する、といった形にしました。
この実装では、マイクロサービスに合う軽量なライブラリとして「spray」を使用しました。Webアプリケーション向けフレームワークとは違い、sprayは必要な部分だけimportできることもあり、非常に軽量です。また、Actorを前提として設計されており、Futureも活用しつつ非同期で好き勝手に動けるマイクロサービス群を構築するのにとても相性の良いものでした。
Scalaでの開発が本格化、新規プロダクトならScalaで!
プロダクトに使い始めたことにより、Scalaの知見が一気に社内に広がることになりました。6月下旬からは自社の技術ブログでScala関連の情報発信も開始。8月に泊まり込みでScala漬けになる「開発室合宿」も実施しました。また、このころからScalaで「とりあえず作ってみる」という段階から、「必要なものを作る」という段階へ移っていきました。
7月に入り、マイクロサービス化とは別のプロジェクトでScalaの採用が決まりました。Appliv海外版をScalaで開発することが決まったのです。PHPで実装された既存システムをコピーする案もありましたが、いつかはScalaで作り直さねばならないことや、稼働させるサーバーが別で機能にも違いがあるといった、ある意味新規システムとなるため、「ダメだったらPHPで作り直そう」と後戻りが効くという点でもScala採用がしやすいものでした。
また、Appliv海外版は開発途中のマイクロサービス化とも関連して、一部動作をこのマイクロサービスに依存させる形での開発が進みました。
さらに8月には検索機能の作り直しが話題に上り、これもScalaで開発することになりました。作り直しの主な目的は検索精度の向上だったのですが、既存のDBに依存しないものがよいことや、これも将来的にScalaへ移行させなければならないことなどから、Scalaで一から構築するのが自然だったのです。社内では徐々に「新規プロダクトならScalaで」と考えるようになっていきました。
理想のマイクロサービスと現実との境界にぶち当たる
実際にScalaのシステム同士を組み合わせてプロダクトを作る中で、ぶつかって始めて気がついた問題がいくつもありました。
そもそもマイクロサービスを作るのは難しい
基本的には扱うデータに基づいてサービスを分割していくのですが、ビジネスロジック上、複数のデータを扱う必要があることは珍しくありません。そういった場合に下手に分割すると効率が悪いと思われるケースがあり、とても悩ましいものでした。
たとえば、Applivはアプリケーションにジャンルを設定して独自のカテゴリを構築しているのですが、このジャンルの一覧を出力する際、アプリケーション情報とジャンル情報の結びつきをどちらが持つのかで、使い勝手が大きく変わってきます。アプリを主体にすればジャンル別のアプリ一覧の取得が面倒になり、ジャンルを主体にすればアプリケーションに設定してあるジャンルを取得するのが面倒になる、といった具合にです。
問題にぶつかるたび、データ構造を変えたりして対応していきましたが、結果として設計からやり直しが必要になるなど、予期せぬつまずきが多く発生し、作業が難航しました。
Scalaもマイクロサービスもゼロから経験を積むのに苦労
実際の運用を考えていく過程で、当初想定しきれていなかったサービスが必要になることもわかってきました。そのため、マイクロサービス全体の構成やソースコードの管理方法、開発の進め方や運用方法についても見直すことがたびたびありました。すでにいくつかのドメインが作られている中で全体の構成変更を行ったりするのには、それなりの手間がかかってしまいます。
慣れてくれば、これらの問題を事前に考慮して設計できると思うのですが、このときには、マイクロサービス化の経験がない中でどうしても既存の設計が基準になってしまい、何度もつまずくことになりました。Scalaという言語に慣れると同時に、新しい発想で設計を行うという問題も同時にクリアするのは大変な苦労でした。
注
[2]: もくもく会は、参加者が各々でひたすらコーディングするという会。