はじめに
エンジニア2年目になり、コードレビューを受ける機会が増えてきました。レビューで指摘される内容も1年目の頃とは変わり、単純な文法エラーよりも「可読性」や「保守性」に関するコメントが多くなりました。そんな中で「リーダブルコード」を読み、普段Python・Djangoでの開発にTDDを取り入れている私にとって、多くの学びを得ることができました。
重要なところの要約
「理解するまでの時間」を最優先に
本書の核心は「コードは他の人が最短時間で理解できるように書かなければならない」という点です。つまり、短いコードよりも、理解しやすいコードの方が価値が高いということです。
表面上の改善(第1部)
命名の重要性が特に印象に残りました。tmp
やdata
といった汎用的な名前を避け、「何を表しているか」を明確にする。
# 悪い例:汎用的すぎる名前
def get_data(request):
data = User.objects.filter(status=1)
tmp = []
for d in data:
tmp.append(d.name)
return tmp
# 良い例:明確で具体的な名前
def get_active_user_names(request):
active_users = User.objects.filter(is_active=True)
user_names = []
for user in active_users:
user_names.append(user.name)
return user_names
限界値にはmax_
/min_
、範囲にはfirst_
/last_
を使うなど、具体的な指針も実践的でした。
# 悪い例:曖昧な限界値
MAX_ITEMS = 10 # 10を含む?含まない?
# 良い例:明確な限界値
MAX_ITEMS_COUNT = 10 # 10個まで(10を含む)
コメントの使い分けについては、「コードから推測できることは書かない」「なぜそうしたかの理由を書く」という原則が参考になりました。
# 悪い例:コードを説明するだけ
# ユーザー一覧を取得
users = User.objects.all()
# 良い例:理由や背景を説明
# パフォーマンス向上のため、非アクティブユーザーは除外
# (過去のA/Bテストで応答時間が30%改善することを確認済み)
users = User.objects.filter(is_active=True)
ロジックの単純化(第2部)
早期リターンによるネスト削減は、すぐに実践できる技法でした。
# 悪い例:深いネスト
def create_post(request):
if request.method == 'POST':
if request.user.is_authenticated:
if request.POST.get('title'):
# メインの処理
return create_post_logic(request)
else:
return JsonResponse({'error': 'タイトルが必要'})
else:
return JsonResponse({'error': 'ログインが必要'})
else:
return JsonResponse({'error': 'POSTのみ許可'})
# 良い例:早期リターンでネストを削減
def create_post(request):
if request.method != 'POST':
return JsonResponse({'error': 'POSTのみ許可'})
if not request.user.is_authenticated:
return JsonResponse({'error': 'ログインが必要'})
if not request.POST.get('title'):
return JsonResponse({'error': 'タイトルが必要'})
# メインの処理(ネストなし)
return create_post_logic(request)
巨大な式の分割で紹介された「説明変数」「要約変数」の概念も有用でした。
# 悪い例:複雑な条件式
if request.user.is_staff and request.user.profile.department == 'IT' and request.user.profile.years_of_service > 3:
# 処理
# 良い例:説明変数で分割
is_staff_member = request.user.is_staff
is_it_department = request.user.profile.department == 'IT'
has_sufficient_experience = request.user.profile.years_of_service > 3
can_access_admin_feature = is_staff_member and is_it_department and has_sufficient_experience
if can_access_admin_feature:
# 処理
コードの再編成(第3部)
- **「一度に1つのことを」**という原則は、関数設計の指針として非常に有用でした。
# 悪い例:複数のことを一度に行う
def process_user_data(user_id):
# ユーザー取得
user = User.objects.get(id=user_id)
# データ変換
user_data = {
'name': user.first_name + ' ' + user.last_name,
'age': calculate_age(user.birth_date)
}
# ログ出力
logger.info(f"User {user_id} processed")
# メール送信
send_notification_email(user.email, user_data)
return user_data
# 良い例:責任を分割
def get_user_by_id(user_id):
return User.objects.get(id=user_id)
def format_user_data(user):
return {
'name': f"{user.first_name} {user.last_name}",
'age': calculate_age(user.birth_date)
}
def log_user_processing(user_id):
logger.info(f"User {user_id} processed")
def notify_user_processing(user_email, user_data):
send_notification_email(user_email, user_data)
def process_user_data(user_id):
user = get_user_by_id(user_id)
user_data = format_user_data(user)
log_user_processing(user_id)
notify_user_processing(user.email, user_data)
return user_data
本書で得た気付き
1. コードレビューでの指摘が理解できるように
これまでレビューで「もう少し読みやすくできませんか?」と言われても具体的にどうすべきかわからないことがありました。しかし、本書の原則を知ることで、レビュアーの意図が理解できるようになりました。
例えば、「この条件分岐は複雑すぎる」という指摘は、8章の「巨大な式を分割する」の話だったのだと今なら理解できます。
2. TDDとの相性の良さ
TDDで開発していると、テストコードも含めて読みやすさが重要だと実感しています。テストメソッド名も「何をテストしているか」が一目でわかるよう命名することで、テストの保守性が向上しました。
# 改善前
def test_user_validation(self):
pass
# 改善後
def test_should_reject_user_registration_with_invalid_email(self):
pass
4. 「6ヶ月後の自分」も他人という視点
特に響いたのは**「6ヶ月後の自分も他人」**という考え方です。実際に過去のコードを見返すと、当時は理解していたつもりでも、今見ると意図がわからないコードが多数ありました。この経験により、未来の自分のためにもコードを書くという意識が芽生えました。
今後のコーディングスタイル
1. 命名規則の徹底
- 変数名・関数名は処理内容を具体的に表現する
- ブール値には
is_
、has_
、can_
を積極的に使用 - 単位がある値には単位を付加(
timeout_sec
、max_retry_count
など)
# 改善予定のスタイル
def fetch_active_users_with_recent_login(days_threshold=30):
cutoff_date = timezone.now() - timedelta(days=days_threshold)
return User.objects.filter(
is_active=True,
last_login__gte=cutoff_date
)
2. 関数設計の原則
- 1つの関数は1つのことだけを行う
- 引数は3つ以下を目指す
- 早期リターンを活用してネストを浅くする
- 副作用のない純粋関数を心がける
3. コメント戦略
- WHATではなくWHYを書く
- TODOコメントには期限や担当者を明記
- 複雑なビジネスロジックには要約コメントを付ける
# 改善予定のコメントスタイル
def calculate_discount_rate(user, product):
# ゴールド会員は特別価格適用のため、
# 通常の割引計算とは異なるロジックを使用
if user.membership_level == 'GOLD':
return calculate_gold_member_discount(user, product)
# TODO(2024-07-01): プレミアム会員制度導入時に追加予定
return calculate_standard_discount(product)
4. コードレビューでの活用
- 自分のコードをcommitする前にセルフレビューする際の基準として使用
- レビューコメントを理解するための共通言語として活用
- リファクタリングの指針として参照
5. 継続的な改善
- 月1回、過去に書いたコードをリーダブルコードの観点で見直す
- 新しい技術や設計パターンを学ぶ際も、可読性を重視した選択をする
まとめ
「リーダブルコード」は、技術的なスキルだけでなく、「他者への思いやり」の重要性を教えてくれました。コードは自分だけのものではなく、チームメンバーや未来の自分のためのコミュニケーションツールです。
2年目という成長段階で本書と出会えたことで、悪い癖が固まる前に正しい方向性を学ぶことができました。まだまだ完璧に実践できているわけではありませんが、意識することから始めて、日々のコーディングで少しずつ改善していきたいと思います。