@cosme￰アプリ用APIゲートウェイを作っている話

アイスタイル Advent Calendar 2018 11日目はアプリ開発チームの@aboyがお送りします。

アイスタイルのアプリ開発チームには、iOSエンジニアとAndroidエンジニアが所属していて、主に@cosmeアプリと@cosmePROアプリの運用を行っています。

このアプリ開発チームで現在、@cosmeアプリと各サービスのAPIを繋ぐAPIゲートウェイの開発を進めています。本記事では、この@cosmeアプリ用APIゲートウェイ開発の概要を紹介します。

解決したい課題

APIゲートウェイによって解決したい課題は、ざっくりわけると以下の2つです。

  • Webとアプリと各サービスのAPIが密結合している
  • アプリから行うAPIリクエストの複雑化

課題1:Webとアプリと各サービスのAPIが密結合している

今までのアイスタイルの開発では、Webやアプリの開発に必要なAPIを、各サービス担当者に依頼して作ってもらうというやり方が一般的でした。各サービスのAPIが、Webやアプリの要件に沿った設計になってしまうことがあります。

すると、例えばWeb用に作られたサービスAPIを、あとでアプリからも使いたくなったときに、Web用に作られたAPIを無理やり使うことになります。これだとWeb側の仕様変更に伴うサービスAPIの修正に、アプリ側も引っ張られることになります。 Webの仕様変更に関係ない場合でもアプリ側のデグレチェックが必要になってしまい、全体の開発速度があがっていきません。

課題2:アプリから行うAPIリクエストの複雑化

アプリ用に作られていないAPIを駆使して要件を満たそうとすると、アプリ側で難しいロジックを組み立てなくてはいけません。まずカテゴリーAPIを叩いて、その結果をもとにランキングAPIを叩いて、その結果の一部を使って商品APIを叩いて…といったようなAPIリクエストのロジックを、iOS/Androidそれぞれで書く必要がありました。

複雑なロジックになればなるほど、iOS/Android間で意図しないロジックの差異が生まれる可能性が出てきます。また、ロジックが複雑になるほど、大抵の場合アプリからのAPIリクエスト数も増えます。


これらの課題を解決するための手段のひとつとして、APIゲートウェイを作ることになりました。次はAPIゲートウェイの説明に移ります。

アプリ用APIゲートウェイについて

アプリとAPIゲートウェイと各サービスのつながりは以下のような感じです。アプリから各サービスのAPIを叩くときはAPIゲートウェイを介する、いたって普通の構成かと思います。アプリ用APIゲートウェイ自体はGo言語で作っています。Web版@cosme用APIゲートウェイも作っているところなので、全体図としてはだいたいこのようになります。

今まではアプリから直接各サービスのAPIにリクエストしていましたが、今後はアプリ用APIゲートウェイを間に挟み、各サービスのデータを必要に応じて集約してからアプリに返してあげることになります。

アプリ用APIゲートウェイの役割

アプリ用APIゲートウェイの役割は以下の3つです。

  • アプリに特化したAPI設計と、その呼び出しを簡単にする
  • アプリの開発効率と品質を向上させる
  • アプリの画面表示を速くする

上2つはアプリ開発者にとって嬉しいこと、下はエンドユーザーにとって嬉しいこと。この3つについてもう少し詳しく説明していきます。

役割1:アプリに特化したAPI設計と、その呼び出しを簡単にする

これがメインの役割です。

@cosmeアプリ専用のゲートウェイなので、アプリ固有の要件を吸収した設計が可能になり、その結果アプリからのAPI呼び出しも簡単になります。もちろん、そのぶんゲートウェイ側で頑張る必要がありますが、iOS/Android両方で頑張るよりは、ゲートウェイひとつで頑張ったほうが効率的なことが多いです。

そして、アプリ固有の要件をゲートウェイが吸収することで、各サービス担当者にモノリシックなAPIの作成を依頼することなく、アプリの開発を行うことができるようになります。
弊社ではマイクロサービス化が進んでいるため、これはとても自然な変化です。

それから、ゲートウェイもアプリチーム内での開発となるので、アプリエンジニアとサーバーサイドエンジニアの距離が物理的にも精神的にも近くなることでコミュニケーションがとりやすくなり開発しやすくなるでしょう。

役割2:アプリの開発効率と品質を向上させる

今まではOSに左右されない共通化可能なロジックも、iOSとAndroidそれぞれで書いていました。このロジックをゲートウェイ1つに書くだけでよくなるため、開発効率の向上が狙えます。

iOS/Android間で意図せず微妙に違うロジックになっていた!ということも減らせるため、テストでの手戻りの軽減や、品質の向上にも繋がると考えています。

それから、iOSアプリはリリースまでにAppleによる審査が必要なので、アプリ内部のロジックにミスがあって不具合が起きても、すぐに修正版をユーザーに届けることができません。ロジックをある程度ゲートウェイに移すことによって、何かあったときにAPI側で対応できることが増えるため、こういったことも少しは減るのではないかと考えています。

役割3:アプリの画面表示を速くする

これは主にキャッシュを使った高速化のことを指します。情報の鮮度にこだわる必要のないデータに関しては、ゲートウェイ側でキャッシュ化することで、APIの応答速度の改善につながり、結果的にアプリの表示速度を向上させることができます。

とはいえ全部が全部ゲートウェイ側でキャッシュするわけではないです。アプリ側でキャッシュすべきか、ゲートウェイ側でキャッシュすべきかはデータの使い方や特性によって変わります。

たとえば、オフライン状態でも使える機能に必要なデータやユーザー情報はアプリ側で保持しておく必要がありますし、複数のAPIレスポンスを集約した結果や、どのユーザーにも一律同じデータ群から返すような場合はゲートウェイ側で保持しておくと都合が良かったりするので、そういった観点でつどつど考えるようにします。

開発をどう進めていくか

これらの役割を担うゲートウェイを、どのように@cosmeアプリに導入していくかを説明します。

検討段階〜開発スタートまで

そもそも最初はアプリエンジニア内における課題の共有から始まり、漠然と「こういうのあったらいいなー」と言っていました。もし作るとしたらやりたいかどうか、チーム内で希望者を募ったところ私含め4人の手があがったのですが、話を進めていくなかでアプリ側の開発のリソースとの兼ね合いもあり、結果的に私とAndroidエンジニア1人の計2人で担当することになりました。

そこから、上述したような課題や役割をインセプションデッキを利用して明確にし、@cosmeアプリのディレクターとデザイナーなど関係者に提案して納得してもらえたので、開発をスタートしました。

開発スタートしてから

ちょうどよさそうな新規機能案件がなかったので、すでに動いている既存のどこかを置き換えようということになりました。すでに動いている部分を移行するやり方はいくつかあるでしょう。

  • エンドポイント単位での移行
  • サービスAPI単位での移行
  • セクション(≒パーツ)単位での移行
  • 画面単位での移行
  • 機能単位での移行

@cosmeアプリチームではこのうち、セクションもしくは画面単位での移行をしていくことにしました。アプリ開発チームによるサーバーサイド運用が初めてということも加味し、まずはミニマムにということで、既存の画面でAPI呼び出しまわりが複雑になっている箇所をあげ、影響範囲は小さく、でも効果は大きいところから徐々に置き換えていくことで、少しずつ成功体験を積みながら徐々に知見を得つつ進めていきます。

もちろん既存からの移行はそれとして、新規機能の開発にあたっては、基本的に全てゲートウェイを間に挟むことになります。実際に今動いている新規機能案件では、ゲートウェイの工数も見積もりの中に入れています。

効果は出たのか?

じゃあ実際のところゲートウェイに置き換えてみてどうなったんだ!という話をしていきます。と言っても、今はまだとある画面の1部分にしか導入していないため、そちらでの効果になります。

定量的な効果

対象の画面は、画面(View)に対応した表示ロジック置き場(ViewModel)がかなり複雑になっていました。今回ゲートウェイに移行した結果、ViewModelはiOSだけで79行減りました。たった1パーツ分のAPIリクエストまわりのロジックを修正しただけでこれだけ減るというのは、もともとどれだけ複雑だったんだ…という話でもあるのですが、だいぶ大きい改善です。

アプリからのAPI呼び出しは2回->1回に削減。また、置き換えしている際にじつは今までiOS/Android間で微妙にデータ取得ロジックが違っていたことが発覚したのですが、そのロジックもきれいサッパリゲートウェイ側に移し、共通化されました。

また、画面表示のパフォーマンスも改善されました。以前と比べてキャッシュなしで約1.2倍、キャッシュありだと約150倍速くなりました。

定性的な効果

役割のところで書きましたが、アプリ開発チーム内で一緒に開発しているため、コミュニケーションがとりやすくなったと感じています。

たとえばレスポンスフォーマットについて。ゲートウェイを作り始めた当初は、アプリに対してHALフォーマットでデータ返そうと思っていたのですが、「Android側で使っているライブラリがHALと相性が悪いため別のフォーマットではどうか」というやり取りがチーム内で自然に発生し、サーバー側も柔軟に対応することができました。 ちなみにあくまでアプリのためのAPIなので、ただのjsonにすることになりました。

今後について

現状はオンプレで稼働させていますが、AWS API Gatewayへ移行するかもしれません。開発体制についても、今このゲートウェイの開発を行えるのは、チーム内で私とAndroidエンジニア1人の計2人だけという状況です。ゆくゆくはアプリ開発チーム全体に知見を共有して、なるべくチームみんなで運用できるような体制を目指します。

また、既存からの移行に関して言うと、iOS/Androidで書いていた複雑なロジックがただゲートウェイ側に移るだけで、それはそれでしんどい気持ちも感じています。アプリ側とゲートウェイ側での分担をどうするかは今後もしっかり考えないとなーと感じています。

…というように考えること、やることはたくさんありますが、まだまだ始まったばかりですので、チーム一丸となって取り組んでいければと思います!

おわりに

いかがでしたでしょうか。アイスタイルアプリ開発チームの新たな取り組みを紹介しました。APIゲートウェイを用意した構成は珍しくないはずなので、すでにこうなっている企業も多いかと思います。私たちはまだまだ始めたばかりで不完全ですが、アイスタイルの事業にブレーキをかけず加速させていくために、様々なことに取り組んでいきたいと思っています。

明日の担当は@sakumayです。引き続きアイスタイル Advent Calendar 2018をお楽しみください。

iOSエンジニア、新卒入社4年目 社内腕相撲大会で優勝しました Flutterが趣味