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

ドメインを組織の資産にする 少人数で複数プロダクトを支えるTypeScript運用の実...

ドメインを組織の資産にする 少人数で複数プロダクトを支えるTypeScript運用の実践_TSKaigi2026登壇資料(須永高弘)

少人数で10プロダクト以上を運用するASSIGNが、散在していた「型とドメイン」を少しずつ組織の資産として整理してきた3年間の変遷を共有します。
AIがコードを量産できる今、そのスピードを破綻させずに事業へ活かす土台となったのは、型による境界定義や業務語彙といった地道な設計でした。
モノレポによる業務語彙の集約、Zodを用いた仕様の一本化、AI駆動開発の土台作りといった、実践的なTypeScript運用の過程をお伝えします。

Avatar for 須永高弘

須永高弘

May 31, 2026

More Decks by 須永高弘

Other Decks in Programming

Transcript

  1. 1 影響調査 どの画面・API・通知に影響するかを追う 例: 状態追加で UI / hooks / schema

    / 通知条件まで確認する 2 整合作業 値・型・表示・検証・通知条件を揃える 画面だけ、APIだけ、通知だけが古い状態を残さない 3 設計検討の 反復 追加開発のたびに、同じ設計検討や判断を繰り返す 過去の判断理由を探し、似た議論をもう一度やり直す 業務変更のたびに、調査・整合・設計検討が繰り返される ©ASSIGN Inc. All Right Reserved. 1
  2. 方針 減らしたい負荷 実装でやること 1. 境界で検知する API変更の追従漏れ、不正な外部値の 混入 API契約・外部値の入口で失敗させる 2. 業務語彙を集約する

    画面・API・通知の整合 型・schema・定数・ラベル・変換・ 判定を shared domain に寄せる 3. ドメインを再利用する 同じ設計検討・判断の反復 根幹ドメインを 共通package にし、 過去の設計を次の開発で参照する 調査・整合・設計検討を、コード上の仕組みに落とす ©ASSIGN Inc. All Right Reserved. 1
  3. 選考プロセスの型・表示・検証・判定を、Web/APIが参照できる入口にする 新卒業務システム モノレポ内に、画面・APIが共通参照でき るdomainを用意 apps/ web api packages/ shared/ domain/

    selectionProcess.ts applicationChannel.ts → selectionProcess.ts 変更時に確認する型・表示・検証・判定を一箇所に寄せる 定義 役割 例 schema / 型 入出力の形 Web/APIの入出力を同じ形で扱う SelectionProcess CreateWireSchema 状態値 選べる状態 追加・削除される業務状態を一覧 化する SELECTION_PHASES SELECTION_STATUSES label / options 画面表示 表示名・選択肢を揃える getLabel() getOptions() parse / validate 外部値の検証 Form/URL/API値を入口で検証す る parseFromWire() rule / predicate 業務判定 終了判定・報告条件を画面から切 り離す isSelectionEnded() canCreateAssignRequest() 業務語彙をshared domainに集約する ©ASSIGN Inc. All Right Reserved. 1
  4. 共通の型・schema・状態値を参照することで、画面とAPIの変更漏れに気づきやすくする Webフロント 型で画面の扱いを揃える 状態値を型で扱う as const で定義した状態値 を参照し、選択肢・表示名の 未対応を見つけやすくする 状態ごとの扱い漏れを検

    知する satisfies で状態値ごとの ラベルや分岐を確認し、新し い状態の扱い漏れを見つけや すくする 参照 ← packages/shared/domain/ selectionProcess.ts 画面とAPIが共有する業務語彙の契約 選考プロセスの型 画面とAPIで扱うデータの形 状態値の定義 選考フェーズ・ステータス・表示名 外部値の受け入れ条件 FormやAPI由来の値を扱えるか 業務判定 選考終了・報告前提などの共通ルール → 参照 API schemaで境界の扱いを揃える 入出力を型で固定 generated types や z.infer で request / response を扱 い、API変更時の修正漏れを検知 しやすくする 外部値を検証 Zod parse でURLやForm由来の 値を検証し、不正な値を domain の手前で止める shared domainを参照して、画面とAPIの整合を保つ ©ASSIGN Inc. All Right Reserved. 1
  5. 共通packageに型と判定を置き、adapterで変換、個別実装で固有フローを書く 新卒支援業務システム プロダクト内に adapter 層と個別実装を分けて持つ 個別実装 新卒固有の後続業務 共通判定のisAcceptedOfferを使い個別フロー を書く 型・値・判定を共通化し、変換と固有業務は個別に実装する

    @assign/career-domain 共通ID・内定結果・判定関数を置く branded typesでIDの取り違えを型で防ぐ zodで実行時の値を検証し、z.inferで型として扱う type Brand<T, N extends string> = T & { readonly __brand: N } export type CandidateId = Brand<string, "CandidateId"> export const OfferOutcomeSchema = z.enum([ "none", "offered", "accepted", "declined", "joined", ]) export type OfferOutcome = z.infer<typeof OfferOutcomeSchema> export const isAcceptedOffer = (v: OfferOutcome) => v === "accepted" adapter 状態値を共通ドメイン値へ変換 satisfiesで状態値の変換漏れを検知する const outcomeByStatus = { noOffer: "none", accepted: "accepted", declinedAfterAcceptance: "declined", joined: "joined", } satisfies Record< NewgradOfferStatus, OfferOutcome> export const toCareerOfferOutcome = ( status: NewgradOfferStatus, ): OfferOutcome => outcomeByStatus[status] export const getPostAcceptanceActions = ( outcome: OfferOutcome, ) => { if (!isAcceptedOffer(outcome)) return [] return [ "confirmGraduationYear", "scheduleOfferEvent", ] } ©ASSIGN Inc. All Right Reserved. 1
  6. プロダクト内で業務語彙の参照元を一箇所にする shared/domainに型、schema、業務ルールなどを集約し、画面・APIの不 整合や変更漏れを減らす 関連プロダクト間で根幹ドメインを再利用する common package + adapterで根幹ドメインを共通化し、固有フローを個 別実装に残して関連プロダクトで再利用する 蓄積したドメインから、次のプロダクトを始める

    既存の業務語彙・型・業務ルール・変換処理を活用して、新たなシステム 開発を始められるようにする 蓄積したドメインから、次のプロダクトを始める 業務語彙 の集約 根幹ドメイン の共通化 新規プロダクト への展開 ©ASSIGN Inc. All Right Reserved. 1