LINEヤフー Tech Blog

LINEヤフー株式会社のサービスを支える、技術・開発文化を発信しています。

LINE公式アカウントのページ移行に伴うコンポーネント開発(インターンレポート)

初めまして。東京工業大学情報理工学院修士一年の池田むつきです。

私は2024年のサマーインターンシップで、LINE公式アカウントのフロントエンドの実開発に参加しました。今回のブログでは、実際にどのようなインターン業務を行ったのかご紹介したいと思います。

タスクについて

私が参加したチームは、LINE公式アカウントのWebフロントエンドの開発を行っているB2C開発チームです。LINE公式アカウントとは、企業や店舗がクーポンや情報をLINEで発信するためのサービスです。企業や店舗はこのサービスを通じてアカウントを作成し、アカウントを友だち追加しているLINEユーザーに対しクーポンやメルマガを送ることができます。一方LINEユーザーはこれらのアカウントを友だち追加することで、アカウントが発行しているクーポンを獲得したり、メッセージを受信したりできます。このようにLINE公式アカウントは企業向け、LINEユーザー向け両方のアプリを提供していますが、B2C開発チームではそのうちのLINEユーザー向けのアプリを開発しています。LINEユーザー向けのアプリは、LIFFブラウザというLINEアプリ内専用のブラウザ上で動作するアプリが主です。

今回取り組んだタスクの対象となるアプリは、公式アカウントの一覧を表示するLIFFアプリ(OA List)とクーポンに関する情報を表示するLIFFアプリ(OA Coupon)です。これまで、獲得済みクーポン一覧ページはOA List側にありました。今回のタスクは、この獲得済みクーポン一覧ページをOACouponに移行することです。これは、クーポンに関する情報はOA Couponにまとめたいという動機によるものです。

移行自体は既存のコードを移すことでほぼ完了しますが、それでは将来に負債が残ってしまう可能性がありました。その原因が、ページ下部にあるボトムナビゲーションです。このボトムナビゲーションは、移行後はOAList、OACoupon双方に同じ見た目・機能のものが存在することが要件です。そのため、移行のために実装を重複させると、将来的に仕様・デザイン・設計・実装の変更が必要になった際に2倍の作業が必要になり、メンテナンスコストが大きくなります。そこで、このボトムナビゲーションをloa-componentsと呼ばれるチーム内のみで利用するWebComponentsライブラリとして実装することで、実装を一箇所にまとめ、コードの重複を避けることにしました。

さらに、このボトムナビゲーション (1) とアイコンボタン (2) は、汎用性を持たせれば、デザインガイドラインで定められている最小単位のコンポーネントとして、今後他のチームでも利用可能なものでした。そのため、これらはより汎用性の高いコンポーネントとして、他のチームからも利用できるshared-componentsというWebComponentsライブラリに実装することにしました。

今回のタスクを簡単にまとめると、以下のようになります。

  1. 汎用的にしたボトムナビゲーションとアイコンボタンを、shared-componentsに実装
  2. OA ListとOA Couponで共通のボトムナビゲーションをloa-componentsに実装
  3. 獲得済みクーポン一覧ページの移行

ボトムナビゲーション(1)とアイコンボタン(2)を表示している OA List のスクリーンショット

技術スタックについて

各アプリケーション・ライブラリは以下の技術スタックで構成されています

  • OA List, OA Coupon: Vue.js
  • loa-components: Svelte
  • shared-components: Lit

loa-componentsとshared-componentsはともにWeb Componentsを提供するライブラリですが、loa-componentsではLitではなくSvelteを用いています。これは、ライブラリの提供範囲に応じた特徴に合わせるためです。loa-componentsは提供範囲が狭く、コンポーネント側で責任を持つべきロジックが多いため、よりロジックの記述がしやすいSvelteが用いられています。

やったこと

1. shared-componentsの実装

shared-components に実装したのは以下の2つのWeb Componentsです。

  • <shared-bottom-navigation />
    • slotでナビゲーションアイテムを受け取り、均等に配置する
    • Safe Areaも考慮した適切な大きさの余白を設定する
  • <shared-icon-button />
    • attributesでラベルテキスト、slotでアイコンを受け取り、決められたサイズに整えて配置する

shared-componentsのコンポーネントは複数のチーム・プロダクトからの利用が想定されているため、可能な限り柔軟な設計が求められました。一方で、社内のデザインガイドラインに厳密に従わせる仕組みをコンポーネント側で持つ必要がありました。この柔軟性と厳密性のバランスが非常に難しく、メンターさんだけでなく複数のエンジニアの皆さんと議論を重ねました。柔軟性の例として、アイコンボタンは純粋なボタンとして利用したい場合とリンクとして利用したい場合の両方が想定されるため、aタグとbuttonタグを使い分けられる仕組みを導入しました。厳密性の例として、ボトムナビゲーションのデザインガイドラインでは3個以上5個以下のナビゲーションアイテムが許可されているため、ナビゲーションアイテムの数が5個より多い場合、CSSを使って6個目以降のアイテムが表示されないようにしました。逆に3個未満の場合は警告メッセージを出すようにしました。

2. loa-componentsの実装

loa-componentsに実装したのは以下の2つのWeb Componentsです。この2つのコンポーネントはそれぞれ<shared-bottom-navigation /><shared-icon-button /> を利用して実装されています。

  • <loa—bottom-navigation />
    • 名前付きslotでナビゲーションアイテムを受け取り、決められた順番で配置する
  • <loa-bottom-navigation-item />
    • どのタブのためのアイテムか、タブがアクティブかどうかをattributesで受け取り、適切なアイコンを表示する

loa-componentsは、プロダクト間で共通の仕様・デザインをプロダクト側の判断で崩させないために、自由度の低い設計にする必要がありました。例えば、表示可能なアイコンの種類を制限したり、ナビゲーションアイテムの順番を固定したりしました。しかし、厳密性を最大限に高めるために単一のWeb Componentsとして実装すると、ナビゲーションアイテムにVue Routerの<router-link /> を使えないという課題がありました。そのため、ナビゲーションアイテムは別のコンポーネントとして切り出し、2つのコンポーネントに分けて実装することにしました。この実装の場合、<router-link /><loa-bottom-navigation-item /> をラップしてから <loa-bottom-navigation />のslotに渡すことで先述の課題を解決可能です。設計段階ではこれ以外の実装方針も考えられたため、まずは設計を細くドキュメントに起こし、どの設計が良いかをチームの皆さんと議論・確認した上で実装を行いました。

3. ページの移行

ページ全体の移植に関しては既存の実装を移すことが主でしたが、Web APIの仕様がOA ListとOA Couponで異なるため、既存の実装が使えませんでした。特に、サーバーから返ってきたレスポンスをフロントエンドでキャッシュする部分は完全に0から実装しました。獲得済みクーポン一覧ページでは、表示するクーポンの数が多い場合無限スクロールで少しずつデータを取得しながら表示を行います。その際、前回のリクエストに伴う処理が完了していない場合や、全てのデータを取得し終えている場合に余分なリクエストをサーバーに送信しないよう工夫しました。その他、移行に伴って不要になるロジックの削除も行いました。

感想

大きい組織で、より長い未来を見据えた開発というのは学生レベルの開発ではなかなかできないことなので、非常に良い経験になりました。特に、ドキュメントを書くことの重要性を学ぶことができました。ライブラリのREADMEやプルリクエストの説明などの文章を分かりやすく簡潔に書くことで、今いるメンバーの皆さんとのコミュニケーションが円滑に行えるだけでなく、将来ライブラリを使う人の助けにもなります。ドキュメントを丁寧に書くということは今回のインターンシップ中、特に意識して行いました。また、コンポーネントの実装にあたってさまざまな方とたくさん議論を重ねることができて楽しかったですし、議論をしていく中で、より良いものになっているということを実感できました。そして、アクセシビリティに気を使った開発も初めての経験で、アクセシビリティに関する知識を身につけることができました。

今回のインターンシップを通じて、さまざまなことを学び、経験することができました。支えてくださったチームの皆さん、本当にありがとうございました。

メンターからの一言

池田さんのメンターを務めたTheo Steiner(シュタイナー・テオ)です。普段はLINE公式アカウントのエンドユーザー向けアプリケーション開発を担当しています。

今回のインターンシップではLINEヤフーでの仕事の多様性を体験していただくために、複数のレイヤーに携わる案件をお願いしました。Adam FrostのAtomic Designを参考に、フロントエンド・エンジニアの日常で扱う最も小さいatomである抽象的なコンポーネントから、具体化された共通コンポーネントのmoleculeを経由して、最終的にユーザーに届くpageまで開発していただきました。全レイヤーに渡った機能開発では大勢のステイクホルダーに触れる機会があります。低レベルのコンポーネントを作る際に、デザイナーにUIのあるべき姿を確認したり、同僚のエンジニアと実装を議論したりする必要があります。開発スタックを登って、ユーザーに配信されるアプリケーションに近づくと、プロダクトの責任者である企画者のメンバーと親密にやり取りすることが重要になってきます。そのように、技術的な能力だけでなく、社会人としてのコミュニケーション・スキルも求められています。

このタスクを考えた時、短い期間しかいないインターンシップにはハードすぎるかもしれないと思いました。しかし池田さんは感動するほどの努力で着手してくれたおかげで、アサインされたタスクだけでなく、追加の成果物であるこのブログ記事を残すことにまで成功しました。

これほどの技術力と社会人力を持ったインターン生のメンターを担当できたことが本当に貴重な体験でした。インターンシップは終わりましたが、またお会いできることを楽しみにしています!