テクノロジー開発部の村上です。以前紹介させて頂いたように、弊社の社内システムはマイクロサービスで構築してあります。 マイクロサービスの一番の利点として、サービスを追加することで新機能・業務に対応出来るというものがありますが、 システムリリース後に本当にサービスを新規追加することがあるのかと思う人もいるかと思います。
そこで今回は、弊社が4月に事業譲受したCASHという即時買取サービス・アプリのために、1サービス追加したのでその事例を紹介したいと思います。
新規サービス追加の背景
以下のリリースのように、7月22日からCASHで専門査定というサービスを開始しました。
CASHはアイテムの種類やブランド名を選ぶだけで買取価格を表示し、その価格でご満足頂ける場合は買取を依頼出来るサービスとなっています。 しかし高額アイテムについては、アイテムをしっかりと見てモデルや状態を精査しないといけないため、これまでほぼ取り扱っていませんでした。 そこで、専門査定対象と判別された場合に追加画像などを入力していただくことで、弊社の専門スタッフが1点1点査定させて頂き、より正確な価格を提示出来るようにしました。
弊社では出張買取のスタッフが、専門性の高いアイテムを査定したい場合に専門スタッフに依頼することがあり、 社内システムでは、マイクロサービス中の査定サービスでそれに対応していました。 しかし今回は入口がCASHだというのと、要件が異なるため、UI上は近いものの、仕様は似て非なるものです。 また、査定サービスチームとCASHチームは別であり、査定サービスを拡張するのは既存影響も考えると工数が大きくなってしまいます。 そこで今回は、画像と入力内容を見て査定するという機能に特化したサービスを新規開発することにしました。
新規サービス追加のポイント
新規サービス追加で大変なのは、土台作成です。 主に以下の作業があります。
- アプリケーションのベース作成
- CI準備
- CD準備
1と2はRailsのテンプレートと自作プラグインで、3はCDツールであるSpinnakerの既存パイプラインをほぼ流用することで、 作業を簡略化しています。また、Kubernetesのマニフェスト自体はほぼサービスごとで共通なので、既存のサービスのものをコピーしてサービス名だけ書き換えるスクリプト等を用意して、生成されたマニフェストの一部を手動で手を入れることで作業を減らしています。
以下ではRailsのテンプレートと自作プラグインをどう使っているかを紹介します。
Railsのテンプレートと自作プラグイン活用
Railsのテンプレートとは、Railsガイドに書かれているように主にrails new実行時の動作をカスタマイズ出来る機能です。 例えば指定したgemの導入やコマンドの実行、Railsジェネレーターの実行などができます。
template.rbとDockerfileを用意してイメージを作成すれば、コンテナを起動するだけで土台となるRailsアプリケーションが作成できます。 DockerfileはDocker公式の以下の例を参考に、ENTRYPOINTなどを変更すれば良いです。
テンプレートで実行するRailsジェネレーターは、既存のものに加えて自作プラグインのものを用意しています。
Railsガイドに従ってプラグインをまずrails plugin new
コマンドで作成し、そのプラグインにbin/rails generate generator
コマンドでジェネレーターを追加します。
生成したジェネレーターには、Cloud Buildの設定ファイルを配置するものや、rails_helper.rb
の指定箇所にrequire文やinclude文を追加するものなどがあります。
テンプレートでgenerateコマンドを実行する際の注意点としては、以下のようにafter_bundle
ブロック内で実行することです。
gemのバンドル後でないと自前ジェネレーターが実行できないからです。
また、DBを使うRailsアプリケーションとそうでないアプリケーションでアプリケーションの内容を変えたい場合、yes?(question)
コマンドを使うと入れるgemやgeneratorの呼び出し自体や引数を変えることができ便利です。
gem 'my_plugin_example' after_bundle do generate('my_plugin:foo_initializer) end
ゲートウェイ・BFFの活用
サービス自体は完全新規で作成出来たのですが、問題はフロントエンドです。
完全新規の画面にしてしまえば開発は楽なのですが、社員の使い勝手としては既存の役割が似ている画面にまとめた方が効率的です。
ここでゲートウェイ・BFFを有効活用します。ゲートウェイ・BFFはクライアントから直接叩かれるAPIを提供するアプリケーションで、
マイクロサービスの各サービスを叩くことでAPIを実現します。"ゲートウェイ・BFF"と・
で繋げて書いているのは、APIを集約するという意味ではゲートウェイですが、iOSアプリとウェブアプリ用にAPIを分けるためにも使っているという意味ではBFF(Backend For Frontend)だという意味合いです。
では実際にどう活用しているかという点ですが、例えば査定依頼の検索APIがあります。 これは社内向けの査定依頼でも使っていてCASH用にも対応する必要がありました。 そこで、CASH用のチェックボックスが押された場合は今回追加した新規サービスのAPIを叩いてその結果もリストに追加するという処理を追加しました。 ここで実装が必要になるのは、新サービスのAPIコール部分と、リクエスト・レスポンスのインピーダンスマッチ部分です。 インピーダンスマッチが比較的面倒なのですが、そこを守れば互換性がある程度保証されるという利点があります。
また、検索結果の詳細表示用部分では、今回の新機能用の査定依頼かどうかは判別がつくので、 レスポンスだけ既存の詳細表示用APIと共通の新規APIを作成し、ゲートウェイではレスポンスのインピーダンスマッチを行っています。
まとめ (追加してみた上での感想)
これまで述べてきたように、マイクロサービスにしたことで開発のスピードややりやすさはかなり上がったと感じました。 一番怖いのはすでに動作している部分への影響なので、そこの考慮ポイントを少しでも減らすことで高速に開発出来ました。 また、今回の新サービスでは、データの性質がリレーショナルではなくドキュメント型だったので、RDBではなくFirestoreを用いました。 このように使う技術の柵がない点もマイクロサービスのメリットと感じました。実際ひとつのサービスはそのサービスの要件を鑑みてGolangで書いてあります。
ただ気をつけないといけない点は、サービスが増えると管理すべき対象も増えるということです。 なので基本的にはドメインごとにサービスを作るのが正解だと思います。今回でいうと、査定の性質が社内向けとは違ったためにドメインも別だと判断しました。もし今後他に一般向けの査定サービスを提供することになった場合はこのサービスを拡張するのが正解だと思います。
参考資料
ゲートウェイ・BFFについては多くの記事がありますが、その中でも以下の2つは定義としてよくまとまっていると感じました。