名前設計
10-5

曖昧な「Info」「Data」名を避ける

〜Info、〜Data という名前は「ただのデータ入れ物です、ご自由にどうぞ」というメッセージを発し、ロジックの置き場所を考える機会を奪う。レイヤー間でデータを運ぶだけなら、その用途を名前で明示して不変にし、ロジックを持つ本体とは分けて名付ける。

蔵書管理の BookData

Bad

Data という名前は責務を何も語らず、あちこちで自由に詰めたり書き換えたりされる入れ物になる

何でも入る「データ」クラス
class BookData:
    isbn: str = ""
    title: str = ""
    price: int = 0
    shelf: str = ""
    is_lending: bool = False
    # 画面表示でも貸出処理でもこのクラスを直接書き換える
Good

「検索画面に運ぶだけ」という用途を名前で宣言した DTO と、ロジックを集める本体クラスに分ける

用途を名乗る DTO とロジックの本体
@dataclass(frozen=True)
class BookSummaryDto:
    """蔵書検索画面へ渡す表示専用データ。ロジックは持たせない"""
    isbn: str
    title: str
    shelf_label: str


@dataclass(frozen=True)
class Book:
    """蔵書。貸出可否などの判断はこちらに集める"""
    isbn: str
    title: str
    lent_to: str | None

    def can_lend(self) -> bool:
        return self.lent_to is None

DTO 自体は悪ではない。「境界をまたいでデータを運ぶ」という目的が名前に書いてあり、frozen で書き換え不能なら、ビジネスロジックが紛れ込む余地がなくなる。曖昧なのは Info / Data という思考停止の名前のほう。

参考: 『良いコード/悪いコードで学ぶ設計入門』(ミノ駆動 著、技術評論社)第10章。コード例は原則を自分の題材で表現し直したオリジナル。
10-5

曖昧な「Info」「Data」名を避ける

〜Info、〜Data という名前は「ただのデータ入れ物です、ご自由にどうぞ」というメッセージを発し、ロジックの置き場所を考える機会を奪う。レイヤー間でデータを運ぶだけなら、その用途を名前で明示して不変にし、ロジックを持つ本体とは分けて名付ける。

蔵書管理の BookData

Bad

Data という名前は責務を何も語らず、あちこちで自由に詰めたり書き換えたりされる入れ物になる

何でも入る「データ」クラス
class BookData:
    isbn: str = ""
    title: str = ""
    price: int = 0
    shelf: str = ""
    is_lending: bool = False
    # 画面表示でも貸出処理でもこのクラスを直接書き換える
Good

「検索画面に運ぶだけ」という用途を名前で宣言した DTO と、ロジックを集める本体クラスに分ける

用途を名乗る DTO とロジックの本体
@dataclass(frozen=True)
class BookSummaryDto:
    """蔵書検索画面へ渡す表示専用データ。ロジックは持たせない"""
    isbn: str
    title: str
    shelf_label: str


@dataclass(frozen=True)
class Book:
    """蔵書。貸出可否などの判断はこちらに集める"""
    isbn: str
    title: str
    lent_to: str | None

    def can_lend(self) -> bool:
        return self.lent_to is None

DTO 自体は悪ではない。「境界をまたいでデータを運ぶ」という目的が名前に書いてあり、frozen で書き換え不能なら、ビジネスロジックが紛れ込む余地がなくなる。曖昧なのは Info / Data という思考停止の名前のほう。

参考: 『良いコード/悪いコードで学ぶ設計入門』(ミノ駆動 著、技術評論社)第10章。コード例は原則を自分の題材で表現し直したオリジナル。