トイレの花子さんに学ぶ仕様変更


発端

この例があまりにも初学者向けに使いやすいと思ったので、投稿してみます。
引用では 一番奥となっていますが例を作るために少し変更しています。

取り急ぎ仕様

  1. 三番目の個室を三回ノックする
  2. 花子さんの名前を呼ぶ
  3. 花子さんが出現する

仕様通りに実装してみる

3回ノック(クリック)して、呼んでみると花子さんが出現されます。

See the Pen call_hanako_san_1 by keima (@matsugena) on CodePen.

仕様を疑え

  1. 三番目の個室を三回ノックする
  2. 花子さんの名前を呼ぶ
  3. 花子さんが出現する

上の3つの仕様書は全く足りていません
1.については、引用ツイートの通り事前にノックされてしまうことで破綻します。
あえて解説のため、グローバル変数として実装しています。
HTMLだと開いた時点で0になっていますが、多数が利用するトイレとして、同じページを複数回操作する再現にしました。
現実ではサーバー側で管理されると思います。
その場合でも、日付でリセットされるのか個人ごとに管理するのか、仕様を詰めるだけ詰める必要があります。

2.については、実装者(私)が呼んだことをトリガーに実装しています。
1.2. 2つの条件が揃った際に花子さんが出現するということなのかどうかを詰める必要があるでしょう。

3.花子さんが複数人出現する。
すでに何人ものハナコさんを召喚されているかたはここを読み飛ばしてください。
花子さんの上限は仕様からは読み取れません。
花子さんはひとりじゃないかもしれませんし、複数かもしれません。
ここも条件を詰めましょう。

仕様変更

さらに、仕様の変更が発生した場合どうなるでしょう。
花子さんは地域によって様々な呼び方ルーティンがあるようです。
例えば、一部の地域(localeId=11110)では、4番目のドアを15回ノックした場合にだけ現れるようにしたいという変更がありました。


function callSomething(){
    let name = document.getElementById('name').value;
    let localeId = document.getElementById('localeId')
    if(localeId != 11110 && knockCount == 3 && name === '花子さん'){
        return appearHanakoSan();
    }else if(localeId == 11110 && knockCount == 15 && name === '花子さん'){
        return appearHanakoSan();
    }else{
      alert("しかし花子さんは現れなかった");
    }

}

もちろん、上の実装はやってしまった例なので真似をしてはいけません。
さらに、別の地域でN番めのドアをM回ノックした場合に現れるようにしてほしいといった要望が続々発生し果ては呼び名も違う場合や時間の指定があることも想定しなければいけません。
else ifが地域の数やパラメータの数だけ増え続けます。
というわけで、改善例は以下になります。


function callSomething(){

    let form = document.getElemetnById('nameForm');
    let name = form.name;

    // クライアント側での最低限のエラーチェック
    if(!name){
        return; // ユーザにエラーを知らせるべきですが、名前を呼ばれていないという認識として省略します
    }

    form.submit(); //送信されたサーバーで花子さんの出現をチェックしましょう
}

もちろんサーバーに実装できずクライアントで判定ロジックを実装しなければいけないこともありますが少数だと思います。
サーバーにロジックを用意することで、全国の学校(仮に5000として)のトイレで地域別に花子さんを用意する必要が発生した際に5000花子さんを用意する必要がなくなります。

まとめ

仕様変更が無いという言葉は信用するな

補足(アンチパターン:マジックナンバー)

仕様書の件と直接関わりはないですが、
花子さんを出現させるための、以下のif文ですが仕様の通り間違ってはいませんが、やってはいけない例(アンチパターン)になっています。
"3"番の個室
"3"回ノックする
"花子さん"という名前
3つの値をif文で直接扱うことで実装した人にしか分からない数字及び文字列になっています。
以下の通り改善できるでしょう。

// 悪い例
if(toiletNumber == 3 && knockNum == 3 && callName === '花子さん'){
    return appearHanakoSan();
}

// 意味をもたせる例
const correctToiletNumber = 3;
const correctKnockNum = 3;
const correctCallName = '花子さん';

if(toiletNumber == correctToiletNumber && knockNum == correctKnockNum && name === correctCallName){
    return appearHanakoSan();
}

ロジックが複雑かつクライアントに実装しなければならない場合であれば、if内の条件式を関数化することも想定できます。