0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rubyで引数が多い時のコード設計と、デフォルト値の使い方について

Last updated at Posted at 2025-01-18

引数が多い時のコード設計についてと、
デフォルト値の使い方について。

状況によって最適に使い分けたい。

引数が多い時のコード設計について

  1. キーワード引数を使う方法
  2. ハッシュ引数を使う方法
  3. 値オブジェクトを作る方法

「オブジェクト指向設計実践ガイド」や「オブジェクト設計スタイルガイド」を読む限り、疎結合で変更に強くなる3の方法が良さそうに感じる。値オブジェクトのクラスにバリデーションを儲けたり、共通利用したり、テスト書きやすかったりもする。型がある言語の方が受ける恩恵は大きい。
ただしIDEのコード補完等の恩恵が受けづらくなったり、人によっては可読性が低くなったり。パラメータの中身がわかりづらいので、yard等書いたほうが良さそう。

1は増減等変更に弱いが、行数が少なくて済み、引数が明示的で直感的に理解しやすく、2はさらに行数が少なくて済むが、呼び出し側の引数指定が多い。

キーワード引数を使う方法

class HogeService
  def initialize(name:, address:, age:, sex:, dob:)
    @name = name
    @address = address
    @age = age
    @sex = sex
    @dob = dob
  end

  def call
    # 何らかの処理
    # @name、@address などを利用
  end
end

HogeService.new(name: 'taro', address: 'tokyo', age: 20, sex: 'M', dob: '2000-01-01')

ハッシュ引数を使う方法その1

class HogeService
  def initialize(**params)
    @params = params
  end

  def call
    # 何らかの処理
    # @params[:name]、@params[:address] などを利用
  end
end

HogeService.new(name: 'taro', address: 'tokyo', age: 20, sex: 'M', dob: '2000-01-01')

ハッシュ引数を使う方法その2

class HogeService
  def initialize(name:, address:, age:, sex:, dob:)
    @name = name
    @address = address
    @age = age
    @sex = sex
    @dob = dob
  end

  def call
    # 何らかの処理
    # @name、@address などを利用
  end
end

  hash = {name: 'taro', address: 'tokyo', age: 20, sex: 'M', dob: '2000-01-01'}
  HogeService.new(**hash)

値オブジェクトを作る方法

class UserParams
  attr_reader :name, :address, :age, :sex, :dob

  def initialize(name:, address:, age:, sex:, dob:)
    @name = name
    @address = address
    @age = age
    @sex = sex
    @dob = dob
  end
end

class HogeService
  def initialize(user_params)
    @user_params = user_params
  end

  def call
    # 何らかの処理
    # @user_params[:name], @user_params[:address] などを利用
  end  
end

params = UserParams.new(name: 'taro', address: 'tokyo', age: 20, sex: 'M', dob: '2000-01-01')
HogeService.new(params)

デフォルト値について

  1. クラス内でデフォルト値を設定する方法
  2. 呼び出し側でデフォルト値を設定する方法

オライリーの「オブジェクト設計スタイルガイド」には以下のように書いてあり、2推し

オブジェクトが必要とする設定値は、常にクラスのユーザーが提供するようにしましょう

理由としては、

  • デフォルト値を知るには、そのクラスのコードを読む必要があること
  • デフォルト値が変更された際にそれを利用している側に影響があるから

クラス内でデフォルト値を設定

class HogeService
  def initialize(name:, address:, age: 20, sex: 'M', dob: '2000-01-01')
    @name = name
    @address = address
    @age = age
    @sex = sex
    @dob = dob
  end
end

HogeService.new(name: 'taro', address: 'tokyo')

メリット

  • 呼び出し側の負担を減らせる。可読性向上
  • デフォルト値の一元管理ができる
class HogeService
  def initialize(params)
    @params = params
  end

  def call
    # 何らかの処理
  end
end

user_params = {
  name: 'taro',
  address: 'tokyo',
  age: 20,
  sex: 'M',
  dob: '2000-01-01'
}
HogeService.new(user_params).call

メリット

  • 呼び出し側でデフォルト値を管理すれば、変更の影響を 特定の呼び出し元 のみに抑えられる
  • 呼び出し側の文脈に応じて適切なデフォルト値を設定できる
  • IDE や型チェックの恩恵を受けやすい
  • 「デフォルトの管理」という責務がなくなり、クラスの責務をシンプルにできる

デフォルト値の使い方のまとめ

クラス内でデフォルト値を設定するのが良い時

  • オプションがあるが、頻繁に変更されるわけではない場合
  • 一方、デフォルト値を変更すると影響が大きいため、変更頻度が高い場合は呼び出し側で設定する方がよい。

呼び出し側でデフォルト値を設定するのが良い時

  • デフォルト値が状況ごとに変わる可能性がある場合
  • 一方、デフォルト値が一貫している場合は、クラス内で設定するほうがコードがスッキリする。

感じたこと

  • 可読性と変更容易性はトレードオフな側面がある
    • 可読性を重視すると影響調査が大変になるかも
    • 変更容易性を重視すると読みづらいかも
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?