
この記事は、CYBOZU SUMMER BLOG FES '26の記事です。
こんにちは、kintoneのシステム管理/外部連携チームでProduct EngineerをしているT.Mです!
本記事では、日々の機能開発と並行して進めているコード改善の取り組みの一つとして、サーバーサイドでテンプレートエンジンへのパラメータ埋め込みを廃止してAPI経由のやりとりに置き換えている話をご紹介します。
コード改善の背景
私たちが現在開発しているkintoneは絶えず機能開発を続けてきており、これまで積み重ねてきた機能や仕組みの中には改善の余地があるコードもいくつかあります。サーバーサイドで採用しているテンプレートエンジンを使ったパラメータ埋め込みの仕組みもその1つとなっています。
サーバーサイドテンプレートエンジンによるHTML配信の仕組み
ここで言うテンプレートエンジンとは、テンプレートと動的なデータを元にHTMLを生成する仕組みのことです。
テンプレートファイルには、HTMLの雛形と、サーバサイドレイヤーから注入されるデータへの参照を記述できるようになっています。 ブラウザからWebページにアクセスがあった場合、サーバサイドレイヤーでテンプレートファイルにデータを埋め込んだ上でHTMLを組み立ててブラウザへレスポンスを返します。
TypeScriptといったフロントエンドの言語側で埋め込まれたパラメータを参照したい場合は、scriptタグの中でグローバル変数を定義し、テンプレートエンジンの変数展開の記法でサーバー側の値を注入します。こうすることでフロントエンドはグローバル変数を参照して初期パラメータを受け取ることができるようになります。
図にすると以下のような構成になります。

テンプレートエンジンを使うことのつらみ
kintoneにおけるテンプレートエンジンの立ち位置
では、kintoneでテンプレートエンジンをどう使っていたかというと以下のようなシステム構成で利用していました。

処理の順としては以下のようになっていました。
- ブラウザがWebページへアクセスする
- Spring serverはHTML生成ロジックで必要な値をDBから取得し、テンプレートに埋め込む。
- Spring serverはテンプレートをHTML化してブラウザへレスポンスする
- ブラウザはHTMLのscriptタグのsrcの情報を元にstatic serverのビルド済みReactコード(js)を読み込む
- Reactコードが動作し、グローバル変数経由でテンプレートに埋め込まれたパラメータを参照して各種機能が動作する
問題点
この構成には、主に以下のようなつらさがありました。
- フロントエンドとバックエンドの結合度が高い
- フロントエンドがグローバル変数経由でのパラメータ参照というテンプレートエンジン前提の設計になってしまうためアーキテクチャの変更容易性が下がる。
- 一連の処理を追跡しづらい
- バックエンドからフロントエンドへのパラメータの渡し方が2系統あることをエンジニアが認知しなければいけない。
- AIエージェントがテンプレートエンジン経由でのフロントエンドへのパラメータ渡しをうまく認識してくれないことが多くコーディングがスムーズに進まない要因にもなっていた。
- テストが書きづらい
- フロントエンドのテストランナーでテンプレートファイルを直接importができないためテストが難しく、E2Eなどの粒度が大きく実行時間が長い傾向にあるテストを書かざるを得なかった。
- 静的解析・Linterの恩恵を享受しにくい
- JavaやTypeScriptといった言語と比較してテンプレートエンジン周りの補助ツールは充実しているとは言い難く、実行時までエラーを捕捉しにくい。
- テンプレートへ埋め込むパラメータは文字列展開されるためパース処理を明示的に記述する必要があった。
どのように解決したか
改善後の設計
前述した問題点を生み出していた根本的要因は、テンプレートファイルへのパラメータ埋め込みによるフロントエンドとバックエンドの結合度の高さにありました。
そのため、シンプルにテンプレートへのパラメータ埋め込みを一切やめて、API経由でパラメータ取得する系統だけに統一する改善を実施しました。 なお、HTMLの骨格の配信には引き続きテンプレートエンジンを使っており、テンプレートエンジン自体を廃止したわけではありません。あくまでテンプレートへのパラメータ埋め込みだけを廃止した形になります。
図としては以下のようになります。

この改善により、テンプレートでグローバル変数にパラメータが展開されなくなり、フロントエンドが必要な値は常にAPI経由で取得するよう経路が統一されました。 フロントエンドのテンプレートエンジンへの依存度合いも一定下がったと思います。
フロントエンドとバックエンドの通信部分の改善
また、パラメータ取得の経路の一本化に加えてフロントエンドとバックエンド間の通信部分の設計も以下のように同時に見直しました。

この見直しではフロントエンドとバックエンドの双方にAPIを定義するレイヤー(internal-api, Service)を設け、それぞれでリクエストとレスポンスの型定義を持つような形にしています。
また、フロントエンドとバックエンドのAPI定義を吸収するための結合レイヤー(APIClient, Controller)を噛ませることで、API定義の多少のズレは許容できるようにしています。 例えば、片側でAPI定義(型)を変更しても、結合レイヤーの変換で吸収できる範囲であればもう一方の修正を即座に強制しません。そのため、API定義が完全に固まりきる前でもフロントエンド・バックエンドがそれぞれ先行して実装を進めやすくなっています。 このように型定義に柔軟性を持たせた構成に整えることによってフロントエンドとバックエンドのそれぞれの領域で独立した開発が従来よりも進めやすくなることを目的としています。
実際に改善を進めてみての所感
では、実際にここまでの改善を実施してみてどうだったのか個人的所感を書き連ねてみます。
良かったと感じたところ
コードリーディングの負荷が下がった
前述したようにテンプレートファイルは静的解析・Linterが充実していないため、バックエンドのどこからパラメータ埋め込みが実施されていて、どういう型定義になっているのかを把握するのに時間がかかっていました。 内部API経由でのパラメータ取得に統一され、フロントエンドとバックエンドのそれぞれの層で型定義付きのAPI定義を持つようになったことで、よりスピーディにAPI仕様を理解できるようになったと感じました。
テストが書きやすくなった
内部API経由に通信経路を統一したことで、これまでできなかったフロントエンドでのAPIをモックしたテストが書けるようになりました。 これはE2Eテストを結合テストや単体テストといった粒度の小さいテストに移行させる余地ができたとも言えます。 粒度の小さいテストに移行することはテスト全体の実行時間の短縮にも繋がりますので、テストピラミッドの改善にも繋がるいい活動になったと思えた部分でした。
バックエンドとフロントエンドの責務の分離についての課題を見つけるきっかけになった
これは今回の活動による副次的な効果ですが、バックエンドからフロントエンドに渡しているパラメータを見ていたことで以下のような課題があることに気づくきっかけにもなりました。
- 画面の表示を担うフロントエンド的には必要のないプロパティがバックエンドから渡されていた。
- 本来バックエンドでの演算処理結果をフロントエンドに渡すべきところを、フロントエンド側が演算処理を実施していた。また演算処理のために必要なパラメータもフロントエンドに渡されていた。
将来的な選択肢の幅を広げる一歩になった
テンプレートが従来よりもシンプルな構造のHTMLを作るようになったので、将来的にテンプレートエンジンを介さずフロントエンド専用の配信サーバーからHTMLを配信する等の選択肢を取りやすくなったと思っています。
本記事の趣旨から外れるため省略しましたが、多くのテンプレートファイルは別のテンプレートファイルと依存関係がある状態になっており、テンプレートエンジンが依存関係を解決してHTMLを生成しています。そのような依存関係をうまく解決することができれば、テンプレートエンジンからの脱却もできるのではと考えています。
工夫が必要だったところ
HTML取得とは別に非同期でパラメータ取得をするためUI/UX面の見直しが必要になった
改善前はテンプレートにあらかじめパラメータを埋め込んだ上でHTMLを生成していたので、Webページアクセス時にすぐ画面がレンダリングされるようなUXになっていました。
これを内部API経由でのパラメータ取得にした結果、ブラウザがHTMLをレンダリングした後に非同期でAPIリクエストの通信が発生するようになり、結果として画面が一瞬真っ白な状態になる期間ができてしまっていました。 そのため、APIとの通信中には画面上にスピナーを表示して通信中である旨を示す、といった追加対応が必要となりました。
機能開発とのコンフリクトを避ける必要があった
kintoneは常に何かしらの機能開発を進めていますので、機能開発の妨げにならないよう、パラメータ埋め込み廃止の対応は、対象機能に対する機能開発のスケジュールと重ならないタイミングで実施する必要がありました。
それでも修正頻度が高くコンフリクトが避けにくい機能に関しては、レビューを同期的に集まって議論することでより短期間でエンジニア間で合意形成し、PRをマージするよう努めていました。
最後に
本記事で紹介した改善活動はまだ走り出して間もない状態で、実はまだまだ対応箇所は残っています。きっと今後も活動を進める中で新たな気づきや改善ポイントが見つかっていくでしょう。
明示的に改善活動の時間を取ることは、日々の機能開発とは別視点で技術的な課題を認知するとても良い機会になります。そこで得た知見は機能開発側にもフィードバックしていけるものだと思います。
地道な活動ですがkintoneのコード品質をより良くするためこれからも改善活動を続けていきます!