レガシーコードからの脱却

2019年10月4日のAWS DevDayで登壇した際のスライドです。

1. レガシーコードからの脱却 2019/10/4 株式会社アトラクタ 吉羽龍太郎 (@ryuzee)
2. 株式会社アトラクタについて ✤ 社名:株式会社アトラクタ 英文表記:Attractor Inc. / https://www.attractor.co.jp ✤ 設立:2016年12月 ✤ 所在:東京都港区 ✤ 開発プロセスに関するコンサルティングやトレーニングを提供 ✤ アジャイル開発 / DevOps / チーム育成 / クラウドコンピューティング / ドメインモデリングなどが専門領域
3. 登壇 各種イベントでの登壇 コーチング オンサイト トレーニング アジャイル開発やDevOps に関するオンサイトコーチ ング アジャイル開発や組織づくり に関するオンサイト トレーニング 認定研修 認定スクラムマスター研修 Suitable for all categories 等の主催 business and personal 執筆・翻訳 技術書やドキュメントの 執筆や翻訳 などなど
4. 自己紹介 ✤ 吉羽龍太郎 (@ryuzee) ✤ 株式会社アトラクタ取締役CTO/アジャイルコーチ ✤ ✤ 野村総合研究所、Amazon Web Servicesなどを経てアトラクタを創業 開発プロセス/アジャイル開発/DevOps/クラウドコンピューティングが専門 ✤ Scrum Alliance Certified Team Coach (CTC) ✤ Microsoft MVP for Azure
5. 著書・訳書(買ってね)
6. 新刊 ✤ レガシーコードからの脱却 ―ソフトウェアの寿 命を延ばし価値を高める9つのプラクティス ✤ 2019/9/19 発売 今日はこちらの話をします
7. レガシー本といえば
8. レガシーコードとは? ✤ 『レガシーコード改善ガイド』による定義 ✤ レガシーコードとはテストのないコード ✤ 「テストのないコードは悪いコードである。どれだけうまく書かれているかは関 係ない。どれだけ美しいか、オブジェクト指向か、きちんとカプセル化されてい るかは関係ない。テストがあれば、検証しながらコードの動きを素早く変更する ことができる。テストがなければ、コードが良くなっているか悪くなっているの かが本当にはわからない」 ✤ きれいなコードは有益だが、それだけでは不十分
9. レガシーコードとは ✤ 『レガシーソフトウェア改善ガイド』による定義 ✤ 保守または拡張が困難なコード ✤ 「保守または拡張が困難な既存のプロジェクトなら、なんでもレガシーと呼ぶこ とにしている。ここでの話題は、単にコードベースだけではなく、プロジェクト全 体であることに注意していただきたい」
10. レガシーコードとは ✤ つまり定義はさまざま ✤ 本セッションでは以下のように定義する ✤ ✤ 理由は問わず修正、拡張、作業が難しいコード ✤ つまり保守に多額のお金がかかる 同じ用語を使っていても、中身の認識に相違がでることが多い ✤ ✤ 議論のときはまず共通認識は何かを確認するとよい レガシーコードがさまざまな方法で生み出された理由は、コードの品質は重要では なくソフトウェアが何をするかだけが重要だと考えてしまったことにある
11. ソフトウェアと変更 変更する 挑戦? 成長 使われない 使われる 塩漬け? 完成? 変更しない
12. 使われるソフトウェア ✤ ✤ 使われるソフトウェアは変更が必要になる ✤ 必要な変更をすべて予測するのは無理 ✤ よって変更可能となるように書くべき ✤ その逆がレガシーコード(修正、拡張、作業が難しいコード) ✤ 必要になったときに対応できるエンジニアリングプラクティスを身に付ける そもそもソフトウェアの保有コストを下げたい
13. リリース後のバグ修正にはとてつもない時間がかかる 問題が見つかったフェーズ 修正までの時間 要求や設計 5分 コードやユニットテスト 15分 結合テストやシステムテスト 1時間 ベータテスト 2時間 リリース後 1日 ✤ 『ソフトウェアの成功と失敗』によると、開発者の時間の半分以上が、過去にやった仕事の手直し ✤ コードを扱いやすくして、保守コストを大幅に下げる方法を見つけなければいけない ✤ ソフトウェアの保有コストを下げたいなら、開発方法に目を向けなければいけない
14. コードを最初から変更可能となるように書く つまり、レガシーコードを最初から作らないようにする
15. ではどうすればいいのか? → 開発プロセスに着目する
17. Scrum
18. エクストリームプログラミング(XP) 初版(1999) 【12】 2nd Edition(2004) 【24】 現在 【19】 主要プラクティス (13) 導出プラクティス (11) 共同のプラクティス (4) 管理者のプラクティス (5) 計画ゲーム 全員同席 本物の顧客参加 イテレーション 責任の受け入れ 短期リリース チーム全体 インクリメンタルなデプロイ 共通の用語 援護 メタファ(比喩) 情報満載のワークスペース チームの継続 オープンなワークスペース 四半期ごとの見直し シンプルな設計 いきいきとした仕事 チームの縮小 ふりかえり ミラー テスト ペアプログラミング 根本原因分析 リファクタリング ストーリー コードの共有 開発のプラクティス (6) ペアプログラミング 週次サイクル コードとテスト テスト駆動開発 顧客のプラクティス (4) 共同所有 四半期サイクル 単一のコードベース ペアプログラミング ストーリー 継続した統合 ゆとり デイリーデプロイ リファクタリング リリース計画 40時間労働 10分ビルド 交渉によるスコープ契約 ソースコードの共同所有 受け入れテスト オンサイトのユーザ(顧客) 継続的インテグレーション 利用都度課金 継続的インテグレーション 短期リリース コーディング規約 テストファーストプログラミング インクリメンタルな設計 最適なペース YAGNI
19. 共同のプラクティス 開発のプラクティス 管理者のプラクティス 顧客のプラクティス XP Scrum 反復 スプリント 共通の用語 (XPを活用) 開けた作業空間 (XPを活用) 頻繁なふりかえり スプリントレトロスペクティブ テスト駆動開発 (XPを活用) ペアプログラミング (XPを活用) リファクタリング (XPを活用) ソースコードの共同所有 (XPを活用) 継続的インテグレーション (XPを活用) YAGNI (XPを活用) 責任の受け入れ コミットメント 援護 スクラムマスター 四半期ごとの見直し スプリントレビュー ミラー デイリースクラム、スクラムボード 最適なペースの仕事 (XPを活用) ストーリーの作成 プロダクトバックログ リリース計画 スプリントプランニング 受け入れテスト 受け入れ基準 短期リリース リリース判断可能なインクリメント
20. ソフトウェアが生み出す成果を決める要素 問題設定力 開発力 チーム力 ✤ 適切な問題設定 ✤ ドメイン知識 ✤ 開発プロセス習熟 ✤ 明確なビジョン ✤ アーキテクチャ設計力 ✤ 心理的安全性 ✤ マーケットの理解 ✤ 開発言語 ✤ 透明性 ✤ 取捨選択 ✤ 性能 ✤ 検査と適応 ✤ 良いプロダクトバックログ ✤ セキュリティ ✤ ムダをなくす ✤ 優先順位付け ✤ インフラストラクチャー ✤ 学習 ✤ ステークホルダー管理 ✤ 自動化 ✤ リーダーシップ ✤ リスク・コスト管理 ✤ 品質・テスト ✤ オーナーシップ ✤ … ✤ … ✤ …
21. レガシーコードを最初から作らないようにするには 具体的にはどうすればよいか?
22. レガシーコードを作らない9つのプラクティス 1. やり方より先に目的、理由、誰のためかを伝える 2. 小さなバッチで作る 3. 継続的に統合する 4. 協力しあう 5. CLEANコードを作る 6. まずテストを書く 7. テストでふるまいを例示する 8. 設計は最後に行う 9. レガシーコードをリファクタリングする ScrumとXPからプラクティスを抽出。 全部やらなければいけないわけではないが 各項目は相互に関係性がある
23. ✤ 今日はそのうちいくつかを紹介します
24. 1 やり方より先に目的、理由、誰のためかを伝える
25. 役割の違い ✤ プロダクトオーナーの責任 ✤ 開発チームの責任 ✤ ビジネス価値を最大化する ✤ リリース判断可能なプロダクトを作る ✤ プロダクトビジョンを周りに理解させる ✤ 設計、開発、テストをする ✤ プロダクトの結果責任 ✤ 決められた品質を満たす ✤ 合意したプロダクトバックログ項目を完成 させるように最善を尽くす ✤ プロダクトバックログの順番の最終決定 ✤ ステークホルダーをマネージする ✤ プロダクトオーナーにフィードバックする ✤ 予算を管理する ✤ 集中して仕事に取り組む ✤ リリース日を決める ✤ 問題があればそれを明らかにする ✤ 開発チームの成果物の受け入れ可否 ✤ 常に改善する など… など…
26. WhatとHowを分離する ✤ 何をほしいか、なぜ欲しいか(What)は顧客やプロダクトオーナーの領域 ✤ やり方は開発者の領域(How) ✤ 物事のやり方は1つではなく、やり方ごとにトレードオフがある ✤ やり方を明示されると選択や交渉の余地が減る ✤ 結果として手続き的なコードになりがち ✤ 双方が創造的に協調することで、無駄な時間や機能が減る ✤ 作る上で重要なのは、まず「コンテキスト」を共有・理解すること
27. ユーザーストーリー ✤ 「何が」「なんのために」「誰のために」存在するかを1文で表したもの ✤ (例) 映画ファンとして、チケットをオンラインで購入したい。そうすれば劇場で 列に並んで待つ必要がない。 ✤ 1つの機能について、1つの種類のユーザーのために、1つの理由を語る
28. ユーザーストーリー ✤ 機能について会話できるくらいの辛うじて十分なドキュメント(仕様書ではない) ✤ 会話によってソフトウェアを作るための理解を深める ✤ 開発プロセスを円滑にするのは会話 ✤ 知識は詳細なドキュメントではなく、コード(テストも含む)にまとめるべき ✤ ストーリーが限定的であることで、テスト可能になる (受け入れ基準と自動化) ✤ ✤ 実例によるふるまいのテストが可能に シンプルに始めて追加はあとで行う (=> 2. 小さなバッチで作る) ✤ 漸進的に進めることで、良い設計が浮かび上がってくる
29. 2 小さなバッチで作る
30. タイムボックスとスコープボックス ✤ ✤ タイムボックス ✤ 固定の時間の中でタスクに取り組む ✤ タスクの分割になれるまでは機能しやすい ✤ ScrumやXP 長い期間で大きなウソをつくのではなく、短 いイテレーションの中で小さなウソをつく スコープボックス ✤ 時間を重視せず、ストーリーやタスクなどの作業単位で終わらせる ✤ 作業単位が比較的均一で小さい場合に選択 ✤ カンバン
31. QCDSの何を調整するのか ✤ スコープと時間を柔軟に考える ✤ リソースという単語は人間には適用できない ✤ 人月の神話 ✤ 人を追加すると、やりとりが増えて速度が落ちていく ✤ 品質を犠牲にすると、あとから辛くなる ✤ スコープを調整し、価値ある機能から順番に作る ✤ (バックログ化)
32. ケイデンス、リソース効率、プロセス効率 ✤ ✤ ケイデンス(リズム)が長くなると、リソース効率化を目指しやすい ✤ 同時に着手するものが増える / タスク切換えが増える ✤ 役割分担が増える ✤ 最後にテストフェーズや統合フェーズが増える ケイデンスを短くすると、プロセス効率があがる ✤ ✤ リリースサイクルのリズムが プロセスを制御する 同時に着手するものを減らす必要(つまり1個流しのようなもの) プロセス内の作業の量を減らすと、システムが安定する
33. モブプログラミング = 究極の1個流し https://www.youtube.com/watch?v=p_pvslS4gEI https://www.youtube.com/watch?v=dVqUcNKVbYg
34. ソフトウェアの評価 ✤ ✤ ソフトウェアの評価は、顧客にとって価値あるものにもとづいて評価すべき ✤ 価値は「完成」して初めて価値になる ✤ 本当に価値が実現できているか? ✤ 価値実現までの時間が期待したとおりか? ✤ 部分最適化を避ける 効率より効果
35. フィードバックサイクル ✤ ✤ 小さなバッチのほうがフィードバックの回数は増える ✤ スプリントレビュー、レトロスペクティブ、継続的統合… ✤ 顧客やPOと同席することで、フィードバックの回数を増やす ✤ ビルドを高速化する フィードバックへの対応をサポートする文化が必要 ✤ 価値やリスクに応じて取捨選択する ✤ フィードバックをバックログに取り込む フィードバックによって価値を高める
36. 5 CLEANコードを作る
37. よくないコードの特徴 (1) 名称 概要 重複したコード 同じコードが2箇所以上に存在する 長すぎるメソッド ルーチンは長くなればなるほど理解しにくくなる 巨大なクラス クラスが多くの仕事をしすぎている 長すぎるパラメータリスト 手続き型になっており、変更に弱い 変更の偏り 1つのクラスが別々の理由で何度も変更される 変更の分散 変更するたびに複数のクラスを書き換える必要がある 特性の横恋慕 自分のクラスよりも他のクラスのメソッドをたくさん呼び出している データの群れ 数個のデータがグループとなってあちこちで使われる 基本データ型への執着 基本データを扱う手続きがクラス外に散らばってしまいやすい スイッチ文 スイッチ文は重複コードを生み出しやすい パラレル継承 新たなサブクラスを定義するたびに他のサブクラスも必要になる 『新装版 リファクタリング―既存のコードを安全に改善する』より
38. よくないコードの特徴 (2) 名称 概要 怠け者クラス 特に役に立っていないクラスは除去する 疑わしき一般化 いつか必要になる、と考えて作られたもの 一時的属性 インスタンス変数の値が特定の状況しか参照されない メッセージの連鎖 受け取ったメッセージの別オブジェクトへの送信が連鎖する 仲介人 メソッドの大半が別のオブジェクトへの移譲になっている 不適切な関係 クラス同士が仲が良すぎる クラスのインタフェース不一致 処理は同じで呼び出し方法だけが違う 未熟なクラスライブラリ 第三者による修正が不可能なライブラリ データクラス 属性やセッター、ゲッターしかもたないクラス。過剰にアクセスされやすい 相続拒否 サブクラスが親のメソッドを継承しない コメント 過剰なコメント 『新装版 リファクタリング―既存のコードを安全に改善する』より
39. ✤ よくない例をあげると数限りなし… ✤ ✤ チームで理解して、よくない例を避ける必要はある 一方で、従うべきガイドラインも必要
40. CLEANコードとは? ✤ 「オブジェクトは、特性が明確に定義されていて、はっきりした責務を担い、実装は隠 ぺいされているべきだ。オブジェクトの状態は自分自身が管理し、オブジェクトの定 義は一度だけにすべきだ。 」
41. CLEANコードとは? ✤ Cohesive (凝集性) ✤ Loosely Coupled (疎結合) ✤ Encapsulated (カプセル化) ✤ Assertive (断定的) ✤ Non redundant (非冗長) これらはテストしやすさと 密接な関係がある
42. Cohesive(凝集性) ✤ それぞれの部品は1つのことだけを扱う ✤ クラスが1つの責任に集中する ✤ つまり名前をつけられるアイデアや概念になる ✤ ✤ 名前重要 複雑なものはコンポジション ✤ 概念をネストする
43. Loosely Coupled(疎結合) ✤ オブジェクト間の関係を明確な意図をもった状態に保つ ✤ サービスを直接呼び出すのではなく中間層を経由する ✤ ✤ コードにつなぎ目を入れておく 全てが悪なわけではない ✤ 意図的な結合と不慮の結合 ✤ 不慮の結合はコード品質が低いときによく現れる ✤ なんでもできる神APIを避ける ✤ 再利用という名目のもとにコードの品質を犠牲にしてはいけない
44. Encapsulated(カプセル化) ✤ 実装の詳細は外から見えなくなっている ✤ オブジェクト指向の最大の利点 ✤ インターフェースと実装を切り離す ✤ アウトサイドインプログラミング ✤ ✤ コンシューマー(呼び出し側)の観点で機能を設計する ✤ 何をやっているかを示す名前をつけて、どう動くかは隠す ✤ 全体と詳細を行き来するが、まずは全体から始める 公開しているものを隠すより、非公開のものを後から公開するほうが簡単
45. Assertive(断定的) ✤ 自分自身の責任は自分で管理する ✤ オブジェクトがフィールドなどを持つなら、それらを管理するふるまいも持つ ✤ 好奇心旺盛すぎてはいけない ✤ ほかのオブジェクトの状態を頻繁に参照するのを避ける ✤ 特性の横恋慕、不適切な関係
46. Non redundant(非冗長) ✤ 同じことを繰り返してはいけない(DRY原則) ✤ 意図的に冗長性を組み込むことはあるが、それはあくまで意図による ✤ 冗長さは状態やふるまいだけに限らない ✤ ✤ 冗長なテスト、冗長な概念、冗長な解釈、冗長なプロセス… コードが違うから冗長でないというわけではない
47. CLEANのメリット テストしやすさが 設計や実装の品質を計測する 基準になる ✤ (C) 凝集性があれば、理解もバグを見つけるのも簡単 ✤ (L) 結合度が低ければ、副作用が減り、テストや再利用、拡張が簡単 ✤ (E) カプセル化されていれば、呼び出し元が実装の詳細を知らなくてもよいように 維持できる。あとから変更するのも簡単 ✤ (A) 断定的であることは、ふるまいを配置する場所が依存データがある場所である ことを示す ✤ (N) 冗長でなければ、バグ修正や変更は1箇所で1回だけやればよい
48. CLEANとテストでバグ発見の時期をシフトレフトする Capers Jones, Applied Software Measurement: Global Analysis of Productivity and Quality
49. 明日のベロシティのために今日品質を上げる ✤ 速度は日々の積み重ねによってしか実現できない ✤ CLEANコードは理解しやすく取り組みやすい ✤ 高品質のコードは拡張しやすい ✤ 高品質のコードはデバッグしやすく保守しやすい ✤ 結果的に総所有コストが下がる ✤ 逆の状態が「技術的負債」
50. https://flickr.com/photos/joanbrebo/38646019434
51. https://flickr.com/photos/joanbrebo/38646019434 すばやく働くということは「きれいに働く」ということ
52. これって5Sだった ✤ 整理 => いらないものを捨てる ✤ 整頓 => 決められた物を決められた場所に置き、いつでも取り出せる状態にする ✤ 清掃 => 常に掃除をする ✤ 清潔 => 3S(上の整理・整頓・清掃)を維持し職場の衛生を保つ ✤ 躾 => 決められたルール・手順を正しく守る習慣をつける
53. 8 設計は最後に行う
54. あくなき追求 ✤ ソフトウェアは書く回数より読む回数の方が多い ✤ テストがあれば安全にコードをクリーアップできる ✤ コードが動作して、テストのサポートがある状態から設計を良いものにする ✤ いかにバグを取るかではなく、いかに保守しやすいかという設計に注意を払う ✤ ✤ 変更しにくいコードをみつけて、それらを取り除いていく ✤ ✤ 良いコードとは変更しやすいコード カプセル化の欠如、継承の過度の利用、具体的すぎる実装、インラインコード、依存 性、自身によるオブジェクトの新規生成 コーディングとクリーニングは分離する
55. 持続可能な開発 死んだコードを消す コメントアウトされたコード、呼び出されないコード、使わない機能は全部消 す。存在しても注意が散漫するだけ 名前を更新する メソッドやクラスの名前を意図のわかる良い名前に更新する。 開発を進めて 分かったことが増えると機能が変わる。今やっていることを反映する名前に 判断を集約する 判断を集約し、1 回だけで済むようにする。冗長なコードも削除できる 抽象化する すべての外部依存性には抽象を作成し利用する。モデルに欠けているエンテ ィは作成する クラスを整頓する 利用範囲においてモデ ルが完全であることを確認する。そうすることで、正し いふるまいと正しい属性を持つようにクラスを整頓できる
56. 持続可能な開発 死んだコードを消す コメントアウトされたコード、呼び出されないコード、使わない機能は全部消 す。存在しても注意が散漫するだけ 名前を更新する メソッドやクラスの名前を意図のわかる良い名前に更新する。 開発を進めて 分かったことが増えると機能が変わる。今やっていることを反映する名前に 抽象化する すべての外部依存性には抽象を作成し利用する。モデルに欠けているエンテ ィは作成する クラスを整頓する 利用範囲においてモデ ルが完全であることを確認する。そうすることで、正し いふるまいと正しい属性を持つようにクラスを整頓できる ソフトウェア開発はあとから分かることが多い それを随時反映していく 判断を集約する 判断を集約し、1 回だけで済むようにする。冗長なコードも削除できる
57. レガシーコードからの脱却 (まとめ) ✤ 使われるソフトウェアは変更が必要になるので、コードは変更可能になるように書くべき。そうするこ とで保有コストが下がる。開発方法にも目を向ける必要がある ✤ プロダクトオーナーは、目的、必要な理由、誰のためのものかが伝わるようにする ✤ 要求は意味のある小さな単位にして、重要なものから作る ✤ 開発チームは小さなバッチで作っていく。作る際は開発チームやプロダクトオーナーと協力する ✤ コードを書くときはテスト駆動開発。テストではふるまいを例示する。コードはテストコードも含めて CLEANを満たすように作っていく。レッド/グリーン/リファクタ。凝集性と名前はとくに重要 ✤ できあがったものは1つづつ統合していき、常にデプロイできるようにしておく ✤ 一度作ったら終わりではなく必要に応じて設計を見直したりコードを見直したりする。良い設計は創発 する。この時テストがあることが重要になる
Attractor Inc. Founder / CTO / Agile Coach / Certified Team Coach / Certified Scrum Professional / Certified ScrumMaster / Certified Scrum Product Owner Twitter : @ryuzee Web : https://www.attractor.co.jp/ Web : http://www.ryuzee.com/

Related Slides