PHPでRASIS四方山話

著:古庄道明氏

保守性を担保するためのリファクタリングとテスト第05回 18年07月更新

今回は、ServiceabilityやIntegrityに深く関わりが出てくる事が多いものの一つである「テスト」、および「リファクタリング」についてお話をしていきたいと思います。

 

まずは「双方とも全くないまま、一通りのコードが書き上がってしまっている」状況からの改善を、少し考えてみましょう。
このやり方は、ごくわずかに応用するだけで「新規開発時」にも使うことができるので、有益なのではないか、と思われます。

前提として「対象になるプロジェクトのソースコードは一通り把握している」もの、とします。
一番はじめに考えたいのが「何をテストして、何をテストしないか」です。

勿論「ありとあらゆる事象と項目とその組み合わせを100%テストする」のが理想……に見えるのですが、それは「完璧な陰影をつけた1セント硬貨」である可能性が高いので、一度、丁寧に考察をしていくとよいように思われます。

少しかみ砕いていきましょう。
前提として「無限のリソース(時間やマンパワー)」があれば、あるいは「全てについて限りなくクォリティを求める」ような事が、できるかもしれません。
しかし現実問題として「締め切りは存在し」「マンパワーは有限である」というのが、おおよそのプロジェクトの現実です。
そのためには、もし注力しているものが「全体のクォリティにはさほど大きな影響を及ぼさない1セント硬貨」であれば、その1セント硬貨に「完璧な陰影をつける」為に多大な工数を払うよりは「その工数を、よりクォリティに直結する別の箇所に回した」ほうが、全体としてのコストメリットが高くなる可能性、が、十分に想起されます。

また、テストもコードである以上は「書いたらメンテナンス対象になる」もの、です。
闇雲に遮二無二に「とにかく大量にテストコードを書く」と、「メンテナンス対象が増える」為に、運用メンテナンスのタイミングで「テストコードのメンテナンスが思った以上に重たくなる」といったケースもあり、バランス感覚が要求されます。
そのバランスを欠いてしまうと「テストコードのメンテナンスに大量の工数が割かれる」ようになるあたりから、テストコードの実質的な意味合いが、欠けてきてしまいます。

そのために、一番はじめに考えたいのが「何をテストして、何をテストしないか」です。
前提として、もし「リファクタリングをしたい」というニーズや必要性があるのであれば「リファクタリングしたい機能」に対するテストの記述、が、最優先になります。
「機能追加をしたい箇所がある」場合、「追加したい機能を含む既存機能」に対するテストの記述、が、最優先になります。
「直近にリファクタリングをしたい訳ではなく、追加機能も現状は想定されていない」という場合、ロジックとして比較的複雑なもの、を切り抜くのがよいと思います。
新規作成時は、「今作っているもののテストを書くか書かないか」を、真摯に考える必要が出てきます。個人的には「単純なCRUDなどは書かない」が上限、「切り出して1つの関数やメソッドにしたいようなロジックは書く」が下限、くらいかと思っております。

上述を書いておくと、テストを書いたコード部分については「リファクタリングをしても機能追加をしても、以前と同じ機能であることが保証できる」ようになるので、リファクタリングや機能追加に対する心理的安全性が増すようになります。

しかし、実際には、特に既存のコードがある時に「……これ、どうやってテストを書こう?」と悩む事も多い、かと思います。
勿論最終的には「コードによる」というお話になってしまうのですが、比較的簡単に分離させやすい方法の「一例」について、少し書いていきたいと思います。

「プログラム」に対する切り口は色々とあるのですが、一つが「入力→処理→出力」であり、また別の一つに「アルゴリズム+データ構造」という見方があります。どちらも比較的「古典」に属する見方ですね。
これらのうち。最低限コードを書いた方がよいのが「アルゴリズム」と「処理」に属する部分になります。
上述のために、もし「入力→処理→出力が1つのメソッドや1つの関数にまとまって書かれている」場合。対象の処理が「テストを書きたい程度に複雑であったり重要であったりする」ものであれば、テストを書きやすい程度に「メソッドや関数を分解する」用にすると、テスタビリティが上がります。具体的には「処理部分」を、関数やメソッドに切り抜きます。
特に「すでに既存のコードがある」場合でこれからテストコードを書く時は、まず「テストしやすいように切り出す(以外の修正はしない)」といった事を、まず初手にやっておくと、テストコードを書く心理的ハードルが、少しは下がるのではないか、と思います。

そうして。
テストコードを書いた以降、機能追加をしたい場合は
・まず、該当機能に対する「期待される挙動」のテストコードを書く
・プログラムを書く
・テストコードを動かして「all green」になるまで修正をする
というループを繰り返します。
また、定期的に
・コードを見直す
・必要に応じてリファクタリングをする
・テストコードを動かして「all green」になるまで修正をする
といった事をやっておくと、コードの不健全さがどんどんと減っていくので。
こちらは「スケジュールや予算の確保」関連のお話にもなりますが、多少のリソースは「リファクタ」用にアサインしておくと、末永いビジネスにとってはよいインパクトが出てくるかと思います。

さて。
今回はServiceabilityに起因する「リファクタや機能追加などのしやすさ」という観点からテストを書いていきました。
次回は「もう少し突っ込んだテスト関連(特に乱数を扱うものなど)」や、高圧テストといったあたりについて、言及をしていきたいと思います。