Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Rails Good Parts, Bad Parts
Search
Shinichi Maeshima
September 12, 2018
Technology
7
14k
Rails Good Parts, Bad Parts
「MedBeer -Rails開発での技術的負債との付き合い方」での発表資料です
Shinichi Maeshima
September 12, 2018
Tweet
Share
More Decks by Shinichi Maeshima
See All by Shinichi Maeshima
Sidekiq vs Solid Queue
willnet
14
12k
どうしてこうなった?から理解するActive Recordの関連の裏側
willnet
6
1.5k
Exceptional Rails
willnet
6
7.7k
Breaking the Flaky Test Cycle
willnet
2
2.2k
mrskで広がるインフラの選択肢
willnet
1
1.1k
アプリケーションを長期にわたって無理なく運用するためのたったひとつの方法
willnet
2
2.2k
HotwireからDHHが考えるこれからのRailsとJSの付き合い方を知る
willnet
14
14k
Rails6.1で新しく入る機能について
willnet
12
16k
Concerns about Concerns
willnet
11
35k
Other Decks in Technology
See All in Technology
Kubernetes における cgroup v2 でのOut-Of-Memory 問題の解決
pfn
PRO
0
380
Microsoft Fabric のネットワーク保護のアップデートについて
ryomaru0825
1
120
ここ一年のCCoEとしてのAWSコスト最適化を振り返る / CCoE AWS Cost Optimization devio2025
masahirokawahara
1
370
生成AI時代のデータ基盤
shibuiwilliam
0
530
衝突して強くなる! BLUE GIANTと アジャイルチームの共通点とは ― いきいきと活気に満ちたグルーヴあるチームを作るコツ ― / BLUE GIANT and Agile Teams
naitosatoshi
0
250
Goss: New Production-Ready Go Binding for Faiss #coefl_go_jp
bengo4com
1
1.1k
進捗
ydah
1
210
Browser
recruitengineers
PRO
6
1.8k
Goでマークダウンの独自記法を実装する
lag129
0
230
見てわかるテスト駆動開発
recruitengineers
PRO
6
2.1k
TypeScript入門
recruitengineers
PRO
33
10k
Grafana MCPサーバーによるAIエージェント経由でのGrafanaダッシュボード動的生成
hamadakoji
0
670
Featured
See All Featured
Scaling GitHub
holman
463
140k
Navigating Team Friction
lara
189
15k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
48
9.7k
YesSQL, Process and Tooling at Scale
rocio
173
14k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
358
30k
Facilitating Awesome Meetings
lara
55
6.5k
Thoughts on Productivity
jonyablonski
69
4.8k
jQuery: Nuts, Bolts and Bling
dougneiner
64
7.9k
StorybookのUI Testing Handbookを読んだ
zakiyama
30
6k
The Cost Of JavaScript in 2023
addyosmani
53
8.9k
Practical Orchestrator
shlominoach
190
11k
Transcript
Rails Good Parts, Bad Parts @willnet
自己紹介 » 前島真一 aka @willnet or @netwillnet » ginza.rb から来ました
» メドピアさんで技術顧問しています » https://github.com/willnet » https://twitter.com/netwillnet » https://blog.willnet.in
技術顧問として 主に負債を減らしたり、負債の増加を防ぐために頑 張っています !
技術顧問について詳しく知りたい方は こちらをどうぞ » Rails Developers Meetup で喋った » https://speakerdeck.com/willnet/ji-shu-gu- wen-toiudong-kifang
» ブログ書いた » https://blog.willnet.in/entry/ 2018/04/09/101808
今日のテーマは技術的負 債 !
負債へのアプローチは2 つ
できてしまった負債を減 らす⬇
新規開発で負債を増やさ ない⬆ !
今日は負債を増やさない 話をします
負債の増加を防ぐにはど うしたらよいか
Railsのレールに乗る
レールに乗る、とは? » みんなよく言ってるけどふわっとした概念 » レールについてきちんと説明している文章がない ように見える
Railsが提供しているべんりな機能を活 用する = レールに乗る ここではこういう定義とします
Railsのべんりな機能 » たくさんある » こういうメソッドないかな?と思って調べると大 抵定義済み
べんりな機能を知らずに スクラッチで実装して微 妙な感じになるケースが よくある !
べんりな機能の具体例 » あまり知られていない&&知ってると便利なもの » 複数のお手伝い先で何回も言ってるやつ
has_many
みんな知ってる
定義することで使えるよ うになる機能がたくさん ある
has_manyで使えるようになるものたち collection collection<<(object, ...) collection.delete(object, ...) collection.destroy(object, ...) collection=(objects) collection_singular_ids
collection_singular_ids=(ids) collection.clear
has_manyで使えるようになるものたち collection.empty? collection.size collection.find(...) collection.where(...) collection.exists?(...) collection.build(attributes = {}, ...)
collection.create(attributes = {}) collection.create!(attributes = {}) collection.reload
全種類知ってますか?
collection=(objects), collection_singular_ids=(ids) » 既存のcollectionをいい感じに置き換える » has_many through の場合は中間テーブルを置き 換える
合わせ技でつかえるview helper » collection_check_boxes これらをスクラッチで書いてしまう人めっちゃ多い (当社比)
コード例 ビールの銘柄にタグ付けをするコードを考えてみま す
None
modelはこんな感じ class Beer < ApplicationRecord has_many :taggings has_many :tags, through:
:taggings end
素直に書くと <% 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 %>
素直に書くと 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
一瞬では読めないです ね… !
既存のタグと入力値との 差分を見て、必要なもの だけinsert, deleteして いる
読みづらいしバグも入り 込みやすそう
便利メソッドたちを使うと <%= form.collection_check_boxes :tag_ids, Tag.all, :id, :name %>
便利メソッドたちを使うと 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
普通に書ける beer.tag_ids = params[:beer][:tag_id] » has_many :tagsでtag_ids=メソッドが生えてい る » いい感じに差分を見て中間テーブルをinsert,
deleteしてくれる
これ、初めて知った人 ✋
どうやってべんりな機能を知るのか » 公式のドキュメントやRailsガイドを読みましょ う » もしくは強い人にレビューやペアプロしてもらい ましょう
ここまでの話をまとめる と
Railsが提供するべんり な機能を使えば負債を作 らずに開発できる!
なんですけど…
Railsが提供している機能が全部無条件 に便利というわけではない » 安易に使うとやけどする機能もある » ググるといろいろでてくるはず » callback » default_scope
» nested attributes
gemも似たように、安易に採用すべきで はないものがある » devise » simple_form » activeadmin » etc
この手のやつ、どう取り扱うべきか » チーム開発のときは特に慎重になったほうが良い » 禁止にしておいたほうが無難なことも多い » 利用シーンやチームの状況によって使えることも あるので、できれば吟味して決めたい
例えばwebpacker » 最近よくdisられている » しかしフロントエンド専任がおらず、片手間でjs を書く&&とりあえずes6使いたい、というケース だと大変便利 » フロントエンド専任がいて、webpackの設定をち ゃんとしたい、というケースでは必要ない
例えばdevise » 昔からよくdisられている » devise wayから外れるとつらい » 管理画面だけ認証が必要、などdevise wayで問題 ないならサッと導入できて便利
要注意なものは » なぜ注意が必要なのか » どう避けるか » どういうときなら使ってもよいのか を把握してまとめておくと良い
例えばhas_manyのcollection<<は要注 意 class User has_many :posts end これはイマイチな書き方 user.posts <<
Post.new(title: 'hello world!')
なぜか collection<<は、レシーバのオブジェクトがDBに 保存済みか否かで挙動が異なる(クエリが発行され たり発行されなかったりする)
どう避けるか user.posts.build(title: 'hello world!') user.posts.create(title: 'hello world!') のように書いたほうが可読性が高く、事故りにくい
どういうときなら使ってもよいのか collection.build や collection.createが適切 でない、かつチームメンバー全員が挙動を理解して いればギリギリOKかと tag = Tag.create(name: 'Ϗʔϧ')
Beer.each { |beer| beer.tags << tag }
(こうも書けるのであんまり例が良くな い) tag = Tag.create(name: 'Ϗʔϧ') Beer.each { |beer| beer.taggings.create!(tag:
tag) }
このように » なぜ注意が必要なのか » どう避けるか » どういうときなら使ってもよいのか を把握してチーム内で共有したい
負債を作らないために は、負債になりそうな要 素の対応法をみんなが理 解している必要がある
少なくとも、レビューで 負債になりそうな要素を 止められるようにしてお きたい
負債を作らないイコール 社内教育を頑張る
メドピアでは » 社内読書会 » ペアプロ » ふりかえり会 などしています
ところで、さっきの例は 簡単すぎ
現実ではもっと判断に悩 むケースが多い
判断に悩む例: コールバックをどう回 避するとよいか? » フォームオブジェクト? » サービスクラス? » その他 ↑方針を決めたとして、具体的にどうやって作ると
いいの?
なるべく具体的に「こう だ!」と道を示さない と、それぞれ思い思いの 実装になってそれが負債 につながる
しかし選択するのが難し い
そこで clean-rails.org ですよ
可読性の高いRailsのコ ードを議論するコミュニ ティ
どのように実装するとよ いか判断に悩むときに相 談できる
皆様からの投稿お待ちし ています !
まとめ » 負債を作らないためには、べんりな機能、要注意 な機能を知ることが大事 » 要注意なものについて、チーム全体で理解できる ように詳細を詰めて周知する » 勉強と教育をがんばりましょう
判断に悩むものは一緒に 勉強していきましょう