こんにちは、フロントエンドエキスパートチームのsakitoです。
本記事ではkintoneをマイクロサービス化するためのPoCプロジェクトにおけるWebフロントエンドの技術選定について紹介します。
プロジェクト背景
本記事で扱うプロジェクトは「kintoneマイクロサービス化Proof of concept(PoC)プロジェクト」です。
現在サイボウズの主力製品であるkintoneは大きなモノリシックなアーキテクチャになっています。 モノリシックなサービスに関わる人数が増えるに伴って、意思決定や開発速度の低下が課題となってきています。
モノリシックなアーキテクチャや組織によって起こる課題を、マイクロサービスとして切り離して小さくすることで解決ができるのではないかと考えました。マイクロサービス化にあたって、まずはPoCとして一部の機能をマイクロサービス化するプロジェクトを発足し、kintoneをマイクロサービスに分離することが現実的で有効な選択肢となり得るのかを検証することになりました。
このプロジェクトの実施にあたって、Architecture Decision Recordsを残すようにしました。
Architecture Decision Recordsとは
Architecture Decision Records(以降はADR)はアーキテクチャの選定理由やコンテキストをドキュメントに残すためのものです。選定の決定内容だけではなく、決定に至るまでの過程を記録することで透明性が高いドキュメントを残すことができます。
参考リンク:
PoCプロジェクトのWebフロントエンドにおけるADR
今回のプロジェクトでは、次のフォーマットでADRを記述しました。
- コンテキスト
- 検討した案
- 決定内容と理由
コンテキスト
(コンテキスト部分には社外秘の内容も含まれているので、簡略化しました)
kintoneは現状としてClosure Libraryというレガシーなフレームワークを使っているので、技術の刷新についても目的の1つとしています。そのため、まずはフレームワークや主要なライブラリを決める必要があります。テストに関する技術は別途ADRを設けているので、このADRの対象外としています。
その他の制約や判断材料として、次のようなものがあります。
- 既存のサービスからは完全に切り離す
- kintoneというサービスの性質上SEOを考慮する必要がない
- APIは既存のREST APIを使用する
- IE11対応は不要
- サイボウズ社内のプロジェクトやスキルを考慮してReactを使う
- TypeScriptを使う
検討した案
次の3つについて検討しました。
- フレームワーク
- スタイル
- データ・状態管理
フレームワーク
今回はPoCプロジェクトなので、立ち上げから検証までを速く実行できることが大事だと考えました。そのため、ビルドや開発ツール周りの設定を自前で用意せずにフレームワークの力を借りることを前提として検討しました。また、背景で挙げたようにReactの使用が前提条件としてあります。
検討したのは次の2つです。
Next.js
Next.jsはVercel社が開発しているReactベースのフロントエンドフレームワークです。Webフロントエンド開発におけるプラクティスを享受できる設定や、ルーティングなどの機能が利用できるのが特徴です。
Pros
- webpackなどを使用したビルドの最適化やバージョンアップ対応の面倒を見てくれるので、今後のアップデートも比較的やりやすく、設定ファイルに時間をかける必要がない
- webpackの作者であるTobias KoppersがNext.jsチームにいるため、Next.jsを利用することはwebpackを使用する場合においてメリットになりそう。
- webpackの設定ファイルを一部だけ追加する手段が用意されている
- React CoreチームもReactを使用したアプリケーションの実験場としてNext.jsチームと関わっているので、Reactに関するアップデートの最適化や設定も今後吸収してくれるだろうと予想される
- パフォーマンスの最適化なども内部で行ってくれている
- ルーティングに関して、React Routerのリリースはしばらく行われていないので、Next.jsのルーティングを使いたい
- 記事執筆中に追記:2021年11月にReact Router v6がリリースされている
Cons
- 内部のバグを見つけた場合はOSSにコントリビュートして直すか、設定を理解して上書きするなど必要
- ADR選定後に追記
- 今回のプロジェクトではVercelなどのサービスを使用しないので、Next.jsの機能をフル活用するために、BFFに相当するサーバーを用意する必要性について記載が漏れていた
- 開発途中に別途BFFの採用について議論し、サーバーを用意した
- 今回のプロジェクトではVercelなどのサービスを使用しないので、Next.jsの機能をフル活用するために、BFFに相当するサーバーを用意する必要性について記載が漏れていた
Create React App
Create React AppはMeta社(旧Facebook社)がメンテナンスしているReactの環境を素早く立ち上げるためのものです。
- Pros
- 環境をすばやく立ち上げることができる
- Cons
- webpackの設定を変えたい場合はejectをして、すべてのファイルを吐き出さなければならない
- しばらくリリースがされていないかつ、メンテナンスが滞っている
スタイル
スタイルを扱う部分は次の2つの分類から選定を行いました。
- 静的なCSSをビルド時に生成するもの
- ランタイムでスタイルを適用するもの
CSS Modules
CSS ModulesはCSSファイルをJSからimportしてスタイルを当てる手法です。Next.jsでは標準でサポートされています。
- 静的なCSSファイルを吐き出す
- JSからimportして使う形式
- Pros
- Nextjsで標準サポートされている、chunkの面倒も見てくれる
- 参考:Basic Features: Built-in CSS Support | Next.js
- CSSに無理なカスタマイズをしないので、css-in-jsに比べると移行がしやすい
- Cons
- CSS Modulesは完璧なスコープではないので、複雑なCSSを書くとCSSの上書きが起きる可能性がある
vanilla-extract
vanilla-extractはCSS Modulesの作者が新しく開発したライブラリであり、TypeSciprtとの親和性が高いのが特徴です。最終成果物としてCSS Modulesのように静的なCSSファイルを書き出します。
- Pros
- CSS Modulesにはない機能が揃っている
- Theme
- custom utility classの生成
- TypeScriptで記述するので、コンパイル時に存在しないプロパティなどをチェックできる
- CSS VariablesなどもTypeScriptで型検知・補完ができる
- 静的なCSSファイルが最終成果物なのでランタイムでスタイルを当てるよりもパフォーマンスがよい
- CSS Modulesにはない機能が揃っている
- Cons
- CSS Modulesと同様に完璧なスコープではないので、複雑なCSSを書くとCSSの上書きが起きる可能性がある
styled-components
styled-componentsはCSS in JSのライブラリの1つです。kintoneの別プロジェクトで採用しています。
- JSでCSSを書いてバンドル時にJSに含めて、ランタイムでスタイルを当てる
- Pros
- CSSのスコープについて考えることが減る
- Cons
- 静的なCSSをよりもパフォーマンスが低い
- 参考:[Real-world CSS vs. CSS-in-JS performance comparison]
- 静的なCSSをよりもパフォーマンスが低い
データ管理・状態管理
候補に挙がったのは次の3つです。
今回のプロジェクトでは、APIから取得するデータとUIの状態を別で管理するという観点を持って検討を進めました。
データ管理
データ管理に使えるReact QueryとSWRですが、この2つは似たような機能を提供しています。そのため、どちらをなぜ採用したか、採用しなかったかを残すことはのちのちに見返したときに重要な情報となります。
React Query
React Queryは非同期でデータを取得、キャッシュ、更新するためのHooksを提供しているライブラリです。
- Pros
- 非同期で取得したデータを取得・キャッシュ・更新できる仕組みがある
- データを取り扱うさまざまなHooksが提供されている
- devtoolがある
- テストをシンプルに書ける
- Cons
- 状態管理は自前で用意する必要がある
- 今回はuseReducerやuseStateと組み合わせれば問題なさそうな規模
- 状態管理は自前で用意する必要がある
SWR
SWRもReact Queryとほぼほぼ同様の目的で使うものです。
- Pros
- Next.jsと同じ開発元
- 非同期で取得したデータを取得・キャッシュ・更新できる仕組みがある
- Cons
- devtoolが不完全
- React Queryとの比較で参考にした記事
状態管理
状態管理に使うものとしてReduxとReactのContext/Reducerが候補に挙がりました。
Redux
- Fluxベースの状態管理ライブラリ
- Pros
- グルーバルな状態管理の仕組みが作れる
- Reduxが定めるベストプラクティスのRedux ToolKitがある
- Cons
- シンプルなアプリでは大仰なもの
- このプロジェクトでは複雑な状態管理にする必要はなさそうなので、useReducerでの管理で十分なはず
- テストが一手間かかる
- ReduxだとStoreの依存などがあるのでテストで考えることが多い
- 参考:Writing Tests | Redux
React Context/Reducer
- Pros
- Reactのエコシステムで完結する
- 最小限のセットアップでよい
- Reduxに比べてStoreやReduxの設定に依存しないので、Testが簡潔に書ける
- Cons
- 自前で1から設計する必要がある
- レンダリングパフォーマンスの最適化
- TypeScriptの型付け
- Reducerの構造と責務
- 自前で1から設計する必要がある
決定内容と理由
それぞれの検討内容を考慮した結果、次のような決定を行いました。
フレームワーク
決定内容
Next.js
理由
Create React Appよりも今後の展望があることや、ビルドの最適化などを考えた場合にNext.jsの方がメリットがあると考えました。
スタイル
決定内容
CSS Modules
理由
初めは次の理由からvanilla-extractに決定しようとしました。
- TypeScriptライクな開発ができること
- 静的なCSSファイルが最終成果物なこと
しかしながら、選定時点ではvanilla-extractのNext.js v11での利用が難しかったです。
※ プロジェクトの実施中にvanilla-extractのドキュメントにNextjsの設定に関するページが追加された
これらの理由から、次点としてCSS Modulesの採用を決定しました。CSS Modulesも静的なCSSが最終的成果物であること、またNext.jsで標準でサポートされていることから決定に至りました。また、将来的な選択としてCSS Module Scriptsへの以降が他にくらべてやりやすそうであることも考慮しました。
データ管理・状態管理
決定内容
ReactのuseReducer + React Query
理由
今回のプロジェクトでマイクロサービス化するサービスでは複雑な状態管理が必要ではなさそうということから、Reduxを使わずにReactのuseReducerで十分だと考えました。また、状態の管理をReactの機能で行うことでテストがやりやすくなる面もあると考えました。
React Queryはdevtoolがあることで開発体験においてアドバンテージがあると考えました。
ADRを残した効果
今回プロジェクトの意思決定の理由や過程をADRとして残しました。その結果、プロジェクトの途中に参加したメンバーにADRのドキュメントを共有することで、このプロジェクトにおいて「なぜこの技術を使うことになったのか、または使わないのか」の説明を簡潔に行えました。
今回のプロジェクトの技術選定についてはプロジェクト外からの注目度も高く、プロジェクト外のエンジニアから「なぜ〇〇を使っているのか?」という質問をもらうことがありました。その際にも、ADRのドキュメントを共有するだけで意思決定の背景や理由を説明することができました。
おわりに
今回はkintoneマイクロサービス化PoCプロジェクトのフロントエンドに関する技術選定とADRを紹介しました。このPoCプロジェクトはフロントエンド以外にもさまざまな取り組みにチャレンジしたので、フロントエンド以外のことについても紹介するかもしれませんのでお楽しみに。
サイボウズではフロントエンドエンジニア(kintoneアーキテクチャ刷新PJ)やフロントエンドエキスパートなど、Webフロントエンドの改善に関する採用を行なっていますので、ぜひ詳細をご覧ください。