Upgrade to Pro — share decks privately, control downloads, hide ads and more …

10年続くJavaシステムの進化を支える戦略 API・DB・キャッシュの互換性設計/cario...

Avatar for Cariot Cariot
May 30, 2026
85

10年続くJavaシステムの進化を支える戦略 API・DB・キャッシュの互換性設計/cariot-jjug-ccc-2026-s

2026年5月30日に開催された『JJUG CCC 2026 Spring』の発表資料です。

https://ccc2026spring.java-users.jp/

Avatar for Cariot

Cariot

May 30, 2026

More Decks by Cariot

Transcript

  1. 10 APIの互換性(設計方針) 一貫性を保つためのポイント 選択肢(例) パスやプロパティの形式 snake / camel 認証方式 APIキー

    / Bearer Token / HMAC署名 バージョニング パス / HTTPヘッダー / クエリパラメータ 時刻の表現 UNIX秒 / UNIXミリ秒 / ISO8601 電話番号の表現 E.164 / ハイフンなしテキスト 古いバージョンのEOLポリシー 最新Nバージョン / N年間 • 一貫性を保つ • バージョニングを考慮する
  2. 11 • 新しいAPIの追加 • 内部的な不具合の修正 • 既存のAPIに新しいプロパティを追加する • 既存のAPIの削除 •

    既存のAPIのプロパティの削除 • 既存のAPIのプロパティのnull/非null、値域、型の変更 バージョニング 「この変更をしたら呼び出し側が困るか?」の視点 破壊的変更をしたらバージョンを変更する 影響:小 影響:大
  3. 12 Spring Bootでの実装例 Spring Framework 6以前 @RestController @RequestMapping(value = {"/api"},

    produces = MediaType.APPLICATION_JSON_VALUE) public class AlcoholCheckController { @GetMapping({"v1/alcohol_checks", "v2/alcohol_checks"}) AlcoholCheckResultDtoV1 getAlcoholChecksV1() { ... } @GetMapping({"v3/alcohol_checks", "v4/alcohol_checks"}) AlcoholCheckResultDtoV3 getAlcoholChecksV3() { ... } } 特に標準の仕組みはないので、バージョンごとに別定義
  4. 13 Spring Bootでの実装例 Spring Framework 7以降 APIバージョニングの仕組みが標準で用意されている @Configuration public class

    WebConfiguration implements WebMvcConfigurer { @Override public void configureApiVersioning(ApiVersionConfigurer configurer) { configurer .usePathSegment(1) .setDefaultVersion("1.0") .addSupportedVersions("1.0", "2.0", "3.0", "4.0"); } }
  5. 16 DBの互換性(設計方針) • スキーマの変更(マイグレーション) ◦ 古くなったスキーマを新しい要件に合わせて修正し、リファクタリング ◦ マイグレーションツールの利用 ▪ 例:Flyway,

    Liquibase • コードの同期 ◦ スキーマの変更を確実にコードへ反映し、不整合をゼロにする ◦ マイグレーションとコードを同一リポジトリで構成管理
  6. 17 よくある失敗と対策 失敗 対策(例) スキーマ変更をしたらテーブル全 体がロックされてしまい、アプリ ケーションが止まった • テーブルロックを伴うDDLを把握しておく(DBMS にもよるが、カラム長の増強などでも起きる)

    テーブルの値を直接UPDATEしたら アプリケーションがエラーになっ た • DB内のデータの直接メンテは避ける • 想定外の値が入っていた場合にデフォルト値に フォールバック(代替)する
  7. 18 コードの同期 enumの序数の範囲外の 値が入っていると エラーになる Spring Data JPA @Column(nullable =

    false, columnDefinition = "TINYINT") @Enumerated(EnumType.ORDINAL) Status status = Status.NORMAL; @Column(nullable = false, columnDefinition = "TINYINT") @Convert(converter = StatusConverter.class) Status status = Status.NORMAL; Bad Better StatusConverterの 実装により、範囲外の値を デフォルト値で代替できる
  8. 19 Expand-Contractパターン Expand Migrate Contract OLD NEW OLD NEW NEW

    アプリ アプリ アプリ 段階的に古いスキーマを削除
  9. 21 Spring Bootのキャッシング • キャッシュがヒットしたら、キャッシュをそのまま返す • キャッシュがヒットしなかったら、メソッドを呼び出し、キャッシュを更新 @Service public class

    ReportService { @Cacheable("reports") public Report generate(Long reportId) { /* ... */ } } • 使えるプロバイダーは ConcurrentHashMap, Caffeine, Valkeyなど色々
  10. 23 よくある失敗と対策 失敗 対策(例) いつの間にか削除(evict)されて しまっていた • キャッシュサーバも適切にモニタリング • ゴミが残り続けないように有効期限

    (TTL: Time-To-Live)を必ず設定 大事なデータが失われてしまった • 消えたら困るデータはDBなどに保存 JavaやSpringのバージョンアップ 後に認証エラー(※) • デシリアライズエラーの適切なハンドリング • JSONなど互換性の高い方式でシリアライズ • バージョンアップ前のキャッシュクリア ※ セッションデータをJavaシリアライズ形式で キャッシュするためバージョン間で非互換になる