個人的にPHPのassert()の使い方を整理する

1人AdventのDay-12です。12ですかぁ〜

adventar.org

PHP*1にはassertというものがあります。

www.infiniteloop.co.jp

これ便利だし、コードを「良くする」ことのできる嬉しい機能だと思っています。
ただ、往々にして「開発を健全に続けていく」という目的の下にあっては、「曖昧さ」「ゆるさ」は罪になることもあります。そんなつもりはないのに・・・

ここでいう「曖昧さ」というのは、「自分以外の、他の人が、同じようなことを書いたり書こうとした時に、同じ感じでかけるか?」という、悩ましさの大きさだと思ってください。
プログラミングをやっていて、醍醐味で貼りますが、こういう風に動けばいいな!って思いついてから「あ〜どうやって書こう、何が正解かな?」って考えさせられる部分というのは、苦しみを招きます。

処方箋として。
「やり方を決める」っていうのは、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ですね