ハクソク

世界を動かす技術を、日本語で。

Specsmaxxing – AI精神病を克服する方法と、なぜYAMLで仕様を書くのか

11時間前原文(acai.sh)

概要

  • Acai.shは、受け入れ基準管理と仕様記述を効率化するオープンソースツールキット
  • feature.yamlによる明確な要件管理と、ACIDタグによるコード・テストとの連携
  • CLI・Webダッシュボード、APIなど多様なインターフェースを提供
  • 継続的なレビューとイテレーションを通じて、仕様主導の開発プロセスを推進
  • 仕様記述・QA自動化・テスト最大化による次世代ソフトウェア開発の展望

Acai.shによる仕様主導開発のすすめ

  • Acai.shは、受け入れ基準(Acceptance Criteria)を中心に据えたソフトウェア開発支援ツール
  • 仕様(spec)をfeature.yaml形式で記述し、要件ごとに一意の**ACID(Acceptance Criteria ID)**を付与
  • ACIDをコードやテスト内で参照・トラッキング可能
  • CLIツール(npm配布・GitHubリリースあり)やWebダッシュボードREST APIを提供
  • GitHub Actions等CI/CDと連携し、要件の実装・テスト・レビュー進捗を一元管理
  • 無料ホスティングも提供、ソースコードはApache 2.0ライセンスで公開

仕様記述の基本

  • feature.yamlは、機能ごとに**要件(requirements)**を階層的・番号付きで記述
  • 各要件は安定したIDで他所から参照可能(例:my-feature.ENG.2)
  • 要件は具体的・テスト可能・機能本位に記述
  • 設計・テストガイド・アーキテクチャ等、あらゆるドキュメントを.md形式で管理推奨

ACIDタグの活用

  • ACIDタグにより、コードと仕様の対応関係を明示
  • 仕様変更時に関連コードの追跡・修正が容易
  • 受け入れ基準のカバレッジ管理や進捗可視化が可能
  • ダッシュボードで要件ごとにコメント・状態(Todo, Assigned, Completed, Accepted, Rejected)を管理

開発フロー

  • Step 1 - 仕様記述
    ・feature.yamlで要件を明文化
    ・曖昧なUIや細部は省き、本質的な機能要件に集中
  • Step 2 - 実装・テスト
    ・CLIやエージェントでACIDをコード・テストに組み込み
    ・CI/CDで自動的にacai pushを実行し進捗をダッシュボードへ反映
  • Step 3 - レビュー
    ・PR単位ではなく、要件単位でレビュー
    ・ダッシュボード上で状態管理・コメント・コラボレーション
  • Step 4 - イテレーション
    ・仕様やノートを随時更新
    ・エージェントが自己割り当てや自律的な対応も可能

仕様管理の価値

  • 受け入れ基準の明文化はプロダクト品質・コラボレーション促進の鍵
  • 仕様は会話や頭の中だけでなく、明示的に記録することで価値を最大化
  • feature.yamlはそのためのシンプルかつ強力な出発点

QA・テスト自動化と未来展望

  • コード生成速度が上がるほど、QA・検証・テスト自動化の重要性が増大
  • 最終的にはLLM(大規模言語モデル)がテスト失敗やアラートに自律的に反応する未来を見据えた設計
  • Acai.shはまず仕様と実装の対応・可視化にフォーカス
  • 今後はQAフィードバックやユーザーレビュー等との連携も想定

まとめ:仕様主導の新しい開発習慣

  • **仕様(Spec)**は常にプロダクトの本質
  • 明確な受け入れ基準リストを維持することが、今後ますます重要
  • Acai.shは、仕様記述・テスト・レビュー・コラボレーションを一元化し、次世代の開発現場を支える
  • 今すぐ仕様を書き始めることが、すべての開発者にとって最良の第一歩

Hackerたちの意見

作者です。全部読むのが面倒なら、要点をうまくまとめた一節を紹介しますね。 > 「私の言いたいことは、仕様はどこかに存在しなければならないということです。たとえ書き留めなくても。仕様は、あなたがソフトウェアに求めるものです。それはしばしばあなたの頭の中や会話の中にしか存在しません。あなたやあなたのチーム、ビジネスは常にその仕様が何を言っているかを気にするでしょう。それは決して変わりません。だから、今のうちに書き留めておく方がいいですよ!そして、受け入れ基準のシンプルなリストから始めるのが良いと思います。(それが実際に`feature.yaml`の全てです。)」
いいね!あなたの仕様を最大限に活用する姿勢、すごく共感できる。私は明確な要件を扱ってきたけど、会話から引き出したり、別のソフトウェアを内省したりしている。ワンショットでそれを得て、"おじいちゃんがクロードに怒鳴る" みたいな反復作業をしながら、常に最新の状態に保ってる。あなたとは違って、LLMにできるだけ多くの作業をしてほしいと思ってるけど、「可能な限り」というのはその文の中でかなりの作業を意味してる。自分がどこで必要とされているのか、Opusや反復作業が最終的にどうなるのかを明確にするのに苦労してる。要件と制約の違いを明確にすることが本当に挑戦的だった(例えば、「データベーススキーマを再発明することはできない、大きなシステムの一部を構築しているから」)。UIの挙動をいつ、どのように指定するかについてもまだ悩んでる。UIの多くは暗黙的で、動作させるためにたくさん指定しなきゃいけないのはかなり大変に感じる。Flutterや他のUIツールキットのために間違いなく膨大なテストを書いた人には新たな敬意を表します。
これとJiraの違いは何?あなたの仕様はすでにどこかに存在してるよ、それを定義した場所だから。だから、何かが壊れたときに仕様を参照できるように、コードやコミットにJiraチケット番号を入れるのがいいんだよね。
最近、エージェント生成のコードには人間が書いたコードのような「組織的記憶」が欠けているって似たようなことを書いたんだ。決定がなぜなされたのかを聞ける人がいないからね。「スペックマキシング」ってのがこの問題に対する正しいアプローチだと思う。著者の記憶に頼れないなら、意図をどこかにしっかり残さないといけない。AI生成コードの道を進むなら、スペックがデフォルトで真実の源になるよ。
> いつもスペックが何を言っているか気にする、それは決して変わらない 何か見逃した?それともみんな1970年代に戻って、ウォーターフォールプロセスで働いてるの?
この仕様の伝統的な名前は「ソースコード」だよ。システムの動作に関する真実の基準で、人間が読めるようにできる限りのものなんだけど、自動化ツールによってコンピュータが実行するためのあまり読めない派生物に処理されるんだ。コンパイルされたアーティファクトをソースコードをチェックせずにコードベースにチェックインするのは、常にリスキーな行動だよね!
自分も似たようなことに行き着いたよ。C++の作業には、2〜3つの仕様書を使ってるんだ。ファームウェアマニュアル(機能やインターフェースを説明)、実装計画(実装の順序、指定されたメカニズム - 新機能はここに入る)、プロダクトマニュアル(ユーザーストーリー、外部効果)。ユーザーストーリーから始めて、実装計画を作り、コードを書いて、ファームウェアマニュアルを書いて、3つのドキュメントとコードの整合性をチェックする。整合した統一された真実を反映するために、コードかドキュメントのどちらかを変更する(実装計画は徐々に実際のものになっていく)。コードには詳しいコメントを付けて、誤解されにくくしてる。「正確で、一貫性があり、整合性があり、コメントがある」このプロセスを機能ごとに繰り返して、時々元のプロダクトマニュアルに戻ってズレを特定する。元のドキュメントがドラフトされたら、エージェントにプレースホルダーファイルを書かせて、必要になるインターフェースを定義させる(後でたくさん追加することになるけど、それは大丈夫)。すべてのファイルは明確な関心の分離を反映し、定義されたインターフェースを通じてのみアクセスできるようにして、他はプライベートにする。手作業よりも多くの個別ファイルができるけど、ファイルの粒度で範囲を制限し、ファイルごとに不変のインターフェースを定義することで、メンテナンスしにくいコードを生むショートカットを避けてる。新しいコンテキストを開くときは、プロジェクトのロゴや理念を簡単に説明するオンボーディングプロセスを設けて、エージェントがプロジェクトの成功に深く投資すべき理由を説明するし、エージェントが特に気をつけているポイントや好みを書いたlearnings.mdも作成する。言うまでもなく、1ミリオンコンテキストを使ってて、トークンが火の海だけど、結果はしっかりしてて、生産性は5〜10倍だよ。
結局、ソースコードが何かに集約されるんだよね。「仕様」と呼ばれる最も一般的な形は、作業チケットの受け入れ基準で、これは加算的な仕様、つまり望ましい変更の説明なんだよね。「既存のものを考慮して、次のように変更してください」って感じ。つまり、製品が始まって以来作成されたすべてのチケットを重ねて要約したら、それが「仕様」になるんだ。でも、それを要約しているのは開発者たちで、各仕様の追加と既存のコードベースの現実を理解しながらやってるんだよね。だから、今の人たちが「仕様」と呼んでいるものと、コードがすでにやっていることとの間のギャップは大きくないし、これからも大きくはならないと思う。ただ、実質的に別の(準)コンパイルステップを追加しているから、今回は非決定的なものになってるんだ。
あなたはソフトウェアアナリストの仕事を再発見したね。90年代初頭までは存在してたんだけど、その後はプロダクトオーナー、プロジェクトマネージャー、開発者/DevOpsのミックスになっちゃった。でも、アナリストは別のスキルセットだってことを無視してると思う。
仕様を書くだけじゃなくて、他の人の仕様を共有したり使ったりもできるよ。それがspeX.buildが作られた理由で、バージョン管理された仕様のハブになって、みんなが自分の実装を好きな言語やスタイル、詳細で作れるようにするためなんだ。
会話を記録するだけでいいんじゃない?必要なことが全部含まれてるし。初期の大まかなスコーピング、xをやろうとしてyをやらなかった失敗、特定のコード行が特定のエッジケースをどう解決するか、などなど。レビューの時間が来たら、コードと会話の両方を見直せばいい。200件の「ユーザーが書いたメッセージで、なぜ、何を?」って?それは良いPRだね。15件の「はい、うん、オッケー、なんでもいいよ」?それはPRにもう少し愛情を注ぎたくなるかも。コミットするとき、記録しないことでやった作業の半分、いや大部分を捨ててる気がする。
すごい!YAMLでプログラミングするの大好き!これをもっと楽しくするためには、Jinjaをちょっと加えたらいいんじゃない?そしたら、ガスで料理できるよ。
仕様に` | nindent 12`を夢見てる! :D
その通り。ある時点で、仕様があまりにも複雑になると、自分でコードを書く方が楽になる。プログラマーがいつも言うように、コードがドキュメントだっていうのはそのためなんだ。詳細なドキュメントを書くのはとても面倒で、誰もやりたくないから。
:) ちょっとクレイジーな考えなんだけど、普通の言語の中で特定のコンピューターレベルの命令に変換できるような、狭められた特定のサブセットがあったらどうなるんだろう?例えば、コンピューターにファイルから何かを読み取って特定の方法で変換するように言う代わりに、ファイルを開くための具体的な命令があって、それを使うたびに同じように動作して、間違った使い方をしたら必ず失敗するっていうのはどう?わぁ、可能性は無限大だね :)
YAML化したRubyでスペックを書いて未来に備えようよ。これならもっと柔軟だし、ベストプラクティスだって言われたよ!
k8sのテンプレートで泣いてる
なんでYamlなのかを知りたくて読み始めたけど、その代わりに素晴らしい投稿を見つけたよ。ただ一つ、"AUTH-1"の番号付けが好きだったけど、YamlがそれをAuthセクションに分けて、"1."のサブセクションにしてるのがあまり好きじゃない。AUTH-1のコーディフィケーションの方が、参照しやすくて検索しやすいから。
この業界を辞めたくてたまらない。だって、結局はYAMLの猿になる道しかないみたいだから。むしろ腐っていたい。
作者がAIの精神病を克服する部分はどこ?どんどん深掘りしているように読める。
それが一番のポイントだよ。「プロンプトを拡張して改善する」って言うけど、彼らはただクロードに精神病を克服するためのAIツールを書かせるだけだよ(そのプログラムは人種差別的なスラングでAnthropicのサーバーをスパムして、ユーザーがすぐにバンされるっていう成功)。
確かに、その点をもっと明確にすればよかったね。いくつかの理由があるんだ。まず、TUIsやハーネス、モデル、サブエージェント、役割、スキル、mcp、mdライブラリなどの実験をやめて、このアプローチに落ち着いたこと。これで他のものを作ることに戻ったんだ。ただ、これが永遠に続くとは思ってないけどね。次に、あまり「感覚でプロンプトを作る」ことがなくなって、もっとエンジニアリングやアイデア出しをしているから、そこでもあまり精神的に不安定じゃなくなった。あと、ちょっと関連するけど、実際に多くの開発者が毎日「プロンプトでニルヴァーナに達する」ことを望んでいると思う。私はそうじゃないけど、スペックは長い間重みを持つと思う。もしかしたら、彼らは私が思っている以上に進むかもしれないし、デジタルの世界全体が一つのチャットボックスになるのかも?
古いことは新しいことだと思う。これはAIか人間が実行するかに関係なく、仕様と実行が時間や空間で離れている場合にはこれが必要だということ。これは基本的にVモデルとプロセスの全体的なポイントで(正しくツールとして使われるべきで、目標として優先されるべきではない)、60年代と70年代にすでに研究されて公式化されていた。
これって、またCucumberの「コホンコホン」行動駆動デザインがYAMLに保存されて、LLMがテキストをトークン化する代わりにASTを読みやすくするためのものなのかな?
書き方が好きだな! > 「オーガニックで放牧された、手書きの仕様書に勝るものはない。」って、めっちゃ共感するわ。最近、デザインドキュメントを「100%手書きのオーガニックコンテンツ」って始めてるから、ちょっとパクっちゃうかも。全体的にいいアイデアだね。君のSaaSは使わないと思うけど、要件や制約にタグを付けて見つけやすくするアプローチはいいと思うよ。君が言及しなかったプロジェクトで、これも面白い視点だと思うのがcodespeak.devなんだけど、まだ試してないんだ。要するに、仕様を維持して、エージェントが仕様の差分をコードの差分に翻訳するのは、未来に向けて有望な分野だと思う。書くのが好きだから、いいことだね!
なんでvibecodingの人たちは、まだマークダウン(ここではyml)がコードよりも良い仕様だって思ってるの?マジで、そうじゃないから。コードは仕様みたいに書けば、ソフトウェアはもっと安定して、メンテナンスしやすく、読みやすくなるよ。コードは一時的なものじゃなくて、まさにその仕様そのものなんだ。もしコードが仕様みたいに構造化されてないなら、LLM駆動の開発の観点から見ると、コードはゴミだよ。
ほとんどの「プログラマー」は、コードをうまく読んだり書いたりできないし(構造やアーキテクチャについて考えることもできない)、だから「英語でプログラムしたい」って思うんだよね。
アイデアとしては、仕様がコードに比べて何らかの形で圧縮されているってことだね。
君は仕様を「これが作られるべきだ」という風に混同してると思うけど、「これがソフトウェアがすべきこと、すべきでないこと」というのが正しいんだ。私にとって「コードが仕様だ」というのは、「ビジネスがこうしたいのは、コードがそう書かれているから」というのと同じことだよ。明らかに逆だよね。ビジネスがこのホットパスにキャッシュを使うことを義務付けてるの?いや、でもビジネスはパフォーマンス目標を設定していて、キャッシュはそれを満たすための合理的な方法だったんだ。違いがわかる?「すべきこと」と「すべきでないこと」は特別な注意を払うべきで、'how'を決める前にしっかり記録しておく必要があると思う。チームによってやり方は違うけど、項目化された機能的受け入れ基準を書くのが、2つのドメインを結びつける実用的な方法だと思う。今はプロセスがもっと重要だと思う。エージェントに出荷させる誘惑が増えてきて、これらの仕様を維持する手間が減ってきてるから。
ソフトウェアエンジニアリングは、他のエンジニアリング分野とは違って、作っているものの最も明確な仕様が実際のものそのものであるところが特徴だよね。橋を作りたいときは、まず青写真を完成させて、誰かが実際にコンクリートを流し込むけど、ソフトウェアの場合、青写真はコードであり、コードがそのまま橋になるんだ。ただし、仕様を書くための抽象度は色々あって、コードはその中で最も明示的な形なんだよね。LLM(大規模言語モデル)のおかげで、私たちはその高い抽象度の部分にもっと時間を使えるようになって、繰り返しの多い退屈な作業から解放されるんじゃないかな。ソフトウェアエンジニアリングの(遠い)未来は、コードを書くことではなく、主に要件を書くことになると思うから、この新しい「プログラミング」の形に基づいてフレームワークや「IDE」を作るのは理にかなってるよね。ACAIがその正解かは分からないけど、方向性は面白いと思う。
そうだね。もし詐欺師やグル、MLMが約束した素晴らしい結果を出せなかったら、彼らはいつでもこう言えるよね。>「誰にでも効果があるとは言ってない、努力次第だよ!」これは詐欺の寿命を延ばすのに完璧なんだ。だって、一般的には努力をすれば結果が良くなるのは明らかだからね、同じことがここでも言える。もちろん、仕様やプロンプトを書く方法には良いものと悪いものがあるけど、正直言って、これに対する多くの注目は、これらのツール全体の限界から注意を逸らすための手段だと思う。つまり、全てが無駄だとは言わないけど、この「プロンプト/仕様エンジニアリング」の大きな側面は、私の見解では「LLMが我々のGDPを10倍にする」という考えを無意識に支える方法になってるんだ。もしその高い期待が実現しなかったら、いつでもこう言える。>「誰にでも効果があるとは言ってない、仕様にどれだけ努力を注ぐか次第だよ!」
その通りだね。必要な詳細レベルまで書かれた仕様とコードの間にはほとんどギャップがないよ。少しはあるけど、何十年もの間に新しいフレームワークや言語、抽象化の新しい形が出てきた後では、大きなギャップではないんだ。誤解の核心は、新しいビルドを作ることと、既存のビルドに変更を加えることの違いにある(実際にほとんどのソフトウェア開発作業が行われるところ)。新しいビルドのために詳細な仕様があれば、確かに良いスタートが切れるよね。でも、その後に続く何百もの変更が問題なんだ。人々は、少し自然言語に近い仕様があるからといって、ショートカットを作ったり、最小限の努力で変更をしようとする欲求が止まると思ってるのかな?それに、AIがその下で確率的にコードを変更しているのに、開発のペースが崩れないと思ってるの?ただ速くなって、継続的な推論コストがかかるだけなのに。LLMはメンタルモデルを形成しないよ。仕様の差に対してLLMを使ってコーディングするのと、コードベースと要求された変更を理解した上で開発者がプロンプトを出すのでは、結果が良くなることはないんだ。
コードのすべての部分が同じわけではないよ。この点に関しては、ユーザーが目にする部分(ライブラリのAPI、CLIのコマンド引数、GUI/TUIアプリのUI、ウェブサービスのエンドポイントなど)は仕様と密接に関連しているんだ。それ以外の部分は、ユーザーが目にする動作が変わらない限り、もっと流動的だよ。選択はメンテナンスやデバッグコストに影響を与えるから、これらの部分を適当に扱うことにはプレッシャーがあると思う。最も難しい設計の決定は、これら二つをどう分けるか、そしてユーザー向けとプログラマー向けの設計決定のスムーズな進化をどう確保するかに関係していると思う。今違うのは、メンテナンスやデバッグの設計決定が過去には人間のコーダーやチームに関して行われていたけど、今は必ずしもそうではないということ。APIを指定して、エージェントに残りを考えさせるべきか、それともメンテナンスやセキュリティを確保するために残りをコントロールしたいのか?1年前はそう思ってたけど、今はもっと曖昧になってる。エージェントはコードベースを素早くブラウズできて、私がタイプして出力を解析するよりも速くランタイムの影響を探れるからね。最も強い経験的観察はランタイムの動作に依存するから、彼らにはその点でアドバンテージがあるんだ。
いいえ、コードは仕様と同じではないよ。顧客が必要としない偶発的な実装の詳細がたくさんあるんだ。コードを仕様にすると、そういった詳細が要件になってしまって、その実装を変更できなくなっちゃう。機能的な動作と実装の詳細を分けておくことは本当に便利なんだけど、通常はそれを同期させるのが面倒なんだよね。
それはどちらか一方である必要はないよ。構造的だけど柔軟な方法で擬似コードを書くのは、すごく効果的だと思う。
AIの時代が来る前は、仕様書って文書のことだったよね。jpeg、png、h.264、docx、usbc、他に思いつくフォーマットの仕様は、ただのC++のソースファイルの束じゃないんだ。コンパイル可能なソースファイルは、仕様そのものを補完する例として機能してた。コードが仕様だっていう考えは、アジャイルの脳みその腐った考えだよ。クリーンコードがあれば文書やコメントを書く必要がないっていうのと同じくらいね。
ここには要求工学を非アジャイルで古臭いものだと考えている人が結構いるね。この考えにいるなら、Vモデルについて少し勉強してみて、これがウォーターフォールモデルだけでなく、問題を分解してすべてが正しく機能することを確認する方法でもあることに気づいてほしいな。小さな趣味のプロジェクトには必要ないかもしれないけど、複数の会社と様々な技術で何かを始めると、すぐに非常に役立つようになるよ。 [1] https://en.wikipedia.org/wiki/V-model
だったら、自分でコードを書けばいいじゃん?製品が何をするべきかを正確に定義するのが難しい部分で、コードを書くのは簡単な部分だよ。仕様をコードとして書けば、もう製品ができあがるじゃん。なんでLLMに楽しい部分をやらせるの?
「すべてのコードを書く能力があるから」ってだけで、事前に大部分の仕様を定義してLLMに実装を生成させる選択肢が好ましいわけじゃないよ。コードのレビューに脳のリソースを使うつもりだし、エッジケースや外部モジュールの相互作用、次のステップについて考えるのにも脳のリソースを使うつもり。なんでその時点に早送りして、80%の時間(そして脳のリソースや注意、モチベーションも)を節約しないの?
俺はこれをやってるのは、LLMがどんどん良くなるって賭けてるからなんだ。スペックは価値を保ちつつ、コードは価値が下がっていく(コモディティ化する)って思ってる。コードには、世界の中でそのコードを位置づける理論が欠けてるんだよね。俺のスペックには、コードが欠いてる理論が含まれてるから、将来的にスペックの方が価値があると思う。スペックは独自のデータだし、データはポストAGIの世界では価値を持つけど、コードはそうじゃない。俺はスペックを単なるアーキテクチャのスペック以上のものとして定義してる。俺にとっては、あるテーマについての小冊子を書いてる感じで、それを使ってLLMにインコンテキスト学習を教えてるんだ。もしかしたら「スペック」って言葉よりも別の言葉が必要かもしれない。
>> 製品が何をするべきかを正確に定義するのが難しい部分で、コードを書くのは簡単な部分だ。製品が何をすべきかを定義するスペックと、どうやってそれを実現するかを定義するコードの間には大きな違いがある。前者から後者に移るのは「簡単な部分」じゃない。どちらかが簡単でストレートな問題に取り組んでると思ってる人は、プログラミングの神か、そうじゃなければ本気でそう思ってるだけだよ。スペックをコードに翻訳するのは、まだ難しくて疲れる作業なんだから。
LLMを使う全体の目的は、特定の言語で仕様を書く必要がないってことだと思う。確かに、仕様主導の開発は理にかなってるけど、何をどうやって作り、テストし、出荷するかを明確にする必要があるからね。でも、YAMLで仕様を書くのは本当に逆行してると思う。