Showing 88 Result(s)

レガシーコードからの脱却 まとめ – 10.7

10.7 テスト駆動開発は失敗することがある 内容 テスト駆動開発はスキルであり、スキルが十分に習得されていないと、開発者の負荷になり、プロジェクトの進行は遅くなる。それが原因でプロジェクトが失敗するというように判断したのなら、テスト駆動開発をやめるのが正しい。 開発者が対応できないときは、開発者に新しい学習曲線の負担をかけるべきではない。テスト駆動開発を続けてプロジェクトを失敗させ倒産するか、テスト駆動開発をやめるかの選択に直面しているなら、テスト駆動開発をやめることはいちばん確実で正しい。リリースの準備ができているなら、テスト駆動開発の導入に挑戦する必要はない。 テスト駆動開発の間違った会社の例 とある会社ではコードの品質、「CLEAN」なコード、優れた開発原則は導入できていたにもかかわらず、テストの運用がうまくいかなかった。 テストが冗長コードをクリーンにするのに1日、テストをクリーンにするのに1週間かかっていた。原因はテストコードもコードであると見直しておらず、テストの冗長性が非常に高くなっていたため。 インターフェースではなく実装に依存したテストインターフェイスに対してテストするのではなく、実装に対してテストをしていたため、コードのクリーンアップをしようとしたときに、テストをクリーンアップするのが困難だった。 ユニットテストの書き方が違うテストを実行するためにOracleに接続していて、モックを使っておらず実際のDBに接続していたため時間がかかっていた。 テストの量を不要に増やした彼らはQAの立場で「テストが多ければ良いテストだ」と考え、あまりにも多くのテストを書いていた。上記の要因を踏まえ、大量の運用できないテストを作っていた。 学び テスト駆動開発はスキルであり、習得が必要。習得には負荷がかかるので導入は計画的にしなければいけない。 負荷が高すぎたり、間違ったやり方で工数が上がりすぎては本末転倒。 学びを活かすアイディア・行動 ユニットテストのコーディング規約づくり失敗するとどうなるかを書く。

レガシーコードからの脱却 まとめ – 10.6

10.6 テスト可能なコードを書く 内容 テスト駆動開発をやっていないし、やりたくもないマネージャーに対して納得させた言葉。 テストファースト開発するかどうかは気にしないが、テスト可能なコードを書くかどうかを気にする。テスト駆動開発はそうするための方法だ。 テスト駆動開発はテストファーストでテストを書くため、自然とテスト可能なコードになる。 うまくいかない状況というのは、設計の問題があって考え直すべきであることを示している。テスト駆動開発は、難易度のダイヤルを持つようなものだ。詰まってしまったときには、いつでも「哀れになるほど簡単」にセットして、そこで少し自信をつけてから難易度を上げる。これを自分自身でコントロールしていくのだ。 このようにして、うまく進めなければ謙虚に前に戻り、設計し直し、最後にはよいテストとテスト可能なコードを作る。 学び テスト可能なコードかどうかが重要。 テスト駆動開発はテストファーストでテストを書くため、自然とテスト可能なコードになる。 間違ったなら、素直に認めて前に戻ろう。 学びを活かすアイディア・行動 テストコードの目的の事前知識整理

レガシーコードからの脱却 まとめ – 10.4 – 10.5

10.4 テスト駆動開発はすばやいフィードバックをもたらす 内容 ソフトウェアを開発するいちばん安価な方法は、最初からバグが発生しないようにすることだ。次に安価な方法は、あとで別のチームが修正するのではなく、発見したらすぐに同じ人または同じチームによって修正することだ。 一連の刺激と反応のトランザクションが精神に定着するためには、刺激に対してすばやい反応を続けることが必要だと、ある生物学者は示している。この生物学的観点でも、バグを生んだ本人がすぐ治すのが早いということになる。 そして、テスト駆動開発はすばやいフィードバックをもたらしてくれる。 10.5 テスト駆動開発はリファクタリングをサポートする コードがテストによってサポートされている場合は、リファクタリングが安全にできる。何かを間違えたらテストが失敗してすぐに教えてくれるからだ。 リファクタリングが必要なシーン 視野が狭くなっていると命名が少しずさんになる傾向がある。 ふるまいを実装している最中に、何に命名をする必要があるかわからなくなることがある。 アジャイルはリファクタリングしながら進むと効率的 アジャイル開発では、すべてを最初から理解しようとせず、反復的にソフトウェアを「間違いながら」「設計しながら」作ることが許されており、そのほうがはるかに効率的。そうするためにはリファクタリングしながら進むのは必須で、そのためにはテストが常にサポートしてくれる環境が必要。 学び 記憶を定着させるには反復練習が必要。 レガシーの匂いがするコードは対処を先延ばしにしないようにしないと、レガシーコードを作った本人がいなくなる可能性がある。レガシーコードが残ると拡張しづらいシステムになるので、レガシーコードはなるべくリアルタイムで修正する。 レガシーコードを産まないようにするにはテスト駆動開発とペアプロすると、正しく進んでいくのがよいのではないか。 リファクタリングにはテストを担保するものが常に横にある必要がある リファクタリングは開発中が一番コストをかけずにできる 学びを活かすアイディア・行動 現場にテスト駆動開発をシフトさせる。どうすればいいか。。 現場のリファクタリング計画のためにリファクタリング内容に紐づく修正ファイル対象の一覧を作る。案件があるときに、合わせて修正を検討する。

レガシーコードからの脱却 まとめ – 10.3 – 10.3.2

10.3 良いテストを書く 内容 テスト駆動開発として実践されている「テストファースト開発」と「テストアフター開発」を紹介し、多くの開発者やマネージャーは「テストアフター開発」によって、テスト駆動開発に対するネガティブな誤解を生んでいることを説明している。 テストファースト開発 説明 小さな機能のテストを書いてから、その機能を実装するやり方。 メリット テストの観点(外部からの観察)と、コードの観点(内部からの観察)を行き来することで、フィードバックをもらいながら堅実に進められる。 最初にテストを書くことで、常に100%のコードカバレッジが確保できる。 失敗したテストに合格するようにコードを書くため、テスト可能なコードが書けていることを保証してくれる。 デメリット テストを書くスキルの習得が要る テストアフター開発 説明 コードを書いてからテストを書く。(著者がそう呼んでいる) メリット 自動化された回帰テストを好きなときに作って実行できる。 デメリット コードを書いたあとにテストを書くのは、かなりの再設計、コードをクリーンアップが必要であることがほとんど。結局、テスト可能なコードを最初に作成するほうが楽。 この実態を前提に、多くのマネージャーと開発者は、テスト駆動開発に対し、テストアフター開発のイメージを持ち「やたら手がかかる」というような先入観を持っている。 テストファースト開発では、テストアフター開発のデメリットを防ぐことができる。 すべてのテストを先に書いてから、実装する方法もある。この方法にはいくつかの利点があるのは事実だが、テストファースト開発で得られる頻繁なフィードバックのほうが大きな利点である。著者はすべてのテストを先に書いてから実装する方法はテスト駆動開発とは考えていない。 10.3.1 テストではない テストは二重の役割を果たしているということを説明している。 1つは、仮説であり、ふるまいの仕様。 もう1つは、回帰テストが常に用意されていて実行され、コードが期待したように機能していることを検証すること コードを書く前に書いているユニットテストはテストではなく仮説。サービスの呼び出し方法と期待する戻り値の仮説を立てている。つまり、どうなったら完成するのかの仮説を立てている。 次に、テストに合格するコードを書いたら実際のテストになる。なんらかのふるまいを実行して検証したから。 そしてこの検証機能はソフトウェアの寿命が来るまで以下の価値を提供し続ける。 影響を与える可能性のあるものは何も変わっていないことを保証する コードが期待したように動くことを保証する 10.3.2 ふるまいの集合体 ユニットとはふるまいの単位で独立した検証可能なふるまいのこと。つまり、どのように使ってどのような結果になるかを検証できるふるまいのこと。ふるまいを表すために、常に必要最小限のテストを書くことが重要。 多くの開発者は「ユニットテスト」の「ユニット」と言う言葉を、メソッド、クラス、モジュール、関数などのような実体を指すものと勘違いするが、違う。この勘違いのため、新しいクラスやメソッドを作るたびに新しいテストを作成し、コードの成長とともに多くのテストを追加することで、肥大化するのではないかと心配したり、実際に追加してしまう。 テストファーストのメリットは、必要に応じてあとから簡単にコードをクリーンアップできるようにすることだ。ユニットの単位を勘違いして、コードをクリーンアップするときに、不要なテストを増やしてしまうと、自動回帰テストを持つことの価値の大部分を失ってしまう。 「ユニット」が表現するのはふるまいだ。ふるまいが変わらないなら、テストを変える必要はない。 「ユニットテスト」は「すべてのクラスやメソッドがテストを持つべき」ではなく「あらゆる観察可能なふるまいが、それに紐づくテストを持つべき」である。「あらゆる観察可能なふるまい」=「すべてのクラスやメソッド」というわけではない。 学び 実際にテストアフター開発が起きているからネガティブな先入観が生まれる。では、なぜテストアフター開発をしてしまうのか。要因は、大きく2つ。 傲慢。ほとんどの開発者はテスト可能でないコードを書いてしまう前提を認識していない。 無知。テストファースト開発が習得が必要なスキルだということを知らない。 間違った認識、無知は失敗を生み、ネガティブな先入観を生む。 テストファーストで書くテストは、実際のコードまで書いて、テストとなる。テストだけの時点では、ふるまいの仕様を表す仮説である。 自動回帰テストの環境がないと効果が薄いように感じる。 ユニットとは観察可能なふるまいの単位である。 ユニットの単位を明確にして不要なテストを増やしてはいけない。 学びを活かすアイディア・行動 テストコードの目的のための事前知識準備 現場の回帰テスト環境作り ユニットの単位の深堀り 現場のテストコードのコーディング規約づくり

レガシーコードからの脱却 まとめ – 10.2 – 10.2.2

10.2 QA 内容 QAテストの種類・形態を紹介。 コンポーネントテストユニットがどのように連携するかを調べる 機能テストユニットを機能ごとにまとめてEnd to End(端から端まで)のふるまいが完全かを調べる シナリオテストユーザーがシステムを使って、実際に使えるかを調べる パフォーマンステスト何百万ものアクセスに耐えうるか調べる セキュリティテストコードの脆弱性を探す プロジェクトに必要なテストはリスクによって異なる。たとえばペースメーカーとソーシャルメディアのアプリケーションではテストの方法は変える必要がある。Google、マイクロソフト、Amazonは品質担当はQAの自動テストを作れる人たちにして成果を上げている。 10.2.1 テスト駆動開発はQAの代わりではない ふるまいを「検証」ではなく「表す」方法としてテストファースト開発(TDD)を行うと、どんなテストが必要かがより明確に理解でき、無駄がなく意味のあるテストの土台が手に入る。これは安心してコードをきれいにするのに役立つ。 しかし、これ自体がQA作業を置き換えるわけではないと言っている。セキュリティ関連のテストをしなくてよいわけでもないし、パフォーマンス関連のテストをしなくてよいわけではない。 10.2.2 ユニットテストは万能ではない 基本的に、ユニットテストはテストファーストで作れば、良い設計の手助けとなる。 しかし、ユニットテストではなくEnd to Endテストで確認したいものもある。たとえば、UIとのやりとり、DBとのやりとり、マルチスレッド、高度なコード、などだが、これらはテスト駆動開発を使用せずに書かれていて、テストのないコードになっておりテストが困難な場合が多い。 設計を変更して構わないなら本質的にテストできない機能はないが、設計を変更できないときもある。(既存のコードとやり取りしている場合、既存のパッケージを使用している場合など。) そういうわけで、ユニットテストはテストファーストで進めば、良い設計の手助けとなるが、万能ではない。 学び テストの種類と目的の理解が深まった 自身のプロダクトはどんなテストが必要か、こういったテストの種類を知った上で考える必要がある テスト駆動開発はパフォーマンステスト、セキュリティテストなどのQAをするのは難しい。(費用対効果が薄い) テストファーストでユニットテストを作れば良い設計の手助けになる UI、DB、マルチスレッド、高度なコードなどはテストが難しい(観測が難しい) 学びを活かすアイディア・行動 テストコードの目的の事前知識整理 現場でのテストコードの運用範囲を決める。 テストコードのコーディング規約づくり(テスト運用の注意点)

レガシーコードからの脱却 10.1 – 10.1.3

10.1 テストと呼ばれるもの 内容 テスト駆動開発の話の前に、一般的なテストの種類と目的を理解しようという前置き。 10.1.1 受け入れテスト=顧客テスト 受け入れテスト、あるいは顧客テストはストーリーのふるまいを明確にするもの。受け入れ基準を定義することで、受け入れテストがどうなったら終わりになるか明確になる。それにより、 開発者が特定のエッジケースや例外のシナリオの理解に役立つ 開発者がどうなれば正解か理解しきれずに進めてしまい、作り過ぎてしまうことを防止する などの効果がある。これにより開発者は安心して進む事が出来る。受け入れテストツールにGherkinという自動化ツールがあることの紹介。受け入れテスト駆動開発に関する書籍2冊紹介。 Lean-Agile Acceptance Test-Driven-Development Specification by Example 10.1.2 ユニットテスト=開発者によるテスト ユニットテストの概要が書いてある。 ストーリーよりも小さいテスト 開発者がテスト駆動開発で作るテストコードによるテスト ドキュメントとしても機能する 将来の変更時のミスを見つけるための回帰テストにもなる 10.1.3 それ以外のテスト=QAテスト ワークフロー中のコンポーネント間の相互作用をテストする結合テストのように、QAプロセスの「一部」になる。結合テストは、モックではない実際の依存関係を使用してコンポーネント間の相互作用をテストする。そのためユニットテストより多くの依存関係をビルドするのでビルド時間がかかる。 機能をテストするために、ユーザーの入力をシミュレーションするツールを使うこともあるが、これがテストの唯一の方法なら、考慮すべき設計上の制約があるかもしれない。できるかどうかはさておき、簡単に検証できるようにテスト可能なコードを書くことを追求すべき。 テストを2つのカテゴリに分類するとする。 リリース候補を検証するために必要なテスト そのほかすべて これらはできるだけ多く自動化することが重要だが、リリース候補のテストをすべて自動化することはさらに重要。人間を介入させると、外部への依存性が生まれ、うまくいかないことがあるからだ。問題が起きる可能性を最小限にするために、できるだけ依存関係を少なくなるようにするが、ソフトウェア開発プロセスも依存関係を少なくすることが必要だ。GPSなどの機能は人間によるテストが必要なケースだが、そういう場合はコンポーネントを切り分けて必要なところだけを人間に任せる。 学び 受け入れテストはストーリーの振る舞いを明確にするものであり、これが要件である。 これを基準にテストの増えすぎや実装の増えすぎを抑えることができる。 テストスイートの意味。テストの集合。 上記「内容」 結合テストの定義について明確になった。モックではなく実際の依存関係を使い、コンポーネント間の相互作用をテストする。 問題を減らすためにソフトウェア開発プロセスにおける依存関係も減らす。 人間を介入させると外部への依存関係が増える。 学びを活かすアイディア・行動 テストコードの目的の前提知識整理 受け入れテスト自動化の学習 現場のテストコードのコーディング規約づくり

レガシーコードからの脱却 まとめ – 10.0

10.0 まずテストから書く 内容 テスト駆動開発(TDD)は死んでしまったと主張する人たちもいる。良いアイデアに見えるものの実際には多くのテストや、実装に依存するテストがかえって負担になってしまうという「テストによるダメージ」となりうまくいっていないという理由で。テストファースト開発を行う利点は、既存のコードを変更するときにサポートを得られることであるが、いつテストを書くのをやめるべきかわからないときに、不必要に多くのテストを書くことになったり、実装依存のテストを書くことになったりと、「テストによるダメージ」が発生する。こうなるとテストの変更が難しくなり、変更しやすさの手助けになるどころか負担となり、コードの変更は困難になり時間がかかるようになる。 しかし、テストを仕様と捉えることで、必要なテストが明確になる。 テスト駆動開発を正しく使用する方法と、落とし穴があることを伝えている。 学び テスト駆動開発を間違って行うと負担になる。正しく使うためには仕組みの理解が必要だ。 不必要に多くのテストや実装依存のテストは 学びを活かすアイディア・行動 テスト駆動開発のノウハウ整理 現場のテストコードのコーディング規約づくり

レガシーコードからの脱却 まとめ – 11.5 – 11.9

11.5 テストは仕様だ 内容 11.2-4までの中で、3つのアサーションを定義した。 1から200までの値が必要で、MINIMUM_AGE – 1もしくは0を渡した場合は例外がスローされる 有効値はMINIMUM_AGE以上MAXIMUM_AGE以下である。この場合は、エラーなしで戻り値を返す MAXIMUM_AGE + 1もしくは201を渡した場合は例外がスローされる これらの3つはすべて独立しており、同じ理由では失敗しない。そしてすべてが通らないとOKにならない。このテストコードは独立した3つの要件そのものである。通常の要求のドキュメントが最新かどうかは担保するのがむずかしいが、テストは実行すればOKかNGがわかるため、OKが出れば最新だし、NGが出るのであれば最新ではない。 11.6 完全であれ ふるまいを書くときは常にテストを先に書く。そうすることで、完全で漏れのないテストスイートが出来上がる。そうすれば最終的には品質が劇的に向上する。 テスト駆動開発をすればテスト容易性とコード品質が上がるが、テスト用意性が高いからといってQAも同時にやればいいというわけではない。テスト駆動開発と同時にQAをやろうとすると、たぶん、QAのためにとても多くのテストを書く羽目になる。最悪、コードがぐちゃぐちゃになり、あとから直しにくくなる。 QAの役割は、開発の段階で考えていないようなケースについても確実にカバーできるようにすることだから、開発者はまずふるまいを作ることに集中しよう。そしてQAで発生したものは必要に応じてあとからクリーンアップする。その方が遥かに効率が良い。 マネジメント側がQAをテスト駆動開発を含めるように言い出した場合、QA(システムが停止する可能性のある箇所の調査、非機能要件の検討、その他)は、テスト駆動開発には含めずに、後でやり、必要に応じて修正するほうが、コードが良い保守性になりやすいと言ったほうが良い。 11.7 テストを一意にする テストファースト開発は設計方法論であり、テストが一意になる設計をしながら進めるためのものだ。 良いテストの基準は テストが未知の理由ではなく既知の理由で失敗すること テストは一意であること であるが、テストに重複を許すと、何かの失敗で複数の失敗が起き、以下の理由で著しくスピードが下がる。 すべての失敗が本当に同じ原因で落ちているかどうかを調べなければいけなくなる リファクタリング箇所が多くなる 11.8 コードをテストでカバーする コードカバレッジ(テスト網羅率)は100%以外は意味がどんどん薄れる。 テストを仕様として書き、テストが難しい仕様はテストができるように設計を工夫する必要がある。難易度が高い、且つテストできなくない状態を続けることは、コード品質が低いことを意味し、後の負債となる。 11.9 バグにはテストがない すべてのバグはテストがないゆえに存在する。 テスト駆動開発を用いてバグを修正するには、まずバグを再現させるような失敗するテストを書く。次に、テストがグリーンに変わるように、バグを修正する。 そのため、すべての仕様に対して理論上はテストがあるようになる。 学び テストコードはプログラムの正しさを検証するとともに、仕様ドキュメントである必要がある。 テストコードは運用していかないと効果を発揮しない。 ドキュメントをテストコードによって表現するスキルが必要だ。 QAとテスト駆動開発は同時にやるとコードの保守性が悪くなる可能性が高い。 テスト駆動開発では機能要件にフォーカスし、非機能要件にはフォーカスしないほうが効率が良い。 テストは一意となるようにしなければ、開発効率がかなり落ちる。 テストを一意にするということはふるまいを一意にするということ コードカバレッジは100%を基準とするべし。信憑性がなくなる。 テストがしづらい仕様が設計のしどころ バグはテストしなかったから顕在化した テスト出来ない箇所は設計の問題がある可能性があるから見直す必要がある 学びを活かすアイディア・行動 現場のユニットテストのコーディング規約づくり テストコードの目的のための事前知識整理 エッジケースを含めたふるまいがテストに網羅されているかチェックする必要がある 業務要件のフローとスマホ独自の中断操作をかけ合わせたケースで考える必要もある