オブジェクト指向を復習してやんよ!!!(技術的負債編)
タグ:オブジェクト指向 | 技術的負債
前回に続いて、「オブジェクト指向設計ガイド」をインプット。
3、4章までを読んだ時点で、書いてる事の大体が
「そうあるべきなことはわかってるし、それが出来たら苦労しないんですけど」という若干モチベが上がりにくい
オブジェクト指向自体が仕様変更に柔軟に対応するための手法ではあるものの、その手法が必要になった実害を理解するという点に興味が湧いた。
今回は「なぜ技術的負債が起こってしまうのか?」という部分を逆説的に探ってみる
技術的負債とは
コードをはじめて出荷することは、借金をしに行くようなものだ。
少しの借金なら、リライトによりそれを埋め合わせることを促し、開発を加速することになる。
危険なのは、この借金が返されなかったときだ。
その適切ではないコードのために費やされた時間はすべて、借金の利子にあたる。
http://c2.com/doc/oopsla92.html
- WikiWikiの発明者で著名なプログラマとして知られるウォード・カニンガム氏が1992年に使ったのが原典
- 借金が生まれる理由 = 納期から逆算した工数の見積もり以上に発生する工数
- そもそも期限が無い(かぎりなく緩い)プロジェクトならば工数の増加は時間が許す限りマイナスにはならない
何故、利子が発生してしまうか?
- 利息と元本が投資の利回りよりも低ければ、負債自体は経済的に無責任ではない(その時点では実質的な損失ではない)
- 価値ある技術を確立しても、明日の生産性向上の実現には役立たず、生産性が低いプロジェクトは顧客の需要や経営者の期待値を満たせない
- 技術的負債は開発陣にとっては"返さなければならない利子"でも財務的負債とは違い、返済しなくてもよい負債(ケースによっては返済する事自体が無駄)と判断されがち
- つまり多くのケースは組織全体に作用する財政債務的なステークホルダーに認識されない問題であり、技術者側の問題意識の枠を出にくい
- 問題にならない問題点より、利益が出ないプロジェクトの方が問題なので、可能な限り早く利益を生まなければならない
何故、負債であることに気付けないのか?
技術者側
- 負債を返済する対象がコードを書いた本人ではなく、後にメンテナンスする開発者であるケースが多い(これが最も厄介だと思われる)
- コピペや不透明なモジュールによる実装など書いた本人による再現性が低いかつ、第三者もその部分の特定や見抜きにくいソースも必ず存在する
- 書かれたコード自体が高品質なものでも、元々の設計が悪い場合もある
- 定期的にメンテナンスされないコードは、全体の影響力の見積もりやライブラリのサポート状況の問題も抱える
管理者 or 経営者側
- 必ずしも決まったスケジュールまたは決まった額を返済する必要がないので、返せない(もしくは改修点が手持ちのリソースを超えたと判断した)段階にならないと具体的な改善点として認知させにくい
- 技術者よりも実際の返済をする担当者の問題が、管理者や組織全体の問題には発展しにくいため、盲目的に他人事になりやすい
- いざ発生した場合でも「技術者の努力不足」的な個人やチーム単位の曖昧な減点式な評価になりやすく問題視や可視化されにくい
その他
- 利子自体を払っているのが組織の誰でもなくユーザーである場合がある(メンテナンスによるサービスを利用できない期間の発生など)
負債を返済のための戦術
戦略による過ちは戦術により補い難く、戦術による過ちは戦闘により補い難し
- 言語選定やアーキテクチャ設計時点の戦略ミスは、開発者のスキルやツールによる戦術ではカバーしきれず、戦術で取り返せない戦況(先の見えないタスクの数々)は開発者のモチベーションそのものに影響し、戦いがどんどん不利になるのビジネス界ではよく聞く言葉
- ほとんどのケースは始まってしまった戦略(プロジェクト)をやり直せる機会はまず無いので、より効果が高い戦い方を学び、実践しなければならない
- 学習
- 外交手腕
- ほとんどの問題あるコードは身内から作成されるものであるから、その指摘を後々引きずらない様にする配慮するコミュニケーション能力
- 自身の過去の失敗談などで個人攻撃を避けて具体的な改善案を提案する
- コードに問題が起きたことが悪いのではなく、今後どう改善を図るかを働きかける
- 形にする
- 技術的負債がソフトウェアのどこで発生しているのかを見極める取り組み
- 多くの場合が実装レベルよりも前の設計レベルから生まれる負債のため、変更のコストが最も高くつく部分であり、認知できないアーキテクチャーが生まれない様な働きかけ
- モックアップやプロトタイプを作って計画的な構造を可視化させる
- ビジネス動作のカプセル化やモデルとビューの密結合の緩和などで連鎖的な不具合を避ける
- テストによる近接航空支援
- コードを変更する = 新たなエラーを生み出す可能性があるため、テストを行うことで間違いに気付く可能性を上げる
- とはいえテストのコストが、負債を取り除くメリットをはるかに上回る可能性もある
- テストを書くよりもコードを書き直す方が良い場合もあるので分析も大事
- 識別可能な効果の計測
- リクエスト処理のレスポンス時間の計測などでコードの見た目などでは測りづらい&改善すべきと優先順位がつけやすい点を見つける基準を確立させる
- 改善専用の流れ
- 開発者がすべての担当をすることは現実的ではないため、新機能開発と負債改善専門の担当者を分断できるチームを作れる環境を作る
- チーム全員 (変更するすべての開発者とテスト担当者) が、実施する改善作業に関与するのが一番良いとされる(現状を把握する役割と引き継ぐ役割を常に交代させながら回ることで知識が全体に循環する)
- 新機能を開発しながら、既存のコードを改善する場合、コスト対メリットの分析と改善計画を立てる中で検討
- 繰り返し
- 上記の戦術を繰り返しながら新たな負債を作り出していかない働きかけ
- 返済した負債以上に新たな負債を作り出していないことを確認するために定期的に学習した内容を取り入れて負債の温床になるケースやパターンを抽出していく
- MTG時に負債部分の洗い出しや優先順位を付けることで、チームの同意を得やすくする空気やリリースまたはプロジェクトの進行を遅らせる可能性のある負債の返済を優先しやすい
- 改善後の状態維持
- 7の働きかけにより、組織が技術的負債の温床を抱えさせない文化づくり
- 組織が長期にわたる持続性を意識して考えられるための期待値を設定する(負債改修に発生したコストを具体的に数値化させるなどして、負債が生まれるデメリットを理解させる)
- 完成させるスタイルのコードよりも、品質が高いコードの方が時間がかかる事への理解など
- 共同作業
- 取り組みに対するチームの支持を取り付け、必ず全員が結果に関心を寄せるようにする働きかけ
- 技術的負債は無知であるか非現実的な期待による人間の問題であり、それを後始末をするのも人間なので全体責任という意識を持たせる
- 「予定通り達成させる」や「常にテストを行う」などの目標設定は根本的な解決にならない場合もある
- 全員がオブジェクト指向の分析と設計の基本を理解するといった初歩的な事の方が効果が高い事もある
技術的負債に対する選択肢
それでもゼロにはならない負債と、完済自体がプロジェクトの目的ではないため、負債コードを抱えることを前提に共存をしていく事も選択肢の1つとして示されている
技術的負債を管理する
- 負債の払い戻し
- 技術的負債だと思われるコード、フレームワーク、プラットフォームをリファクタリングするか、置き換える
- 負債の転換
- 現時点で実行できる解決策を「完璧ではないけれども良い」解決策と置き換える
- 完璧な解決策を模索する事自体にもコストが発生するならば
- 利息のみ支払う
- コードとともに生きる。リファクタンリングは、それほど良くないコードに取り組むよりも高くつくから
まとめ
価値ある技術への歩みは、最初は遅々として進まず、厳しい道程になる可能性があります。
粘り強い取り組み、継続的な学習、なによりも本気の姿勢が、厳しい時期を耐えしのぎ、負債で身動きがとれなくなったコードを黒字に転換する唯一の道です
- 関わる人間が趣味以上(生活費の元となる)のプロジェクトになった時点で、期限内に利益を出さなければならない宿命
- 結局のところ技術的負債は起こるべくして起こる自然現象であり、技術的負債が常に悪い訳ではない
- すべての場合に負債を完全に支払わなければならないものではないこと(殆どの人は家を買うためにローンという手段で利子と返済義務を抱えながら生活しており、返済できてる間は個人の信用問題には発展しにくい)
- ただその時が来た際に致命傷をさけるために少しでも勉強しとけという当たり前の事に着地
- とはいえ、その取り組み自体が将来的にはコストを増やす場合もあるので、支払うもの(コストや労力やリスク)はその都度、ビジネス上で判断し決定する