ソフトウェア開発のコツ
ソフトウェア開発をうまくやるコツはなんだろうかと考えた時に、個人的には「ウォーターフォールをやめてアジャイルをうまくやる(いい感じにアジャイルな状態になる)」が一番のコツなのではないかと思った。
生成AIによってソフトウェア開発における設計・実装・テストの進め方は劇的に変わってきているけれど、「プロジェクト」を円滑に進めるコツは、あまりAIの影響を受けていないように感じる。(プロジェクトの中で、開発においてはAIを有効に活用しているけれど、プロジェクトとしては失敗気味に傾いているものは未だにある、という意味で)
プロジェクトを円滑に進めるには、チームの成熟度を上げ、フィードバックサイクルを回しながら開発とマネジメントをうまくやることが重要で、それ自体は生成AIの登場前からあまり変わっていない。そして、チームの成熟度を上げ、フィードバックサイクルを回しながら開発とマネジメントをうまくやる、を一言でまとめると「アジャイルをうまくやる」になると思う。
しかし、「アジャイルをうまくやる」を実現するのはなかなか難しい。
ウォーターフォール型の開発しか経験がない人はそもそもアジャイル的な考えの良さを実感することがとても難しい。長年ウォーターフォールの開発ばかりを経験してその思考が染み付いている人も、なかなかアジャイル的な思考ができない。ウォーターフォール型の思考に慣れている人は、一度ウォーターフォール的な思考をアンラーニングする必要があるのだろうと思います。
色々な考え方はあるけれど、なんとなく、ソフトウェア開発全体の流れを1つのシステムとして捉えることが、アジャイル的な思考を身につけるうえでのヒントになるんじゃないかと思った。
システムとしてのソフトウェア開発
ここでいうシステムとは、複数のアプリやサービスが連携して全体を構成するような、いわゆるソフトウェアシステムのことではなく、より広い意味合いでのシステムのことを指す。
以下はAIに簡潔に説明してもらった「システム」の定義。
システムとは、複数の要素が互いに影響を及ぼし合いながら、特定の目的や機能を達成するための一連の仕組みや構成体のことです。
ソフトウェア開発そのものを、上記の意味でのシステムとして捉えること。
これが、ソフトウェア開発プロジェクトを円滑に進めるための1つのヒントになるのではないかと考えている。
ソフトウェア開発を構成する要素は、例えば「要件定義」「設計」「実装(製造)」「テスト」などが挙げられる。
ウォーターフォール型の開発では、一般に「計画 → 要件定義 → 設計 → 実装 → テスト → リリース」という流れで開発が進んでいく。
アジャイルの場合は、小さな機能単位でリリースを繰り返すという点でウォーターフォール型とは異なるものの、1つの機能をリリースするまでに必要な工程は基本的に同じであり、上記のような流れになる。
この矢印の方向は一般的に作業の流れ(順番)を表すものだが、影響を与える方向の矢印と捉えることもできる。要件定義は設計に影響を与えるし、設計は実装に影響を与え、実装はテストに影響を与える。
一方、実際に開発をしてみると、影響を与える(受ける)方向は一方向ではない場合がほとんどである。実装中、設計の段階では気づかなかったことに気づき、その気づきによって設計方針が変わることはよくある。テスト中に重要な気づきがあり、それが設計や実装に影響を与えることだってある。テスト駆動で開発をする場合、テストが設計や実装に与える影響はより大きくなる。
- 設計は、実装とテストに影響を与える
- 実装は、設計とテストに影響を与える
- テストは、設計と実装に影響を与える
つまり、実際の開発においては、設計・実装・テストは、相互に影響を与え合う。
整理すると、以下のようなイメージ。
矢印は、影響を与える方向。
(ウォーターフォールでも、アジャイルでも)リリース後は大抵ユーザーからのフィードバックがあり、その内容によって、新たな要件が生まれたり、既存の要件が変更になることがある。つまり、リリース後はユーザーからのフィードバックが要件に影響を与える。
図にすると以下のイメージ。
要件に影響を与えるのはユーザーの声だけに限らない。開発者が開発をしている最中に、課題に対するより良い解決策を思いつくこともある。その場合、開発の工程が要件に影響を与えることになる。
矢印を追加して、以下の状態になる。
そして、要件が変われば、全体の計画にも影響が及ぶ。
計画もソフトウェア開発の要素として追加すると、最終的に影響の与え方は以下のようなイメージとなる。
ここまでをまとめると
- 計画は、ソフトウェア開発全体に影響を与える
- 要件は、開発内容に影響を与える
- 設計・実装・テストは、相互に影響を与え合う
- 実装やテストでの気づきは、要件に影響を与える
- ユーザーからのフィードバックは要件に影響を与える
- 要件が変わることで、全体の計画にも影響を与える
となる。
このように、ソフトウェア開発の仕事は、1つ1つの要素が全体に対して大きく影響を与えており、それ自体がシステムになっていると捉えられる。
ウォーターフォール的なプロジェクトでは、最初に決めた計画や要件定義を絶対視し、その通りに進めることが正義であるかのように振る舞うケースが多いと感じている。そのような契約ベースの進め方は責任の所在を明確化するという意味では正しいようにも思えるが、不確実性の高い要件が多い場合、最初の計画どおりに進めることは難しくなる。また、開発中の気づきやフィードバックがソフトウェアに反映することが難しいため、ソフトウェアの価値を高めるには限界がある。
最初の計画や要件を重視して影響が出ないようにコントロールするのではなく、フィードバックサイクルを回しながら変化を受け入れ、その影響をプロジェクト全体へ適切に反映することが、ソフトウェア開発プロジェクトを円滑に進めるためにとても大事であると思う。
アジャイル的な思考を持つ人は、変化を受け入れ、その上でどうやって全体を最適化していくかを考える。そのため、開発中の気づきやフィードバックが、ソフトウェアの価値に繋がりやすくなる。とはいえ、やみくもに変化や要望を受け入れていては、いずれカオスな状態になりかねないし、プロジェクトのリソースも枯渇してしまう。そうならないように、エンジニアやマネージャーに上手くコントロールするスキルが求められる。
エンジニアの役割
変化を受け入れることが大事とは言いつつ、やみくもに変更要求を受け入れていては、無秩序やカオスが生まれ、ソフトウェアは徐々に崩壊していく。ソースコードには技術的負債が増えていったり、コードとドキュメントのズレが大きくなってドキュメントが意味をなさなくなったり、テストコードが陳腐化したり。
熱力学のエントロピーを比喩として借りるなら、ソフトウェアも、何も手を施さなければ次第に無秩序へ向かっていく。
エンジニアの役割は、ユーザーの要望を満たす機能を開発しながら、設計・実装・テストのバランスが崩壊しないようにコントロールすること。つまり、エンジニアとは、要件・設計・実装・テストの間で得られた情報を循環させ、変更に耐えられる構造を維持する人ともいえる。
そう考えると、エンジニアの役割は生成AIの登場以前と比べても、さほど変わっていないのかもしれない。AIによって設計・実装・テストの進め方は大きく変わってきているけれど、構造を維持することの重要性は今も昔もあまり変わらないし、それがエンジニアのスキルに大きく依存することも、今と昔では大きく変わっていない。むしろ、AIによって一つ一つの作業スピードが劇的に速くなったので、うまく扱わなければ崩壊までのスピードも速くなってしまう可能性が高い。そういう意味では、エンジニアの役割はAIによってより重要になったとも言えるのかもしれない。
どれだけ変化を取り込みながら、理解可能で変更可能な構造を維持できるかは、エンジニアとしての腕の見せ所である。
※相互作用によってソフトウェアが崩壊しないようにコントロールする。
マネージャーの役割
マネージャーは、エンジニアとは異なる範囲をコントロールする。設計・実装・テストだけでなく、計画や要件、チーム、コストを含めたプロジェクト全体が対象になる。
ソフトウェアの構造をどれだけきれいに保っても、ユーザーに価値が届かなければ開発の意味がない。かといって、要件を無条件に受け入れて計画が破綻したり、リソースを使いすぎてプロジェクトが赤字になるのも望ましくない。プロジェクトとして破綻してしまわないようにコントロールする。
具体的には例えば、
- 要件変更に応じて計画や優先順位を調整する
- 開発者が得た気づきを要件側へ戻せるようにする
- 納期・品質・スコープのトレードオフを判断する
- 情報が特定の人だけに偏らないようにする
- フィードバックの経路を塞がない
といった調整を行う。それがソフトウェア開発におけるマネージャーの役割。
※計画・要件・開発の相互作用を調整し、プロジェクト全体が破綻しないようにする。
まとめ
ソフトウェア開発を一方向の工程ではなく、相互に影響し合うシステムとして見ると、変更や手戻りに対する捉え方も変わってくる。アジャイルかウォーターフォールという単純な話ではなく、どこでどのような変化が起き、それがどこにどう影響するのかを捉えながら、プロダクトやプロジェクトをより良いものにするためのアプローチを考え続けることが大事であると思う。