アヒルのある日

株式会社AHIRUの社員ブログです。毎週更新!社員が自由に思いついたことを書きます。

コードの可読性

こんにちは みにくい社長です。
今日から株式会社AHIRUの社員ブログが始まります!
毎週更新しますので、ヒマな時にチェックしてみてくださいね。

今年の夏休みはたくさんのインターンシップの学生が来てくれました。
1週間の研修期間でどれだけのことを教えられるか悩んでいたのですが、やる気のある学生が集まってくれたので、しっかり学んでもらえたと思います。
プログラムを始めた時は誰でもそうなのですが、課題通りに実装することに注力するあまり、プログラムが複雑になったり、他人に読めないようなコードになってしまったりします。

今日は基本的なプログラムの可読性を上げる為の方法を紹介します。
言語はC#で書きますが、ほとんどの言語で共通している内容です。

(1)変数名や関数名に気を遣う

コメントが無いプログラムは不親切かというと、そうでもなかったりします。
コメントを書かなくても、適切な変数名、関数名を付けることで、多くのことを伝えることができます。
悪い例:

int GetSumA(int value1, int value2)
{
    int a = 0;
    for(int i = value1; i < value1 + value2; i++)
    {
        a += i;
    }
    return a;
}

int GetSumB(int value1, int value2)
{
    int a = 0;
    for(int i = value1; i < value2 - value1; i++)
    {
        a += i;
    }
    return a;
}

良い例:

int GetSumCount(int from, int count)
{
    int sum = 0;
    for(int i = from; i < from + count; i++)
    {
        sum += i;
    }
    return sum;
}

int GetSumRange(int from, int to)
{
    int sum = 0;
    for(int i = from; i < to - from; i++)
    {
        sum += i;
    }
    return sum;
}

関数名と引数の名前だけでも、ある程度使い方が伝わるかと思います。
プログラムは英語で記述されているので、英語でコメントを書くとコメントはほとんど不要であることがわかりますね。
コメントを書くことよりも、関数名、変数名を的確に記述するようにしましょう。

(2)returnを多用しない

nullチェックが抜けていたため、関数の最初にこのように追加したくなることがあります。
悪い例:

void CheckList(List<Object> list, id)
{
    if(list == null)
    {
        return false;
    }

    foreach(var obj in list)
    {
        if(obj.id == id)
        {
            return true;
        }
    }   
    return false;
}

この関数をデバッグするときにreturn文が3箇所に分かれている為、ブレークポイントを3箇所に設定することになります。
下記のように書き直してみましょう。
良い例:

void CheckList(List<Object> list, id)
{
    bool found = false;
    if(list != null)
    {
        foreach(var obj in list)
        {
            if(obj.id == id)
            {
                found = true;
                break;
            }
        }   
    }
    return found;
}

これでreturn文が1つになるので、最後にブレークポイントを設定すれば結果を確認することができます。
もっと長い処理が書かれた関数の場合、returnが分散しているとデバッグ時に見落として混乱することがありますので、できるだけ集約するようにしましょう。

(3)条件を反転しない

条件分岐を書くときに、できるだけ真偽を反転させないようにした方が直感的に読みやすいです。
悪い例:

if(obj != null)
{
    if(!(a < 0))
    {
        result = a;
    }
}
else
{
    a = 5;
}

良い例:

if(obj == null)
{
    a = 5;
}
else
{
    if(a >= 0)
    {
        result = a;
    }
}

(4)変数の寿命を短くする

他人のコードを読む時やデバッグをする時には、コンピュータと同じ動きを自分の頭の中でシミュレートすることになります。
その際に、記憶することはできるだけ少ない方が頭が疲れなくて楽です。
関数内のローカル変数を宣言する場所を整理すると、コードが読みやすくなります。
悪い例:

bool found = false;
List<Object> objects;
if(listA != null)
{
    objects = listA;
}
else
{
    objects = listB;
}

foreach(var obj in objects)
{
    if(obj.id == id)
    {
        found = true;
        break;
    }
}
return found;

良い例:

List<Object> objects;
if(listA != null)
{
    objects = listA;
}
else
{
    objects = listB;
}

bool found = false;
foreach(var obj in objects)
{
    if(obj.id == id)
    {
        found = true;
        break;
    }
}
return found;

変数にはスコープという有効範囲があり、C言語系であれば{}でスコープが区切られています。
変数を宣言してから変数がメモリから失われるまでの範囲を変数の寿命と呼びますが、この寿命が短いほど、変数の影響範囲が狭くなるためコードが読みやすくなります。

(5)定数を定義する

他人のコードを読むときに一番辛いのが、意味のわからない定数(マジックナンバー)です。
この計算式は何を表しているのでしょうか。

double value = 1000 * 8 * 20 * 1.08;

定数を定義してみます。

const int cost = 1000;
const int hour = 8;
const int day = 20;
const double tax = 1.1;
double totalCost = cost * hour * day * tax;

時給から月給の支払額を計算しているというのがわかりますね。
変数でない場合でも数字を直接書くのではなく、定数として定義すると読みやすくなります。

僕が新人のころに最初に教わったことでとても重宝しているのが、エディターの機能で定数が定義されているかどうかを確認する方法です。
Visual Studioでは定数の部分の色を変えることができます。
f:id:minikui_ahiru:20191024185105p:plain これで、プログラム内に色がたくさんついている場合は悪いプログラムである、ということが視覚的に確認できます。

コードの可読性を上げる方法をいくつか紹介しました。
プログラムは宗教論などと言われることもありますが、いつでも正しいテクニックはあるので、押さえておきたい所ですね。

またねー