前セツ
どうも、カナヘビ・トカゲ用の餌用コオロギがSSサイズから成虫まで育ってしまって家の中がクソうるさい事になってる、え~すけさんですよ。
※消費者3匹(カナ2、トカ1)に対して、供給500匹は消費しきれんのよ。。。
※ちなみに成虫はレオパ1のご飯になるけど、こっちも消費が遅くて。。。
※ちょっと草原に消費者を誘か、ゲフンゲフン、迎えに行くか。。。
さてさて、前回(公開しました)で、業務画面を「定義」で作るフレームワーク hatake を
公開した話を書きました。
で、当然こう思うわけです。
自分で作ったフレームワーク、自分で使ってないじゃん。
デモは作ってました。でもデモって、フレームワークのリポジトリの中で、フレームワークの
ソースを直接参照して動かしてるんですよ。外から使ってない。
配ったものを配られた側として使ってない。これは、使ってるとは言わない。
というわけで、別リポジトリを立てて、外から入れて、業務システムを1本まるごと作りました。
→ https://github.com/ASIL-E-Hatake/hatake-example
結論から書くと 21.0人日 → 3.75人日(▲82%) になりました。
ただし減らないものが2つあるのと、1本目は回収できないのが正直なところです。
計算の中身、全部出します。
作った案件
社内マスタメンテナンス。 人事部と購買部が使う、社員・部署・取引先の管理画面。
「いまは Excel で管理していて、更新のたびに情シスに依頼が来ている」という、
どこの会社にもあるやつを想定しました。
| 画面 | 4枚(CRUD・マスタ保守・詳細・複雑な検索) |
| 役割 | 3種(情シス admin / 人事 hr / 一般 viewer)で見え方が変わる |
| 業務の作り | 認証・権限・一括処理(部分失敗つき)・同時更新の排他・監査・CSV 出力 |
| 構成 | 画面(Flutter Web)+ API(Node / Express)+ DB(PostgreSQL) |
わざと「業務システムあるある」を全部入れました。権限で列が消える、一括処理に上限がある、
法人のときだけインボイス番号が必須、範囲検索と複数選択、監査ログ……。
きれいなところだけ作ると、何の検証にもならないので。
動きます
git clone https://github.com/ASIL-E-Hatake/hatake-example.git
cd hatake-example/apps/master-maintenance-prj
docker compose up
これだけです。Flutter SDK も Node も入れなくていい。
画面は http://localhost:8080、ログインは admin / admin、hr / hr、viewer / viewer。
役割で見え方が変わるので、3つとも試すのが早いです:
| admin | hr | viewer | |
|---|---|---|---|
| CSV 出力(社員・部署) | 出る | 出る | 出ない |
| CSV 出力(取引先) | 出る | 出ない | 出ない |
| まとめて退職にする | 出る(50件) | 出る(20件) | 出ない(選択欄ごと消える) |
| 内線の列 | 見える | 見える | 見えない |
※ 1回目は Flutter Web のビルドで数分かかります。2回目からは速い。
結論(先に数字)
| 人だけ(見積もり) | 人+AI(実測) | |
|---|---|---|
| 工数 | 21.0 人日 | 3.75 人日 |
| 人が書いた行数 | 全部 | 206 行 |
206行の内訳は、案件の説明 57行+案件の前書き 149行です。
定義 345行も、アプリのコード 1,052行も、1行も手で書いてません。
できあがったもの全部:
| 行数 | 誰が書いたか | |
|---|---|---|
| 案件の説明 | 57 | 人 |
案件の前書き(hatake.project.yaml) |
149 | 人(下書きは AI) |
画面の定義(app.yaml・4画面) |
345 | AI |
| アプリのコード(Flutter + Node) | 1,052 | AI |
| テストのコード・台本 | 1,353 | AI(何を確かめるかは人) |
| 道具(資料の生成・テストの実行) | 449 | AI |
| 設計資料(画面一覧・遷移図・設計書・API 一覧・権限表) | 431 | 生成物(定義から) |
| テストの記録(ケース一覧・API・画面) | 1,188 | 生成物(実行結果) |
人が 206行、残り約 4,800行は AI が書いたか定義から生成されたもの、という配分です。
計算の中身
「82%減」とだけ言われても信用できないと思うので、両方の内訳を出します。
自社の数字に置き換えられる形にしておきます。
人だけで作った場合(これは見積もり)
1人日 = 7時間、画面まわりに慣れた開発者1人で計算。
| 工程 | 作業 | 人日 | 根拠 |
|---|---|---|---|
| 要件定義 | ヒアリングとメモ | 1.0 | AI でも人でも同じ |
| 設計 | 画面設計書 4枚 | 2.0 | 1画面 0.5人日 |
| 設計 | 画面一覧・遷移図・API 一覧・権限表 | 1.0 | 並べて図を描く |
| 実装 | 画面 4枚(検索・一覧・入力・権限・一括) | 6.0 | 1画面 1.5人日 |
| 実装 | API(CRUD 3本・認証・一括・監査) | 4.0 | |
| 実装 | 環境(Docker・DB・初期データ) | 1.0 | |
| テスト | ケース設計 | 1.5 | 57件ぶんの条件と期待 |
| テスト | 実施とエビデンス | 2.5 | 手で撮って貼るのがここ |
| 手直し | 仕様の食い違い・レビュー指摘 | 2.0 | |
| 合計 | 21.0 人日 |
人+AI(こっちは実測)
| 工程 | 人がやったこと | 人の時間 | AI の作業 |
|---|---|---|---|
| 要件定義 | 案件の説明を書く(57行) | 1.0 人日 | 枠組みの外を仕分ける |
| 設計 | 前書きを育てる・用語と決めごとを直す | 0.5 人日 | 定義を書く・自分で読み返す |
| 設計 | 問い6件に答える | 0.5 人日 | 答えを前書きに書く |
| 設計 | 生成された設計書を読む | 0.25 人日 | 設計資料5種を生成 |
| 実装 | 出てきたコードを読む・繋ぎの判断 | 0.5 人日 | 画面・API・Docker |
| テスト | 何を確かめるかを決める・記録を読む | 0.5 人日 | 57件を書いて回す・記録を作る |
| 手直し | 踏んだ問題の判断 | 0.5 人日 | 直す |
| 合計 | 3.75 人日 |
減らないものが2つある
ここが一番言いたいところです。
削減率 = 1 −(人がやる工程の合計 ÷ 全工程の合計)
この案件で人に残ったのは
・要件を書く(1.0) … AI でも減らない
・決めごとを判断する(1.0) … AI に任せてはいけない
・読んで確かめる(1.75) … 量に比例して増える
要件を書くのと、業務の判断をするのは人の仕事として残ります。
減るのは書く作業(設計書・コード・テスト・納品資料)だけです。
「AI で開発工数が9割減」みたいな話、たぶんここを数えてないだけなんですよね。
要件書かないシステム開発は無いので。
画面が増えるとどうなるか
| 画面数 | 人だけ(人日) | 人+AI(人日) | 削減率 |
|---|---|---|---|
| 4(この案件) | 21.0 | 3.75 | 82% |
| 10 | 45.0 | 6.0 | 87% |
| 20 | 85.0 | 9.5 | 89% |
※ 10画面・20画面はこの案件からの外挿です。実測じゃありません。
画面1枚あたり、人だけは +4.0人日、人+AI は +0.25〜0.4人日(読む時間)で計算してます。
2本目を作ったら実測に置き換えます。
人+AI が緩やかにしか増えないのは、増えるのが「読む時間」だけだからです。
書く量は画面数に比例しますが、書くのは人じゃない。
実際どんな感じで書かれているのか
定義(AI が書いた345行の一部)
社員マスタの、権限で列を隠すところと、条件付き必須のところ。
table:
pagination: { pageSize: 50 }
rowActions: [edit, delete]
columns:
- { field: employeeNo, label: 社員番号, width: 110, sortable: true }
- { field: name, label: 氏名, sortable: true }
- { field: hireDate, label: 入社日, type: date, width: 120, sortable: true }
- { field: employmentStatus, label: 在籍区分, type: badge, width: 100 }
# 内線は情シスと人事だけ(一般には見せない)。
- { field: extension, label: 内線, width: 90, roles: [admin, hr] }
form:
sections:
- title: 在籍
fields:
- field: retireDate
label: 退職日
type: date
# 退職のときだけ必須(在籍中に退職日が入ってると話が合わない)。
requiredWhen: { field: employmentStatus, value: retired }
validators:
- { type: compare, field: hireDate, operator: gte,
message: 退職日は入社日以降にしてください }
コメントも AI が書いてます。※ requiredWhen みたいなのを手で実装すると、
だいたい画面だけに入ってサーバ側に無い、というやつが起きます。
Flutter 側(画面のコードは1行も無い)
void main() => runApp(MasterMaintenanceApp(session: Session(_baseUrl)));
/// 社内マスタメンテナンス。
///
/// **画面のコードは1行も無い。** 出しているのは
/// ・ログイン画面(認証は枠組みの外なので、ここだけ手で書いた)
/// ・`HatakeApp(app: <定義>)` … 社員・部署・取引先の4画面はこれで全部
Flutter 側は全部で 447行、うち画面に関するものはゼロ。中身はログイン画面(81行)、
セッション、HTTP アダプタの配線、一括処理のプラグイン、CSV の出し口です。
面白かったのはこの2行:
// strict: 知らないキーがあれば**起動時に落ちる**。黙って無視されて
// 「書いたのに効かない」画面が出るより、早く気づきたい。
.then((yaml) => parseAppYaml(yaml, strict: true));
前回の記事で「知らないキーを黙って捨てるのが AI が転ぶ場所」と書いたやつ、
実際に使う側になったら自分で strict を付けてました。やっぱりそうなるんですよ。
Node 側(同じ定義をサーバも読む)
// 画面と**同じ定義**を読む。
//
// ここが hatake の主張そのもの: 画面を描く定義と、API がリクエストを検証する定義が
// 同じ1枚。だから `definitions/` は案件の直下に置いてあり、この API は `../definitions`
// を見る(コピーを持たない=コピーを持った瞬間、ずれても誰も気づかない)。
リポジトリの構成がこうなってます:
apps/master-maintenance-prj/
├─ definitions/ 定義(YAML)。flutter-src と node-src が**同じものを読む**
├─ flutter-src/ 画面(Flutter + hatake_material)
├─ node-src/ API(Express + @hatake-fw/api)
├─ docs/ 人が AI に渡したもの・工程ごとの成果物
└─ docker/
definitions/ を案件の直下に置いてるのは意図的です。同じ定義でフロントとバックの
バリデーションがずれないが hatake の主張なので、アプリごとに定義をコピーしたら
リポジトリ自身が主張を否定することになる。
API 側は、画面ごとにルートを手で書きません。受け取る項目も検索できる条件も必須も
全部定義に書いてあるので、ルートが持つのは「DB にどう当てるか」だけです。
/** 定義の入力枠に書いてある項目だけを拾う(書いていないキーは**捨てる**)。 */
const fieldsOf = (page) =>
(page.form?.sections ?? []).flatMap((s) => s.fields ?? []).map((f) => f.field);
マスタ3つぶんの CRUD が、1本の作り方で出ます。
納品物が全部そろう(ここが一番効いた)
工数の数字より、実務的にはこっちのほうがデカいかもしれません。
設計書
| 作り方 | |
|---|---|
| 画面一覧 | 定義から生成 |
| 画面遷移図 | 定義から生成(Mermaid + SVG) |
| 画面設計書 × 4 | 定義から生成(DSL のキー名を出さない) |
| API 一覧 | 定義から生成 |
| 権限マトリクス | 定義から生成 |
全部生成物です。 定義を直したら作り直すだけ。
で、これの何が嬉しいかというと、設計書が腐らない。
手で書いた設計書って3か月で嘘になるじゃないですか。あれが無い。
しかも --check を CI に置けるので、定義と設計書がズレたら CI が落ちます。
※ 画面設計書に field とか requiredWhen みたいな DSL のキー名を出さないようにしてます。
読む人(お客さん)は YAML を知らなくていいので。
テストのエビデンス
| 件数 | |
|---|---|
| ケース一覧 | 57件(値31/API 20/画面6) |
| 値のテスト | 31件・まだ試していない分岐は0件 |
| API テスト | 20件・投げたものと返ってきたものをそのまま記録 |
| 画面テスト | 6枚・役割ごとのスクリーンショット |
docker compose up -d
bash tools/run-tests.sh
何度回しても同じ結果になります(回す前にデータを戻すので)。
「テスト実施とエビデンス」が人だけ見積もりで 2.5人日ある工程です。手で撮って手で貼るやつ。
ここが自動になるのは、正直いちばん体感が大きかった。
※ ただし hatake にエビデンスを出す機能はありません。 様式が案件ごとに違うので、
認証と同じく「枠組みの外」です。ここは自分で道具を書きました(約600行)。この話は記事4で。
効く条件・効かない条件
1本作ってみて分かった、向き不向きです。
| よく効く | 効きにくい |
|---|---|
| 画面の形が決まっている(マスタ・検索・一覧・入力) | 画面そのものが要件(凝った UI・独自の操作感) |
| 画面数が多い | 1〜2画面で終わる |
| 同じ規則をフロントとバックの両方で守りたい | 画面だけ・API だけ |
| 権限や一括処理など決まりごとが多い | 決まりごとが少ない |
| 納品物(設計書・エビデンス)が要る | 動けばいい |
画面の中身より「決まりごとの多さ」で効きます。
権限・検証・一括の上限・監査って、手で書くと画面とサーバの2か所に散って必ずズレるんですが、
定義なら1か所なので。
逆に、社内ツールで納品物が要らないなら、いちばん効くところ(設計書とエビデンスの自動生成)が
空振りします。
この数字の限界(正直に)
- 1案件・1人の結果です。
- 「人だけ 21.0人日」は見積もりで、実際に人が作って測った値ではありません。
比べるための数字なので、自社の単価と生産性で置き換えてください - AI の待ち時間は人の時間に数えてません(実際は読みながら待てるので)
- 慣れの分が入ってません。1本目は手順を作りながらなので、2本目はもっと短くなるはず
あと、1本目には「枠組みの外」を作る分が乗ります。
認証・本当の権限遮断・監査・同時更新・一括の中身・納品資料の道具で、この案件では
約1,200行。ただし大半は案件をまたいで使い回せるので、効果が出るのは2本目からという
見方が正しいです。この内訳も記事4で全部出します。
次
数字の話はここまでで、次は**「じゃあ人は具体的に何をしたのか」**です。
このリポジトリで一番見てほしいのは実は工数じゃなくて、
人が AI に渡した紙を全部残してあるところなんですよ。
案件の説明・前書き・依頼文・AI から返ってきた問い、全部。
定義を書くのは AI ですが、AI に依頼を出すのは人なので、
その人が何を用意して何を決めたかが残ってないと真似できないので。
→ 記事3: AI への頼み方(人が書く紙は2枚だけ。AI に答えさせてはいけない6件)
→ 記事4: 転んだ話13件と、まだ出来ていないこと(本体のバグ3件を含めて全部)
ツッコミ募集してます。特に 「その見積もり甘くない?」 系、大歓迎です。🌱
※優しくね