6
3

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 5 years have passed since last update.

人に優しいコードを書こう

Last updated at Posted at 2019-11-01
1 / 42

何のためにコードを書くの?

ソースコードは動かすために書くんじゃないよ。
人に読んでもらう為に書くんだよ。

  • 今後入ってくるエンジニアへ
  • 1年後、そのシステムのメンテナンスをする自分にむけて

汚いコードとは?


見た目が汚い

読む速度が落ちる

  • ネストしすぎ
  • なんかぎゅっとしてる(スペース・改行全然空いてないとか)
  • 絵として汚い

何をしてるのかわからない

理解する速度が落ちる

  • 名前以上の事を行う関数 (getXXX()がDBに書き込みとか)
  • 読み手の記憶力に頼る
    • 関数が長い
    • 変数多い
    • 変数名の使い回し
  • 名前が適当(クラス・メソッド・変数)

コメントが嘘

間違った理解をする


実例


その1: 見た目が汚い


ダメなコード

function main() {
 $endValue=30;
 for ($i=1;$i<$endValue+1;$i++){
  if($i%15==0){echo 'FizzBuzz';}
  elseif($i%5==0){echo 'Buzz';}
  elseif($i%3==0){echo 'Fiz';}
 else{echo $i;}
 echo '<br>';
}}

システムリニューアル案件の既存コードの調査とかでよく見る。
そもそも読む気にならない。


良いコード

function main() {
    $endValue = 30;
    for ($i = 1; $i <= $endValue; $i++) {
        echo getAnswer($i) . '<br>';
    }
}

function getAnswer($value) {
    switch (true) {
        case isFizzBuzz($value): return 'FizzBuzz';
        case isFizz($value): return 'Fiz';
        case isBuzz($value): return 'Buzz';
        default: return $value;
    }
}

function isFizzBuzz($value) { return $value % 15 == 0; }
function isFizz($value) { return $value % 3 == 0; }
function isBuzz($value) { return $value % 5 == 0; }

  • インデント、適切な改行・スペースは当たり前。
  • 処理を関数化するほど情報量は増えていく。
  • 処理の粒度が大きい方から書くと読みやすい。
    • 上から下へ読める
    • 不要な定義を読む必要がない
  • if文などの条件には じゃなく が書いてあった方が読みやすい。

その2: 名前が適当


ダメなコード

def main():
    data = get_data()
    value = get_value(data)
    return value

なにやってるのかさっぱりわからない。。


def main():
    # モデルの一覧を取得します
    data = get_data()
    # タスクタイプ毎の件数をカウントします
    value = get_value(data)
    return value

コメントを書くぐらいなら、適切な名前をつけよう


良いコード

def main():
    models = get_model_list()
    count_per_task_type = get_count_per_task_type(models)
    return count_per_task_type

その3: 名前以上の事をしてる


ダメなコード

def main():
    models = get_model_list()
    count_per_task_type = get_count_per_task_type(models)
    return count_per_task_type

def get_count_per_task_type(models):
    count_per_task_type = ...
    save_count('classification', count_per_task_type['classification'])
    save_count('object_detection', count_per_task_type['object_detection'])

気軽に呼んでたらガンガンDBに書き込んでる件。


良いコード

def main():
    models = get_model_list()
    count_per_task_type = get_count_per_task_type(models)
    save_count('classification', count_per_task_type['classification'])
    save_count('object_detection', count_per_task_type['object_detection'])
    return count_per_task_type

def get_count_per_task_type(models):
    count_per_task_type = ...
    return count_per_task_type

名前以上のことはしない!


その4: カッコつけない


ダメなコード

# 内包表記の方が速度的には早いらしいが。。
model_images = {
    model: flatten([
        [
            image
            for image in dataset.images
            if image.filepath.exists()
        ]
        for dataset in model.datasets
    ])
    for model in models
    if model.is_archived is False
}

競技プログラミングとかでやってくださいませ!


良いコード

model_images = {}
for model in models:
    if model.is_archived is True:
        continue
    
    if model not in model_images:
        model_images[model] = []
    
    for dataset in model.datasets:
        for image in dataset.images
            if not image.filepath.exists():
                continue
            model_images[model].append(image)

ネストは深いけど、こっちのほうが理解はしやすい。


綺麗に書くテクニック


コントローラ部分に処理の流れをコメントとして書く


def main():
    # モデルの一覧を取得します
    pass

    # タスクタイプ毎の件数をカウントします
    pass

    # テンプレートをレンダリングします
    pass

    # レスポンスを返します
    pass

このコメントがそのまま関数になります。
(簡単な処理は関数化しなくてOKです)


呼び出し側だけ先に書く


def main():
    # モデルの一覧を取得します
    models = get_model_list(order='-creation_date', limit=30);

    # タスクタイプ毎の件数をカウントします
    count_per_task_type = get_count_per_task_type()

    # テンプレートをレンダリングします
    html = render_template(
        template_path='./path/to/template.html',
        models=models,
        count_per_task_type=count_per_task_type,
    )

    # レスポンスを返します
    return Response(200, html)

クラスや関数を作る際に先に呼び出し側を先に書く。
こうするとInput/Outputが決まるので、作るものが明確になる。
テストを先に書くと TDD になるよ!


できるだけ関数を小さく書く


def main():
    data = get_model_list()
    value = get_count_per_task_type(data)
    save_count('classification', value['classification'])
    save_count('object_detection', value['object_detection'])
    return value

def get_count_per_task_type(data):
    value = # Get count per task type
    return value

def save_count(name, value):
    obj = ModelCount.objects.get(name=name)
    obj.count = value
    return obj.save()

関数が小さいと変数名が適当でも意味が通じる。
長い変数名を定義しないと意味が通じない場合は、関数が大きすぎる。
10〜30行ぐらいが目安。


同じパターンで書く


def get_model_list():
    # Check parameters
    ...

    # Get data from db
    ...

    # Response
    ...

def get_model_detail():
    # Check parameters
    ...

    # Get data from db
    ...

    # Response
    ...

WEBサーバーのエンドポイントとか、Reactコンポーネントとか、
大量に似たようなものを作る場合は、書き方(書く順番)を統一すると読みやすい。


おしまい

6
3
0

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
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?