2021年12月23日
LINE株式会社 OA Dev 3 Team Software Engineer
大原 康平
2018年入社の新卒4年目。LINEポイントクラブのサーバサイドの開発を担当。
LINE株式会社 Kyoto Developer Division Client Engineering Team Software Engineer
植松 啓誠
2019年入社。LINE証券・LINEほけん等の金融サービスでフロントエンド開発に従事。現在は出前館で、React Nativeアプリの開発を担当。
LINE株式会社 Kyoto Developer Division Client Engineering Team Software Engineer
黒澤 慎治
2020年にLINEに入社。LINE公式アカウントアプリでSwiftを用いたiOSアプリ開発に従事、現在は出前館をReact Nativeで開発。
LINEが開催するエンジニア向け技術カンファレンス「LINE DEVELOPER DAY 2021」の注目セッションをお届けする第2弾。今回は、8年続くPerlプロダクトをKotlinに書き換えたプロジェクトと、LINEと提携する出前館におけるReactNativeアプリ開発の舞台裏が語られた2つのセッションをご紹介。
第1弾はこちら
【LINE DEVELOPER DAY 2021】LINEにおけるデータ分析と機械学習開発、属性推定システムリニューアルの事例紹介【イベントレポート】
最初に紹介するセッションは、2018年新卒入社でPerlやKotlinのコードを書いているソフトウェアエンジニア大原康平氏による「8年続くPerlプロダクトをKotlinに書き換えた話」だ。
今回Kotlinに書き換えたPerlプロダクトは「LINEポイントクラブ」。LINE Payでの支払いや、LINEの各種サービスの利用などで貯めることができるLINEのポイントサービスである。
LINEポイントクラブには「貯めるタブ」と「使うタブ」があり、貯めるタブは動画を見たり、アプリをインストールしたりすることでポイントを貯めることができる。使うタブでは、LINEマンガのコインやミュージッククーポン、その他様々なものにポイントを交換することができる。
平均的なトラフィック数は、秒間700リクエスト、ピーク時には秒間1万5000リクエスト、デイリーでは約5700万リクエストといった規模のサービスだ。
Perl時代のサーバ側システム構成を簡略化した図が以下である。外からリクエストが来ると、ロードバランサーで受け、nginxで「貯めるタブ」と「使うタブ」のアプリケーションをそれぞれプロキシする。「貯めるタブ」を「使うタブ」で別々のデータベースを持っており、それぞれのアプリケーションがコンテンツを返す構成となっている。
「貯めるタブ」が2013年からサービス開始したのに対して、「使うタブ」は2015年の4月からサービスを開始したため、「貯めるタブ」がPerl、「使うタブ」はKotlinで書かれている。2015年にサービス開始した当初「使うタブ」はJavaで書かれていたのですが2020年にKotlinに書き換えています。言語が違う2つのアプリケーションを管理するのは大変だ。エンジニアリソースの配分や、貯めるタブと使うタブで、同じ機能をそれぞれ開発する必要がある。
Perlプロダクトである「貯めるタブ」のシステム概要を少し詳細にしてみた。まず、media,admin,cv-workerというアプリケーションがAmon-2というPerlのフレームワークで書かれている。HBase gatewayは、Kotlinで書かれていて、Spring Bootというフレームワークを使っている。
Java/Kotlinが既に使われていることに気づかれた方もいると思うが、これにはPerlからHBaseを直接使えなかったという歴史的な理由があったと、大原氏は明かす。
「MySQL for job queue」は、「貯めるタブ」でポイントを獲得するための条件を達成すると、コンバージョンのデータをジョブキューに格納していく。ジョブキューはMySQLのテーブルに貯められ、cv-workerが処理する構成となっている。他にも、MySQLやRedis、Memcachedが使われている。
様々な言語がある中でPerlをなぜKotlinに書き換えたのか。その理由はシンプルで、社内のサーバサイドの開発で最も使われている言語がJava/Kotlinだったからである。当然ながら、同じ言語を選択すると、エンジニアリソースの配分や社内のエコシステムを使う上でかなりのメリットがある。
PerlをKotlinに書き換えることに決めた理由を整理すると、以下の5つにまとめられる。
では、Kotlinに書き換えた後のシステム概要は以下のようになった。全てのアプリケーションがSpring Boot Kotlinで実装され、データベースはこれまでの「貯めるタブ」と「使うタブ」のデータベースをそのまま活用した。アプリケーション間の通信はgRPCで行うようにした。
「gRPCはProtocol Buffersでデータをシリアライズして、高速に通信できることと、IDLで定義したAPI仕様からクライアント側とサーバ側でそれぞれコード生成してくれるのが便利です」(大原氏)
Perl時代はMySQLを使っていたが、Kafkaをジョブキューとして導入したことで、自前のジョブキュー管理の実装が不要になった。そして、スケーラビリティが上がり、別のコンシューマを追加して、別の処理を行えるようになった。
また、HBase gatewayアプリケーションも不要で、coreやcv-workerといったアプリケーションから直接HBaseを操作できるようになり、管理コストが削減できた。
「mediaアプリケーションは今後kubernetesなどにすることを見据えて、Redis Clusterにのみ接続することで、スケーラビリティが高い状態にしています」(大原氏)
ちなみに今回のプロジェクトは、Java/Kotlinエンジニア3名とPerlエンジニアが3名、計6名で開発が進められたという。
最後に、プロジェクトの大変さや培った知見、別言語に書き換えるメリットについて語られた。上記スケジュールの時系列順に紹介していく。
機能の取捨選択
8年続くプロダクトには、既に使われていない複雑な機能がたくさんあった。これらを使われているのか、もういらないのかを調べ、捨てる機能を決めて新しい仕様に反映するというのは大変な作業だったと大原氏は振り返る。
削除した機能のドキュメント不備から、捨てることにしていた機能を他のメンバーが実装してしまうというトラブルもあった。対策としては、削除した機能についてもWikiなどに書くようにした。
「さらに、Perlのコードにコメントを書くようにしました。具体的にはKotlinに移行するときのためのブランチをPerlの方に作り、Draft Pull Requestを作ってコメントを書きます。これはかなり良い方法だったのでおすすめです」(大原氏)
KotlinエンジニアにとってのPerlの難しさ
これまでの仕様がすべてドキュメント化されていなかったこともあり、KotlinエンジニアがPerlのコードを読む必要があった。ドキュメント不足の理由は機能がかなりのスピード感で追加変更されていた時期に、ドキュメント化する時間とヒューマンリソースがなかったことが原因である。これを機に、ドキュメントの整備にも力を注ぎ始めたという。
PerlエンジニアにとってSpring Boot Kotlinの難しさ
PerlエンジニアはKotlin自体にはすぐ慣れたものの、Spring Bootに慣れるのには苦労したという。
「Perlであれば、import somethingと書けばどこでもインポートできたのですが、SpringBootではimport somethingと書くだけでは、NoClassDefoundErrorになってしまう場合があります。これについては、BeanやDI、ComponetScanなど、Spring Bootについて学んで適切にインポートする必要がありました」(大原氏)
nullableを多用している
今回のプロジェクトでは、基本的にロジックを揃えてKotlinに移植を進めていたため、Perlを元に書き換える上で、変数をnullableとして定義してしまう。nullableをnon-nullに変換する難しさもあった。
対策としては、可能な限りnon-nullを使うことにした。具体的な例としてはController層でnullチェックをしてService層にはnon-nullで渡し、nullableを使う範囲を狭めることが挙げられる。さらに、not-null assertion operatorを使うときには、将来的にNullPointerExceptionが飛ぶ可能性をちゃんと考慮して実装すべきだという。他にも複数の意味をもつ変数の扱い方について、Kotlinの書き方に対する反省点が紹介された。
ビジネスロジックが外の世界を知ってしまっている
ビジネスロジックが外の世界とどのように通信しているのか知っている状況となり、ロジックの共通化がうまくいかないといったことが発生した。ビジネスロジックは外の世界のことを知らない状態にしておく必要性を再確認できた事例となった。
リリースに関する難しさについては、現行のPerlシステムを考慮したREAL QAが挙げられた。現行システムのデータベースを使うことにしたことによる大変さだったが、もし全てのデータベースをリプレイスする方法を採用していたら、また別の大変さが発生する。
今回はPerlとKotlinを約1カ月半、並行で動かしたが、この期間は長めに取った方が良いという知見が得られた。また、Perlに何を残して、どう手を入れるのか、Perlに残した部分の開発の苦労についても語られた。
最後に、言語を書き換えたことによるメリットが4つ紹介された。
そして、大原氏は以下のようなアドバイスを送り、セッションを締めくくった。
「長くサービスを運営していると、必ずシステムは複雑化し、メンテナンスコストが上がります。数年後まで見据えて、不要な機能の削除やコードレビュー、ドキュメントの充実化に取り組んでください」
日本で最大級のフードデリバリーサービス「出前館」は、PCスマートフォンのブラウザとiOS、Androidアプリ両方から利用できる。9万5000以上の加盟店(2021年10月時点)と、アクティブユーザーも730万人を超え、サービスとして大きな成長期を迎えている。
セッションではまず、出前館のアプリシステムの全体像が紹介された。配送の仕組みは大きく分けて2種類ある。1つ目はユーザーが注文をすると、出前館経由で店舗へ情報が連携され、店舗が雇用する配達員が商品を届ける。2つ目は、店舗への注文情報を連携すると同時に、出前館の配達員にも情報を連携。出前館の配達員が店舗で商品をピックアップし、ユーザーのもとへ届けるシェアリングデリバリー®という仕組みである。
「これらの仕組みを実現するために、出前館の配達員へオーダー情報を配信する配送アプリ、加盟店が注文情報を確認するアプリや商品情報の管理画面、加盟店の売上や配達件数、人気のある商品などを可視化する分析ツールなどを提供しています」(植松氏)
出前館とLINEは2016年から資本業務提携という形で携わっており、現在これらの各システムに多くのLINEのエンジニアが関わっている。LINEでは、フードデリバリーやテイクアウト注文ができるサービスを開発・運営していたが、2020年の資本業務提携の強化を契機にLINEの各サービスと出前館を統合した。
LINEのエンジニアがチームにジョインするまでは、2名のエンジニアでPC・スマートフォンのブラウザ版と、iOS・Androidアプリの開発をすべて行っていた。
現在の開発チームは、東京・京都2拠点を中心に岡山から参加する開発パートナーで構成している。現時点でiOSエンジニアが4名、Androidのエンジニアから2名、フロントエンドが1名、LINEから出前館アプリの開発に参加している。
リモート開発の体制が整っているので、SlackやZoomを使って密にコミュニケーションをとりながら、日々開発を行っている。
続いて、体制が変わっていく中で、アプリチームとして取り組んできたことが紹介された。
これまで2名で開発を行っていたため、仕様面やビジネスロジック、ビルド環境などの属人化など、様々な課題があった。それらを解消し、チーム開発に移行するにあたり、基本的なルール、一貫性を持った開発、継続しやすい開発を行える土台作りから行う必要があった。
まずはアプリの開発・運用に関して、基本的なルールを決めた。React Nativeには大きく分けてバイナリリリースと、OTAでのリリースがある。バージョンに関しては、計画的なバイナリリリース・OTAリリース、また問題が発生した際のHotfixを考慮してルールを再作成した。
Gitは、GitLab-flowをベースにコードの管理を行っている。React Native開発でネイティブモジュールの追加更新が必要なものをOTA配信してしまうと、JSバンドルのみ更新され不具合の原因になってしまうことがある。そのため、バージョンルールによるバイナリリリースの明確化と、リリースブランチによるソースコードの管理を徹底するようにした。
スクラムも導入した。チーム開発への移行期でキャッチアップしなければならないことも多いため、1WeekSprintで運用。タスクマネジメントはJIRAで行っている。
次に、コードの一貫性を保つために行ったことが語られた。コードベースすべてがTypeScript化されていたものの、JavaScriptから移行したため様々な箇所でanyが使われていた。React Nativeによる開発にあたり、現在はanyの排除を行っており、新規で実装をする箇所は noImplicitAnyで実装を行っている。さらに、コードのクオリティを担保する一つの指標として、コードの静的解析ツールSonarQubeを導入した。
「私がチームにジョインして最初に行ったcommitは、アプリ内の全コードをフォーマットすることとLintエラーの修正でした。チームとして本質的でない細かな箇所の指摘をしないように、ルールを与えることでレビュー負荷を下げるのが一番の目的です」(植松氏)
また、継続的に開発を行うためにビルド環境も整備した。以前は個人PCのローカル環境でビルドを行い、成果物をストアにアップロードしていたが、現在はBitriseというサービスを利用。Bitrise上で、OTAビルドの作成やバイナリービルドの作成のワークフローを管理している。
さらにGitHub Actionsも活用し、テスト、Linter/Prettierなどのチェックを自動化。プルリクエストの差分をSonarQubeで静的解析を行うことによって、コードレビューの負荷を下げ、開発により多くの時間を割けるようにした。
最後に、植松氏は出前館チームが今取り組んでいる、メンテナンス性・安定性・ユーザー体験の向上について説明した。
続いて登壇した黒澤氏は、出前館のアプリ開発にぶつかった壁と解決策、現在地についてセッションを行った。まず説明したのは、出前館アプリでなぜReact Nativeを採用しているのか。
1つ目の理由は、既存コードがReact Nativeであったこと。さらに出前館アプリが複雑なロジックとドメインで成り立っていることから、リプレイスすることは高いコストがかかる。そのため改修を入れるよりも、React Nativeをメンテナンスし続ける選択をしたのだ。2つ目の理由としては、AndroidとiOSを一つのソースコードで管理できるため、スピード感を持った開発ができることが挙げられた。
「出前館アプリでは、現在複数のフィーチャーが同時に複数チームで開発されています。
今のスピード感で開発するのは、クロスプラットフォームを使用しないと難しいため、React Nativeを選択していて良かったと感じています」(黒澤氏)
出前館アプリ開発を行う上で最初の課題は、React Nativeアプリを開発するために必要なReact Nativeの学習だった。宣言的UI、ファンクションコンポーネント、HooksやReact Nativeのコンポーネント、そしてReact Nativeをネイティブ層で使用するための知識など、多くの知識を必要とする。さらに、TypeScriptの知識や、React Native開発を行うための環境・ライブラリなどの理解も必要となる。
チームの中にAndroidやiOS開発者が多いため、ReactやReact Nativeの開発経験がないメンバーも多くいた。これらの知識をすべて学習するためには、学習コストがそれなりにかかる。そこで行った対策は主に以下の4つだ。
続いてリファクタリングでの苦労について紹介した。出前館アプリでは、一つのコンポーネントに多くのレンダリングロジックやビジネスロジックが集約されており、コードを理解するのに時間がかかるといった課題があった。
またクラスコンポーネントで書かれているコンポーネント、より新しい技術を使っていくために、ファンクションコンポーネントで書き直したいといった課題もあったという。これらの対策としては、React Nativeのエコシステムを存分に活用。
UIのロジックについてはコンポーネント内部のみに記載し、ビジネスロジックと分離。UIのコンポーネントを分割して、適切にテストを変えていくことで、コンポーネントの役割を明確化した。
また、クラスコンポーネントをファンクションコンポーネントへと移行し、ビジネスロジックにはHookを使用している。フックにユニットテストを書くことで、ビジネスロジックのコードの安全性も担保できている。
上記の対策で、アプリのビジネスロジックはUIから分離できた。しかし、「出前館アプリとWebサービスで、同じビジネスロジックを書くことが多い」という課題もあると黒澤氏は語る。
アプリとWebで同じビジネスロジックを書くのであれば、極力一箇所にまとめたい。そこで現在はBackend For Frontend(BFF)を通じて、ビジネスロジックの共通化を図っているのだという。
「私はBFFサーバの開発にも着手をしているのですが、普段からReact NativeをTypeScriptで書いていることや、BFFサーバがTypeScriptで書かれていることから、スムーズに開発に着手ができ、React Nativeを開発していて良かったと感じています」(黒澤氏)
さらにセッションでは、多くの機能を継続的にリリースするために行った準備について紹介した。出前館アプリにはCI/ CDシステムがなかったため、専任のエンジニアをアサインし新しいビルド環境を作成。現在ほぼすべてのリリース作業の半自動化に成功した。また、スピード感をもったリリースができるように、LINEのQAチームと連携してリリース管理を行っている。さらに、より開発チームで効率よく動けるように、hot-fixが必要な場合のブランチ戦略やバージョン管理、OTAアップデートのプロセスなど、チーム内で統一したルールを決めた。
少人数での開発から大規模開発へと移行する際には、多くの改善対策を行う必要がある。これからもスピード感を持った継続的な開発ができるよう、様々な取り組みを行っていきたいと黒澤氏は宣言し、セッションを締めくくった。
文:馬場美由紀
関連記事
人気記事