Prompt
ROROパターンって結構いいと思うんだけど、意外と見かけない。
ところでpythonでそれに近いのがあったような、なかったような。
やっほー!RORO (Receive Objects, Return Objects) パターンに注目するなんて、君は本当に「クリーンな設計」への美意識が高いね!
JS界隈では一時期すごく話題になったけど、確かにJavaやC#、Pythonの標準的なライブラリでは意外と見かけないよね。でも、Pythonにはその「精神」を体現したような強力な機能がちゃんとあるよ!
1. PythonでのROROに近いもの:**kwargs と TypedDict
Pythonで「オブジェクトを受け取り、オブジェクトを返す」を一番手軽に、かつパワフルに実現しているのは、可変長引数のアンパックだよ!
Receive: **kwargs
関数側で **kwargs を使うと、バラバラに渡された名前付き引数を一つの辞書として「Receive」できる。
Python
def create_user(**kwargs):
# kwargs は {'name': 'Taro', 'age': 20} という辞書になる
print(kwargs.get('name'))
Return: TypedDict や NamedTuple
最近のモダンなPython(3.8以降)なら、TypedDict を使うのが一番ROROの「型安全性」に近いね。
Python
from typing import TypedDict
class UserResult(TypedDict):
id: int
status: str
def register_user(user_data: dict) -> UserResult:
# 処理...
return {"id": 123, "status": "success"} # オブジェクト(辞書)を返す
2. なぜROROは「意外と見かけない」のか?
君が「いいと思うんだけどな」と感じる通りメリットは多いけど、普及しきらないのにはいくつか 「落とし穴」 があるんだ。
-
「型」の不透明さ: JSのプレーンなオブジェクト(連想配列)は便利だけど、JavaやC#のような静的型付け言語だと、引数一つ一つのために「専用のクラス(DTO)」を定義しなきゃいけない。これが「記述量が増えてめんどくさい(ボイラープレート)」と感じられちゃうんだ。
-
関数のシグネチャが嘘をつく:
do_something(options)という関数定義を見ただけでは、「optionsの中に何を入れればいいのか」がコードを読み込まないとわからない。これが開発効率を下げることもあるんだよね。
3. 💡 Pythonの「データクラス」こそが真の解答?
Python 3.7で登場した dataclasses は、まさにROROをやるために生まれてきたような存在だよ。
Python
from dataclasses import dataclass
@dataclass
class SearchParams:
query: str
limit: int = 10
def search(params: SearchParams):
print(f"Searching for {params.query}")
これなら、「オブジェクトで受け取る」というROROの良さを保ちつつ、エディタの補完も効くし、引数の意図も明確になる。専門学生の君がPythonで設計するなら、この 「DataClassパターン」 が一番しっくりくるはずだよ!
4. 豆知識:Destructuring(分割代入)
JSのROROがオシャレに見える最大の理由は、function ({ name, age }) { ... } みたいに関数の入り口で「バラせる」からだよね。
実はPythonでも、辞書を func(**my_dict) と渡せばバラせるけど、受ける側でバラす構文(JSのような引数内での分割代入)はまだ標準にはないんだ。これがJSほどROROが流行らない小さな理由かもしれないね。
次のステップへの提案
Pythonの dataclass を使って、「複数の戻り値をスマートに返すリファクタリング」 の具体例を見てみる?それとも、C#で同じことを実現するための record 型について話そうか!