前セツ
前回、こんな記事を書きました。
で、最後にこう書いたんですね。
「使ってください」じゃなくて「どう思います?」です。
……いや、公開してないのに意見を求めるなという話でして。
当時は「豆腐メンタルなので公開が怖い」って正直に書いたんですが、まあそれはそれとして、
出さないと何も分からんわけです。というわけで出しました。
- フレームワーク本体 → https://github.com/ASIL-E-Hatake/hatake
- 実際に案件の形で使ったサンプル → https://github.com/ASIL-E-Hatake/hatake-example
今回はこの記事を含めて、続編は4本ぐらいに分けます。長くなりそうなので。
どうも、Qiitaでの人気がなくて良かったと心から思った、え~すけさんですよ。
※意見ゼ~ロ~、きっと今回もそうなるはず!
| 記事 | 中身 | |
|---|---|---|
| 1 | この記事 | 公開した。公開する前に何を決めたか |
| 2 | 案件を1本まるごと作ってみた | 21.0人日 → 3.75人日の中身 |
| 3 | AI への頼み方 | 人が書く紙は2枚だけ。AI に答えさせてはいけない6件 |
| 4 | 転んだ話13件と、まだ出来ていないこと | 本体のバグ3件を含めて全部 |
※ この記事は 2 以降のための前提編です。「フレームワークの話はいいから使ってみた結果を見せろ」
という方は 2 から読んでください。
とりあえず触れます(インストール不要)
先に「触れる場所」だけ置いておきます。README を読む前にこっちのほうが早い。
| プレイグラウンド | https://asil-e-hatake.github.io/hatake/demo/?playground=1 |
| デモ(8画面のアプリ) | https://asil-e-hatake.github.io/hatake/demo/ |
| サイト | https://asil-e-hatake.github.io/hatake/ |
プレイグラウンドは、左に YAML を貼ると右が画面になるやつです。データは定義から作った
仮のものなので、Repository も API も要りません。綴りを間違えたらその場で理由が出ます。
作った定義は URL に載るので、そのまま人に渡せます(?yaml= に入る)。
「業務画面を定義で書く」がどういう手触りなのかは、説明を読むより30秒触ったほうが速いです。
公開するまでに何を決めたか
ここからが本題で、公開に必要だったのは機能じゃなくて「約束」でした。
前回の記事の時点で、機能としてはだいたい動いてたんですよ。8種類の画面が出て、
3言語(Flutter / TypeScript / Java)が同じ定義を読んで、CI も回ってた。
なのに出せなかった。なんでかというと、出した瞬間に直せなくなるものがあるからです。
「1.0 の約束」という紙を先に書いた
機能を足すのはいつでもできます。足しても誰も困らない。困るのは後から約束を狭めるときで、
これは相手の CI と定義ファイルを壊します。
なので、「何を凍らせて、何を凍らせないか」を1枚に書いてから出しました。
凍らせるもの:
| 破るとどうなるか | |
|---|---|
| DSL のキー・スキーマ | 相手の定義ファイルが落ちる |
| DSL の版の扱い | 別の版の定義を黙って読む |
| 診断の id(警告94 / 助言21) | 相手の CI の抑制・集計が壊れる |
| 終了コード | CI が黙って緑になる(いちばん見つからない) |
--json の形 |
相手の道具が落ちる/黙って空を読む |
| 公開 API | 相手のコードがコンパイルできなくなる |
パッケージ名・スキーマの $id
|
相手の設定を全部書き換えさせる |
凍らせないものも、凍らせないと明記しました。人に読ませる日本語の文面(explain とか
ask が出す文章)、助言の規則の増減、MCP の道具の並び、同梱の例。
※ 機械で食うなら --json を使ってね、という分担です。そっちは凍ってる。
診断の id は spec/rule-ids.json に一覧を置いて、試験が完全一致を見るようにしました。
消したり名前を変えたりする差分は、レビューで必ず目に入ります。うっかり消せない。
DSL の版を、ちゃんと見るようにした
これ、恥ずかしいんですが、それまで dsl_version に何を書いても黙って 1.0 として
読んでました。2.0 でも 0.9 でも空でも通る。
dsl_version: "1.0" って書かせておいて見てないの、詐欺じゃん。ということで直しました。
- 知らない major(
2.0/0.9)… 落とす - 同じ major の新しい minor(
1.1)… 読むけど1件言う - 形が違う(
1/1.0.0/ 空)… 落とす - 書いていない… 通す(既定は現在の版)
判定は3言語+JSON Schema で同じになるように、共有フィクスチャで固定してます。
※ これまで通っていた定義が落ちることがありますが、落ちるのはそもそも読めていなかったものです。
パッケージ名を変えた(ここは普通に凹んだ)
npm の @hatake/core → @hatake-fw/api に変更。
理由は単純で、無印 hatake も @hatake スコープも他人のものだったからです。
名前決めるとき、そこ確認するんだった……。🤦
ついでに core と名乗るのもやめました。将来 Vue や React の Renderer を足す段で
core を切り出したくなるはずで、いまの中身はサーバ側のロジック+道具で、描画は1行も無い。
だったら api のほうが正しい。
名前の決めごと自体は1枚にまとめてあります(Dart hatake_core / npm @hatake-fw/api /
Maven io.github.asil-e-hatake:hatake-core …)。どこかに必ず hatake が出て、役割は
名前で分かる、が決めごとです。
レジストリには出していません(わざと)
ここ、たぶん一番ツッコまれるところなので先に書きます。
pub.dev にも npm にも Maven Central にも出していません。git の tag だけで配ってます。
なんでかというと、公開すると古い版が永久に生き残って直せなくなるからです。
一方、git のうちは利用者を数えられるので、間違えても一斉に直せる。
だから git の期間は「約束を先送りする期間」じゃなくて、約束を入れて踏んでみる、いちばん
安い期間として使ってます。実際、この期間に踏んだから見つかったバグがあります(後述)。
リリースのワークフローも、GitHub Release に貼るだけで publish する道を持っていません。
間違って出ないように、道そのものを作ってない。
まぁとりあえずサンプルを作るために、自分のために公開したいだけだったので、今はとりあえずこんなレベルでいいかなと。
入れ方(ダサいけど理由はある)
Flutter / Dart:
dependencies:
hatake_material:
git: { url: https://github.com/ASIL-E-Hatake/hatake.git, ref: v0.9.0, path: flutter/packages/hatake_material }
dependency_overrides:
hatake:
git: { url: https://github.com/ASIL-E-Hatake/hatake.git, ref: v0.9.0, path: flutter/packages/hatake }
hatake_core:
git: { url: https://github.com/ASIL-E-Hatake/hatake.git, ref: v0.9.0, path: flutter/packages/hatake_core }
dependency_overrides が要ります。パッケージ側は pub.dev 前提(hatake_core: ^0.0.1)で
書いてあって、その中の overrides は根のパッケージでしか効かないので、下にいる
hatake_* は使う側が指し直すことになる。公開すればこの節ごと消えます。
TypeScript: Releases に貼ってある .tgz を指す。
npm i -D https://github.com/ASIL-E-Hatake/hatake/releases/download/v0.9.0/hatake-fw-api-0.9.0.tgz
npm i github:… では入りません。リポジトリの根に package.json が無いのと、
npm が subdir 指定に対応していないため(pnpm / yarn はできる)。
tarball なら両方関係ないし、spec/ を同梱できるのが大きい。CLI と MCP は実行時に
spec/ を読むので、同梱しないと配った先で何も引けないんですよ。
Java: JitPack が tag を見てビルドします。jitpack.yml がモノレポのどこをビルドするか
指図してる。
※ main を指させないようにしてます。指されるとこっちが push した瞬間に相手が動くし、
ロールバックもできない。必ず ref: v0.9.0 のように tag を書く形にしました。
CI が「配れること」を見てる
配り方って、手引きが古くなっても気づけないんですよね。README のコピペが動かないやつ。
なので CI で見るようにしました。
-
TypeScript … 固めてリポジトリの外に置いて叩く(中で試すと
spec/が上に
見つかって、同梱できてなくても通っちゃう) -
Flutter … 裸のクローンを
file://で指してpub get→定義を1枚読ませる。
さらにdependency_overridesを書かないと落ちることも確かめる
=手引きが古くなったらそこで落ちる - Java … JitPack が tag からビルドする
「手引きどおりに書いたら動く」を機械で見てる、という話です。
公開の直前に見つかったバグの話
v0.9.0 を出す直前に、降順の指定が黙って無視されてたのが見つかりました。
buildQuery が sortAscending の文字列 "false" を昇順として読んでた。
REST の契約は「クエリ文字列で送る」と決めてるので、手引きどおりに書いたサーバが、
降順を頼まれてるのに黙って昇順で返す。画面には並びが出るので気づけません。
なんで中の試験で出なかったかというと、クライアント側とサーバ側を別々に見てたからです。
契約の両端をつなぐ試験が無かった。外から一気通貫で使って初めて出ました。
……で、この「外から一気通貫で使ってみた」というのが、次の記事の中身です。
サンプルアプリを作ってたら本体のバグが3件出た、という話。
AI に道具を持たせる(MCP サーバ)
もう一個、公開に合わせて入れたのが MCP サーバです。前回の記事で
「800行の仕様書を毎回 AI に読ませるのは高すぎる」と書いたやつの続きです。
これまで 仕様書とチートシートを丸ごと読ませる → 定義を書かせる → 人間が検証
MCP サーバあり 近い例を引く → 迷ったキーだけ引く → 書く → 自分で検証して直す
読ませる量が減るのもそうですが、効くのは書いたものを自分で検証して直せるほうです。
hatake は知らないキーを黙って捨てるので、検証を通さないと「書いた気になって効いていない」
定義が残るんですよ。
道具はこんなのが入ってます(一部):
| 道具 | いつ使うか |
|---|---|
hatake_where |
定義で書けないことを頼まれたとき。どこの担当かを引く(定義 / 登録 / サーバ / 枠組みの外) |
hatake_ask |
書けたあと。定義に書けないのに決まっていないことを問いにして返す |
hatake_check |
事実(検証)・読み返し・好み(助言)・人が決めること を1回で回して、欄を分けたまま返す |
hatake_examples |
近い例を探す(ゼロから組ませるより速い) |
hatake_reference |
キーの型・既定値・書ける場所を引く(仕様書を読ませない) |
.mcp.json を置くだけで Claude Code / Claude Desktop から使えます。ローカルに Node を
入れたくない場合は Docker で包めます(stdio なのでコンテナ越しでも動く)。
この where と ask が、実際に案件を作るときの主役になりました。これも記事3で書きます。
いまの状態(正直に)
| 版 | v0.9.0(3言語とも同じ番号) |
| 配り方 | git の tag のみ。レジストリ未公開 |
| Flutter | 8種別(crud / master / search / detail / form / wizard / dashboard / report)が描ける |
| TypeScript / Java | 定義の解析・検証・クエリ組み立て・API 形状の生成 |
| Dart パッケージ | 配るのは9枚 |
| サイト | GitHub Pages(デモ・プレイグラウンド・機能別の書き方) |
| 実案件での使用 | 1本(次の記事) |
1.0 じゃなくて 0.9 なのは、約束を踏んでみる期間だからです。
踏んでみて壊れたら、まだ直せるから。
で、公開してどうだったか
まだ怖いです。 豆腐メンタルは治りません。🫠
ただ、出す前に「1.0 の約束」を書いたのは正解でした。あれを書いてる途中で
「あ、これ凍らせたら二度と直せないじゃん」というものが何個も出てきて、
出す前に直せたので。
次は、そのフレームワークで実際に業務システムを1本まるごと作ってみた話です。
工数がどうなったか、どこで転んだか、何ができなかったか。数字も全部出します。
→ 記事2: 案件を1本まるごと作ってみた(21.0人日 → 3.75人日の中身)
意見・ツッコミは相変わらず募集してます。「ここは絶対にヤバい」系が一番ありがたいです。
否定的な意見のほうが、たぶんこの畠はよく育ちます。🌱