アプリケーション開発をしていて、種別ごとに処理が分岐されているコードはよく見ると思います。例えば、次のコードは自然言語の種別ごとに挨拶を返す関数です。
usev5.40;subhello($lang){if ($langeq'JP') {say'こんにちは'; }elsif ($langeq'EN') {say'Hello'; }else {die'Unknown language'; }}
この挨拶コードで、もしフランス語も対応することになったら、どうしましょうか?
$lang eq 'FR'の分岐を追加すれば良いでしょうか。こういった種別による対応箇所が少なく自明であれば問題は起きにくいかもしれないですが、種別による分岐がアプリケーションコードの至るところにあり、コードが肥大化していた場合、種別の追加漏れで不具合が発生しがちです。しかも、事前に問題は気づきにくいです。
静的型付け言語であれば、例えば、never型を利用して、コンパイル時にエラーを検知できます。

では、動的型付け言語のPerlの場合はどうすれば良いでしょうか?ここでは2つのアプローチを書きます。
非常に素朴なアプローチですが、全種別で正常動作することを確認するテストを書けば、種別の追加漏れを事前に気づける可能性は上がります。
useTest2::V0;use constantLANG => ['JP','EN'];subtest'全種別でhelloが動く' =>sub{formy$lang (LANG->@*) { ok lives { hello($lang) }; }};
単純な方法ですし、応用力もあります。ただ、実行したい関数の事前準備が多い場合、手間もあるため、個人的には次のアプローチも手札にいれることをおすすめします。
2つ目のアプローチは、種別の違いをマッピングし、これをAssertionする方法です。このアプローチの場合、自動テストで全種別で回す必要はなく、assertを通りさえすれば良いです。この方法でも網羅性チェックができます。
useSyntax::Keyword::Assert;use constantLANG => ['JP','EN'];subcheck($mapping, $keys){return !grep{ !exists$mapping->{$_}}$keys->@*;}subhello($lang){state$mapping = {JP =>'こんにちは',EN =>'Hello', }; assert(check($mapping, LANG));$mapping->{$lang}}
余談ですが、これまでのPerlのAssertionライブラリの場合、パフォーマンスに影響を与えることがありますが、このSyntax::Keyword::Assertは、コンパイル時にAssertionを削除するため、パフォーマンスに影響を与えません。
Perlで網羅性チェックのために、全種別で自動テストを回すアプローチとマッピング漏れをAssertionするアプローチを紹介しました。
以上です!
引用をストックしました
引用するにはまずログインしてください
引用をストックできませんでした。再度お試しください
限定公開記事のため引用できません。