Skip to content

残件:受注管理検収、詳細設計横展開、クロスDB対応 #1

Description

@daisukenishino2

要件定義から基本設計までは全 9 モジュール分が揃い、詳細設計は受注管理のみ先行して作成した。
記載レベルの型を確定させたうえで他モジュールへ広げる方針のため、その検収と横展開が残っている。
あわせて、DB スクリプトが SQL Server 専用になっている点への対応も残件とする。

現状

工程 成果物 範囲 状態
要件定義 RDD/Home.md 全 9 モジュール 完了
基本設計 HLD/(共通仕様・機能一覧・テーブル一覧・画面一覧・画面遷移) 全 9 モジュール 完了
詳細設計 LLD/TableSchema.md 全 14 テーブル 完了
詳細設計 LLD/UI_ElementsAndEventList.md / LLD/EventSpec.md 受注管理のみ 一部
DB スクリプト Northwind/SQLSvr/ 4 DB 中 SQL Server のみ 一部

規模の実績値:機能 59 / 画面 40 / テーブル 14 / イベント 31(受注管理の 5 画面分)。


1. 受注管理の検収

横展開の前に、受注管理の詳細設計が「実装入力として行間がないか」を人が検収する。
ここで確定した記載レベルが、以降 8 モジュールすべての型になる。

対象:画面定義書(受注管理)イベント仕様書(受注管理)

検収の観点

  • 画面項目のデータソースが テーブル.列 または算出式で埋まっており、曖昧な記述がない
  • 算出項目が式で示されている(「合計を表示する」ではなく 合計 = 小計 + 送料
  • イベント仕様の 9 項目(概要/トリガー/事前条件/入力/出力/処理内容/検証/エラー/依存)が全 31 イベントで揃っている
  • 処理内容の DB アクセスに、対象テーブル・結合・抽出条件・並び順・件数が書かれている
  • 分岐(モード・状態・NULL の有無)が網羅され、実装者の判断に委ねていない
  • 更新系イベントにトランザクション境界と楽観排他の判定方法が明記されている
  • 共通仕様(PRE-* / VAL-* / ERR-*)の参照が正しく、個別分だけが追記されている
  • 過剰設計(ワークテーブル・採番テーブル・変更履歴・論理削除・非同期処理・キャッシュ・DDD)が混入していない
  • 特定フレームワークの用語(コントロール名・ライフサイクル名)が混入していない

最も確実な検収方法

詳細設計をコーディング・エージェントに渡して実装させ、設計の穴を洗い出す。
本リポジトリの目的がここにあるため、実装させたときに質問・推測・手戻りが発生した箇所こそが
「行間が残っている箇所」であり、修正すべき対象になる。

完了条件

  • 受注管理の詳細設計だけで受注管理モジュールが実装できること
  • 検収で見つかった記載不足を修正し、その修正内容を記載ルールへ反映していること
    (個別の直しで終わらせず、横展開時に同じ穴を空けないようにする)

2. 詳細設計の横展開

受注管理で確定した型を、残る 8 モジュール+共通に広げる。

対象

モジュール 画面数 画面定義書 イベント仕様書
共通(CMN 1 未作成 未作成
顧客管理(CUS 5 未作成 未作成
商品管理(PRD 4 未作成 未作成
仕入先管理(SUP 5 未作成 未作成
担当者管理(EMP 5 未作成 未作成
配送管理(SHP 5 未作成 未作成
売上分析(SLS 4 未作成 未作成
在庫分析(INV 3 未作成 未作成
パフォーマンス分析(PRF 3 未作成 未作成
合計 35

受注管理の実績(5 画面 = 31 イベント、約 6 イベント/画面)から、35 画面でおよそ 200 イベントの規模になる見込み。

進め方

  1. 業務系(CUSPRDSUPEMPSHP)を先に進める
    受注管理と同じ CRUD 構造のため、型をそのまま適用できる
  2. 分析系(SLS / INV / PRF)は最後に回す
    画面項目より集計定義が主になり、記載の型が業務系と異なるため

分析系で先に決めること

分析系は受注管理の型がそのままでは当てはまらない。以下を記載ルールとして先に確定する。

  • 集計クエリの記載粒度(集計軸・集計関数・母数・除外条件をどこまで書くか)
  • グラフの仕様の書き方(種類・軸・系列・凡例)
  • 期間指定の共通仕様(既定は直近 12 か月。機能一覧の集計定義に準拠)
  • 0 件・0 除算・目標未登録時の表示規則(一部は ST-T2 / ST-T4 に既出)

完了条件

  • 全 40 画面の画面定義書とイベント仕様書が揃っていること
  • FN-* / SC-* / EV-* の相互参照に未定義参照・未参照定義がないこと

3. クロス DB 対応

Northwind/ 配下に 4 DB 分のディレクトリを用意済み。SQL Server 以外は空のため、中身を作る。

ディレクトリ DB 状態
Northwind/SQLSvr/ Microsoft SQL Server 作成済0103 + README)
Northwind/Oracle/ Oracle Database
Northwind/Postgres/ PostgreSQL
Northwind/MySQL/ MySQL

現状の SQL Server 依存(実測)

依存箇所 DDL DML 移植時の論点
rowversion 0 0 解決済int の版数列へ変更した(下記の決定事項)
IDENTITY (1,1) 6 0 シーケンス/SERIALAUTO_INCREMENT
money 4 0 decimal(19,4) 等へ読み替え
ntext / image 6 0 CLOB / BLOBtext / bytea
tinyint 1 0 SQL Server 固有(0〜255)。smallint
nchar / nvarchar 52 0 PostgreSQL に N 系型はない
SET IDENTITY_INSERT 0 12 明示 ID 投入の方法が DB ごとに異なる
DBCC CHECKIDENT 0 6 シーケンスの再設定方法が異なる
SET DATEFORMAT mdy 0 2 日付リテラルの解釈。ISO 8601 へ統一すべき
GO バッチ区切り 33 50 sqlcmd 固有。標準 SQL ではない
sys.* カタログビュー 12 0 検証クエリ。information_schema へ寄せられる
角括弧識別子 [x] 381 32,693 標準は "x"。MySQL はバッククォート

楽観排他の実現方式 → 決定済み(2026-08-05):版数(整数 +1)方式

RowVersionint NOT NULL DEFAULT 1 とし、アプリが更新のたびに +1 する方式を採用した。

方式 採否 理由
整数の版数列 ○ 採用 全 DB で同一に動作する。精度差・時刻同期の問題が原理的に発生しない
DB 固有の行バージョン機構 × SQL Server の rowversion に他 DB の同等物がない。Oracle の ORA_ROWSCNROWDEPENDENCIES なしではブロック単位、PostgreSQL の xminVACUUM FREEZE で変化、MySQL の TIMESTAMP は既定の秒精度では同一秒内の更新を検知できない
GUID × 一意性は得られるが順序を持たず、整数より記憶域・比較コストが大きい
UNIX 時間・タイムスタンプ × DB 間で精度が異なり、時刻同期のリスクも排除できない

特別の事情がない限り、DB 間での精度差や時刻同期リスクを完全に排除できる版数(整数 +1)方式が最も安全という判断。
制約をアプリで管理する本システムの方針とも一致する。

反映済みの内容

  • 共通仕様 9.1 を改訂(定義・制御方式・更新の定型文・選定理由)
  • テーブル定義書 9 テーブルの列定義を rowversionint(既定値 1)へ変更
  • イベント仕様書の更新系イベントに SET RowVersion = RowVersion + 1 を明記
  • SQL Server 版 DDL を [int] NOT NULL DEFAULT (1) へ変更し、実行検証(競合検知の動作確認まで実施)

実装時の注意(重要)

RowVersion = RowVersion + 1 の記述漏れは、競合検知を無言で無効化する。
加算を忘れると版数が進まず、後続の更新が古い版数のまま通ってロストアップデートが起きる。
検証で再現済み。トリガーを使わない方針のため
DB 側では救えない。更新系イベントは必ず共通仕様 9.1 の定型文から書き始めること。

型の読み替え

現行(SQL Server) Oracle PostgreSQL MySQL
int NUMBER(10) integer INT
smallint NUMBER(5) smallint SMALLINT
tinyint NUMBER(3) smallinttinyint なし) TINYINT UNSIGNED
bit NUMBER(1)(23c 未満は BOOLEAN なし) boolean TINYINT(1)
money NUMBER(19,4) numeric(19,4) DECIMAL(19,4)
real BINARY_FLOAT real FLOAT
datetime DATE timestamp DATETIME
nchar(n) / nvarchar(n) NCHAR(n) / NVARCHAR2(n) char(n) / varchar(n) CHAR(n) / VARCHAR(n)
ntext NCLOB text LONGTEXT
image BLOB bytea LONGBLOB
IDENTITY (1,1) GENERATED BY DEFAULT AS IDENTITY(12c+)/SEQUENCE GENERATED BY DEFAULT AS IDENTITY AUTO_INCREMENT

※ PostgreSQL にも money 型はあるが、ロケール依存で精度も固定のため使わない
PostgreSQL / MySQL は DB を UTF-8 にすれば N 系の型・リテラルは不要。

DB 固有の落とし穴

移植時にデータが変質するものを優先して挙げる。

  • Oracle は空文字列 ''NULL として扱う。原典データに空文字列があると意味が変わる(現データは NULL 済みだが要確認)
  • 識別子の畳み込み方向が逆。引用符なしだと Oracle は大文字、PostgreSQL は小文字に畳み込む。
    CustomerID のような混在表記を保つには全 DB で引用符が必須になる
  • Order Details は名前に空白を含む。原典忠実を優先する以上、全 DB で引用符必須。
    MySQL はバッククォート、または ANSI_QUOTES モードで "..."
  • GOsqlcmd 固有。Oracle は /、PostgreSQL / MySQL は不要(; 区切り)
  • 日付リテラルを ISO 8601(YYYY-MM-DD)に統一する。現行の SET DATEFORMAT mdym/d/yyyy は移植できない。Oracle は TO_DATENLS_DATE_FORMAT の指定が必要
  • 明示 ID 投入の方法(SET IDENTITY_INSERT 相当)と採番値の再設定(DBCC CHECKIDENT 相当)を DB ごとに用意する
  • 検証クエリの sys.* カタログビューを information_schema に寄せる(MySQL / PostgreSQL は対応、Oracle は USER_* / ALL_*
  • ページングの記法(仕様は 1 ページ 20 件)。OFFSET ... FETCH は SQL Server 2012+ / Oracle 12c+ / PostgreSQL で使えるが、MySQL は LIMIT ... OFFSET
  • 原典データの取得元。SQL Server 版は
    instnwnd.sql から
    機械抽出している(画像バイナリのみ NULL 化)。他 DB でも同じ出典から生成し、同一データを保つ
  • 検証方法。SQL Server 版は投入後に件数・参照整合性 14 系統・値の妥当性 9 項目・売上合計
    自己検証している。売上合計 1,265,793.29 は DB を跨いだ同一性の確認に使える

注意:制約を DB に持たせない方針との関係

DB に持たせない制約の方針により、
外部キー・CASCADE・CHECK・UNIQUE・トリガーは DB に定義していない。
この方針は移植を容易にする方向に働く(DB ごとの制約構文の差異が問題にならない)一方で、
参照整合性の検証は各 DB の投入スクリプトで必ず実施する必要がある。

完了条件

  • Northwind/Oracle/ Northwind/Postgres/ Northwind/MySQL/ の各ディレクトリに
    SQL Server 版と同じ構成(01_CreateDatabase / 02_CreateTables / 03_InsertData + README)が揃うこと
  • 各 DB で 010203 が通ること
  • 4 DB すべてで件数(14 テーブル)・参照整合性(14 系統)・値の妥当性(9 項目)・売上合計 1,265,793.29 が一致すること

進め方の順序

1 → 2 → 3 の順を推奨する。

  • 1 を先にやる理由:記載レベルが未確定のまま 35 画面へ広げると、手戻りが 35 画面分になる
  • 3 を後に回す理由:楽観排他の方式(方式 A / B)を変えると共通仕様
    全テーブル定義書に波及するため、詳細設計が固まってから着手した方が影響を抑えられる

ただし 3 の「楽観排他の方式」だけは先に決めておくとよい。
仕様の根幹に関わるため、2 の横展開が進むほど変更コストが上がる。

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions