Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

コード分割から始める複雑さの解消に向けたkintoneのアーキテクチャ改善 / アーキテクチャ...

Avatar for hirokuni-maeta hirokuni-maeta
November 20, 2025
10k

コード分割から始める複雑さの解消に向けたkintoneのアーキテクチャ改善 / アーキテクチャConference 2025

Avatar for hirokuni-maeta

hirokuni-maeta

November 20, 2025
Tweet

Transcript

  1. 自己紹介 ▌前田 浩邦 / Hirokuni Maeta ▌2014年4月 サイボウズ入社 ▌kintone開発チーム /

    プロダクトエンジニア ▌サーバーサイドとフロントエンド、最近はサーバーサイドの改善を担当 2
  2. 機能についての考え方: PdMのメンタルモデル ▌メンタルモデル: どのような部分から構成され、どう関係し合ってるかという捉え方 ▌PdMが持つメンタルモデルが、コード分割にも適用できるものだった ⚫ アプリを使う人と作る人のように、異なる属性のユーザーが存在している ⚫ それぞれの属性で違った使い方をしている ⚫

    属性に合わせてアプリ機能、アプリ設定機能と分けて考えると、見通しがよい 12 アプリ機能 アプリ設定機能 レコードを 閲覧する フィールドを 設定する アプリを使う人 (現場で業務をする人) アプリを作る人 (情シス・業務リーダー)
  3. コード分割で目指す構成 14 com.cybozu.kintone.appsettings アプリ機能 アプリ設定機能 com.cybozu.kintone.app FieldSetting Controller FieldSetting Service

    Field Repository RecordController RecordService RecordData RecordRepository .export FieldSetting ServiceExport 機能に対応するパッケージを作成し、 機能に属する全コードをパッケージに配置
  4. コード分割で目指す構成 15 com.cybozu.kintone.appsettings アプリ機能 アプリ設定機能 com.cybozu.kintone.app FieldSetting Controller FieldSetting Service

    Field Repository RecordController RecordService RecordData RecordRepository .export FieldSetting ServiceExport 必要なら専用インターフェイスを 外部に公開
  5. コード分割で目指す構成 16 com.cybozu.kintone.appsettings アプリ機能 アプリ設定機能 com.cybozu.kintone.app FieldSetting Controller FieldSetting Service

    Field Repository RecordController RecordService RecordData RecordRepository .export FieldSetting ServiceExport 内部実装への依存はNG exportへの依存はOK
  6. 外部には専用インターフェイスを公開し、内部実装を隠ぺい public interface FieldSettingServiceExport { FieldSettingDto get(long appId); record FieldSettingDto(List<Field>

    fields, …) {} record Field(long fieldId, FieldType type, …) {} } 17 アプリ側が機能実装する際、 アプリ設定側の情報についてはこれらにのみ依存
  7. コード分割をしてみて ▌機能ごとの開発が容易になった ⚫ 機能に対応するパッケージのコードを読めばよいので、範囲が明確 ⚫ 他機能には影響が出るのか、どのような影響が出るのか、出さないようにするにはど うすればいいか、検討しやすくなった ▌複雑さの要因が一つ見つかった ⚫ 要因:

    複数のアクター (アプリを使う人、作る人) の処理が、一つのクラスに混在 ⚫ 詳しくは「複雑性に立ち向かうためのサーバーサイドコード分割」として発表 ⚫ https://blog.cybozu.io/entry/2023/03/14/110000 ⚫ https://speakerdeck.com/hirokunimaeta/jjug-ccc-2023-spring 22
  8. webアプリケーションとしての設計 ▌Service ⚫ ビジネスロジック ⚫ 例: ブックマークの追加、取得 ▌Data ⚫ 主要な情報

    ⚫ 例: ブックマーク ▌Controller (SpringのController) ⚫ リクエストを受け取り、Serviceを呼び出し、DataをResponseに変換 24 Bookmark Service Bookmark Controller Bookmark Data List Response
  9. 背景 ▌Controllerでの、DataからResponseへの変換処理が曖昧だった ⚫ 基本的には単純なメンバ変数のマッピングで、機能の知識を必要としない ⚫ 実際は、単純なマッピングを超えた機能寄りな処理も混ざっていた ⚫ 例: DBを参照してアプリIDからアプリ名を引く、アクセス権が無ければ除去 ⚫

    機能寄りの処理はどこまで書いていいのか? ▌曖昧なまま開発を続けることで、開発が非効率に ⚫ どこに書くか迷いながら開発 ⚫ 書き手のさじ加減で決まることで、可読性の低下 ⚫ どこでアプリ名を引いているのかなかなか見つからない 25
  10. 機能の振る舞いをApiServiceに記述 public interface BookmarkApiService { ListResponse list(long userId); record ListResponse(List<App>

    apps, …) {} record App(String name, …) {} void add(…); } 27 Bookmark ApiService Bookmark Controller
  11. ApiServiceを導入してみて ▌曖昧だったControllerの役割が明確になった ⚫ 機能寄りの処理はどこまで書いていいのか? → 書かない ⚫ ApiServiceを呼ぶのみ ⚫ 必要なら、

    SpringやHTTPリクエスト等のweb層のオブジェクトから情報を取り出す ⚫ 機能についての知識は持たず、フロントエンドと機能とを繋げることが役割 ▌さらに、下のような効果もあった ⚫ Dataクラス、Serviceクラスの肥大化が抑制された ⚫ Javaのinterfaceで機能を定義できるようになった 29
  12. ApiServiceの導入で判明した複雑さ ▌アプリ名やフォーマットされた値は、 JSONにのみ必要な情報 ⚫ view modelに近い概念 ⚫ 返却されるJSONをviewと解釈としたときに、viewを生成するためのmodel ▌view modelの生成箇所が不適切で、これが複雑化につながっていた

    ⚫ Controllerでアプリ名を引く → Controllerで生成 ⚫ Controllerではどこまでが変換処理なのか曖昧に ⚫ Dataにフォーマットした値も置く → Serviceで生成 ⚫ Dataクラスが肥大化、Dataクラスを生成するServiceクラスも肥大化 32
  13. ApiServiceの役割 ▌ApiServiceは以下の特徴を持つことから、ユースケースを実装する役割 ⚫ 常に機能の外から利用され、機能内の再利用は想定されない ⚫ 外部からの入力と、出力 (view model) を定義している ⚫

    したがって、外部が期待する振る舞いを実現する責任を持つ ▌ユースケースの考えを導入して実装を見直すことで、複雑さの解消が見込める ⚫ 外部が期待する振る舞いを分析し、責務を割り出してクラスに定義する等 ⚫ ApiServiceがResponseを生成する際にフォーマットさせるのはこれに該当 ⚫ DataからResponseへの変換処理が曖昧になっていることの見直しも 33
  14. 応用: 機能開発の際、修正を考える起点になる 40 Bookmark ServiceExport .export Bookmark ApiService ▌ApiServiceやResponseはどうなるのか、そのために Service、Dataはどう変えるのか、というトップダウンな考

    え方が可能になる ⚫ 機能の一番外側から、全体を俯瞰した検討が可能 になる ▌今までは、ServiceとDataをどう変えるか、というボトム アップな考え方がほとんど ⚫ ServiceやDataに詳しくないと修正箇所を見つけら れず、Serviceの役割も曖昧なので考慮漏れが起き やすい