Rails Good Parts, Bad Parts

Rails Good Parts, Bad Parts

「MedBeer -Rails開発での技術的負債との付き合い方」での発表資料です

6ac7c50770603b53964d44db373e8e48?s=128

Shinichi Maeshima

September 12, 2018
Tweet

Transcript

  1. Rails Good Parts, Bad Parts @willnet

  2. 自己紹介 » 前島真一 aka @willnet or @netwillnet » ginza.rb から来ました

    » メドピアさんで技術顧問しています » https://github.com/willnet » https://twitter.com/netwillnet » https://blog.willnet.in
  3. 技術顧問として 主に負債を減らしたり、負債の増加を防ぐために頑 張っています !

  4. 技術顧問について詳しく知りたい方は こちらをどうぞ » Rails Developers Meetup で喋った » https://speakerdeck.com/willnet/ji-shu-gu- wen-toiudong-kifang

    » ブログ書いた » https://blog.willnet.in/entry/ 2018/04/09/101808
  5. 今日のテーマは技術的負 債 !

  6. 負債へのアプローチは2 つ

  7. できてしまった負債を減 らす⬇

  8. 新規開発で負債を増やさ ない⬆ !

  9. 今日は負債を増やさない 話をします

  10. 負債の増加を防ぐにはど うしたらよいか

  11. Railsのレールに乗る

  12. レールに乗る、とは? » みんなよく言ってるけどふわっとした概念 » レールについてきちんと説明している文章がない ように見える

  13. Railsが提供しているべんりな機能を活 用する = レールに乗る ここではこういう定義とします

  14. Railsのべんりな機能 » たくさんある » こういうメソッドないかな?と思って調べると大 抵定義済み

  15. べんりな機能を知らずに スクラッチで実装して微 妙な感じになるケースが よくある !

  16. べんりな機能の具体例 » あまり知られていない&&知ってると便利なもの » 複数のお手伝い先で何回も言ってるやつ

  17. has_many

  18. みんな知ってる

  19. 定義することで使えるよ うになる機能がたくさん ある

  20. has_manyで使えるようになるものたち collection collection<<(object, ...) collection.delete(object, ...) collection.destroy(object, ...) collection=(objects) collection_singular_ids

    collection_singular_ids=(ids) collection.clear
  21. has_manyで使えるようになるものたち collection.empty? collection.size collection.find(...) collection.where(...) collection.exists?(...) collection.build(attributes = {}, ...)

    collection.create(attributes = {}) collection.create!(attributes = {}) collection.reload
  22. 全種類知ってますか?

  23. collection=(objects), collection_singular_ids=(ids) » 既存のcollectionをいい感じに置き換える » has_many through の場合は中間テーブルを置き 換える

  24. 合わせ技でつかえるview helper » collection_check_boxes これらをスクラッチで書いてしまう人めっちゃ多い (当社比)

  25. コード例 ビールの銘柄にタグ付けをするコードを考えてみま す

  26. None
  27. modelはこんな感じ class Beer < ApplicationRecord has_many :taggings has_many :tags, through:

    :taggings end
  28. 素直に書くと <% Tag.all.each do |tag| %> <%= form.label tag.name do

    %> <%= check_box_tag 'beer[tag][id][]', tag.id, beer.tags.find { |t| tag.id == t.id } %> <%= tag.name %> <% end %> <% end %>
  29. 素直に書くと def update @beer = Beer.find(params[:id]) @beer.attributes = beer_params original_taggings

    = @beer.taggings taggings_ids = params[:beer][:tag][:id] delete_taggings = original_taggings.reject { |bt| taggings_ids.include?(bt.tag_id.to_s) } delete_taggings.each(&:destroy) add_tags = taggings_ids.reject { |id| original_taggings.map(&:tag_id).include?(id.to_i) } add_tags.each do |tag_id| @beer.taggings.build(tag_id: tag_id) end if @beer.save redirect_to @beer, notice: 'Beer was successfully updated.' else render :edit end end private def beer_params params.require(:beer).permit(:name) end
  30. 一瞬では読めないです ね… !

  31. 既存のタグと入力値との 差分を見て、必要なもの だけinsert, deleteして いる

  32. 読みづらいしバグも入り 込みやすそう

  33. 便利メソッドたちを使うと <%= form.collection_check_boxes :tag_ids, Tag.all, :id, :name %>

  34. 便利メソッドたちを使うと def update @beer = Beer.find(params[:id]) if @beer.update(beer_params) redirect_to @beer,

    notice: 'Beer was successfully updated.' else render :edit end end private def beer_params params.require(:beer).permit(:name, tag_ids: []) end
  35. 普通に書ける beer.tag_ids = params[:beer][:tag_id] » has_many :tagsでtag_ids=メソッドが生えてい る » いい感じに差分を見て中間テーブルをinsert,

    deleteしてくれる
  36. これ、初めて知った人 ✋

  37. どうやってべんりな機能を知るのか » 公式のドキュメントやRailsガイドを読みましょ う » もしくは強い人にレビューやペアプロしてもらい ましょう

  38. ここまでの話をまとめる と

  39. Railsが提供するべんり な機能を使えば負債を作 らずに開発できる!

  40. なんですけど…

  41. Railsが提供している機能が全部無条件 に便利というわけではない » 安易に使うとやけどする機能もある » ググるといろいろでてくるはず » callback » default_scope

    » nested attributes
  42. gemも似たように、安易に採用すべきで はないものがある » devise » simple_form » activeadmin » etc

  43. この手のやつ、どう取り扱うべきか » チーム開発のときは特に慎重になったほうが良い » 禁止にしておいたほうが無難なことも多い » 利用シーンやチームの状況によって使えることも あるので、できれば吟味して決めたい

  44. 例えばwebpacker » 最近よくdisられている » しかしフロントエンド専任がおらず、片手間でjs を書く&&とりあえずes6使いたい、というケース だと大変便利 » フロントエンド専任がいて、webpackの設定をち ゃんとしたい、というケースでは必要ない

  45. 例えばdevise » 昔からよくdisられている » devise wayから外れるとつらい » 管理画面だけ認証が必要、などdevise wayで問題 ないならサッと導入できて便利

  46. 要注意なものは » なぜ注意が必要なのか » どう避けるか » どういうときなら使ってもよいのか を把握してまとめておくと良い

  47. 例えばhas_manyのcollection<<は要注 意 class User has_many :posts end これはイマイチな書き方 user.posts <<

    Post.new(title: 'hello world!')
  48. なぜか collection<<は、レシーバのオブジェクトがDBに 保存済みか否かで挙動が異なる(クエリが発行され たり発行されなかったりする)

  49. どう避けるか user.posts.build(title: 'hello world!') user.posts.create(title: 'hello world!') のように書いたほうが可読性が高く、事故りにくい

  50. どういうときなら使ってもよいのか collection.build や collection.createが適切 でない、かつチームメンバー全員が挙動を理解して いればギリギリOKかと tag = Tag.create(name: 'Ϗʔϧ')

    Beer.each { |beer| beer.tags << tag }
  51. (こうも書けるのであんまり例が良くな い) tag = Tag.create(name: 'Ϗʔϧ') Beer.each { |beer| beer.taggings.create!(tag:

    tag) }
  52. このように » なぜ注意が必要なのか » どう避けるか » どういうときなら使ってもよいのか を把握してチーム内で共有したい

  53. 負債を作らないために は、負債になりそうな要 素の対応法をみんなが理 解している必要がある

  54. 少なくとも、レビューで 負債になりそうな要素を 止められるようにしてお きたい

  55. 負債を作らないイコール 社内教育を頑張る

  56. メドピアでは » 社内読書会 » ペアプロ » ふりかえり会 などしています

  57. ところで、さっきの例は 簡単すぎ

  58. 現実ではもっと判断に悩 むケースが多い

  59. 判断に悩む例: コールバックをどう回 避するとよいか? » フォームオブジェクト? » サービスクラス? » その他 ↑方針を決めたとして、具体的にどうやって作ると

    いいの?
  60. なるべく具体的に「こう だ!」と道を示さない と、それぞれ思い思いの 実装になってそれが負債 につながる

  61. しかし選択するのが難し い

  62. そこで clean-rails.org ですよ

  63. 可読性の高いRailsのコ ードを議論するコミュニ ティ

  64. どのように実装するとよ いか判断に悩むときに相 談できる

  65. 皆様からの投稿お待ちし ています !

  66. まとめ » 負債を作らないためには、べんりな機能、要注意 な機能を知ることが大事 » 要注意なものについて、チーム全体で理解できる ように詳細を詰めて周知する » 勉強と教育をがんばりましょう

  67. 判断に悩むものは一緒に 勉強していきましょう