何故書こうと思ったか
エンジニアになってからもう少しで1年になろうとしているので、自分の知識を整理するためにも今まで学んできたTipsをまとめてみようと思いこの記事を書きました。
読みやすいコードとは
読みやすいコードとは脳内メモリーを使わないコードである。
と誰かが言っていて、確かにその通りだなと思ったので、この言葉を使わせていただきます。
また、エンジニアにはおなじみのリーダブルコードには
コードは短くした方がいい。だけど、「理解するまでにかかる時間」を短くする方が大切だ。
と書いてあり、最短で理解できるコードが良いコードだとされています。
この記事で一人でも良いコードを書くためのきっかけをつかんでいただければ幸いです。
記事内のコードはほとんどpythonで書いていて、改善前のコードと改善後のコードを並べ、適宜説明を挟む形で書いております。また、変更箇所には末尾に●をつけてコメントを入れてありますので参考にしてください。
それでは早速読みやすいコードについて見ていきましょう。
1.名前を適切につける
改善前
moq = 100
皆さんはこの変数名を見て何のことだかわかりますでしょうか?運送関係の方だともしかしたらわかるかもしれませんが、
正解はMinimum Order Quantity(最低発注数量)です。
これを書いた人は変数名が長くなりすぎるのを嫌い、略字を使いましたが、これではぱっと見て変数に何が入っているかはわかりません。(運送業で見慣れている人は別ですが。)
これは変数名が長くなってもいいので意味がわかるように記述するべきです。(minimumはminでも伝わるので省略しています。)
改善後
min_order_quantity = 100
また、値が変わらないものであれば定数とするとさらに良いです。(pythonに定数はありませんが、慣習的に大文字とアンダーバーで記述します。)
MIN_ORDER_QUANTITY = 100
ただし、プログラマーが共通で認識しているものであれば略して書いても構いません。
i # イテレーター変数
str # stringの略、文字列を表す
num # numberの略、数字を表す
2.変数スコープを小さくする
改善前
def variable_scope(num):
val1 = 0
val2 = 10
#val1もval2も関係ない処理
#val1もval2も関係ない処理
#val1もval2も関係ない処理
#val1もval2も関係ない処理
#val1もval2も関係ない処理
#val1もval2も関係ない処理
#val1もval2も関係ない処理
#val1もval2も関係ない処理
if val1 == num:
print(b)
改善後
def variable_scope(num):
#val1もval2も関係ない処理
#val1もval2も関係ない処理
#val1もval2も関係ない処理
#val1もval2も関係ない処理
#val1もval2も関係ない処理
#val1もval2も関係ない処理
#val1もval2も関係ない処理
#val1もval2も関係ない処理
val1 = 0 # aを使う直前で初期化を行う ●
if val1 == num:
val2 = 10 # if文の中で初期化を行う ●
print(val2)
変数のスコープが大きいとその変数をコードを戻って探さなければならず脳内メモリを使います。理想的なコードというのは上から下に読んで理解できるコードです。そのためできるだけ変数は使う直前で初期化するようにします。
また、例にある変数のval2はif文の中でしか使われていないのでif文の中で初期化するべきです。もちろんこのパターンが使えないこともありますが、変数のスコープは小さくするというのは基本なので意識するようにしたいものです。
3.マジックナンバーを避ける
改善前
def magic_number(num):
if num == 1:
print('おはよう')
elif num == 2:
print('こんにちは')
改善後
def magic_number(num):
GREET_MORNING_NUM = 1 # 定数で数字を説明 ●
GREET_AFTERNOON_NUM = 2 # 定数で数字を説明 ●
if num == GREET_MORNING_NUM: # ●
print('おはよう')
elif num == GREET_AFTERNOON_NUM: # ●
print('こんにちは')
急に数字の1や2が出てくるとこれは何の数字だろうと考える必要が出てきます。
これを定数として初期化することで数字に意味を持たせて理解しやすくすることができます。
ただ、すぐ理解できるかが重要なため、全ての数字を変数にする必要はなく、必要に応じて使うことが必要です。
4.説明変数を使う
改善前
if a > b and a > c and a > d and a > e: # aが一番大きいかを判定しているが、ぱっとみて何をしているかわかりづらい
#処理
改善後
is_a_largest = a > b and a > c and a > d and a > e # aが一番大きいかを判定 ●
if is_a_largest: # ●
#処理
説明変数を使うことで複雑な条件に名前をつけることができ、コードが読みやすくなります。
例ではaが一番大きいかを判定していますが、改善前のコードが何をしているのかパッとはわかりません。
そこでこの条件に名前をつけましょう。今回はis_a_largestという名前をつけました。(変数名はa,b,cと良い名前ではありませんが、わかりやすくするためにあえてこのような名前にしています。)
こうすることで条件を読まなくてもaが一番大きいか判定しているんだなと変数名を見ればわかります。
ちなみにTrue,Falseといった真偽値が入っている変数名にはisやhas、canといった接頭辞をつけるとわかりやすいです。
ただし無駄な変数は使わない方が良いため、説明変数は適切な場所で使うようにしましょう。
例えば以下のような説明変数は適切ではありません。
now = datetime.datetime.now()
nowという変数はなくてもdatetime.datetime.now()を見れば現在時刻が入っていることはわかります。
このnowを色々な場所で使うのであれば文字数を減らす効果があり読みやすくなるかもしれませんが、そうでなければこのような無駄な変数は作成しない方が良いです。
5.ガード節(アーリーリターン)
改善前
def early_return(num):
if num == 1:
for i in range(3):
print(num)
改善後
def early_return(num):
if num != 1: # num == 1をnum != 1に変更 もしnumが1じゃなかったらreturnして処理を終える。 ●
return
for i in range(3):
print(num)
if文の条件を否定にすることでfor文のネストを一段消すことができました。
このように条件にかからなかったらすぐにreturnすることでネストを減らしたり、コードを読みやすくすることができます。
ただし、否定の条件は肯定の条件よりも脳内メモリを使うため、このような理由がない限り使わないようにした方が良いと思います。
ネストの方が否定より脳内メモリを使うことが多いので、ここでは否定を使っています。
6.else、if文を消す
改善前
def if_statement(num):
if num == 1:
return True
else:
return False
改善後
def if_statement(num):
if num == 1:
return True
return False # numが1じゃなかったらFalseを返す。 ●
この場合numが1だったらTrueを返して処理終了、
1ではなかったらFalseを返して処理終了なのでelseを省略しても同じ結果になります。
またさらにこの関数では直接TrueとFalseを返しているだけなので以下のようにも記述することができます。
def if_statement(num):
return num == 1 # num == 1はTrueかFalseなのでif文を消すことができる。 ●
num == 1の結果はTrueかFalseになるのでそのまま返すことができ、if文を消すことができました。
7.switch文やelifを消す
改善前
def many_elif_statements(num):
if num == 1:
return 'おはよう'
elif num == 2:
return 'こんにちは'
elif num == 3:
return 'こんばんは'
elif num == 4:
return 'おやすみ'
JavaScriptのswitch文(pythonにはswitch文がないためJavaScriptを記述)
switch (num) {
case 1:
return 'おはよう'
case 2:
return 'こんにちは'
case 3:
return 'こんばんは'
case 4:
return 'おやすみ'
改善後
def many_elif_statements(num):
greetings = { # 辞書型の変数を用意 ●
1: 'おはよう',
2: 'こんにちは',
3: 'こんばんは',
4: 'おやすみ',
}
return greetings[num] # 辞書の値を返す ●
switch文は連想配列(pythonでは辞書)を使うことで消せることがあります。
例では辞書のキーに条件で比べる数字を書き、値に返したい文字を入れています。
辞書の値には変数名[キー]とすることで値にアクセスできるのでこのようにすっきり書くことができます。
javascriptでも同じようにかけます。
最後に
以上、読みやすいコードを書くためのTipsを紹介させていただきました。
ここに挙げた以外にもコードを読みやすくする方法はたくさんありますので興味がある方は是非調べてみてください。
また、まだリーダブルコードを読んだことがない方はこの機会に読んでみるのも良いかもしれません。
正直いうとプログラムを書き始めたばかりの人が読むには難易度が高く、私も一度読んだだけでは全てを把握しきれませんでした。
一度で全て覚えるのは無理だと思うので何回も読む気持ちで取り組むと少しずつ理解できて良いコードが書けるようになっていくと思います。
他にももっと良い書き方があるよという方はコメントで教えていただけると幸いです。