こんにちは!kintone フロントエンドリアーキテクチャプロジェクト(フロリア) の AppShell チームで活動している 22 新卒のアルベスです。この記事は、Cybozu Advent Calendar 2022 の 21 日目です。 AppShell チーム でマイクロフロントエンドを用いた取り組みを経験したことで、エンジニアとして成長するきっかけになったので共有したいと思います!
目次
- 新卒でマイクロフロントエンドを実践するチームにジョインした
- マイクロフロントエンドを実践することになった経緯
- マイクロフロントエンドを実践するためにチームが行ったこと
- マイクロフロントエンドを経験してどうだった?
- まとめ
新卒でマイクロフロントエンドを実践するチームにジョインした
私は、新卒で AppShell というチームに入りました。フロントエンドエンジニアとして、kintone の共通ヘッダー部分の開発をするのが仕事です。
技術的なバックグラウンドとしては、学生時代に Next.js や ReactNative、TypeScript を用いてモバイルアプリや Web サービスの開発経験があります。 アルバイトでの実務の経験などはなく、主に個人開発でスキルを身につけてきました。 大学では IoT や Bluetooth など、Web とは少し離れた領域の研究をしていました。
この度、10 月から AppShell チームはマイクロフロントエンドを実践することになったので、私もチームの一員として参加することになりました。
マイクロフロントエンドを実践することになった経緯
マイクロフロントエンドを実践することに決まるまでにもいくつかの経緯がありました。チームのゴールとともに、マイクロフロントエンドを実践するに至るまでの経緯を紹介します。
AppShell チームのゴール
AppShell チームのゴールは、Closure Library で実装されている kintone の全画面の共通ヘッダーを React コンポーネントに置き換えることです。このゴールに決まった経緯は AppShell チームの記事にて紹介しています。
AppShell チームがゴールに向けて開発を進めていく上で、次のような懸念がありました。
- Closure Library と React をページ内でうまく協調させられるかどうかわからない
- 既存ページのオーナーシップがフロリア外のチームにあるため、コミュニケーションコストが高くなりそう
これらの懸念を解決する方法を模索していたところ、その手段としてマイクロフロントエンドが候補にあがりました。
マイクロフロントエンドの魅力
マイクロフロントエンドとは、アプリケーション開発を機能ベースで分割するアプローチです。 フロントエンド、バックエンドといった一般的な職能ごとの分割とは異なり、それぞれのチームが一つの機能を提供すべく、DB から UI まで一連の開発・運用を行います。
コンセプトとしてはマイクロサービスと似ていますが、バックエンドとフロントエンドを含めて E2E で分割し、フロントエンドでそれぞれの機能が結合されるという点が異なります。 また、マイクロサービスと同じように、それぞれのチームがオーナーシップを持つ機能に対して独自に技術選定ができるという特徴を兼ね備えています。
AppShell チームが実践しようとしている、別チームが Closure Library で実装したページコンテンツと AppShell チーム が React で実装した共通ヘッダー部分を結合させるというのは、マイクロフロントエンドが解決しようとしている課題と共通しています。 そのため、私たちはマイクロフロントエンドで用いられるプラクティスを使用することで、今回の問題を解決できるのではないかと考えました。
マイクロフロントエンドを実践するためにチームが行ったこと
マイクロフロントエンドを実践するために、まずはチームでマイクロフロントエンドへの理解を深める取り組みを行いました。
マイクロフロントエンドの学習
AppShell チームでは、私を含めほとんどのメンバーがマイクロフロントエンドに対する知見を持っていませんでした。 また、メンバー一人一人の知識にも差があったため、最初にメンバー内の知識のベースを揃える必要があると考え、スプリント内で学習時間を確保することにしました。
マイクロフロントエンドの学習は、ほかのチームが過去に行っていた「Micro Frontends in Action」という書籍の輪読会の資料をベースに行いました。こちらの書籍では、Web Components による結合の方法や、Custom Event を用いた機能同士のコミュニケーション方法についてとても参考になりました。
また、マイクロフロントエンドについて書かれた Web 上の資料も参考にしました。こちらの記事は、マイクロフロントエンドに関してとてもコンパクトにまとめられています。
結合方法の洗い出し
次に一人一人が学んだことや、調べてきた結合方法をホワイトボード上(Miro)に挙げて、メリット・デメリットをまとめました。 結合可能かどうかだけではなく、アクセシビリティやパフォーマンスなど、その時点で考えられる懸念点も多角的な視点から挙げました。
そして、挙げられた内容から、現実的に取り得る手段を検討して絞り込みました。 最終的に、次の 2 つの手段を調査して検討しようということになりました。
- Web Components を使った方法
- Closure Library から React コンポーネントを描画する方法
共通ヘッダーコンポーネント(React)を Web Components でラッピングして、Closure Library で作成したコンポーネントと結合する方法
一つ目が Web Components を使用する方法です。次のように、Shadow DOM 内に React コンポーネントを閉じ込めることで、Custom Elements として呼び出せるようにします。Web Components はスタイルのカプセル化が可能であり、グローバルスタイルによる影響を受けないため、調査してみることにしました。
class AppShellWebComponent extends HTMLElement { private readonly mountPoint: HTMLElement; constructor() { super(); this.mountPoint = document.createElement('div'); this.attachShadow({ mode: 'open' }); } connectedCallback() { if (this.isConnected) { this.shadowRoot?.appendChild(this.mountPoint); ReactDOM.render(<AppShell />, this.mountPoint); } } disconnectedCallback() { if (!this.isConnected) { this.shadowRoot?.removeChild(this.mountPoint); } } }
Closure Library から共通ヘッダーコンポーネント(React)を描画する方法
二つ目が window オブジェクトに ReactDOM の render 関数を差し込み、Closure Library から呼び出すことで描画する方法です。 こちらは、Web Components で結合する方法と違い、Closure Library から共通ヘッダーコンポーネントへデータを渡すことが容易であるため、調査してみることにしました1。
window.renderAppShell = () => { render(<AppShell />, document.getElementById("#app-shell-root")); };
結合方法の調査
これら2つの手法に対して PoC (概念実証)を行い、Draft PR としてまとめました。 PoC を通して実装上の懸念点を洗い出し、ホワイトボードに追記する形で調査を進めました。
私は学習フェーズで Web Components の学習を重点的に行っていたため、Web Components による結合の PoC を任せてもらいました。 しかし、PoC を開始してすぐに CSS in JS で記述していたスタイルがうまく適用されない問題にぶつかりました。一人で中々解決できずにいた私を見て、他の開発メンバーが素早く手助けに来てくれたおかげもあり、試行錯誤しながら無事に問題を解決できました。
私が PoC を行った React コンポーネントを Web Components でラッピングする方法は、残念ながら最終的に一部のカスタム hooks が動作しないことがわかり、採用するには難しいとチームで結論づけました。 しかし、自分で担当した手法が採用できないことになったことに対して、残念である気持ちよりも私が活躍できるような場を作ってくれたことに対しての感謝や嬉しい気持ちの方が勝っていました。
今回の調査で分かったそれぞれの手段における具体的な問題点など、技術的な詳細は今後別記事でまとめる予定です。
マイクロフロントエンドを経験してどうだった?
マイクロフロントエンドを新卒で経験してみて、次のように感じました。
- フロントエンドエンジニアとしての教養が身に付く
- 最高のチームだからこそ新卒でも活躍の場があった
それぞれについて詳しく紹介します。
フロントエンドエンジニアとしての教養が身に付く
チームに参加してまず最初に、フロントエンドエンジニアとして必要な知識が私に全然足りていないと認識できました。
マイクロフロントエンドの実践には、使用するバンドラーの高度な知識が必要になってきます。Webpack や Vite など、雰囲気でバンドラーを使ってきた私にはとても勉強になりました。
また、Broadcast Channel API や Custom Event など、Web API に対する知識も得られました。普段フレームワークを使用した開発をしているだけでは身に付かない、フレームワークを跨いだ開発を行うための応用力が身につきます。新卒で経験できるのはとても価値のあることだと感じました。
最高のチームだからこそ新卒でも活躍の場があった
今回のマイクロフロントエンドの取り組みでは、事前にチームで学習時間を確保しました。この時間は、新卒としてジョインした私がチームの活動についていけるように、メンバーが設けてくれたものだと私は思っています。このような、温かい気遣いが AppShell チームにはあります。
この学習時間で Web Components について学習ができたからこそ、Web Components を使った結合手段についてオーナーシップを持って調査ができたと考えています。チームメンバーが裏で支えてくれたからこそ自信が身につきましたし、成長もできました。
私は最初 AppShell チームに配属されたとき、この中で自分はやっていけるのか、ちゃんと貢献していけるのかという漠然とした不安がありました。 チームメンバーはその不安に対して真摯に向き合ってくれました。「わからないことを解消する会」を毎週開催したり、スプリントの振り返りでフィードバックをもらえたり、新卒でも安心して活躍できる環境がしっかりと整備されていました。
これからは、自分の得意な分野をどんどん広げていきながら、一人前のエンジニアとして貢献する形でチームに恩返ししていけたらなと思っています!
まとめ
今回の記事では、新卒でマイクロフロントエンドを経験して私が感じたことを紹介しました。AppShell チームにジョインしたことで、新卒では中々経験できない貴重な経験を積めていると感じています。
AppShell チームでは、これから実際に Closure Library のページの共通ヘッダーを置き換えていくフェーズに入ります。 フロリアは新卒でもチャレンジできる環境が整備されているので、興味を持っていただいた方がいれば、ぜひご応募お待ちしております!
- Custom Elements は HTML タグとして呼び出すため attribute に文字列しか渡せず、内包している React コンポーネントにも文字列化できる値しか渡せない。↩