Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

テスト駆動開発

472 views

Published on

テスト駆動開発のノウハウについて解説します。

Published in: Engineering
  • Login to see the comments

テスト駆動開発

  1. 1. テスト駆動開発(TDD)
  2. 2. TDDを始める
  3. 3. アジャイルを始める アジャ イル 2週間に一 度完成させ る 顧客に見 せる 顧客に常 駐してもら う 2週間単位 でしか要求 を受け付け ない 結果を約 束しない 個人での導入は難しいものが多い
  4. 4. TDDを始める 要求分析 基本設計 機能設計 詳細設計 コーディング 単体テスト システムテスト 受け入れテスト 結合テスト
  5. 5. 要求分析 基本設計 機能設計 詳細設計 コーディング 単体テスト システムテスト 受け入れテスト 結合テスト TDDを始める
  6. 6. TDDはなぜ行うか?
  7. 7. なぜTDDを行うか? 楽にプログラミングをしたいからです!
  8. 8. 楽にプログラミングするには バグが少なく高品質な実装 リファクタリングによる高品質な設 計 考え抜かれた開発手法の手順
  9. 9. 品質 そもそもなぜ品質は必要か?
  10. 10. 品質 楽に生産するためですよ?
  11. 11. ウォーターフォール時代 要件定義 基本設計 詳細設計 実装 テスト 運用 3日 3ヶ月
  12. 12. アジャイル時代 30秒 3時間
  13. 13. 自動テスト 自動化 生産性 の向上
  14. 14. 即応性 楽しさ 生産性 品質 複雑さ ウォーター フォール 開発手法
  15. 15. アジャイル 楽しさ 生産性 品質 複雑さ ウォーター フォール 即応性
  16. 16. アジャイルを使う場合のTDD
  17. 17. アジャイルを使う場合のTDD アジャイルでは顧客を大切にしています 2週間に一度できた機能を顧客に見せる 変更要求は積極的に受ける できれば顧客に常駐してもらう
  18. 18. アジャイルを使う場合のTDD • 出来るならやっていたのでは?ウォーターフォールでは顧客 を大切にしていなかった? • 無理だから断っていたのでは?顧客の要求を全部聞いてい たら開発が炎上 • テスト駆動開発(TDD)機能変更が非常にやりやす い開発手法が不可欠
  19. 19. TDDの呼び方
  20. 20. TDDと似た手法 テストファースト テスト駆動開発(TDD) 振る舞い駆動開発(BDD)
  21. 21. TDDと似た手法 テストファースト テスト駆動開発(TDD) 振る舞い駆動開発(BDD)
  22. 22. TDDの呼び方 • テストを最初にやればいいんでしょ? テストファースト • なんだかんだ言ってテスト技法なんだよ ね?テスト駆動開発(TDD) • 振る舞いが開発を駆動するんです!! 振る舞い駆動開発(BDD)
  23. 23. TDDの手順の詳細解説 レッド・グリーン・リファクタリング
  24. 24. 作業の流れ レッド まず自動テストを書く グリーン テストが成功する最小限のプログラムを書く リファクタリング 機能を追加変更せず、単純作業の繰り返しで 内部設計をわかりやすくする。
  25. 25. TDDのサイクル レッド グリーン リファクタリ ング
  26. 26. TDDのサイクル レッド グリーン リファクタリ ング レッド
  27. 27. TDDのサイクル レッド グリーン リファクタリ ング グリーン
  28. 28. TDDのサイクル レッド グリーン リファクタ リング リファクタリ ング
  29. 29. TDDのサイクル レッド グリーン リファクタリ ング レッド
  30. 30. TDDのサイクル レッド グリーン リファクタリ ング グリーン
  31. 31. TDDのサイクル レッド グリーン リファクタ リング リファクタリ ング
  32. 32. TDDのサイクル レッド グリーン リファクタリ ング レッド
  33. 33. TDDのサイクル レッド グリーン リファクタリ ング グリーン
  34. 34. TDDのサイクル レッド グリーン リファクタ リング リファクタリ ング
  35. 35. TDDのサイクル レッド グリーン リファクタリ ング
  36. 36. 手順を説明
  37. 37. TDDの手順を説明 実際にTDDで作ってみます CSSを組み立てるDSL 小規模だが一部面倒 C#で
  38. 38. DSLの設計 DSL 生成 クラス CSS
  39. 39. DSLの設計 DSL 生成 クラス CSS ① 説明順
  40. 40. DSLの設計 DSL 生成 クラス CSS ①② 説明順説明順
  41. 41. レッド [Test] public void 指定したPathがプロパティとして取得できます() { var tested = new CssFile(@"C:File1.css"); Expect(tested.Path, Is.EqualTo(@"C:File1.css")); }
  42. 42. レッド public class CssFile { public string Path { get; } public CssFile(string path) { } }
  43. 43. public string Path { get; } public string Path { get { return @"C:File1.css"; } } グリーン
  44. 44. レッド[Test] public void 指定したPathがプロパティとして取得できます() { var tested = new CssFile(@"C:File1.css"); Expect(tested.Path, Is.EqualTo(@"C:File1.css")); } public void 指定したPathがプロパティとして取得できます() { var tested = new CssFile(@"C:File1.css"); Expect(tested.Path, Is.EqualTo(@"C:File1.css")); var tested2 = new CssFile(@"C:File2.css"); Expect(tested2.Path, Is.EqualTo(@"C:File2.css")); }
  45. 45. public string Path { get; set; } public CssFile(string path) { Path = path; } public string Path { get { return @"C:File1.css"; } } public CssFile(string path) { } グリーン
  46. 46. public string Path { get; set; } リファクタリ ング public string Path { get; private set; }
  47. 47. レッド [Test] public void ToStringで基本的なCSSの出力ができます() { var tested = new CssStatement(); tested.Selectors = new[] { "H1" }; tested.Declarations = new Dictionary<string, string> { { "font-size", "12pt" } }; Expect(tested.ToString(), Is.EqualTo( @"H1 { font-size: 12pt }")); }
  48. 48. レッド public class CssStatement { public Dictionary<string, string> Declarations { get; set; } public string[] Selectors { get; set; } }
  49. 49. public Dictionary<string, string> Declarations { get; set; } public string[] Selectors { get; set; } public override string ToString() { return @"H1 { font-size: 12pt }"; } グリーン public Dictionary<string, string> Declarations { get; set; } public string[] Selectors { get; set; }
  50. 50. [Test] public void ToStringでセレクタの種類を見分けて出力に反映します() { var tested = new CssStatement(); tested.Selectors = new[] { "H2" }; tested.Declarations = new Dictionary<string, string> { { "font-size", "12pt" } }; Expect(tested.ToString(), Is.EqualTo( @"H2 { font-size: 12pt }")); } レッド
  51. 51. return $@"{Selectors[0]} {{ font-size: 12pt }}"; グリーン return @"H1 { font-size: 12pt }";
  52. 52. レッド public void ToStringで複数のセレクタを出力に反映します() { var tested = new CssStatement(); tested.Selectors = new[] { "H1", "H2" }; tested.Declarations = new Dictionary<string, string> { { "font-size", "12pt" } }; Expect(tested.ToString(), Is.EqualTo( @"H1, H2 { font-size: 12pt }")); }
  53. 53. return $@"{Selectors[0]} {{ font-size: 12pt }}"; グリーン return $@"{string.Join(", ",Selectors)} {{ font-size: 12pt }}";
  54. 54. public override string ToString() { return $@"{string.Join(", ",Selectors)} {{ font-size: 12pt }}"; } リファクタリ ング public override string ToString() { return $@"{CssForSelectors()} {{ font-size: 12pt }}"; } private string CssForSelectors() { return string.Join(", ", Selectors); }
  55. 55. [Test] public void ToStringでプロパティの種類を出力に反映します() { var tested = new CssStatement(); tested.Selectors = new[] { "H1", "H2" }; tested.Declarations = new Dictionary<string, string> { { "line-height", "12pt" } }; Expect(tested.ToString(), Is.EqualTo( @"H1, H2 { line-height: 12pt }")); } レッド
  56. 56. return $@"{CssForSelectors()} {{ font-size: 12pt }}"; グリーン return $@"{CssForSelectors()} {{ {Declarations.Keys.First()}: 12pt }}";
  57. 57. [Test] public void ToStringで値を見て出力に反映します() { var tested = new CssStatement(); tested.Selectors = new[] { "H1", "H2" }; tested.Declarations = new Dictionary<string, string> { { "line-height", "10pt" } }; Expect(tested.ToString(), Is.EqualTo( @"H1, H2 { line-height: 10pt }")); } レッド
  58. 58. return $@"{CssForSelectors()} {{ {Declarations.Keys.First()}: {Declarations.Values.First()} }}"; グリーンreturn $@"{CssForSelectors()} {{ {Declarations.Keys.First()}: 12pt }}";
  59. 59. return $@"{CssForSelectors()} {{ {Declarations.Keys.First()}: {Declarations.Values.First()} }}"; return $@"{CssForSelectors()} {{ {Declarations.First().Key}: {Declarations.First().Value} }}"; リファクタリ ング
  60. 60. private string CssForDeclaration(KeyValuePair<string, string> delaration) { return $"{delaration.Key}: {delaration.Value}"; } リファクタリ ング
  61. 61. return $@"{CssForSelectors()} {{ {Declarations.First().Key}: {Declarations.First().Value} }}"; リファクタリ ング return $@"{CssForSelectors()} {{ {CssForDelaration(Declarations.First())} }}";
  62. 62. [Test] public void ToStringで複数の特性を出力に反映します() { var tested = new CssStatement(); tested.Selectors = new[] { "H1", "H2" }; tested.Declarations = new Dictionary<string, string> { {"font-size", "12pt" }, {"line-height", "10pt" } }; Expect(tested.ToString(), Is.EqualTo( @"H1, H2 { font-size: 12pt; line-height: 10pt }")); } レッド
  63. 63. return $@"{CssForSelectors()} {{ {string.Join(";rn ", Declarations.Select(delaration => CssForDeclaration(delaration)))} }}"; グリーン return $@"{CssForSelectors()} {{ {CssForDeclaration(Declarations.First())} }}";
  64. 64. public override string ToString() { return $@"{CssForSelectors()} {{ {CssForDeclarationCollection()} }}"; } private string CssForDeclarationCollection() { return string.Join(";rn ", Declarations.Select(delaration => CssForDeclaration(delaration))); } public override string ToString() { return $@"{CssForSelectors()} {{ {string.Join(";rn ", Declarations.Select(delaration => CssForDelaration(delaration)))} }}"; } リファクタリ ング
  65. 65. return string.Join(";rn ", Declarations.Select(delaration => CssForDelaration(delaration))); リファクタリ ング return string.Join(";rn ", from delaration in Declarations select CssForDelaration(delaration));
  66. 66. private string CssForDelaration(KeyValuePair<string, string> delaration) { return $"{delaration.Key}: {delaration.Value}"; } private string CssForDelarationCollection() { return string.Join(";rn ", from delaration in Declarations select CssForDelaration(delaration)); } private string CssForDelarationCollection() { return string.Join(";rn ", from delaration in Declarations select $"{delaration.Key}: {delaration.Value}"); } リファクタリ ング
  67. 67. [Test] public void ヘルパーを使ってCssが組み立てられます() { var tested = "H1".Css( font_size => "12pt", line_height => "10pt"); Expect(tested.ToString(), Is.EqualTo( @"H1 { font-size: 12pt; line-height: 10pt }")); } レッド
  68. 68. using CssWriter.Helpers; namespace CssWriter.Helpers { public static class ExtensionsForCssWriter { public static CssStatement Css( this string selector, params Func<string, string>[] decdeclarations) { return null; } } } レッド
  69. 69. var ret = new CssStatement(); ret.Selectors = new[] { "H1" }; ret.Declarations = new Dictionary<string, string> { {"font-size", "12pt" }, {"line-height", "10pt" } }; return ret; グリーンreturn null;
  70. 70. リファクタリ ング return new CssStatement { Selectors = new[] { "H1" }, Declarations = new Dictionary<string, string> { {"font-size", "12pt" }, {"line-height", "10pt" } } }; var ret = new CssStatement(); ret.Selectors = new[] { "H1" }; ret.Declarations = new Dictionary<string, string> { {"font-size", "12pt" }, {"line-height", "10pt" } }; return ret;
  71. 71. [Test] public void Helperを使ったCssの組み立てではセレ クターの種類を反映します() { var tested = "H2".Css( font_size => "12pt", line_height => "10pt"); Expect(tested.ToString(), Is.EqualTo( @"H2 { font-size: 12pt; line-height: 10pt }")); } レッド
  72. 72. return new CssStatement { Selectors = new[] { selector }, Declarations = new Dictionary<string, string> { {"font-size", "12pt" }, {"line-height", "10pt" } } }; グリーン return new CssStatement { Selectors = new[] { "H1" }, Declarations = new Dictionary<string, string> { {"font-size", "12pt" }, {"line-height", "10pt" } } };
  73. 73. [Test] public void Helperを使ったCssの組み立てでは複数 のセレクターが指定できます() { var tested = new[] { "H1", "H2" }.Css( font_size => "12pt", line_height => "10pt"); Expect(tested.ToString(), Is.EqualTo( @"H1, H2 { font-size: 12pt; line-height: 10pt }")); } レッド
  74. 74. public static CssStatement Css(this string[] selector, params Func<string, string>[] declarations) { return null; } レッド
  75. 75. return new CssStatement { Selectors = selector, Declarations = new Dictionary<string, string> { {"font-size", "12pt" }, {"line-height", "10pt" } } }; グリーンreturn null;
  76. 76. リファクタリ ング public static CssStatement Css(this IEnumerable<string> selector, params Func<string, string>[] declarations) { return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {"font-size", "12pt" }, {"line-height", "10pt" } } }; } public static CssStatement Css(this string[] selector, params Func<string, string>[] declarations) { return new CssStatement { Selectors = selector, Declarations = new Dictionary<string, string> { {"font-size", "12pt" }, {"line-height", "10pt" } } }; }
  77. 77. リファクタリ ング public static CssStatement Css(this string selector, params Func<string, string>[] declarations) { return Css(new[] { selector }, declarations); } public static CssStatement Css(this IEnumerable<string> selector, params Func<string, string>[] declarations) { return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {"font-size", "12pt" }, {"line-height", "10pt" } } }; } public static CssStatement Css(this string selector, params Func<string, string>[] decdeclarations) { return new CssStatement { Selectors = new[] { selector }, Declarations = new Dictionary<string, string> { {"font-size", "12pt" }, {"line-height", "10pt" } } }; } public static CssStatement Css(this IEnumerable<string> selector, params Func<string, string>[] decdeclarations) { return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {"font-size", "12pt" }, {"line-height", "10pt" } } }; }
  78. 78. [Test] public void Helperを使ったCssの組み立てでは特性を反映します() { var tested = "H2".Css( line_height => "12pt", font_size => "10pt"); Expect(tested.ToString(), Is.EqualTo( @"H2 { line-height: 12pt; font-size: 10pt }")); } レッド
  79. 79. グリーン public static CssStatement Css(this string selector, params Expression<Func<string, string>>[] declarations) { return Css(new[] { selector }, declarations); } public static CssStatement Css(this IEnumerable<string> selector, params Expression<Func<string, string>>[] declarations) { return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {declarations[0].Parameters.Single().Name.Replace('_', '-'), "12pt" }, {declarations[1].Parameters.Single().Name.Replace('_', '-'), "10pt" } } }; } public static CssStatement Css(this string selector, params Func<string, string>[] declarations) { return Css(new[] { selector }, declarations); } public static CssStatement Css(this IEnumerable<string> selector, params Func<string, string>[] declarations) { return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {"font-size", "12pt" }, {"line-height", "10pt" } } }; }
  80. 80. リファクタリ ング private static string GetParameterName(Expression<Func<string, string>> declaration) { return declaration.Parameters.Single().Name.Replace('_', '-'); }
  81. 81. return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {GetParameterName(declarations[0]), "12pt" }, {declarations[1].Parameters.Single().Name.Replace('_', '-'), "10pt" } } }; return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {declarations[0].Parameters.Single().Name.Replace('_', '-'), "12pt" }, {declarations[1].Parameters.Single().Name.Replace('_', '-'), "10pt" } } }; リファクタリ ング
  82. 82. リファクタリ ング return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {GetParameterName(declarations[0]), "12pt" }, {GetParameterName(declarations[1]), "10pt" } } }; return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {GetParameterName(declarations[0]), "12pt" }, {declarations[1].Parameters.Single().Name.Replace('_', '-'), "10pt" } } };
  83. 83. private static string GetParameterName(Expression<Func<string, string>> declaration) => declaration.Parameters.Single().Name.Replace('_', '-'); private static string GetParameterName(Expression<Func<string, string>> declaration) { return declaration.Parameters.Single().Name.Replace('_', '-'); } リファクタリ ング
  84. 84. [Test] public void Helperを使ったCssの組み立てでは値を反映します() { var tested = "H2".Css( font_size => "10pt", line_height => "12pt"); Expect(tested.ToString(), Is.EqualTo( @"H2 { font-size: 10pt; line-height: 12pt }")); } レッド
  85. 85. グリーン return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {GetParameterName(declarations[0]), declarations[0].Compile().Invoke("") }, {GetParameterName(declarations[1]), declarations[1].Compile().Invoke("") } } }; return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {GetParameterName(declarations[0]), "12pt" }, {GetParameterName(declarations[1]), "10pt" } } };
  86. 86. private static string GetValue(Expression<Func<string, string>> declaration) => declaration.Compile().Invoke(""); リファクタリ ング
  87. 87. return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {GetParameterName(declarations[0]), GetValue(declarations[0]) }, {GetParameterName(declarations[1]), declarations[1].Compile().Invoke("") } } }; return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {GetParameterName(declarations[0]), declarations[0].Compile().Invoke("") }, {GetParameterName(declarations[1]), declarations[1].Compile().Invoke("") } } }; リファクタリ ング
  88. 88. return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {GetParameterName(declarations[0]), GetValue(declarations[0]) }, {GetParameterName(declarations[1]), GetValue(declarations[1]) } } }; return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {GetParameterName(declarations[0]), GetValue(declarations[0]) }, {GetParameterName(declarations[1]), declarations[1].Compile().Invoke("") } } }; リファクタリ ング
  89. 89. return new CssStatement { Selectors = selector.ToArray(), Declarations = new Dictionary<string, string> { {GetParameterName(declarations[0]), GetValue(declarations[0]) }, {GetParameterName(declarations[1]), GetValue(declarations[1]) } } }; return new CssStatement { Selectors = selector.ToArray(), Declarations = declarations.ToDictionary( declaration => GetParameterName(declaration), declaration => GetValue(declaration)) }; リファクタリ ング
  90. 90. [Test] public void 指定したStatementsがプロパティとして取得できます() { var statements = new[] { new CssStatement() }; var tested = new CssFile(@"C:File1.css"); tested.Statements = statements; Expect(tested.Statements, Is.SameAs(statements)); } レッド
  91. 91. グリーン public class CssFile { public string Path { get; private set; } public CssStatement[] Statements { get; set; } public class CssFile { public string Path { get; private set; }
  92. 92. レッド [SetUp] public void SetUp() { if (File.Exists(@"C:File1.css")) { File.Delete(@"C:File1.css"); } } [Test] public void SaveでCssの保存ができます() { var tested = new CssFile(@"C:File1.css", new[] { "H1", "H2" }.Css( font_size => "12pt", line_height => "10pt")); tested.Save(); Expect(File.ReadAllText(@"C:File1.css"), Is.EqualTo( @"H1, H2 { font-size: 12pt; line-height: 10pt }")); }
  93. 93. レッド public class CssFile { public string Path { get; private set; } public CssStatement[] Statements { get; set; } public CssFile(string path) { Path = path; } } public class CssFile { CssStatement cssStatement; public string Path { get; private set; } public CssStatement[] Statements { get; set; } public CssFile(string path) { Path = path; } public CssFile(string path, CssStatement cssStatement) {} public void Save() {} }
  94. 94. グリーン public CssFile(string path, CssStatement cssStatement) : this(path) { this.cssStatement = cssStatement; } public void Save() { File.WriteAllText(Path, cssStatement.ToString()); } public CssFile(string path, CssStatement cssStatement) {} public void Save() {}
  95. 95. 実際のサンプル •https://github.com/potimarimo/m aterial-of-a-study- meeting/tree/master/CssWriter •履歴もだいたいそのままでおいてあります
  96. 96. 機能変更の手順
  97. 97. 機能変更 レッド まず動作が変更になった機能のテストを修 正する グリーン テストが成功する最小限のプログラムを書 く リファクタリ ング 機能を追加変更せず、単純作業の繰り返し で内部設計をわかりやすくする。
  98. 98. 機能変更 レッド まず修正したい機能について、テストを修正する グリーン 修正したテストが通るようにプログラムを修正する レッド 通らなくなったテストを精査し、変えるべきものは変える グリーン テストがすべて通るようにプログラムを修正する リファクタリ ング 機能を追加変更せず、単純作業の繰り返しで内部設計をわかり やすくする。
  99. 99. レッド・グリーン・リファクタリングの特徴
  100. 100. テストカバレッジ
  101. 101. テストカバレッジ 実コード テストコード レッド なし 失敗するケースの100% グリーン 100% 成功するケースの100% リファクタリング そのまま100% そのまま100%
  102. 102. テストカバレッジが100%にならない場合 テストのリファクタリング エラーになるケースが動かなく なっているかもしれない 100%にするために必要なケー スを消しているかもしれない リファクタリングでできたクラ スの単体テスト TDDの手順が使えず、ただ頑 張ってテストを書くしかない こちらにできたテストがあるから と元のテストを消してしまうと 100%ではなくなる可能性が
  103. 103. 各手順で考えるべきことと 考えてはいけないこと
  104. 104. 考えるべきこと レッド • APIの外部設計 • APIの使い勝手 グリーン • とにかくできるだけ早くテストが通るように実 装 リファクタリング • 内部設計 • いかにわかりやすいコードにするか
  105. 105. レッド • 実装方法 • 実装しやすいかどうか • テストの網羅性 グリーン • きちんとしたわかりやすい設計 • アルゴリズムの正当性 • ミスしていないことを注意深く確認する リファクタリ ング • 機能追加 • 機能変更 • ミスしていないことを注意深く確認する
  106. 106. を考えると 結局手順通りにも考えなくてはならないので無駄 手順に合わない時はまだ情報がそろっていない 手順に合わない時はまだ動作を確認できる環境がない 違う情報で二つ出した結論の整合性
  107. 107. アルゴリズムの正当性はいつ確認するか
  108. 108. アルゴリズムの正当性 リファクタリングで設計を整理している時に、足りないロジックは 目に見える レッドでそのロジックについてのテストを追加 グリーンで実装 リファクタリング
  109. 109. レッド・グリーン・リファクタリングの どれが一番重要か
  110. 110. レッド・グリーン・リファクタリングのどれが一 番重要か リファクタリング • 「リファクタリングはTDDのコアだっつ の」(マーチン・ファウラー) • 設計品質に直結
  111. 111. レッド・グリーン・リファクタリングのどれが 一番重要か レッド • 「レガシーコードとは、単にテストのない コードである」(マイケル・C・フェザーズ) • 一度足りなくなると挽回が難しい
  112. 112. レッド・グリーン・リファクタリングのどれが一 番重要か グリーン • 大事だと特に言われてはいないが、一回で もさぼると進まないはず • 息をするように大切
  113. 113. レッド・グリーン・リファクタリングのどれが一 番重要か 3つとも大事です!!! • 大事さの意味はそれぞれ違います。 • どれが一つ欠けても成り立たない。
  114. 114. リファクタリング不足の対処
  115. 115. 不足する場合 不足する場合 対処の容易性 レッド • テストを書くのをサボった • 最初から自動テストがない • サボった分だけ頑張る • テスタビリティを考慮していなければ 大変 グリーン • ありえない - リファクタリ ング • いつの間にか • 思いつかないでいるうちに • 不足していくと加速度的に大変に • ノウハウが必要
  116. 116. リファクタリングの挽回方法 自動テストを十分に用意する 1行~数行の範囲で見やすく修正する 機械的にコードの重複を排除する 全体の見通しがついてきたら正しい設計に
  117. 117. リファクタリングの練習問題 • リファクタリングが大幅に不足したコードをリファクタリングする練 習問題をGitHubに公開してあります • 実際にリファクタリングを行う解答例も上げています • http://qiita.com/potimarimo/items/9ea1e04a1ac63c3b8d0a • https://github.com/potimarimo/practice-of-refactoring
  118. 118. プロジェクトへの導入
  119. 119. たとえ話をします。
  120. 120. 空気の汚れた地域ですが、上空はまだきれいです。
  121. 121. 上空を飛べば、気持ちよく飛べます。
  122. 122. 一度下に向かうと、戻るのに苦労します。
  123. 123. 下のほうを飛ぶと、ずっと大変です。
  124. 124. 下から上に上がろうとしても、なかなか上がれません。
  125. 125. 力尽きて、結局上がれないかもしれません。
  126. 126. いっそ本当に力尽きるかも。
  127. 127. これはTDD導入のたとえ話です。
  128. 128. TDDに必要な コード品質
  129. 129. 最初からTDDを使って実装した場合
  130. 130. 少しうまくいかなくても挽回の余地はある
  131. 131. 途中から自動テストを導入しようとした場合
  132. 132. 途中から自動テストを導入しようとした場合
  133. 133. 途中から自動テストを導入しようとした場合
  134. 134. 途中からの導入が難しい理由 自動テストがな いとリファクタリ ングがやりにくい リファクタリングして ないと自動テストが 書きにくい
  135. 135. 途中からの導入が難しい理由 自動テストを後から書く とても面倒
  136. 136. 途中からの導入が難しい理由 自動テストを後から書く 自動化を利用できるのは最後だけ コストが減らない
  137. 137. 結論 TDDは最初から導入しましょう せめて新機能追加のタイミングで導入 機能修正はなるべくTDDで
  138. 138. TDDを生み出した人たち
  139. 139. TDDを作った人(の一人) ケント・ベック • ケント・ベック (Kent Beck) はエクストリーム・ プログラミング (XP) の考案者でアジャイルマ ニフェストの起草者の一人。(Wikipedia)
  140. 140. 名言 • 僕は、偉大なプログラマなんかじゃない。偉大な習慣を身 につけたプログラマなんだ。 ケント・ベック • だが、ケントなら絶対、 何かうまい手を思い付くだろう。 マーチン・ファウラー
  141. 141. 朝会 ミーティングは時間 をかけずに行いま しょう
  142. 142. 朝会 ミーティングは時間 をかけずに行いま しょう ミーティングは10分 で終わりましょう
  143. 143. 朝会 ミーティングは時間 をかけずに行いま しょう ミーティングは10分 で終わりましょう ミーティングは立っ てやりましょう
  144. 144. 様々な工夫が凝らされている TDD ケント・ベックの最 高傑作 いろいろな 工夫が凝ら された手順
  145. 145. TDDは死んだのか?
  146. 146. TDD IS DEAD AND LONG LIVE TESTING •2014年 •David Heinemeier Hansson(DHH) • TDD is dead. Long live testing. • TDD is dead. Long live testing.(日本語訳) • Is TDD Dead? • Is TDD Dead?(日本語訳)
  147. 147. TDD IS DEAD. LONG LIVE TESTING. テストファースト原理主義 は禁欲のみを唱えた性教 育のようなものだ。 つまり、自己嫌悪に陥って いる人に向けた、非現実 的で効果のない、道徳教 育のようなものだ。 テストファーストのユニット テストは、中間的オブジェ クトや間接的で過剰に複 雑な構造を生みがちだ。 「遅い」ものをすべて避け ようとするのがその理由で、 データベースやファイルIO などを避ける。 私はアクティブレコードを 直接、データベースをアク セスし、フィクスチャを使っ てテストする。 そう、私にとってテスト ファーストは死んだ。 テスティングよ栄えよ。
  148. 148. IS TDD DEAD? TDDを機能させることに 伴う犠牲は何かというこ とです。 モックをよく使う人たちは リファクタリングを難しい と捉えるが、 自分はテストのおかげで リファクタリングが楽にな ると思うと話しました。 テストによる設計の弊害 をTDDのせいにするのは、 変な場所に車で行ったこ とを車のせいにするよう なものだと言います。 多くのビジネスでTDDが 採用されてQA部門が排 除されたと言いました。 Kentは再びQAの話題に 戻って、QA部門との関係 がうまく機能しなかった昔 の経験に言及しました。 深夜2時の電話であらか じめミスを指摘されておく 方が得策だというのが Kentの意見です。
  149. 149. 結論 死んでません
  150. 150. TDDはなぜ変更に強い開発手法か
  151. 151. TDDはなぜ変更に強い開発手法か TDDでは、す べての機能は 機能追加とし て実装します 常に最大限変更に強く作 らないと作業が進まない 最大限に変更容易性に気 を付けて作ることになる 変更は必ずあると考えると、 早く作ることができる
  152. 152. TDDの自動テストとQCテスト
  153. 153. TDDの自動テストとQCテスト • QCテストなどの代わりにはならない • 本質的にはQCテストのテスト理論とは関係ない • ただし、コストをかけずに大量にできる TDDで作る自動テストはユニットテストです • 単体テストが大量にあるなら、QCテストは減らしても目的は達成できる ただし、テストの目的は総合的に品質を良くすること • テストとコストが比較されるので QCテストにも自動化
  154. 154. コードがドキュメント
  155. 155. コードがドキュメント コードがドキュメント 設計書を提出しろ?コードをコミットしたでしょ?あれが設 計書だよ。バグまで記述してある。 なわけがないです。全然意味が違います。
  156. 156. コードがドキュメント テストコード 外部設計書と して利用、保 守できる 実装コード 内部設計書と して利用、保 守できる
  157. 157. コードがドキュメント 大変で すよ?
  158. 158. コードがドキュメント ドキュメントとして読めるコード 可読性を極限まで上げる コメントがあると邪魔なんで書くな 様々なプログラムテクニック 大変です
  159. 159. コードがドキュメント 設計書 コード
  160. 160. 二度手間
  161. 161. 二度手間 一見、二度手間になる作業が多い コンパイルが通らないコードを書く 動かないテストを一度は実行 一度コードを書いてからリファクタリング リファクタリングで一度作ったクラスをまた消す
  162. 162. 二度手間 プログラムを組むときのボトルネックは手を動か すことではない!! ボトルネックは考えをまとめること。 考えるための手順を効率化し、考えることの 二度手間を最低限にする

×