見出し画像

【開発哲学_ちょいとブレイク】〜CODECOMPLETEのここまでの話の復習を兼ねてコード書いてみた

有料にしようかなと思ったけど、無料でw
簡単なコードをゆっくり手直し(=リファクタリング)
していく手順を書いているので長文です🕺

概要

GASで簡単なツールを作って、
作る間に書いたコードを
これまでの内容を加味して、
リファクタリングする過程も含めて紹介。

VBAについては、

も覗いてみてね。

作った機能

正規処理(下の要件を全て満たすもの)

  1. インプットボックスを表示

  2. 1 〜 5のいずれかの半角数字を入力

  3. 現在の日付が、

  4. 明治、大正、昭和、平成、令和で

  5. 何年にあたるかを計算

エラー処理(入力ミスの対処)


1 〜 5のいずれかの半角数字以外を入力すると、エラーメッセージを表示。

完成品の画像

実行前

半角数字(ここでは4)を入力

実行後

令和4年は、平成だと34年。

コード(完成形。コピペでOK)

//グローバル
const year = '年';
const ganNen = '元';
const saiMeiji = 1867; 
const saiTaisho = 1911;
const saiShowa = 1925;
const saiHeisei = 1988;
const saiReiwa = 2018;
const inputMsgStr = 'いずれかの半角数字を入力。明治:1,大正:2,昭和:3,平成:4,令和:5';
const errorMsgStr = '1~5のいずれかを入力してください。';
let gengo,gengouAry,gengouAryNum,thisYear,wareki,warekiMsg,errorMsg;

function 現在を元号ごとの年数に変換_完成形(){  
  gengouAry = ['明治','大正','昭和','平成','令和']; 
  gengouAryNum = Browser.inputBox(inputMsgStr);
  if(gengouAryNum == 1 || gengouAryNum == 2 || gengouAryNum == 3 || 
     gengouAryNum == 4 || gengouAryNum == 5){
    gengouAryNum = gengouAryNum - 1;
    switch (gengouAryNum){
      case 0:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiMeiji; 
        元号判定_(gengo,thisYear,year);
        break;     
      case 1:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiTaisho;
        元号判定_(gengo,thisYear,year);
        break;
      case 2:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiShowa;
        元号判定_(gengo,thisYear,year);
        break;
      case 3:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiHeisei;
        元号判定_(gengo,thisYear,year);
        break;
      case 4:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiReiwa;
        元号判定_(gengo,thisYear,year);
        break;
    }  
  } else {
    errorMsg = Browser.msgBox(errorMsgStr);
  }
}

function 元号判定_(gengo,thisYear,year){
    if(thisYear == 1){
      thisYear = ganNen;
    }    
    wareki = gengo + thisYear + year;
    warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');

    return;
}

コード作成手順

まずはif文で書いてみると、

function 現在を元号ごとの年数に変換_If文(){
  let gengo,gengouAry,gengouAryNum,thisYear,wareki,warekiMsg,errorMsg;
  gengouAry = ['明治','大正','昭和','平成','令和']; 
  gengouAryNum = Browser.inputBox('いずれかの半角数字を入力。明治:1,大正:2,昭和:3,平成:4,令和:5');
  if(gengouAryNum == 1 || gengouAryNum == 2 || gengouAryNum == 3 || 
     gengouAryNum == 4 || gengouAryNum == 5){
    gengouAryNum = gengouAryNum - 1;
    if(gengouAryNum == 0){
      gengo = gengouAry[gengouAryNum];
      thisYear = new Date().getFullYear() - 1867;      
    } else if(gengouAryNum == 1){
      gengo = gengouAry[gengouAryNum];
      thisYear = new Date().getFullYear() - 1911;
    } else if(gengouAryNum == 2){
      gengo = gengouAry[gengouAryNum];
      thisYear = new Date().getFullYear() - 1925;
    } else if(gengouAryNum == 3){
      gengo = gengouAry[gengouAryNum];
      thisYear = new Date().getFullYear() - 1988;
    } else if(gengouAryNum == 4){
      gengo = gengouAry[gengouAryNum];
      thisYear = new Date().getFullYear() - 2018;
    }  
    if(thisYear == 1){
      thisYear = '元';
    }    
    wareki = gengo + thisYear + '年';
    warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
  } else {
    errorMsg = Browser.msgBox('1~5のいずれかを入力してください。');
  }
}

定型句を改修しやすいように、

マジックナンバーやマジック文字列対策で、

function 現在を元号ごとの年数に変換_If文マジック対策(){
  const year = '年';
  const ganNen = '元';
  const saiMeiji = 1867; 
  const saiTaisho = 1911;
  const saiShowa = 1925;
  const saiHeisei = 1988;
  const saiReiwa = 2018;
  const inputMsgStr = 'いずれかの半角数字を入力。明治:1,大正:2,昭和:3,平成:4,令和:5';
  const errorMsgStr = '1~5のいずれかを入力してください。';
  let gengo,gengouAry,gengouAryNum,thisYear,wareki,warekiMsg,errorMsg;
  gengouAry = ['明治','大正','昭和','平成','令和']; 
  gengouAryNum = Browser.inputBox(inputMsgStr);
  if(gengouAryNum == 1 || gengouAryNum == 2 || gengouAryNum == 3 || 
     gengouAryNum == 4 || gengouAryNum == 5){
    gengouAryNum = gengouAryNum - 1;
    if(gengouAryNum == 0){
      gengo = gengouAry[gengouAryNum];
      thisYear = new Date().getFullYear() - saiMeiji;      
    } else if(gengouAryNum == 1){
      gengo = gengouAry[gengouAryNum];
      thisYear = new Date().getFullYear() - saiTaisho;
    } else if(gengouAryNum == 2){
      gengo = gengouAry[gengouAryNum];
      thisYear = new Date().getFullYear() - saiShowa;
    } else if(gengouAryNum == 3){
      gengo = gengouAry[gengouAryNum];
      thisYear = new Date().getFullYear() - saiHeisei;
    } else if(gengouAryNum == 4){
      gengo = gengouAry[gengouAryNum];
      thisYear = new Date().getFullYear() - saiReiwa;
    }  
    if(thisYear == 1){
      thisYear = ganNen;
    }    
    wareki = gengo + thisYear + year;
    warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
  } else {
    errorMsg = Browser.msgBox(errorMsgStr);
  }
}

動きはするけど、場合分けが多く、

コードが冗長

なので、Switch文にする。

if文をSwitch文に変えただけ

function 現在を元号ごとの年数に変換_Switch文に変えただけ(){
  const year = '年';
  const ganNen = '元';
  const saiMeiji = 1867; 
  const saiTaisho = 1911;
  const saiShowa = 1925;
  const saiHeisei = 1988;
  const saiReiwa = 2018;
  const inputMsgStr = 'いずれかの半角数字を入力。明治:1,大正:2,昭和:3,平成:4,令和:5';
  const errorMsgStr = '1~5のいずれかを入力してください。';
  let gengo,gengouAry,gengouAryNum,thisYear,wareki,warekiMsg,errorMsg;  
  gengouAry = ['明治','大正','昭和','平成','令和']; 
  gengouAryNum = Browser.inputBox(inputMsgStr);
  if(gengouAryNum == 1 || gengouAryNum == 2 || gengouAryNum == 3 || 
     gengouAryNum == 4 || gengouAryNum == 5){
    gengouAryNum = gengouAryNum - 1;
    switch (gengouAryNum){
      case 0:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiMeiji; 
      case 1:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiTaisho;
      case 2:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiShowa;
      case 3:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiHeisei;
      case 4:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiReiwa;
    }  
    if(thisYear == 1){
      thisYear = ganNen;
    }    
    wareki = gengo + thisYear + year;
    warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
  } else {
    errorMsg = Browser.msgBox(errorMsgStr);
  }
}

だいぶスッキリしたけど、実行してみると、

動きはするけど、元号が令和から明治に変わっただけで明らかにおかしい。

元号ごとの判定をSwitch文の内側に埋め込む

function 現在を元号ごとの年数に変換_Switch文に元号判定はめ込み(){
  const year = '年';
  const ganNen = '元';
  const saiMeiji = 1867; 
  const saiTaisho = 1911;
  const saiShowa = 1925;
  const saiHeisei = 1988;
  const saiReiwa = 2018;
  const inputMsgStr = 'いずれかの半角数字を入力。明治:1,大正:2,昭和:3,平成:4,令和:5';
  const errorMsgStr = '1~5のいずれかを入力してください。';
  let gengo,gengouAry,gengouAryNum,thisYear,wareki,warekiMsg,errorMsg;  
  gengouAry = ['明治','大正','昭和','平成','令和']; 
  gengouAryNum = Browser.inputBox(inputMsgStr);
  if(gengouAryNum == 1 || gengouAryNum == 2 || gengouAryNum == 3 || 
     gengouAryNum == 4 || gengouAryNum == 5){
    gengouAryNum = gengouAryNum - 1;
    switch (gengouAryNum){
      case 0:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiMeiji; 
        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
      case 1:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiTaisho;
        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
      case 2:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiShowa;
        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
      case 3:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiHeisei;
        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
      case 4:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiReiwa;
        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
    }  
  } else {
    errorMsg = Browser.msgBox(errorMsgStr);
  }
}

実行してみると、

うまくいったかな?
OKを押すとメッセージが連続で出てきて、元号もおかしい。
同じ、、、
現象が、、、
起きている

実は、

Switch文ではよくやりがちなんだけど、これは

各case文の間にbreak文を挟まないので、起きる現象 = フォールスルー

各caseの間に、break文を挟む

function 現在を元号ごとの年数に変換_各casebreak(){
  const year = '年';
  const ganNen = '元';
  const saiMeiji = 1867; 
  const saiTaisho = 1911;
  const saiShowa = 1925;
  const saiHeisei = 1988;
  const saiReiwa = 2018;
  const inputMsgStr = 'いずれかの半角数字を入力。明治:1,大正:2,昭和:3,平成:4,令和:5';
  const errorMsgStr = '1~5のいずれかを入力してください。';
  let gengo,gengouAry,gengouAryNum,thisYear,wareki,warekiMsg,errorMsg;  
  gengouAry = ['明治','大正','昭和','平成','令和']; 
  gengouAryNum = Browser.inputBox(inputMsgStr);
  if(gengouAryNum == 1 || gengouAryNum == 2 || gengouAryNum == 3 || 
     gengouAryNum == 4 || gengouAryNum == 5){
    gengouAryNum = gengouAryNum - 1;
    switch (gengouAryNum){
      case 0:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiMeiji; 
        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
        break;     
      case 1:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiTaisho;
        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
        break;
      case 2:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiShowa;
        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
        break;
      case 3:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiHeisei;
        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
        break;
      case 4:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiReiwa;
        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
        break;
    }  
  } else {
    errorMsg = Browser.msgBox(errorMsgStr);
  }
}

とやると、実行後

OKを押す
連続で表示される事象は解消できた。

念のため、他の元号も試すと、

大正OK
昭和OK
平成OK
令和OK

で、確認できた。

このままだと

        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');

の部分が重複していて、引数

  const year = '年';
  const ganNen = '元';
  const saiMeiji = 1867; 
  const saiTaisho = 1911;
  const saiShowa = 1925;
  const saiHeisei = 1988;
  const saiReiwa = 2018;
  const inputMsgStr = 'いずれかの半角数字を入力。明治:1,大正:2,昭和:3,平成:4,令和:5';
  const errorMsgStr = '1~5のいずれかを入力してください。';
  let gengo,gengouAry,gengouAryNum,thisYear,wareki,warekiMsg,errorMsg;  

が冗長で、メインの処理が見にくい。

そこで、

繰り返される処理を
関数名の後、()の前に'_'(:アンダースコア)
付きでルーチン化

function 元号判定_(gengo,thisYear,year){
    if(thisYear == 1){
      thisYear = ganNen;
    }    
    wareki = gengo + thisYear + year;
    warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');

    return;
}

して、引数をグローバル化

//グローバル
const year = '年';
const ganNen = '元';
const saiMeiji = 1867; 
const saiTaisho = 1911;
const saiShowa = 1925;
const saiHeisei = 1988;
const saiReiwa = 2018;
const inputMsgStr = 'いずれかの半角数字を入力。明治:1,大正:2,昭和:3,平成:4,令和:5';
const errorMsgStr = '1~5のいずれかを入力してください。';
let gengo,gengouAry,gengouAryNum,thisYear,wareki,warekiMsg,errorMsg;

しておくと、実行できる処理が

function 現在を元号ごとの年数に変換_完成形(){  
  gengouAry = ['明治','大正','昭和','平成','令和']; 
  gengouAryNum = Browser.inputBox(inputMsgStr);
  if(gengouAryNum == 1 || gengouAryNum == 2 || gengouAryNum == 3 || 
     gengouAryNum == 4 || gengouAryNum == 5){
    gengouAryNum = gengouAryNum - 1;
    switch (gengouAryNum){
      case 0:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiMeiji; 
        元号判定_(gengo,thisYear,year);
        break;     
      case 1:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiTaisho;
        元号判定_(gengo,thisYear,year);
        break;
      case 2:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiShowa;
        元号判定_(gengo,thisYear,year);
        break;
      case 3:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiHeisei;
        元号判定_(gengo,thisYear,year);
        break;
      case 4:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiReiwa;
        元号判定_(gengo,thisYear,year);
        break;
    }  
  } else {
    errorMsg = Browser.msgBox(errorMsgStr);
  }
}

になる。

仮に元号が増えたら、

  1. 配列要素を追加

  2. 配列要素の数に応じたcase文を増やす

だけだから、変更しやすさもOK。

まとめ(コード比較)

どちらが見やすいか最終的には、お好みで〜〜〜🕺

分割前

function 現在を元号ごとの年数に変換_各casebreak(){
  const year = '年';
  const ganNen = '元';
  const saiMeiji = 1867; 
  const saiTaisho = 1911;
  const saiShowa = 1925;
  const saiHeisei = 1988;
  const saiReiwa = 2018;
  const inputMsgStr = 'いずれかの半角数字を入力。明治:1,大正:2,昭和:3,平成:4,令和:5';
  const errorMsgStr = '1~5のいずれかを入力してください。';
  let gengo,gengouAry,gengouAryNum,thisYear,wareki,warekiMsg,errorMsg;  
  gengouAry = ['明治','大正','昭和','平成','令和']; 
  gengouAryNum = Browser.inputBox(inputMsgStr);
  if(gengouAryNum == 1 || gengouAryNum == 2 || gengouAryNum == 3 || 
     gengouAryNum == 4 || gengouAryNum == 5){
    gengouAryNum = gengouAryNum - 1;
    switch (gengouAryNum){
      case 0:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiMeiji; 
        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
        break;     
      case 1:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiTaisho;
        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
        break;
      case 2:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiShowa;
        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
        break;
      case 3:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiHeisei;
        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
        break;
      case 4:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiReiwa;
        if(thisYear == 1){
          thisYear = ganNen;
        }    
        wareki = gengo + thisYear + year;
        warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');
        break;
    }  
  } else {
    errorMsg = Browser.msgBox(errorMsgStr);
  }
}

分割後(完成形のコードと同じ)

//グローバル
const year = '年';
const ganNen = '元';
const saiMeiji = 1867; 
const saiTaisho = 1911;
const saiShowa = 1925;
const saiHeisei = 1988;
const saiReiwa = 2018;
const inputMsgStr = 'いずれかの半角数字を入力。明治:1,大正:2,昭和:3,平成:4,令和:5';
const errorMsgStr = '1~5のいずれかを入力してください。';
let gengo,gengouAry,gengouAryNum,thisYear,wareki,warekiMsg,errorMsg;

function 現在を元号ごとの年数に変換_完成形(){  
  gengouAry = ['明治','大正','昭和','平成','令和']; 
  gengouAryNum = Browser.inputBox(inputMsgStr);
  if(gengouAryNum == 1 || gengouAryNum == 2 || gengouAryNum == 3 || 
     gengouAryNum == 4 || gengouAryNum == 5){
    gengouAryNum = gengouAryNum - 1;
    switch (gengouAryNum){
      case 0:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiMeiji; 
        元号判定_(gengo,thisYear,year);
        break;     
      case 1:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiTaisho;
        元号判定_(gengo,thisYear,year);
        break;
      case 2:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiShowa;
        元号判定_(gengo,thisYear,year);
        break;
      case 3:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiHeisei;
        元号判定_(gengo,thisYear,year);
        break;
      case 4:
        gengo = gengouAry[gengouAryNum];
        thisYear = new Date().getFullYear() - saiReiwa;
        元号判定_(gengo,thisYear,year);
        break;
    }  
  } else {
    errorMsg = Browser.msgBox(errorMsgStr);
  }
}

function 元号判定_(gengo,thisYear,year){
    if(thisYear == 1){
      thisYear = ganNen;
    }    
    wareki = gengo + thisYear + year;
    warekiMsg = Browser.msgBox('現在は、'+ wareki + 'です。');

    return;
}

以上です✨

この記事が気に入ったらサポートをしてみませんか?