沖永凌のブログ

現場Hub, AI, スタートアップ, CTO

仕様駆動開発を2ヶ月間実践してみた感想

最近話題になっている 仕様駆動開発(Spec Driven Development)を、約2ヶ月間実践してみた。

その率直な感想をまとめてみる。

前提

感想

開発の前提が根本から変わってしまった感覚がある。

これまで自分がやってきた「ざっくりとした仕様書を書き、残りはコードを書きながら考える」という進め方には、もう戻れない気がしている。

開発におけるAI活用のポイントは、実装イメージが明確に湧いているプログラマーが、プログラミングという作業を短縮するために使うことだと捉えている。

また、現時点でAIを使った開発は指示が明確であればあるほど効果を発揮する。

そのため、AIが生成した中間ドキュメントを人間がレビューしながら固めていき、それを元に開発するこの手法が最適解だろう。

メリット

ソースコードに対応した日本語の仕様書が常に存在する

既存コードを調査して仕様を推測する必要がない。

新規メンバーのオンボーディングがしやすく、正確な仕様書が存在すること自体が、今後も複利的に効いてきそう。

人間がやりがちな仕様の抜け漏れをある程度防げる

考慮すべき観点を網羅した形で仕様書を生成できるため、人間だけで考えていると見落としがちなポイントを補完してくれる。

デメリット

コードを書く楽しさが減る

(人によってはデメリットにならないかもしれない。)

これまでは、開発の過程でパズルを解けた時のような小さな達成感を得られていた。

仕様駆動開発ではその感覚はほとんどなくなる。

対策としては、  プログラマーのやりがいを「実装そのもの」ではなく、顧客満足度の向上や社会課題の解決に見出す必要があると感じた。

チーム体制への影響

結論としては下記のチーム体制で構成するのが良いと考える。

- ドメインエキスパートやプロダクトオーナー

- UI/UXデザイナー

- 設計者

- 設計者が扱う多数の開発エージェント(セッション)

仕様作成・設計・実装は同一人物が担当した方がよい。

仕様はドメインエキスパートを交えながら詰めていくが、ほとんどの場合最初に書いた仕様には漏れがある。

実装してみて実装者自身が再びドメインエキスパートと共に仕様を修正する。このサイクルを何度も繰り返す必要がある。

 

仮に、仕様作成者と実装者が分かれているケースを考える。

この場合、

  • 実装者が AI が生成した成果物をレビューし
  • 実装後に仕様作成者が実装成果物をレビューする

というように、1サイクルあたり必ず2回のレビューが発生する。

仕様駆動開発は、レビューの負荷が非常に高い。

仕様から実装までのサイクルを高速に何度も回すこの開発スタイルでは、レビュー回数の増加はあまりに非効率である。

 

そのため仕様作成・設計・実装は分担せずに一人に集約した方が、仕様駆動開発とは相性が良いと感じた。

おわりに

あまりにAIの進化が早いため、この記事の寿命も1年もないかもしれない。

一度目の産業革命は50年かけてゆっくり進んだらしいが、今回は数年で完了しそうな勢いである。

生きている間にこれほどの変革に立ち会えることは、大変幸運に思う。

せっかくだから存分に楽しみたいと思う。

DockerfileのRubyのバージョンを上げた時に、bundle installが失敗する問題の解決策

前提

Railsアプリケーション(7.1.0)を動かすためのコンテナで遭遇したバグ。

Dockerfileに記載したRubyのバージョンのみを3.2.2から3.3.0に変更した時に発生。

事象

コンテナを起動しようとすると、以下のエラーを吐き出して、コンテナが終了する。

Ignoring psych-5.1.2 because its extensions are not built. Try: gem pristine psych --version 5.1.2
Ignoring psych-5.1.1.1 because its extensions are not built. Try: gem pristine psych --version 5.1.1.1
Ignoring psych-5.1.1 because its extensions are not built. Try: gem pristine psych --version 5.1.1
Ignoring stringio-3.1.0 because its extensions are not built. Try: gem pristine stringio --version 3.1.0
Ignoring stringio-3.0.9 because its extensions are not built. Try: gem pristine stringio --version 3.0.9
Ignoring stringio-3.0.8 because its extensions are not built. Try: gem pristine stringio --version 3.0.8
<internal:/usr/local/lib/ruby/3.3.0/rubygems/core_ext/kernel_require.rb>:127:in `require': libruby.so.3.2: cannot open shared object file: No such file or directory - /usr/local/bundle/gems/psych-5.1.2/lib/psych.so (LoadError)

コンテナ外から

docker compose run app bundle install

を実行しても、同じエラーが発生。

原因

Gemfile.lockに書かれている&installされているbudlerやgemのバージョンは古いままだが、Rubyのバージョンだけが上がっており競合が起きた。

解消方法

一旦競合の起きているgemをuninstallし、再度bundle installをすると解決した。

1.Gemfile.lockを削除

2.コンテナ外から競合するgemをuninstall(上記のエラー文を参照してgemを特定)

docker compose run app gem uninstall psych
docker compose run app gem uninstall stringio

3.コンテナ外からbundle installを実行

docker compose run app bundle install

何のために働くのか

私が働く理由

私は、日本が天国だと思っている。

何ヶ国か海外に旅行してきた結果、日本だけはずっと住み続けたいと思えた。

衣食住が当たり前に満たされていて、その上様々な娯楽を楽しめる。

これは、多くの人が各々で生産・供給してくれているから成立する。

全員が、巨大な分業・協同社会の中に生かされている。

この素晴らしい社会を、子供やそれより下の世代にも維持し続けたいと考えている。

そのために解決しなければいけない社会問題がある。

その一つが、生産年齢人口の減少による生産量の減少である。

解決しなければ、今当たり前に消費できているものが当たり前でなくなっていく。

私はこの社会問題をソフトウェアで解決していきたい。

SaaSで提供することで、(個別開発に比べれば)少ない開発コストで、多くの会社の生産効率を上げられると考えている。

人口が減っても今の社会を維持していきたい。

私が株式会社ARTISANでやること

上記の社会問題のうち、設備工事・メンテナンス業界の労働人口減少について取り組む。

労働人口が減ることを放置していれば、修繕されないままの設備が多発するようになる。

そうならないように現場Hubを開発・サービスし、コア業務以外の時間を減らすことで、設備工事・メンテナンス会社の生産性を向上する。

株式会社ARTISANのCTOとしてやること

使命

上記課題を解決するためのソフトウェア企業を作る

説明責任

時期によって変わるとは思うので、現時点の認識を記載する

  • 上記課題を解決するソフトウェアについての持続可能なアーキテクチャ
    • 保守性
    • セキュリティ
    • 最適な設計・仕様
    • 品質保証
  • アウトカムが早く出る、最適な開発組織の模索・編成
  • 開発組織の行動指針の決定、それを実行する組織作り
  • 開発者の採用計画と実施

※株式会社ARTISANの創業の経緯についてはこちらに記載しております。 もし興味を持っていただけたら、こちらも読んで頂けると幸いです。 okjnag.hateblo.jp

Renovateで言語・パッケージのバージョンを最新に保つ

Renovateとは

GitHub Apps - Renovate · GitHub

Repository内のパッケージマネージャのファイルを検査し、記載したパッケージのバージョンが新しくなる度にPRを作成するアプリケーションでです。

ほとんどの言語に対応しています。

得られる恩恵

設定ファイルでPR作成頻度やPRのまとまりを定義でき、アップデートを定型業務化できます。

また定期的にアップデートすることで、

  • アップデートのコストが下がる
  • 時々、発生していたbugが解消される

という恩恵が受けられます。

設定ファイル例

React×Typescriptのプロジェクトの場合

設定方針

  • 毎週金曜日朝にPR作成
  • マイナー・パッチバージョンは1つにまとめてPR作成
  • Node, Typescriptは別途PR作成
{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["config:base"],
  "timezone": "Asia/Tokyo",
  "automerge": false,
  "prHourlyLimit": 0,
  "schedule": ["after 8am on friday", "before 10am on friday"],
  "dependencyDashboard": true,
  "packageRules": [
    {
      "groupName": "Minor and Patch Dependencies",
      "matchUpdateTypes": ["minor", "patch"]
    },
    {
      "groupName": "Node Version",
      "matchUpdateTypes": ["minor", "patch"],
      "matchPackageNames": ["node", "node-version"]
    },
    {
      "groupName": "Typescript Version",
      "matchUpdateTypes": ["minor", "patch"],
      "matchPackageNames": ["typescript"]
    }
  ]
}

この設定で毎週金曜日午前に、

  • メジャーバージョンの更新(破壊的変更あり)は、パッケージごとにPR作成
  • マイナー/パッチバージョンの更新は、Node, Typescript, その他 それぞれ1つずつPR作成

が行われます。

是非お試しください。

カレンダーバージョニングのためのGitHubアクションを作った

背景

もともとは、プロダクトのAPIサーバー・フロントエンドのリポジトリそれぞれで、セマンティックバージョンを利用していた。

しばらく運用していくなかで、

  • デプロイの頻度が高まってきたことで、上げる数字の判断が面倒になってきた(メジャー?マイナー?パッチ?)
  • 少数の開発メンバーしか触らないので、そもそも後方互換性があるかどうかを示す必要がないことに気づく

という理由で、カレンダーバージョニングを利用するようになった。

現在日付とbuild回数でバージョン番号が自動で決まるため、運用してみると便利なバージョニング方法だとわかる。

せっかくなのでみんなが使えるようGitHubのカスタムアクションを作ることにした。

GitHubのカスタムアクション

github.com

セマンティックバージョニングと違い、カレンダーバージョニングには画一的なスキーマはなく、 プロダクトのデプロイ頻度に併せて自由に定義する。 作成したカスタムアクションでも、スキーマを定義できるようにした。

例えば、1日に数回デプロイすることがある場合は、

YYYY.0M.0D.MICRO

年に数回のデプロイであれば、

YYYY.MICRO

と定義する。

特にセマンティックバージョニングを使う理由がなければ、是非カレンダーバージョニングを始めよう。

なぜか時々Macでファイルを開けないことがあった

MacBookを使っていると、なぜか時々ファイルを開けない機会に遭遇していた。

Webアプリケーションでファイルを生成する機能を実装しており、その機能の検証時によく発生した。

デバッグに結構な時間を費やしてしまったので、わざわざ記事にしてみる。

 

結論から書くと、濁点・半濁点が含まれるファイルにおいてのみ発生することがわかった。昔からある有名な問題らしく、macOSのみ文字の正規化方法が異なることによって引き起こされるものだ。

詳しくはNFD・NFCのワードでググると出てくる。

濁点・半濁点を含む文字について1つの文字で扱うか2つの文字で扱うかが、OSによって異なっているのだ。

 

以下が原因特定までの道のりである。

1. ファイルの生成プログラムには問題ないことを確認

2. 生成時に利用しているライブラリには問題ないことを確認

3. 特定のファイルにのみ発生することを確認

4. ファイルの中身が関係ないことを確認

5. 特定のファイル名にのみ発生することを確認

6. 濁点・半濁点がファイル名に含まれている時にのみ発生することを確認

 

知っているか否かでデバッグ速度が大きく変わってしまう、典型的な問題だと思う。

NFDという概念を知らないことにより、調べるべきキーワードが思いつかない負のループに陥っていた。

なので、この記事のタイトルを「なぜか時々Macでファイルを開けないことがあった」という、NFDを知らない人が検索した時に引っかかりそうなものに設定した。

studioで公開しているHPの独自ドメインを変更する

地味にハマったので記録しておく。

達成したいこと

  1. studioで公開しているHPの独自ドメインを変更したい
  2. ドメインのHPの検索順位を維持したい

背景

  • コーポレートサイトをstudioというホスティングサービスで公開している。
  • 会社名を検索すると一番上に出てくるので、ドメイン変更後、ページランクをまた一から育てるのは苦しい
  • studioのサポートに連絡したところ、提示してくれた方法では2が達成できなかったので色々調べる必要があった。
  • ドメイン・新ドメインの両方とも、AWSのRoute53で管理している。

やる必要がある作業まとめ

注意点

  1. ドメインの接続が解除されてから、新ドメインの接続が完了するまでダウンタイムが発生する。 サポートの方は、予め新ドメインでAレコードにIPアドレスを設定していれば問題ないという話だったが、Aレコードの値が解除前と異なったので、結局ダウンタイムは発生していた。
  2. リダイレクトの方法は複数ある。Googleが最も推奨している301リダイレクトを実施する。

参考: リダイレクトによる SEO への影響 | Google 検索セントラル  |  ドキュメント  |  Google Developers

リダイレクト設定の手順

httpsプロトコルでリダイレクトするにはAWSのS3のみでは不可で、Cloudfrontを使う必要があるとのこと。 なので、

  1. S3でbucketを作成
  2. 1で作成したbucketをオリジンドメインに指定して、CloudFrontのディストリビューションを作成
  3. ドメインを2のディストリビューションに紐付け(Aレコード)
  4. 2のディストリビューションに「新ドメインにリダイレクトする」関数を定義

サンプル: ビューワーを新しい URL にリダイレクトさせる - Amazon CloudFront

検証

curlコマンドで旧ドメインにリクエストし、301が帰ってきたら成功。