`reading`ロールでの`prevent_writes`デフォルト値をメソッドパラメータへ移動
connected_toなどのロール切り替えメソッドにおけるprevent_writesのデフォルト化ロジックを、メソッド本体からパラメータのデフォルト値へ移動しました。あわせて、readingロールでprevent_writes: falseを明示した場合はArgumentErrorを送出するように変更されています。
背景
これまでprevent_writesの「readingロール時はtrueに強制する」というロジックは、メソッドシグネチャではなくメソッド本体に隠れていました。connected_to、connected_to_many、connected_to_all_shardsといった公開ロール切り替えメソッドはいずれもprevent_writes: falseをデフォルトパラメータに持ちつつ、内部でprevent_writes = true if role == ActiveRecord.reading_roleという上書き処理を行っていました。この実装では、呼び出し側がprevent_writes: falseを意図的に渡しても黙って無視されるという問題があり、またプライベートメソッド#with_role_and_shardにも同様のロジックが点在していました。
PRでは、このデフォルト化ロジックがドキュメントにも一貫して記載されていなかった点も指摘されています。メソッドシグネチャを見るだけで挙動が把握できるようにし、矛盾した引数の組み合わせに対しては黙って修正するのではなく明示的にエラーを返す設計へ改めることが今回の動機です。
技術的な変更
prevent_writesのデフォルト値をfalseからrole == ActiveRecord.reading_roleという式に変更し、本体内の上書き処理をArgumentErrorチェックへ置き換えました。
変更前(connected_to):
def connected_to(role: nil, shard: nil, prevent_writes: false, &blk)
# ...
with_role_and_shard(role, shard, prevent_writes, &blk)
end
変更後(connected_to):
def connected_to(role: nil, shard: nil, prevent_writes: role == ActiveRecord.reading_role, &blk)
# ...
if role == ActiveRecord.reading_role && !prevent_writes
raise ArgumentError, "cannot set `prevent_writes` to false when `role` is `reading`."
end
with_role_and_shard(role, shard, prevent_writes, &blk)
end
connected_to_manyも同様に、prevent_writes: falseからprevent_writes: role == ActiveRecord.reading_roleへ変更され、本体内のprevent_writes = true if role == ActiveRecord.reading_roleがArgumentErrorを発生させるガード節に置き換わっています。
テストも整備されており、#connected_toとconnected_to_all_shardsに対してそれぞれ次の2ケースが追加されています:
-
readingロールで呼び出した際にcurrent_preventing_writesがtrueになること -
readingロールかつprevent_writes: falseで呼び出した際にArgumentErrorが送出されること
設計判断
「黙って上書き」から「明示的なエラー」への転換がこのPRの核心です。
従来の実装はprevent_writes: falseを渡しても無視してtrueに変更するものでした。これは安全側に倒した設計ではありますが、呼び出し元の意図を無視しているとも言え、デバッグ時に混乱を招く可能性があります。connected_to(role: :reading, prevent_writes: false)という組み合わせは意味的に矛盾しており、矛盾した引数はArgumentErrorで弾く方が「フェイルファスト」の原則に沿っています。
デフォルト値をRubyの式評価(role == ActiveRecord.reading_role)として宣言することで、メソッドシグネチャ自体がドキュメントとして機能するようになっています。RDocやYARDでシグネチャを参照するだけでreadingロール時の挙動が一目瞭然になり、メソッド本体を読まなくてもデフォルト動作を理解できます。
ただし、この変更には破壊的変更の側面があります。これまでprevent_writes: falseを明示的に渡していたコード(実際には意図と異なる動作をしていたとしても)は、アップグレード後にArgumentErrorで失敗するようになります。
まとめ
本PRは、ロール切り替えメソッドの暗黙的な挙動を明示的なインターフェースへ昇格させた変更です。デフォルト値のパラメータ化により「メソッドシグネチャがドキュメントである」という設計原則を実現しつつ、矛盾した引数の組み合わせをエラーとして弾くことでAPIとしての整合性を高めています。