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

ソフトウェアを迅速に構築する方法

2025年7月14日原文(evanhahn.com)

概要

  • ソフトウェア開発 では、品質と納期のバランスが重要
  • 完璧さよりも 「十分良い」 コードを重視する姿勢
  • ラフドラフト (荒い試作)を活用し、早期に問題点を発見
  • 要件の見直しや 小さな変更 の積み重ねが効率化に寄与
  • 具体的なスキル や作業習慣で開発速度と品質を向上

ソフトウェア開発における「十分良い」とは

  • 納期品質 の両立が求められるソフトウェア開発現場
  • 速さを優先しすぎると バグ保守性の低下 を招く
  • 完璧を目指しすぎると リリース遅延 や進捗停滞
  • プロジェクトやチームごとに「どこまで良くすべきか」の 基準 が異なる現実
  • 8割の完成度 を期限内に出すことを個人ルールとする実践
    • ただし、用途やプロジェクトによって 柔軟な対応 も必要

ラフドラフト(荒い試作)活用術

  • 「スパイク」「ウォーキングスケルトン」 と呼ばれる手法の活用
  • まずは 動くが粗いコード を素早く作成し、後から洗練
  • ラフドラフトの特徴
    • バグ未対応ケースTODOコメント が多い
    • print文ハードコーディングパフォーマンス無視
    • WIP (Work In Progress)などの暫定コミット
  • この段階で 未知の課題不要な機能 を早期発見
  • 最終版に仕上げる前に 問題点を洗い出し修正

ラフドラフト作成時の具体的工夫

  • 変更しにくい設計要素 (言語選定やDB設計)を早めに検証
  • 手抜き箇所には TODO を明記し、後で一括修正
  • トップダウン (UIやAPIの理想像から作り始める)アプローチ
  • ラフドラフト中に発見した改善点は 個別パッチ で先に対応
  • 参考資料:「Throw away your first draft of your code」「Best Simple System for Now」「YAGNI」など

要件の見直し・緩和

  • やらないことを増やす ことで開発効率化
    • 画面を 統合 して数を減らす
    • 難しい エッジケース の対応を見送る
    • API入力数 を制限
    • プロトタイプ で済ませる提案
    • 実施自体を見直す (不要ならやらない)
  • 組織文化の変革も視野に、 小さな提案 から始める工夫

コードベースで迷子にならない工夫

  • タイマー をセットし、作業の脱線を防止
  • ペアプログラミング で集中力維持
  • 自己管理や 意識的な行動 で生産性向上

小さな変更を積み重ねる

  • 大規模パッチ は管理・レビュー・ロールバックが難しい
  • 小さく焦点を絞った差分 の利点
    • 書きやすく、 頭の負担 が小さい
    • レビューしやすい、マージも早い
    • バグのリスク低減、ロールバックも容易
  • 例:新画面追加前に バグ修正依存関係アップグレード を個別パッチで対応

開発を速くするための具体的スキル

  • コードリーディング 力:デバッグや学習、外部依存の理解に必須
  • データモデリング :不正な状態を防ぎ、後々のトラブル回避
  • スクリプト作成 :BashやPythonでの自動化・補助ツール活用
    • Bashには Shellcheck 推奨
  • デバッガ の活用:print文より効率的な問題解決
  • 適切な休憩 :行き詰まり時のリフレッシュで効率回復
  • 純粋関数イミュータブルデータ 推奨:バグ減少と理解容易化
  • LLM (大規模言語モデル)の活用:得意分野を見極めて日常利用

まとめ

  • 求められる品質レベル を見極める
  • ラフドラフト から始めて早期に課題を発見
  • 要件緩和 を積極的に提案
  • 小さな変更 を重ねて品質とスピードを両立
  • 個別スキル作業習慣 の継続的な向上

必要に応じて、次の話題や具体的なテクニックに関するセクションを追加できます。

Hackerたちの意見

記事であまり触れられていない重要なポイントは、時間とともに開発スピードがどう変わるかってことだね。プロジェクトやチームの規模が大きくなると、時間が経つにつれてそのスピードは落ちていく。減少率を最小限に抑えるためには、長期的な速度のために短期的な開発を遅らせるようなことをしなきゃいけないかもしれない。例えば、テストやドキュメント、意思決定ログ、アジャイルのセレモニーなんかがそうだね。初期開発でのいくつかの見落としは、後々長い間ネガティブな影響を及ぼすことがある。例えば、最初からコードに観測可能性を組み込まなかったり、テストしやすさを明確な目標にしてコードを構造化しなかったりすることが挙げられる。

ソロ開発者として、僕は意思決定ログ、テスト、ドキュメントの順で重要だって言えるよ。個人的には「決定ログ」じゃなくて「ラボノート」を使ってるんだけど、リアルタイムでデザインを記録していて、それがテストやドキュメントの基礎になるんだ。ラボノートがあると、たとえ遅れて始めても、より良いドキュメントを早く書けるし、テストによってデザインが時間とともにずれないか確認できる。週末に書く一回限りのツールなら盲目的に始めるのもアリだけど、長く使うものなら、ゆっくりとした基盤を作ることで、その上に築くものがしっかりして、問題に対して合理的で、何より理解しやすくてメンテナンスしやすいものになるよ。あと、あまり人気のない意見だけど、まず紙でデザインしてからデジタル化するのがいいと思う。

「未知の未知」を明らかにすることができる。プロトタイプは、予想できなかったことを明らかにすることが多い。これは僕の経験とは真逆だな。何かをいじっているときは、良い部分だけを体験していて、悪い部分は全く感じない…いわばハネムーン期みたいなもんだ。エッジケースをカバーしたり、無効な状態を防いだり、ユーザーに役立つエラーメッセージを表示したり、潜在的な副作用を排除しようとするまで、「未知の未知」に気づくことはない。

あなたが言ってるのは、ツールやフレームワーク、ライブラリにおける未知の未知のことだと思う。著者は問題空間における未知の未知について話しているんじゃないかな。

そうだね、自分だけが使うツールを作るのはすごくスムーズだよね。穴だらけで、全体的に揺れるカードハウスみたいでも、うまく使えるから。

そうだね。ラフドラフトがあまりにもラフすぎることについて警告したかったんだ。実際の問題があるところは、手を抜いてはいけない部分だと思う。ラリーのパイロットは、持続的なペースで偵察をするんじゃないかな。そうしないと、例えばコーナーの前のバンプが厄介だって気づかないかもしれない。

スケールがここではかなり重要だと思う。自分で何かを作ったり、小さなチームでやっているなら、投稿に書いてあることには完全に同意するよ。実際、そういう状況では迅速で雑な開発手法に頼るべきだと思う。これが小規模開発の強みだからね。うまくやれば、大きなプロジェクトよりもずっと早く進められる。バグは小さなチームやソロ開発者にとってはほとんどいつでも簡単に修正できるし、関わる全員がプロジェクト全体のほぼ完璧なメンタルモデルを持っているから、コード自体もコンウェイの法則のおかげで比較的シンプルに保たれる。大規模な開発プロジェクトでは、バグや特にアーキテクチャのミスを修正するのは、コードの理解が断片的で、アーキテクチャが悪夢のように複雑だから、指数関数的にコストがかかる。大規模なリファクタリングは、コードベースの一部をロックダウンすることを意味して、数十人から数百人が何もできなくなる(つまり、ほとんど起こらない)。そんな状況では、全てのステップでの正確さが重要な焦点になるべきだと思う。スケールの経済は、個々の開発者がそんな風に働いていても、許容できるペースで物事を進める助けになるよ。

うーん、コンテキストがすごく大事だね。君が考える大規模な開発プロジェクトが何を指しているのか分からないけど、私が思っているよりももっと大きいかもしれない。でも、アプリ間のAPIを早めに立ち上げて、データベースチームからフロントエンドチームやアプリチームに、何らかのバックエンド/APIチームを通じて作業環境を整えるのが正しい選択だったといつも思ってる。できるだけ早くプロダクションサーバーに載せて、DNSだけが欠けている状態にするのが、テストやチーム間のバグや問題を浮き彫りにするのにすごく役立つよ。著者は主にコードの観点から話してるけど、個人的には大きなチームではもっと重要だと思う。(余談だけど、チーム間で依存関係の層を作るようなアーキテクチャは、私の視点では悪いアイデアだと思うけど、まだよく行われているね。)

ここがスケールダウンするポイントだね。誰もこんな巨大なシステムは必要ないのに、なぜかみんな欲しがるんだよね…

最近、十分に堅牢なシステムを素早く構築する方法を学んだよ。ここで学んだことをいくつか挙げるね。* 一つのツールをしっかりと使いこなすこと。表面的には問題に適しているように見えるツールよりも、自分がよく知っているツールを使う方が多くの場合良い。非常に多くの現実の問題に対して、Djangoは絶妙な選択なんだ。何度かプロジェクトを始めるときにDjangoは重すぎるかもと思ったけど、すぐにそのプロジェクトは初期のアイデアを超えて成長した。例えば、最近ステータスページアプリを作ったんだけど、最初は単一ファイルのDjangoアプリだったけど、Djangoの制限を回避するのは意味がないとすぐに気づいた。* Djangoモデルに合うアプリケーションでは、データモデルが全ての中心にある。ラフなプロトタイプを作るときでも、データモデルのリファクタリングを後回しにしないこと。時間が経つにつれて、変更するのがどんどん高くつくし難しくなるから。* ほとんどのアプリケーションはシングルページアプリである必要もないし、重いフロントエンドフレームワークも必要ない。恩恵を受けられるものでも、従来のDjangoビューで80%のページは十分だよ。残りについてはAlpineJS/HTMXを考えてみて。* ほとんどの場合、自分で作った方が簡単だよ。顧客を保存して編集する必要がある?Djangoを使えば、数時間でアプリ内にシンプルなCRMアプリを開発できる。商業CRMを統合するのはもっと時間がかかる。これはステータスページ、CRM、サポートシステム、営業プロセスなど、ほとんどのDjangoアプリやライブラリにも当てはまるよ。* いつも超つまらない技術を選ぶこと。全てにPython/Django/Postgresを使って。KubernetesやRedis、RabbitMQ、Celeryは忘れて。Alpine/HTMXは例外だけど、JavaScriptスタックの多くを避けられるからね。

僕もDjangoが大好きだよ。すぐに動くプロジェクトを簡単に立ち上げられるからね。普段の仕事ではGoを使ってるけど、まあそれも悪くはないけど、シンプルなAPIエンドポイントを書くのに10倍のコードを書く羽目になるし、フィルタリングやページネーションのためにクエリパラメータを追加すると、さらに長くなる。権限モデルを追加するのも同じような感じだよ。もちろんパフォーマンスの違いは大きいけど、ほとんどのことに関してはDBクエリがパフォーマンスを支配してるから、Pythonでもそうだね。

完全に同意だね。自己完結型のSaaSスタートアップには、Djangoを(ほぼ)何にでも使うのが簡単だと思う。マーケティングはWagtailでできるし、サポートは再利用可能なアプリで管理してる。これは、各ページにあるシンプルな静的要素(Intercomに似てる)で、標準のDjangoページにリダイレクトして、問題についての情報を集めるんだ(認証されてるユーザーなら、そのユーザー情報も含めて)。さらにスタックを簡素化するために、バックアップにはSQLiteとBorgを使ってる。キャッシングはDiskcacheを利用してる。デプロイは少し複雑だけど、コンテナとpodmanをsystemdで使ってるけど、git pull & gunicorn restartでも簡単にできるよ。フロントエンドのやり方は何度か変わったけど、Alpine & HTMXは自分には制約が多すぎて、代わりにTypescriptをdjango-viteと組み合わせて使うのが好きだね。フロントエンドのツールを使うことになるけど、TailwindCSSやReact、Typescriptなんかも使えるからね。

Hacker Newsで議論の続きを見る