レガシーコードからの脱却 まとめ – 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%を基準とするべし。信憑性がなくなる。 テストがしづらい仕様が設計のしどころ バグはテストしなかったから顕在化した テスト出来ない箇所は設計の問題がある可能性があるから見直す必要がある 学びを活かすアイディア・行動 現場のユニットテストのコーディング規約づくり テストコードの目的のための事前知識整理 エッジケースを含めたふるまいがテストに網羅されているかチェックする必要がある 業務要件のフローとスマホ独自の中断操作をかけ合わせたケースで考える必要もある

gradleのビルドスクリプトで外部ライブラリを使う

概要 gradleのビルドスクリプトのプログラムで外部ライブラリを使う方法です。ライブラリをプロジェクト自体で使う場合の dependencies に設定するのとは違います。 背景・用途 gradleでビルドするとき、最終的なwarファイルやapkファイルを作る直前にソースコードの一部を編集した上でビルドしたい場合や、ビルド後にとあるサーバーと通信して成果物をアップしたい時に、ビルドスクリプトをgradleファイル内に書くと思いますが、デフォルトで用意されているgroovy、またはjavaのライブラリでは書くのが面倒臭く、外部ライブラリを使いたかった。 方法 ポイントは、buildscript の dependencies に classpath で設定する(設定値はhttps://mvnrepository.com/ からコピーできる値でよい)のと、importを自前で書くということです。これでimportしたクラスを使えます。 ↑本当に普通な内容でした。。。 ハマったのは、classpath で設定しただけじゃ、自動ではコード補完候補に出てこないということでした。java.ioとかであれば、自動で候補に出てくるし選んだら自動でimportも補完してくれるので、そのノリで書いたらダメでした。

CleanArchitecture要素のMVVMサンプル作った

サンプル 出来上がったサンプル(GitHub) アーキテクチャ図 動機 現場のプロダクトで、内部品質を高めるために定期的なリファクタリング習慣を取り入れて行きたく、リファクタリング計画を作るにあたり、目標とするアーキテクチャをはっきりさせたかった。 アーキテクチャサンプルの概要 CleanArchitecture の考え方を一部取り入れた MVVM です。構成は以下のようなレイヤーのマルチモジュール構成になっています。マルチモジュールにしている理由は依存性をシステム的に制御して人為的なミスによる間違った依存関係を生むのを減らすためです。 モジュール構成と主要ライブラリ app UI、バックグラウンド系のAndroidコンポーネントを持つモジュール 画面遷移: [Navigation Component](https://developer.android.com/guide/navigation?hl=ja) 画像取得: Coil domain ビジネスロジックを持つモジュール ViewModel、LifeCycleのための androidx.lifecycle系 repository データアクセスを持つモジュール Coroutine DB: Room HTTP通信: Retrofit2 JsonParser: Kotshi di DI機能を持つモジュール DI: Koin testlib テスト系の共通クラスを持つモジュール JUnit5: JUnit5 Mock: mockk 以下に、どのようにして上図のようになったかを解説します。(ライブラリはKotlinの言語仕様に合わせて簡単に書けるものやパフォーマンスが良いものを選んでいるつもりです。) アーキテクチャの方針 目指すところとしては、変更しやすいアーキテクチャを目指したいので、変更に特化した考え方の Clean Architecture を参考に考えます。 CleanArchitectureの基本的な考え方の1つである「関心事の分離」により、コンポーネント間、レイヤー間を切り離しを容易にすることで、柔軟性を上げます。関心事の分離の観点は以下の5つで フレームワーク非依存:システムをフレームワークに縛るのではなく、フレームワークをツールとして使う。 テスト可能:ビジネスロジックはUI、DB、外部IFなどがなくてもテストできる。 UI非依存:UIはシステムの他の部分を変更せずとも簡単に変更できる。(例えばビジネスロジック) データベース非依存:例えばOracleをMySQLに簡単に置き換えることができる。 外部エージェント非依存:ビジネスロジックは外部IFの世界を知らなくて良い。 これらを実現するために ソースコードの依存性は上位レベルの方針にだけ向かっていなければならない …