1人AdventのDay-12です。12ですかぁ〜
PHP*1にはassertというものがあります。
これ便利だし、コードを「良くする」ことのできる嬉しい機能だと思っています。
ただ、往々にして「開発を健全に続けていく」という目的の下にあっては、「曖昧さ」「ゆるさ」は罪になることもあります。そんなつもりはないのに・・・
ここでいう「曖昧さ」というのは、「自分以外の、他の人が、同じようなことを書いたり書こうとした時に、同じ感じでかけるか?」という、悩ましさの大きさだと思ってください。
プログラミングをやっていて、醍醐味で貼りますが、こういう風に動けばいいな!って思いついてから「あ〜どうやって書こう、何が正解かな?」って考えさせられる部分というのは、苦しみを招きます。
処方箋として。
「やり方を決める」っていうのは、1つの手だと思います。「これはこういう時に」「こういう風に使いましょう、使って良い」っていうガイドラインがあれば、気持ちが軽くなりますね。
さて、話を戻して「assert」や・・・いつなら使っていいんだ・・・
実際に業務のコードにチラホラと織り交ぜて見ているのですが、自分なりに「ここはOK、これは微妙」っていうラインを形にしてみようと思いました。
今日はそういうブログです。
前提として
- assertは、プロダクション環境では使わない。実行されるのは、開発環境においてのみである
- すなわち、実行時にデータを守ったり、ユーザーを守るためのものではない
- 要するに、「開発時に実装のミスをしないように」、「開発者を支援するため」のもの
と思っています。
「実行されるコメント」という感覚。
私の場合
「assertは使って良いもの」としつつ、先述の「曖昧になっていく」のを恐れています。そのため、限定的な使い方をしています。
とりわけ、 LogicException
とはなぁ。。。という風に感じています。
かなり探り探りでありつつ、「このくらいなら・・・」というのを書き連ねてみます。
privateメソッド内での利用
assertを「実装ミスをあぶり出す」という目的で使うとなると、「どういう使われ方をしそうか」というのは限定して考える必要があります。
その点、privateメソッドに関しては「まぁ、うっかりミスは少ないかな・・」という自信を持ちやすいかと思います。
protected, publicだと、どう使われるか保証できるとは言い切れないので、LogicExceptionをしっかりつかうかもしれません。
「ここに来る前に、このメソッドを実行されているか」みたいなチェックなど。インスタンスメンバーの設定状況だったり、DIの注入状況だったり・・・といったケースでしょうか。
自作トレイト内での呼び出し元クラス設定状況
インターフェイスや抽象クラスでは「メソッドの定義を強制できる」と思うのですが、クラス定数・クラスメンバーについてはどうでしょう。
「このトレイトを使うには、 $this->config
に arrayをいれてある」とかは、「実相時点で拾える必要がある」と思います。
そういった意味で、assert()を安全に使えるのではないでしょうか。
テスト中の前提条件
これを結構よく使っているかもしれません。
テストなんて「検査」しかしなくない?という話もあると思います。
たとえば、「ユーザー削除処理を行うAPIの実行時に、ユーザーの持っている投稿をすべて削除する」など。
この場合、「このユーザーIDに紐付いている投稿が0件になっている」ことをテストケースに絡めることが可能です。
が、それを実行する場合、利用するフィクスチャデータに「そもそも投稿がなかった」という状況だと、「検査は通るけどテストの意味を持たない」ことになってしまいます。
とはいえ・・・「もともと、なにか投稿していたよね?」という確認は、このテストケースにおいて「やりたいこと」ではないわけです。
そうした場合、「やりたいこと」と「守らないといけない前提」を明示的に区別するために、PHPUnitのconstraintとassertを併用するのはありかな〜と思います。
まとめ
もう少し使ってもいいんじゃないかな〜活躍してくれ!!という気持ちはあります。
その一方で、別にどんな機能も「無理に使う」必要はないと思います。
それでいて、「どっちでも良い部分」という根拠の説明がふわっとしやすい部分は辛いのです。とりわけ、チーム開発を行っていると、「なんとなくこう!」というのは、レビュイーに対して出来ることではありません。でも許容していると、「緩さ」が蔓延していき、より辛く・・・・誰も幸せになれないわけです。
なので、「チームとしての基準を決める、合意をとっていく」「アイディアや思考プロセスも含めて、プラクティスを蓄積していく」ことが重要なのかな〜と思っています!
*1:ここで言っているのは7.xですね