881
455

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

テストしやすい「純粋」な関数とは?

Last updated at Posted at 2020-01-18

とある日の弊社にて

ハスケル子「やめ太郎さん、今日は何してるんですか?」

ワイ「おお、今日はな」
ワイ「JavaScriptでお正月判定関数を書いてんねん」

ハスケル子「お正月判定関数・・・」

ワイ「せや」
ワイ「株式会社ブラックはんから、こんな依頼をもらったからな」

お世話になっております。
株式会社ブラックの暗井 暗人(くらい・あんと)です。
2020年の元日に弊社Webサービスのメンテナンスを行いますので、
元日の間のみ画面上に「ただいまメンテナンス中です」と表示する機能を実装していただきたいです。
予算は800万円までに抑えていただけると幸いです。

ワイ「システムのメンテナンス作業自体は、ブラックはんの方でするみたいなんやけど」
ワイ「お正月判定関数だけがどうしても作られへんらしく、弊社に依頼が来たという経緯や」

社長「(相変わらず設定メチャクチャやな・・・)」

ハスケル子「ちょっと何言ってるか分からないですけど」
ハスケル子「そのお正月判定関数とやらは書けたんですか?」

ワイ「おお、書けたで」
ワイ「一ヶ月かけて書いた力作や」
ワイ「ちょっとハスケル子ちゃんも見てみてくれや」

ワイのお正月判定関数

JavaScript
function shogatsuHantei() {
  const today = dayjs(new Date()).format("YYYY/MM/DD");

  if (today === "2020/01/01") {
    return true;
  } else {
    return false;
  }
}

const isShogatsu = shogatsuHantei();

ワイ「↑こんな感じや」

JavaScript
  const today = dayjs(new Date()).format("YYYY/MM/DD");

ワイ「↑まずこの部分で、現在の日付を"2019/12/15"みたいな文字列に変換して」

JavaScript
  if (today === "2020/01/01") {
    return true;
  } else {
    return false;
  }

ワイ「その現在の日付が"2020/01/01"と一致していたらtrueを返す」
ワイ「一致していなければfalseを返す」
ワイ「そんな関数や」

ハスケル子「はぁ」

ワイ「関数自体は書けたから、今から自動テストを書かなあかんのや」

また、Gitコミット時に自動テストが走る設定もよろしくお願いいたします。

ワイ「↑こう暗井はんから頼まれたからな」

ハスケル子「なるほど」
ハスケル子「自動テストいいですよね」

ワイ「せやな」
ワイ「Gitにコミットするときに毎回自動でテストが走るように設定しておけば」
ワイ「今後何かコードの修正をしたときにも」

「あ、修正したかった部分はちゃんとできたけど」
「〇〇機能のテストが通らんくなっとる!」
「今回の修正の影響で、知らんうちに他の部分をバグらせとったみたいや!」

ワイ「って場合に、ちゃんと気づけるからな」
ワイ「間違ったことをしていたらコミットすらできない・・・」
ワイ「これが自動テストの大事なところやで!」
ワイ「覚えといてや?ハスケル子ちゃん」

ハスケル子「はぁ」
ハスケル子「でもそのお正月判定関数
ハスケル子「純粋じゃないから自動テストしづらいですよ」

ワイ「純粋じゃない・・・?」
ワイ「テストしづらい・・・?」
ワイ「ど、どういうこと・・・?」
ワイ「ワイが汚れたおっさんやから、純粋やないってこと・・・?」

ハスケル子「例えば今からテストをするとして」
ハスケル子「今日はお正月じゃないから、falseが返ってくることは確認できますけど」

今日がお正月だったらtrueが返ってくること

ハスケル子「↑これが確認できないじゃないですか」

ワイ「そんなもんPCの時刻設定をいじって2020/01/01にすればええだけやろ」

ハスケル子「自動テストはどうするんですか」
ハスケル子「Gitコミットしたときに自動テストが走るんですよね?」

ワイ「せ、せや」

  • 2019/12/15だったらfalseを返す
  • 2020/01/01だったらtrueを返す
  • 2020/01/15だったらfalseを返す

ワイ「↑この3種類の自動テストをするように言われとるわ」

ハスケル子「自動テスト中に、どうやってPCの時刻設定を変更するんですか」

ワイ「ぐぬぬ」
ワイ「しゃあないな・・・」
ワイ「自動テスト中にPCの時刻設定を自動変更してくれるプログラムを・・・」
ワイ「ハスケル子ちゃん書いてくれへん?

ハスケル子「書いてくれへんです」

ワイ「ほな、どうせえ言うん・・・」

ハスケル子「純粋な関数に書き換えればいいんですよ」

ワイ「さっきから何なん、その純粋な関数って」

ハスケル子「参照透過な関数のことです」

ワイ「その参照透過も分からへんわ・・・」

ハスケル子「やめ太郎さんのお正月判定関数は」
ハスケル子「何月何日に実行するかによって、返ってくる値が変わるじゃないですか」

ワイ「そらそうや」
ワイ「そのための関数やもん」

ハスケル子「そうじゃなくて、同じ引数を与えれば毎回必ず同じ値を返してくれるのが」
ハスケル子「参照透過な関数です」

ワイ「ぐ、具体的には」
ワイ「さっきの関数をどう変えればいいの・・・?」

ハスケル子「説明しますね」

純粋な関数に書き換え

ハスケル子「さっきのやめ太郎さんの関数だと」
ハスケル子「関数の中で現在の年月日を取得していましたけど」
ハスケル子「それを関数の外に出します」

JavaScript
const today = dayjs(new Date()).format("YYYY/MM/DD");

function shogatsuHantei() {
  // 省略
}

ハスケル子「↑こうですね」
ハスケル子「そして、そのtodayは」
ハスケル子「お正月判定関数の引数として渡すようにします」

JavaScript
const today = dayjs(new Date()).format("YYYY/MM/DD");

function shogatsuHantei(today) {
  if (today === "2020/01/01") {
    return true;
  } else {
    return false;
  }
}

const isShogatsu = shogatsuHantei(today); // 引数として渡す。

ハスケル子「↑こうですね」

ワイ「へぇ・・・」

ハスケル子「こうすることで、今日の日付だけじゃなく」
ハスケル子「引数として任意の日付を渡して実行することもできるようになったので」
ハスケル子「テストの要件である3パターンの日付も簡単に試せます」

JavaScript
shogatsuHantei("2019/12/15"); // false
shogatsuHantei("2020/01/01"); // true
shogatsuHantei("2020/01/15"); // false

ワイ「ほんまや・・・」

ハスケル子「現在の年月日という状態に依存しなくなって」
ハスケル子「引数によってのみ結果が変わる純粋な関数になりました」
ハスケル子「つまり引数の渡し方戻り値をコントロールできるようになったので」
ハスケル子「自動テストも簡単に複数パターン試せるわけです」

ワイ「なるほどな・・・!」
ワイ「関数の純粋性・・・!」

ハスケル子「PCの時刻設定を自動で変更するバッチファイルとかも」
ハスケル子「書けなくはないですけど」
ハスケル子「もしバグが出た場合に」
ハスケル子「そのバッチファイルが間違っているのか」
ハスケル子「関数自体が間違っているのか」
ハスケル子「って感じで」
ハスケル子「懸念するポイントが増えてしまうじゃないですか」

ワイ「せやな・・・」

ハスケル子「そんな感じで」
ハスケル子「周囲の状態に依存しない純粋な関数は」
ハスケル子「自動テストとの相性が良いんです」
ハスケル子「数ある言語の中には、純粋な関数しか書けない純粋関数型言語なんてのもあるんですよ」

ワイ「おお、初めから純粋にしか書けなければ」
ワイ「ワイみたいにうっかり状態依存の関数を書いてしまうこともないもんな」
ワイ「テストする段階になって気づいて」

「この関数、書き換えなアカンやん!」

ワイ「なんてことがなくなるんか」
ワイ「ええやん」
ワイ「純粋関数型言語って、例えばどんなんがあるん?」

ハスケル子「フロントエンドの言語だと、例えばElmです」

ワイ「おお、『実用上実行時エラーが出ない』と言うあの言語か・・・!」
ワイ「ワイもこのあと勉強してみるわ!!!」

ハスケル子「公式ガイドの日本語訳が読みやすくてオススメですよ」

ワイ「おお、ありがとう!」
ワイ「ほな、また明日な!」

そしてやめ太郎は、飲み屋街へと消えていった・・・

翌日

ハスケル子「昨日ちゃんとElmの勉強しましたか?」

ワイ「ああ、一応酒を飲みながらElmのこと勉強したんやけど」
ワイ「かなり飲んだから何もかも忘れてもうたわ」
ワイ「やっぱ、酒飲みながら勉強しても得るものないな」
ワイ「Elmやなくて得る無やわ!」
ワイ「ガーファファファ!」

ハスケル子「・・・」
ハスケル子「(純粋にイラつく・・・)」

〜おしまい〜

881
455
11

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
881
455

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?