はじめに
ソフトウェア開発において、コードの可読性はプロジェクトの成功に直結する重要な要素です。読みやすいコードは、メンテナンスや拡張を容易にし、チーム全体の生産性を向上させます。
しかし、「読みやすいコード」 の定義は人によって異なります。個々のスタイルや好みによって解釈が分かれることもあるでしょう。それでも、できる限り多くの人にとって理解しやすいコードを書くことが、プロフェッショナルとしての責任です。このガイドでは、そんな読みやすさを意識した具体的なテクニックなどを紹介していきます。「もう知ってるよ!」と思った方も、今一度できているかを確認してみてください。
弊社Nucoでは、他にも様々なお役立ち記事を公開しています。よかったら、Organizationのページも覗いてみてください。
また、Nucoでは一緒に働く仲間も募集しています!興味をお持ちいただける方は、こちらまで。
注意点
ここで紹介するのは、効率性を最優先したコードの書き方ではなく、誰が見ても理解しやすい、可読性の高いコードの作成方法です。効率的なコードを書くことも大切ですが、可読性を犠牲にしてしまうと、結果的にメンテナンス性が低下し、プロジェクトの長期的な成功に悪影響を及ぼす可能性があります。
また、コードを簡潔に書くことが重要だと思われがちですが、簡潔さが必ずしも読みやすさにつながるわけではありません。この記事では、可読性を重視した具体的なテクニックなどを紹介します。
また、現場で実際にコードを書いている方には、「いや、そこはちょっと違うんじゃないか」と感じる部分があるかもしれませんが、その点はご理解いただけると幸いです。
ソースコードを綺麗にする17つのポイント
これから、私が考えるソースコードを綺麗に保つための17のポイントを紹介していきます。それでは、一緒にこれらのポイントを見ていきましょう!
名前に情報を詰め込む
まず最初に紹介するのは、名前に情報を詰め込むことの重要性です。コードの中で使われる変数や関数の名前は、単なるラベルではなく、その役割や意味を伝える重要な要素です。適切な名前を付けることで、コードの可読性が大幅に向上し、他の開発者や自分自身が後からコードを見返したときに、その意図や機能をすぐに理解できるようになります。
それでは、具体的にどのように名前に情報を詰め込むべきか、見ていきましょう!
命名規則に従う
命名規則とは、「コード内で使われる変数名や関数名などの命名スタイルを統一する」 ためのルールです。これに従うことで、プロジェクト全体で一貫性が保たれ、コードの可読性が向上します。一貫した命名規則があれば、誰がコードを見てもすぐに理解でき、メンテナンスや新しい開発者の参入がスムーズに進みます。
同じ種類のデータや操作に対して一貫した名前付けをすることで、コード全体が統一されたスタイルになり、読み手がその意図をすぐに理解できるようになります。逆に、一貫性が欠けると、コードが雑然として見え、理解やメンテナンスが難しくなってしまいます。
それでは、以下の表で各命名規則の例を確認してみましょう。
命名規則 | 説明 | 例 |
---|---|---|
キャメルケース (camelCase) | 最初の単語は小文字で始め、次の単語は大文字で始める。 | userId |
アッパーキャメルケース/パスカルケース (UpperCamelCase/PascalCase) | すべての単語を大文字で始める。クラス名や構造体名によく使われる。 | UserId |
スネークケース (snake_case) | 単語をアンダースコアで区切り、すべて小文字にする。関数名や変数名に使われることが多い。 | user_id |
コンスタントケース/アッパースネークケース (CONSTANT_CASE/UPPER_SNAKE_CASE) | 単語をアンダースコアで区切り、すべて大文字にする。定数に使用されることが多い。 | USER_ID |
チェインケース/ケバブケース (chain-case/kebab-case) | 単語をハイフンで区切り、すべて小文字にする。URLやCSSクラス名で使用されることが多い。 | user-id |
この表を基に、命名規則に従った良い例と悪い例を見てみましょう。
def get_user(user_id):
# ユーザーデータを取得する
def modify_user_data(user_id, data):
# ユーザーデータを更新する
この例では、get_user
とmodify_user_data
のように、同じユーザーデータを操作する関数で異なる命名規則が使われており、一貫性がありません。これでは、コードを読む人が混乱しやすくなります。まだこの例は簡単なので大きな混乱を招くことはありませんが、コードが複雑になればなるほど、こうした一貫性の欠如がより大きな混乱を生じる可能性が高くなります。
def fetch_user_data(user_id):
# ユーザーデータを取得する
def update_user_data(user_id, data):
# ユーザーデータを更新する
この例では、ユーザーデータに関連する操作で一貫した命名fetch_user_data
と update_user_data
が行われており、コードの意図が明確で統一感があります。
命名規則を守り、一貫性を保つことで、コード全体が統一されたスタイルになり、他の開発者がその規則に従って命名する際の手がかりにもなります。少し気を配るだけで、チーム全体の作業効率が上がり、コードの品質も向上するはずです。
理解しやすい関数名をつける
関数名は、その関数が何をするのかを一目で理解できるようにすることが重要です。
def calc():
# 何を計算するのか不明確
この例では、関数名が抽象的すぎて、他の開発者が理解するために余分な質問や確認が必要になります。
def calculate_total_price(items):
# 商品の合計価格を計算する
この例では、関数名から何をする関数かが一目で分かり、レビュー時に説明する必要がほとんどありません。
適切な関数名をつけることで、チーム内での理解が早まり、余計なやりとりを減らせるというメリットがあります。名前を見ただけでその機能が理解できるように意識してみましょう。
適切な名前をつける
また、理解しやすい関数名だけではなく、コードを書く際には、関数や変数に適切な名前をつけることも重要です。名前は、その関数や変数が何をするのか、何を表しているのかを正確に伝える役割を持っています。時には、初めて名前をつけたときよりも、もっと具体的で分かりやすい名前があるかもしれません。
例: データを処理する関数
-
processData:
最も広い意味でデータを処理する。具体的な処理内容は定義されていないため、汎用的な名前として使用されますが、処理内容を明確にするためにさらに具体的な名前を検討することが推奨されます。 -
cleanData:
データの欠損値の除去や異常値の修正など、データの質を向上させるための処理を行う。 -
normalizeData:
データを正規化する。データのスケーリングやフォーマットの統一など、データを一貫した形に整える処理を行う。 -
sortData:
データを昇順や降順に並び替える処理を行う。 -
mergeData:
複数のデータセットを一つに統合する処理を指します。
このように、関数名は、処理内容に応じて具体的かつ適切に選ぶことが大切です。関数名は、その関数が何を行うかを明確に伝える重要な役割を持っています。データ処理に限らず、すべての関数において、処理の目的に最も合致する名前を選ぶことで、コードの可読性が向上し、他の開発者にも意図が伝わりやすくなります。
名前に具体性をもたせる
コードを書く際には、変数や関数にできるだけ具体的な名前をつけることが重要です。たとえば、変数にa
, b
, c
のような抽象的な名前をつけるのではなく、その変数が何を表しているのかが一目でわかるような具体的な名前を使用しましょう。
a = 10
b = 20
c = a + b
この例では、a
, b
, c
という変数名が何を意味しているのか全くわかりません。これでは、コードを読む人が混乱しやすくなります。
price_item1 = 10
price_item2 = 20
total_price = price_item1 + price_item2
ここでは、変数名をprice_item1, price_item2, total_priceとすることで、何を表しているかが明確になります。このように具体的な名前をつけることで、コードの意図が伝わりやすくなり、可読性が向上します。
具体的な名前をつけることで、コードがより読みやすくなり、他の開発者がその意図を正確に理解できるようになります。抽象的な名前ではなく、具体性を持たせた名前を選ぶことを常に意識しましょう。
ただし、info
やdata
のような汎用的で曖昧な名前は避けるべきです。これらの名前は何を意味しているかが不明確であり、コードの意図が伝わりにくくなります。
略語や省略を避ける
変数名や関数名に略語や省略形を使うことは、コードの可読性を下げる原因になります。略語や省略形を使うと、名前が短くなりすぎて意味が不明確になり、コードを読む他の開発者や将来の自分が混乱する可能性があります。そのため、名前には必要な情報をしっかりと含めることが重要です。
ただし、略語を避けることが絶対的なルールではありません。例えば、よく使われる略語や業界標準の略語など、一般的に理解されやすい場合は使用しても問題ありません。大切なのは、情報を省略しすぎて意味が伝わらなくならないようにすることです。まずは必要な情報を含めた上で、名前を簡潔に保つことを目指しましょう。
ただし、具体性を重視する一方で,スコープが限定されている場合には、短い名前が許容されることもあります。
if(product){
let p = product.details.price
alert(`商品の価格: ${p}`)
}
この例では、スコープが狭いため、p
という短い変数名が使用されています。変数の参照先がすぐ近くにあるため、このような短い名前が適用されても問題が生じにくいです。
しかし、このp
がグローバル変数として使用される場合は、product_price
のように、より具体的で情報を伝えやすい名前を使う方が適切です。
英語の命名規則を守る
コードを書く際には、変数名や関数名に適切な英語を使用することが基本です。初歩的ではありますが、変数名をローマ字で書くのではなく、必ず英単語を使用しましょう。例えば、「価格」をkakaku
ではなく、price
と表記しましょう。
また、変数や関数が単数形か複数形かを適切に使い分けることも重要です。例えば、1つのユーザーを扱う場合はuser
、複数のユーザーを扱う場合はusers
とすることで、コードの意図がより明確になります。
さらに、関数名においてis
、has
、can
、should
などを適切に使用することで、関数が何を返すのかが一目で分かるようになります。例えば、isValid
は真偽値を返す関数であることを示し、hasItems
はアイテムが存在するかどうかを確認する関数であることが伝わります。
コードの一貫性
次に紹介するのは、コードの一貫性についてです。プロジェクトの成功において、コードの一貫性は欠かせない要素です。一貫性のあるコードは、他の開発者が理解しやすく、メンテナンスも容易になります。特にチーム開発では、全員が同じルールやスタイルに従うことで、コードの可読性が向上し、プロジェクト全体の効率も高まるでしょう。
一貫性のある書き方
コードの一貫性を保つためには、チーム全体で一貫性のある書き方を徹底することが重要です。一貫性のある書き方をすることで、コードの可読性が向上し、他の開発者がその意図を理解しやすくなります。
では、具体的な例を見ていきましょう。
# 同じ条件式でも異なる書き方が混在している
if (is_ready and (count > 10)):
process_data(data)
if (count > 10 and is_ready):
process_data(data)
# 統一された書き方:
# すべての条件式で、論理演算子の順序やカッコの使い方を統一する
if is_ready and (count > 10):
process_data(data)
この例では、論理演算子の順序とカッコの使い方を統一することで、コードの一貫性が保たれています。同じ条件をチェックするコードが異なる書き方をしていると、理解が難しくなりますが、一貫性を持たせることで、意図が明確になり、バグの発生も防ぎやすくなります。
# 関数や変数名の命名規則が統一されていない
def get_user_info():
pass
def fetchUserData():
pass
# 統一された書き方:
# プロジェクト全体で同じ命名規則を徹底する
def get_user_info():
pass
def fetch_user_data():
pass
この例では、命名規則を統一することで、コード全体に統一感が生まれます。先ほど説明したキャメルケースやスネークケースなど、プロジェクトで定めた命名規則に従うことで、コードの可読性が向上します。
形式とスタイルの統一
一貫性のある書き方に加えて、コードの可読性を高めるためには、形式とスタイルの統一も欠かせません。インデント、ブレースの配置、スペースの使い方などを統一することで、コードが整理され、読みやすくなります。これらは個人差が出やすい部分でもあるため、全員が同じルールを守るように気をつけましょう。
ただし、無理にコードを共通化しようとすることは避けるべきです。共通化は、重複を減らし、メンテナンス性を向上させるために有効な手段ですが、異なる目的や文脈で使用されるコードを無理に一つにまとめると、かえって複雑になり、可読性が低下することがあります。必要な場合にはシンプルで明確なコードを個別に書く方が、結果的にコードの可読性が高まります。
コードドキュメントの作成
可読性の高いコードを書くためには、コードドキュメントを作成するのも一つの手です。関数やクラスの役割や使用方法を明確に説明するドキュメントを作成することで、他の開発者がコードを理解しやすくなります。また、プロジェクト全体の概要や設定方法などをまとめたREADMEファイルも、コードの可読性を向上させるために欠かせません。
しっかりと整備されたコードドキュメントとREADMEは、新しい開発者がプロジェクトにスムーズに参加できるようにするだけでなく、既存のメンバーがコードの意図や構造を再確認する際にも役立ちます。
外部ツールの使用
他にも、外部ツールを使用することで、コードのスタイルやフォーマットを自動的に統一し、手作業によるチェック漏れを防ぐことができます。これにより、コード全体の一貫性が保たれ、読みやすさが向上します。特に、チーム開発では、ツールの導入が全員のコードスタイルを揃え、コードの可読性をさらに高める要因となるでしょう。
例:
-
リンター(Linter): コードのスタイルやフォーマットを自動でチェックし、統一されたスタイルを維持するツール。
-
フォーマッター(Formatter): インデントやスペースの使い方を自動で整え、視覚的な一貫性を保つツール。
-
静的解析ツール: コードの潜在的なバグやセキュリティリスクを検出し、品質と一貫性を保つツール。
など
コメントの使用
コードを書く際、すべてを名前や構造だけで説明しきれないことがあります。そんなとき、コメントはコードの意図や仕組みを補足するための有効な手段となります。適切なコメントは、他の開発者がコードを理解する助けとなり、将来のメンテナンスやデバッグを容易にします。しかし、コメントは必要最小限に留め、コードが読まれる際の邪魔にならないようにすることが大切です。
それでは、可読性を上げるコメントの有効活用法についてみていきましょう!
重要事項をコメントで補足する
コードの中には、一見して理解しにくい部分や、特殊な処理が必要な箇所があります。こうしたトリッキーな箇所には、補足的なコメントを残すことで、他の開発者が意図を理解しやすくなります。
たとえば、特定の条件下でのみ動作する処理や、最適化のための工夫が必要な部分などが該当します。コメントを適切に補足することで、コードの可読性が向上し、将来的なメンテナンスや拡張もスムーズに行えるようになります。
マジックナンバーの説明
マジックナンバーは極力使用しない方が良いですが、どうしても使用する場合には、その意図を明確にするためにコメントを付けることが重要です。マジックナンバーは、数値自体がその意図を伝えにくいため、コメントで補足することで、コードの可読性が向上します。
if (18 < age <= 65) or (70 < age <= 80):
# 18-65歳は通常割引、70-80歳はシニア割引
print("Eligible for discount")
このように、マジックナンバーを使用する際には、必ずその意図をコメントで説明することで、他の開発者がコードを理解しやすくなります。
不要なコメントを削除する
コードを書く際、途中経過や意図を示すコメントを残すことは非常に重要です。しかし、不要なコメントは削除することも同じくらい大切です。コメントが多すぎると、コードが読みにくくなり、本当に必要な情報が埋もれてしまうことがあります。
特に、コードから直接理解できる内容をわざわざコメントに残す必要はありません。たとえば、以下のような例を見てみましょう。
def add_numbers(a, b):
# 2つの数字を足す
return a + b
この例では、add_numbers
という関数名とその内容から、2つの数字を足すという動作が明確にわかります。それにもかかわらず、2つの数字を足す
というコメントが付けられています。このようなコメントは不要であり、コードの可読性を下げる要因になります。
こうした自明なコメントは削除し、コード自体が意図を十分に伝えている場合には、コメントを省略することで、コードがシンプルかつ読みやすくなります。
ロジックの複雑度を減らす
コードの可読性を高めるためには、ロジックをできるだけシンプルに保つことも大切です。複雑なロジックは、後から見返したときに理解するのが難しくなります。ここでは、ロジックの複雑度を減らし、コードをよりわかりやすくするための具体的な方法について説明していきます。
単一責任
単一責任の原則とは、「一つの関数やメソッドは、一つの機能だけを担当するべき」 というルールです。この原則を守ることで、コードがシンプルになり、各関数が何をするのかが明確になります。例えば、複数の役割を一つの関数に詰め込むと、修正や変更が必要なときに、どこを手直しすればよいのかが分かりにくくなり、結果的に他の部分にも影響が出る可能性が高まります。
一方、単一の機能に専念した関数は短く、シンプルで管理しやすくなります。これにより、コードの保守性が向上し、作業がスムーズになります。複数の役割を持たせるのではなく、機能ごとに分割してコードを整理することで、後から見返しても理解しやすくなり、エラーやバグの発生も防ぎやすくなります。
def manage_project(project):
# プロジェクトの進捗を確認
if not project.is_on_track():
print("Project is behind schedule")
return
# 予算をチェック
if not project.is_within_budget():
print("Project is over budget")
return
# チームメンバーに通知
project.notify_team("Project is on track")
この関数では、進捗確認、予算チェック、チームへの通知という3つの異なる機能を一つの関数で処理しています。これだと、コードが長くなり、管理が難しくなります。
def check_progress(project):
if not project.is_on_track():
print("Project is behind schedule")
return False
return True
def check_budget(project):
if not project.is_within_budget():
print("Project is over budget")
return False
return True
def notify_team(project):
project.notify_team("Project is on track")
def manage_project(project):
if not check_progress(project):
return
if not check_budget(project):
return
notify_team(project)
改善例では、各機能を独立した関数に分けています。これにより、それぞれの関数が何をするかが明確になり、コード全体が読みやすくなります。
ガード節を活用してネストを浅く保つ
コードを書く際に、条件分岐が多くなり、ネストが深くなることがあります。ネストが深くなると、コードが読みにくくなり、理解しにくくなります。そこで役立つのが 「ガード節」 です。ガード節とは、条件を満たさない場合に早期に処理を終了させることで、メインの処理が深くネストされないようにするテクニックです。
def process_data(data):
if data is not None:
if len(data) > 0:
if isinstance(data, list):
# メインの処理
for item in data:
print(item)
この例では、条件がすべてネスト化されており、メインの処理部分が深く入り込んでしまっています。これでは、どの条件で何が起こるのかが分かりにくく、コードの可読性が低下しています。
def process_data(data):
if data is None:
return
if len(data) == 0:
return
if not isinstance(data, list):
return
# メインの処理
for item in data:
print(item)
この改善例では、ガード節を使って、条件が満たされない場合は早期にreturn
で処理を終了しています。これにより、メインの処理部分が深いネストの中に埋もれず、コードがすっきりとし、読みやすくなっています。
意味のないマジックナンバーを用いらない
コード内で具体的な数値が突然現れると、その数値が何を意味しているのかが分かりにくくなります。このような数値を 「マジックナンバー」 と呼びます。マジックナンバーを使うと、コードの可読性が低下し、後から見たときにその意図が理解しにくくなります。意味のないマジックナンバーは避け、意味のある名前を持つ定数や変数に置き換えることが大切です。
def calculate_total(price):
return price * 1.10
この例では、1.10
が消費税を加算した数値を表していますが、コードを見ただけでは、これが何を意味しているのかが明確ではありません。
TAX_RATE = 0.10
def calculate_total(price):
return price * (1 + TAX_RATE)
改善された例では、TAX_RATE
という定数を使って消費税率を表現しています。これにより、1.10
というマジックナンバーを使うことなく、コードが何を意味しているのかが明確になり、可読性が向上します。
処理の順序
コードの可読性を高めるためには、処理の順序を論理的かつ自然な流れで配置することが重要です。不自然な順序や、関連のない処理が挟まっていると、コードが理解しにくくなります。処理を行う順番を整理し、読み手がスムーズにコードを追えるようにすることで、意図が明確で分かりやすいコードになります。
def process_user_data(data):
# 1. 入力データの検証
if not validate_data(data):
return "Invalid data"
# 2. データベースに保存
save_to_database(data)
# 3. ユーザーに確認メールを送信
send_confirmation_email(data["email"])
return "Process completed successfully"
この例では、処理の順序が論理的に並んでおり、最初にデータの検証を行い、問題がなければデータベースに保存し、その後にユーザーへの確認メールを送信しています。処理が一貫していて、コードの流れがスムーズに読めるため、理解しやすくなっています。
コードの可読性を向上させるためのおすすめ書籍
コードの可読性を上げるためには、優れた書籍から学ぶことが一つの有効な手段です。これから紹介する本は、読みやすくてメンテナンスしやすいコードを書くためのコツや原則がぎっしり詰まっています。実践的なスキルを磨くために、ぜひ参考にしてみてください。
-
リーダブルコード
著者: Dustin Boswell, Trevor Foucher -
Clean Code アジャイルソフトウェア達人の技
著者: Robert C. Martin -
コードコンプリート 第2版 ― 開発現場の手引き
著者: Steve McConnell
可読性を上げるメリット
可読性を上げるメリットは、想像以上に大きいと私は思います。まず、読みやすいコードはバグが見つけやすく、修正もしやすくなります。これにより、デバッグやメンテナンスの時間が大幅に短縮され、結果的に開発スピードが向上します。
さらに、他の人がそのコードを読んだ際にすぐに理解できるため、チーム開発がスムーズに進みます。可読性を意識することで、将来的に自分や他の開発者が作業しやすくなるため、リーダブルコードを意識することは非常に重要です。
まとめ
コードの可読性を高めることは、単に見た目を良くするだけでなく、プロジェクト全体の品質向上やチーム開発の効率化に直結する重要な要素です。この記事で紹介した「名前に情報を詰め込む」、「コードの一貫性」、「コメントの使用」、「ロジックの複雑度を減らす」といったポイントを実践することで、読みやすく、保守しやすいコードを書くことができます。
これからの日常の開発において、可読性を意識する際にこの記事が参考になれば幸いです。コードの可読性を高めることで、あなたのスキルがレベルアップし、チーム全体にも大きな貢献を果たせるはずです。
弊社Nucoでは、他にも様々なお役立ち記事を公開しています。よかったら、Organizationのページも覗いてみてください。
また、Nucoでは一緒に働く仲間も募集しています!興味をお持ちいただける方は、こちらまで。