Upgrade to Pro — share decks privately, control downloads, hide ads and more …

書くときにひと呼吸おいて考えてから 書いてほしいRailsコードの書き方 / Rails programing code that I hope you will consider if you really need it

ShinkuFencer
February 23, 2023

書くときにひと呼吸おいて考えてから 書いてほしいRailsコードの書き方 / Rails programing code that I hope you will consider if you really need it

社内勉強会で喋ったスライドです。

下記資料内に登場するリンクです

Railsで with_indifferent_access を使うときは一呼吸おいて考えて欲しい - コード日進月歩
https://shinkufencer.hateblo.jp/entry/2019/08/18/000000

Rails: メールをActive Recordのコールバックで送信しないこと(翻訳)
https://techracho.bpsinc.jp/hachi8833/2019_09_12/76762

ShinkuFencer

February 23, 2023
Tweet

More Decks by ShinkuFencer

Other Decks in Technology

Transcript

  1. 可変長引数 • Rubyでは可変長引数を下記のように書くことができる。 6 def all_print(*args) p args.join(" , ")

    end all_print("Suzuki") # "Suzuki" all_print("Suzuki","taro") # "Suzuki , taro" • 可変長引数はメソッド側でどの程度引数が来るかが予想できないのでいろ いろなことを考慮しなければならなくなるので大変(テストも大変) • 本当に必要なシーンは限られるので、奥の手ぐらいに捉える • 起きうるパターンが増えれば増えるほどバグを生まれやすいので避ける
  2. 呼び出し元に干渉する記述 • まずはコード例として以下を紹介する 8 class Monoire def initialize(value) @atai =

    value end def set_atai(value) @atai = value end def get_atai return @atai end end def change_monoire(target) target.set_atai(target.get_atai + 100) end temp = Monoire.new(100) pp "before atai = #{temp.get_atai}" change_monoire(temp) pp "after atai = #{temp.get_atai}" # 結果は以下のようになる # "before atai = 100" # "after atai = 200" • tempは呼び出し元なので、メソッドでの変更には干渉してほしくないと ころだが、この記述は干渉されてしまう
  3. 呼び出し元に干渉する記述 • いくつか回避方法はあるが、原則は再代入や不変(immutable)を意識する と回避することができる。 • 先程の例だとMonoireクラスは生成後に中の値を変化させることができる から起き得るバグだったので、set_ataiを廃止すれば防げる 9 class Monoire

    def initialize(value) @atai = value end def get_atai return @atai end end def change_monoire(target) Monoire.new(target.get_atai + 100) end temp = Monoire.new(100) pp "before atai = #{temp.get_atai}" charged_object = change_monoire(temp) pp "after atai = #{temp.get_atai}" pp "charged = #{charged_object.get_atai}"
  4. with_indifferent_access • hash.with_indifferent_access をすると、文字列でもシンボルでもアク セスできるようになる • 一見便利そうだが、受け取った側はどっちでも使えるので文字列アクセス とシンボルアクセスが乱立して可読性を下げる • メソッド提供側としても、どっちを主として使ってほしいかコードから読

    み解きにくくなるので、避けたほうが無難 • 起きうるパターンが増えれば増えるほどバグを生まれやすいので避ける • 代替として何を使うといいかなどはブログ記事を参考のこと 12 該当のブログ記事は下記 Railsで with_indifferent_access を使うときは一呼吸おいて考えて欲しい - コード日進月歩 https://shinkufencer.hateblo.jp/entry/2019/08/18/000000
  5. 分岐の多いpartial • 下記のようなerbがあったとする 14 <%= render :partial => "content", :locals

    => { title: @content.title , body:@content.body } %> <p>タイトルは<%= title %>です</p> <p><%= body %></p> • partialの使い方としてlocalsで値を与えてpartial側で当て込むやりかたが 機能としては存在する contents/index.html.erb contents/_content.html.erb
  6. 分岐の多いpartial • 「bodyの中身がないパターンもあるのでそのときにも使いたい」という ユースケースが増えたとする 15 <%= render :partial => "content",

    :locals => { title: @content.title } %> <p>タイトルは<%= title %>です</p> <% if defined?(body) do %> <p><%= body %></p> <% else %> <p> 本文はありません </p> <% end %> • Partial側では「bodyが定義されていない」と認識できれば、値の未セッ トを検知することができるので defined? を使うと実現はできる。が… contents/no_body.html.erb contents/_content.html.erb
  7. after_saveと後続処理 • 「記事が更新されたらメールを送信する」というような処理のときに、記 事のActiveRecordのafter_saveでメール送信処理を書く、としたくなる ときがある • after_saveのときを使えば便利そうに見えるが、saveのときにはなんで もかんでも発火してしまうので後で苦しむことが多い • 例えば「Railsコンソールで直接修正をかける」や「関連モデルの保存の兼

    ね合いで一度saveをする」などでも発火してしまうので予期せぬことがお きる • after_saveに後続処理を書きたくなったら、本当に毎回必須でやる処理な のかを見直すと良い。 20 詳しくは下記記事で説明されているので参考のこと Rails: メールをActive Recordのコールバックで送信しないこと(翻訳) https://techracho.bpsinc.jp/hachi8833/2019_09_12/76762
  8. まとめ 21 • 多くの話は「複雑さ」を減らして、使い方や使われ方をシン プルに保つということが大事。 • メソッドや機能として使い方のバリエーションが多いと、連 動してメソッドの振る舞いも発生するケースが増えて考慮す ることが増える。 •

    その結果として「分岐が増える」「想定外のルートが増え る」「バグが増えやすい状態になる」という連鎖が起きる。 • Railsは使い方次第で「複雑さ」が簡単に増えるので気をつけ る。