コードが想定外の事態を起こすパターン: マジックバリューを戻り値に使わない

コードが想定外の事態を起こすパターン: マジックバリューを戻り値に使わない プログラミング

コードが想定外の事態を起こすことは、ソフトウェアのバグにつながります。
本記事では、マジックバリューを関数の戻り値として使わないことで、想定外の事態を避ける方法について解説します。

マジックバリューが引き起こす問題

マジックバリューとは、関数の正常な戻り値と同じ型を持ちながら、特別な意味を持つ値のことです。
例えば、ユーザーが見つからなかったことを示すために-1を返すなどがこれに当たります。

以下のコードは、ユーザーIDを受け取り、ユーザーオブジェクトを返す関数の例です。

def get_user_by_id(user_id: int) -> User:
    user = search_user_in_database(user_id)
    if user is None:
        return User(-1, "Not Found", "")  # 見つからない場合は特殊なユーザーオブジェクトを返す
    else:
        return user

get_user_by_id関数は、ユーザーオブジェクトを返すため、呼び出し元は常に有効なユーザーが返ってくると期待します。
しかし、実際にはユーザーが見つからない場合に、IDが-1という特殊な値を持つユーザーオブジェクトを返しています。

このコードを使ってユーザーの情報を表示する関数を書いたとします。

def display_user_info(user_id: int) -> None:
    user = get_user_by_id(user_id)
    print(f"User ID: {user.user_id}")
    print(f"Name: {user.name}")
    print(f"Email: {user.email}")

display_user_info関数は、get_user_by_idが特殊なユーザーオブジェクトを返す可能性があることを考慮していません。
そのため、ユーザーが見つからない場合に、”-1″というユーザーIDが表示されてしまいます。

呼び出し元がマジックバリューの存在を認識していない場合、このようなバグを生み出すリスクがあります。

Optionalを使ってNoneを返す

マジックバリューの代わりに、Optionalを使ってNoneを返すことで、ユーザーが見つからないことを明示的に示せます。

from typing import Optional

def get_user_by_id(user_id: int) -> Optional[User]:
    user = search_user_in_database(user_id)
    if user is None:
        return None  # ユーザーが見つからない場合はNoneを返す
    else:
        return user

戻り値の型をOptional[User]にすることで、呼び出し元はNoneが返る可能性を認識できます。
これにより、Noneのチェックを行うことが強制され、バグのリスクを減らせます。

def display_user_info(user_id: int) -> None:
    user = get_user_by_id(user_id)
    if user is None:
        print("User not found.")
    else:
        print(f"User ID: {user.user_id}")
        print(f"Name: {user.name}")
        print(f"Email: {user.email}")

display_user_info関数では、userがNoneの場合に適切なメッセージを表示するように修正されています。
これにより、マジックバリューによる想定外の動作を避けることができます。

カスタム例外を発生させる

ユーザーが見つからない理由を明確にしたい場合は、カスタム例外を発生させるのも有効です。

class UserNotFoundError(Exception):
    pass

def get_user_by_id(user_id: int) -> User:
    user = search_user_in_database(user_id)
    if user is None:
        raise UserNotFoundError(f"User with ID {user_id} not found")
    else:
        return user

ユーザーが見つからない場合にUserNotFoundErrorを発生させることで、呼び出し元は適切なエラーハンドリングを行えます。
これにより、マジックバリューによる想定外の事態を避けられます。

def display_user_info(user_id: int) -> None:
    try:
        user = get_user_by_id(user_id)
        print(f"User ID: {user.user_id}")
        print(f"Name: {user.name}")
        print(f"Email: {user.email}")
    except UserNotFoundError:
        print("User not found.")

display_user_info関数では、UserNotFoundErrorをキャッチし、適切なエラーメッセージを表示します。

まとめ

マジックバリューを関数の戻り値に使うことは、バグを生み出すリスクがあります。
代わりにOptionalを使ってNoneを返したり、カスタム例外を発生させることで、ユーザーが見つからないことを明示的に示しましょう。

呼び出し元にとって想定外の事態を避け、堅牢なコードを書くことができます。
常にコードのリーダビリティと安全性を意識し、適切な値を返すように心がけましょう。

この記事のポイント

  • マジックバリューは呼び出し元に想定外の事態を引き起こすリスクがある
  • OptionalでNoneを返すことでユーザーが見つからないことを明示できる
  • カスタム例外の発生でより詳細な情報を呼び出し元に伝えられる
  • 想定外の事態を避けるためには適切な値を返すことが重要

適切な値を返すようにすることが、コードの品質と安全性を高めるための鍵と言えます。
マジックバリューに頼るのではなく、呼び出し元に分かりやすいインターフェースを提供しましょう。

タイトルとURLをコピーしました