Keecom's Yuruyuru Outputs

興味のある事をゆる〜くアウトプットしていきます

良いコードを目指して ~先を見据える~

今回は、初回に定義した"良いコード"には近づきませんが、保守性という意味での良いコードに近づいていきたいと思います!

今回のメインテーマは"先を見据える"です。

プログラムの保守性について

コンピュータシステムに関する評価指標[RASIS]の1要素である、保守性について。
保守性とは、一般的に以下であるそうです。(Wikiより引用)

ソフトウェアプログラムの場合、バグなどの不具合要因を修正したり,性能や使い易さといった特性を改善したり、製作当初に想定していなかった機能の追加や変更を少ない手間やコストで実施・改変が行える容易さを表す。

つまり、作成後にどれだけ手が加えやすいか、また加えるコストが少ないかという観点です。

保守性が高いプログラムにすることは、コストに直結するのでより良いコードであると言えるでしょう。

そんな保守性の高いプログラムに近づいて行こうと思います。


先を見据えるとはどういうことか


皆さんはコードを書く際にどんなことを考えていますか?

私は、設計書などを元に頭の中でロジックを考えながら書いたり、不具合などが起きる要素はないか確認しながら書いていることが多かったです。

ですが、先日職場でこんな言葉を耳にしました。

"このコードは先が見えてないからイケてないね"

そこで、"先を見据える"という事を以前よりも強く意識するようになりました。

"先を見据える"と言うことは、後々のことを考えて効率の良いコードを考えることです!

すみません、噛み砕いて書けなかったので実例を読んでいただければと思います、、、。


先を見据えるコーディング(具体例)

画面に生年月日を入力するインターフェースを考えましょう。

顧客から以下の要件が必須であると依頼を受けました。

  • 1.和暦入力にしてほしい
  • 2.入力チェックをし、和暦として存在しない年月日の場合はエラーにしてほしい

実際に画面側を考えるならば、一般的には以下のような感じでしょう。
※以下、平成30年1月現在のものなので新元号は記載してません。



今回はコントローラ側の入力チェック処理に着目します。

まず、必要な入力チェック処理を考えます。
- 1.和暦毎の"年"の妥当性チェック
- 2."月"の妥当性チェック
- 3.月毎の"日"の妥当性チェック(厳密には和暦とも関連)

これらのチェックを通過した値が正常な生年月日として処理されるでしょう。


さて、前置きが長くなりましたが、実際に"先を見据える"ことを意識してコーディングをしていきましょう。

今回は先のチェック項目の[1]について考えていきます。

まず何も考慮しなかった場合、チェック処理を担うメソッドは以下のように記述することができるでしょう。
(正確には全てStringの引数になりますが省略します。)

public Boolean checkBirthDay(String birthJa , Integer year , Integer month , Integer day){
    //和暦毎の"年"値の妥当性チェック
    if( birthJa == "T" ){
        if( year < 1 || year > 15 ){
            return false;
        }
    }else if( birthJa == "S" ){
        if( year < 1 || year > 64 ){
            return false;
        }
    }else if( birthJa == "H" ){
        if( year < 1 || year > 30 ){
            return false;
        }
    }
    //**以下省略**
}

上記コードは動作すると思いますが、明らかに問題点があります。

既に2019年5月から新元号となるため、必ずプログラムの改修が必要になります。

これは保守性の観点でいくと、あまり良いとは言えないでしょう。

今回の改善策としては、和暦データをメタデータなどに外出ししてしまいましょう。

和暦などは、処理するロジックに使用する"数値"というよりは"データ"という表現が正しいと思うので、ハードコードすることは極力避けましょう。

では、実際にメタデータを利用してMapを使った処理を記述してみましょう。

public Boolean checkBirthDay(String birthJa , Integer year , Integer month , Integer day){
    //                  jpCalendarMap #  [key]:和暦アルファベット1文字  [value]:和暦の最後の年
    Map<String,Integer> jpCalendarMap = jpCalendarDao.getJpCalendarMap();

    //和暦毎の"年"値の妥当性チェック
    if( jpCalendarMap.containsKey(birthJa) ){
        if( year < 1 || year > jpCalendarMap.get(birthJa) ){
            return false;
        }
    }
    //**以下省略**
}

行数として凄くシンプルになりました。

そして何より、後者のプログラムではメタデータ側にデータを追加するだけでチェック処理は正常に動くんです!!

こういった形で、コードを書く際に"この先に起こりうること"を意識することで保守性の高いプログラムを目指すことができます。

プログラム例の余談

西暦年をメタデータ側に持ち、DateFormat型のparse処理で入力チェックを行うのも良いでしょう



"先を見据える"ことは正直、経験と知識が大きく関連してくるでしょう。

事実私もまだまだイケてるコードを書けてる時は少ないと思います。

しかし、少しでも念頭に置いておくことで多少なりとも磨きがかかってくると思うので、より良いコードを目指していきましょう!!