今回は私が実装をする際に特に気をつけているポイントをいくつかピックアップしました。
1. 単一責任の原則とテスト容易性
クラスや関数には単一責任を持たせることが大切です。これにより、テストや保守がしやすくなり、モックや修正にも柔軟に対応できます。
例えば以下のように、各クラスや関数が明確な責任を持つことを意識します。
class User:
def calculate_age_from_birthdate(self):
# 年齢を計算する責任だけを持つ
...
class UserValidator:
def validate_user(self, user: User):
# ユーザー検証の責任だけを持つ
...
2. 命名規則
一貫した命名規則を守ることで、コードの可読性を高め、認知負荷を下げることができます。例えば以下のような規則を意識して命名します。
- 名は体を表すを意識して命名する
- マジックナンバー禁止。必ず命名する
- ぱっと見で理解できない省略語は使わない
- True/Falseの変数や返り値の関数には
has
,is
などから始める - 定数は大文字+アンダースコア(例:
MAX_RETRIES
) - クラス名はキャメルケース(例:
UserAuthenticator
)
3. Docstring と Type Hint
関数やメソッドにはDocstringとType Hintを追加し、コードの目的や引数・戻り値を明確にします。これにより、他の開発者や自分がコードを理解しやすくなります。
def add_numbers(a: int, b: int) -> int:
"""
2つの数値を足し合わせる
Args:
a (int): 1つ目の数値
b (int): 2つ目の数値
Returns:
int: 足し算の結果
"""
return a + b
4. リカバリ対応を意識したアトミック処理
アトミック処理とは、ある操作が全体として完了するか、まったく実行されないかのどちらかを保証することです。特にデータベースへのCRUD操作で意識しておかないと、インシデント時のリカバリ対応が困難になります。
例えば、振込処理で一部の処理が成功し、別の処理が失敗することを避けるために、トランザクションを利用してアトミック処理を実現できます。Djangoではtransaction.atomic()
を活用します。
from django.db import transaction
with transaction.atomic():
# 複数のデータベース操作を一度に実行
update_balance(user)
...
if some_error_condition:
raise Exception("処理失敗") # すべての操作がキャンセルされる
5. メモリ使用量の最適化
大量のデータを扱う際には、メモリ効率を考慮しないと、メモリ超過エラーを引き起こす原因になります。
そのため、リストではなくジェネレータを使用するなど、メモリ効率を意識した実装を心がけています。
6. スパゲッティコードの回避
スパゲッティコードとは、コードが複雑に絡み合い、どこで何が起こっているのかが分かりづらい状態です。この状態になると、保守や修正が非常に困難になります。
スパゲッティコードを回避するためには、コードの構造を整理し、各モジュールや関数が明確な責任を持つように設計することが重要です。
7. 早期リターン
複雑な条件分岐やネストを避けるために、早期リターンを積極的に使用します。これにより、コードがすっきりし、可読性が向上します。
# 早期リターンを使わないとネストが深くなりがち
def sample():
for item in data:
if condition(item):
# 処理
else:
# 処理
# 他の処理
# 早期リターンを使うとネストが浅くなる
def sample():
for item in data:
if not condition(item):
return # 早期リターン
# 処理
# 他の処理
8. TODOコメントの活用
仕様が未確定であったり、後から修正が必要な場合は、必ずTODO
コメントをつけて記載します。TODO
を使うことで、後から曖昧な実装を洗い出し、修正を漏れなく行えます。
# TODO: ユーザーのロール管理機能を実装
def manage_roles(user_id: int):
pass
IDE(例: PyCharm)ではTODOコメントを一括管理できるので便利です。
まとめ
私が実装を行う際に特に意識しているポイントを紹介しました。
何かしら参考になれば幸いです。
ご拝読ありがとうございました!