Object(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社エンジニアの「?」を「!」に。原著者の許諾を得て翻訳・公開いたします。selleo.comパターンの種別は原則として英語表記にしました。Rails開発における一種の聖杯とも呼ぶべきパターンです。Objectを使うかこのパターンは非常にシンプルかつ強力なので、つい使いすぎてしまうほどです。多数のモデルに対するコールバックやアクセスを含み、多くの手順で構成される複雑なアクションを定義する場所が必要で、かつ他に適切な置き場所がない場合に有用です。Objectは、モデルで外部クラスとやりとりするコールバックによって生じる問題(関連記事)を軽減するのにも用いられます。命名規則を1つに定めるプログラミングで難易度が高いのは、適切かつ意味のわかる名前を割り当てることです。Objectの場合、UserCreatorやTwitterAuthenticatorやCodeObfuscatorなどのように「〜or」で終わる名前を付ける方法が広く採用されています。この命名規則に従おうとすると、OrderCompleterのように英語的に少し無理が生じることがあります。私は、CreateUserやAuthenticateUsingTwitterやObfuscateCodeやCompleteOrderのように、コマンドやアクションを先に書く命名方法ならややわかりやすくなることに気づきました。Objectの責務が明確になります。どの方法を選ぶにせよ、一度命名規則を決めたらそこから外れないようにすることが重要です。Objectをインスタンス化しても、単にcallメソッドを実行する以外にあまり使いみちがありません。Objectへの呼び出しをより簡潔にすることを検討しましょう。endendこのモジュールをincludeすることで、UserCreator.new(params).callやUserCreator.new.call(params)をUserCreator.call(params)のように簡潔に記述でき、読みやすさも向上します。Objectはインスタンス化も可能なので、内部のステートを取り出す必要が生じた場合にも有用です。Objectの呼び出し方法を1つに定める個人的にはcallメソッドを使うのが好みですが、他の方法を使わない特別な理由があるわけではなく、performやrunやexecuteも候補として優れています。重要なのは呼び出し方法を常に統一することです。いうのも、クラスの責務は既にクラス名に明示されており、これ以上明確にする必要はないからです。Objectの使い方をすぐに理解できるという効用もあります。Objectに複数の責務が混入する可能性が残ります。Objectにさまざまなアクションをまとめることもできますが、アクションのセットは1種類に限定するべきです。Objectでありがちなアンチパターンとしては、たとえばManageUserというserviceがユーザーの作成と削除の両方を引き受けてしまうというものがあります。そもそもmanageという言葉だけでは責務があいまいになってしまい、オブジェクトがどんなアクションを実行すべきかを制御する方法も明確になりません。代わりにDeleteUserとCreateUserという2つのserviceに分けて導入すれば、コードも読みやすくなり、より自然になります。Objectのコンストラクタを複雑にしない一般に、実装するほとんどのクラスではコンストラクタをシンプルにしておくのがよい考えです。Serviceの主な呼び出し方法はクラスメソッドを呼び出すことですが、コンストラクタの責務を「引数をserviceのインスタンス変数に保存すること」に限定する方がずっとメリットが多くなります。endend上と下を見比べてみましょう。endend下のようにすれば、テストのときにコンストラクタではなくcallメソッドに集中できるようになりますし、コンストラクタに何を置くことができ、何を置けないかという線引きも明確になります。開発者が日々決定しなければならないことはたくさんあるので、こういう点を標準化して決めごとをひとつ減らしましょう。Objectに2つ以上の引数が与えられる場合、引数をわかりやすくするためにキーワード引数の導入を検討するとよいでしょう。Objectの引数が1つの場合であっても、キーワード引数にしておくことで読みやすさが向上するでしょう。false)上と下を見比べてみましょう。Objectから何らかの情報を取り出さなければならないような状況はめったにありませんが、その必要が生じた場合に取りうるアプローチはいくつか考えられます。Objectはcallメソッドの結果をたとえば次のように返すことができます。実行が成功した場合はtrue、失敗した場合はfalseを返す、という具合です。Object自身を返すようにすればより柔軟になります。Objectインスタンスのステートを読み出せるようになります。update_user.errors.inspectendこの方法は、例外のraiseなど、めったに起きない事象を扱うような場合にも効果的にエッジケースとやりとりできます。Objectの中心となるメソッドです。Objectでは、callメソッドをできるだけ読みやすく保つことをおすすめします。callメソッドには関連する手順だけを記述し、それ以外のロジックは最小限に抑えるようにします。andやorなどを使って、特定の手順のフローを制御してもよいでしょう。Objectが自らの責務を果たすために複数の手順が必要になった場合、手順をトランザクションでラップするとよいでしょう。しておけば、その手順に失敗した場合にも常にロールバックできます。Objectは遅かれ早かれ何十個にも増えるでしょう。Objectをグループ化することをおすすめします。Objectをグループ化する名前空間は、「外部サービス」や「高レベルの機能」など考えられるどんな基準で決めてもかまいません。Objectの命名規則や配置を読みやすい素直なものにするのが名前空間の主要な目的であることをお忘れなく。規則を1つにしていれば、適切な配置は自然に定まります。不要な選択肢を増やさないようにするのがコツです。Objectはテストを書きやすくするのに役立つシンプルかつ強力なパターンであり、広く応用できます。Objectは実装が容易ですが、その分実装がばらつかないよう制御が必要です。Objectクラスの内部状態をシンプルかつ読みやすく保てば、コードベースでこのパターンから多くのメリットを得ることができます。gemや類似のユースケースを検討しましょう。gemではさらに薄いレイヤを提供しています。コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。チュートリアル第2版の監修および半分程度を翻訳、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れて更新翻訳中。enno.jpを運営。実は最近Go言語が好きで、Goで書かれたRubyライクなGoby言語のメンテナーでもある。仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。Storageを使ってはいけない(翻訳)#Tags#会社紹介#自社サービス#勉強会#Rails#PHP#デザイン#実績#週刊RailsウオッチCONTACTお気軽にご相談ください。(翻訳)CONTACTTechRachoでは、パートナーシップをご検討いただける方からのご連絡をお待ちしております。お気軽にご意見・ご相談ください。