Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

週刊Railsウォッチ: Railsで「Read Model」を使う、Ruby Prize 2021受賞者決定、pru gemほか(20211201後編)

こんにちは、hachi8833です。TechRachoのアドベントカレンダー2021が始まる季節になりました。

週刊Railsウォッチについて

  • 各記事冒頭には🔗でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • お気づきの点がありましたら@hachi8833までメンションをいただければ確認・対応いたします🙏

TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)

🔗 Rails

🔗 Read Model


つっつきボイス:「TechRacho翻訳記事でお世話になっているArkencyさんの記事です」「ざっと見たところ、複雑なJOINをするようなデータを毎回Active Recordで取り出したりする代わりに、よく使うデータをRead Modelというもので共通化している感じかな」「広義のFacadeパターンのような趣ですね: 自分はこういうふうに複雑なものをうまく共通化するのは割と好き❤️」「そうそう、よく使うクエリ結果を取り出すFacadeみたいな感じですね」「それにRead Modelという呼び方を与えたということでしょうね」

# 同記事より
ApplicationRecord.transaction do
  booking = Booking.create!(params)
  CalendarReadModel.handle_booking_created(booking)
end

「ちなみに自分はそういうときにデータベースVIEWを使いたい方です」「例の記事で推している方法ですね↓」

RDBMSのVIEWを使ってRailsのデータアクセスをいい感じにする【銀座Rails#10】

「上のRead Modelみたいなもので仮にActiveRecord::Relationを不用意に返してしまうと、他の開発者がすぐそこにスコープを追加し始めて壊れたりするんですよ」「そうそう、とてもありがちですよね」

ActiveRecord::Relationを返す共通化モデルの中でJOIN済みだったものを、知らずにJOINしてしまって結果がおかしくなるというのはありがちな事故」「そうそう、そもそもJOINしなくていいように作ったはずのものだったのに、それに気が付かずにJOINされてしまうという」

「書いた自分すら後でそういうことをやりかねないので、安全と安心のためにもデータベースVIEWを作るのがいいよと各所で普及に努めてます: データベースVIEWにしておけば、たとえばunscopeされても問題が生じなくなるのが嬉しい」「ですよね」

参考: unscope -- ActiveRecord::QueryMethods

「ORDER BYとかWHEREで絞り込むぐらいはRead Model的なもので共通化してもいいと思うんですけど、そのモデルで何をやってよくて何をやってはいけないかを厳密に定義するのは結構悩ましい問題ではある」「そういうのを考えるとデータベースVIEWにするのがいいという結論に落ち着きそうかな」

「記事のRead Modelは、ActiveRecord::Relationを返さないようにすれば何も気にしないで使ってもよいものですね👍: その代わり返す結果が巨大だとメモリを大量に消費しますが」「そうそう」「もっともCQRS(コマンドクエリ責務分離)↓の文脈ではActiveRecord::Relationを返すことはしなさそうですけどね」

Railsドメイン設計: イベントソーシングでCQRS Read Modelが基本的に必要な理由(翻訳)

🔗 HanamiとRailsの違いがわかる図


つっつきボイス:「久しぶりのHanami記事ですね」「Hanamiの公式ブログ記事にあったRailsとHanamiのアーキテクチャ比較図がよかったので取り上げてみました」「なるほど、RailsでRoutesから直接コントローラのアクションを呼ぶとか、そこからビューやヘルパーを呼び出すとかはおなじみの部分」「HanamiはモデルのところがPersistanceになってる」「こういう比較の図があるといいですね: Railsを知るにもよさそう👍」


同記事より

「以前Hanamiを少しやってみたことがあるんですが、RailsだったらこうなのにHanamiは何でこうなってないんだろうみたいなところで悩みました」「もう自分たちはすっかりRailsに慣れているから最初はそうなるでしょうね」「当時こういう図があったらな〜」「自分たちがRailsという圧倒的に複雑なフレームワークに慣れてきた分、よりシンプルなHanamiを理解するのに時間がかかるというのはありそう」「それはあるかもです」

🔗 Rails Tutorial(英語版)の更新


つっつきボイス:「この間自分が英語版Rails Tutorial(以下Rails Tutorial)の更新を確認したときに、N+1クエリ問題とsessino replay攻撃とsession fixation攻撃への対応がRails Tutorialに反映されたことを知りました: 上はRails Tutorialの更新部分から参照されていた2本の記事です」「お〜なるほど」「それぞれの更新に関連する演習問題もいくつか追加されていました」「よく大学の教科書で『第x章のy節にあるzを修正せよ』というような解答なしの演習問題が付いていたりしますけど、ちょうどそんな感じですね」

なお、上記2記事の中でもRails Tutorialが対応済みであることについて言及しています。

「Railsを学ぶ人はまずRailsチュートリアルを最後まで走り抜けて一度ちゃんと動かすことが大事ですね: N+1クエリ問題はその後で学んでも大丈夫👍」「そうですね」

「2本目の記事はsession replay攻撃に関するもので、Rails Tutorialでもログインとログアウトの前後にsession_resetを追加するように更新されていました」「そうそう、基本的な処置ですね: session_resetを追加するのはRailsガイドにも載っています↓」

参考: Rails セキュリティガイド - Railsガイド

上述の変更内容は今後Railsチュートリアルにも反映される予定です。

「Railsチュートリアルは教育目的なのであえて認証機能を手作りしていますけど、最初からDeviseを使うとマジックが増えて初学者につらくなってしまうからでしょうね」「チュートリアルでいきなりDevise使ったらマジックオブマジックになっちゃいそう😆」「ちなみにRailsチュートリアルの本文では認証ライブラリとしてDeviseを推しています」

heartcombo/devise - GitHub

🔗Ruby

🔗 Ruby 3.1のMatchData\#matchMatchData\#match_length


つっつきボイス:「なるほど、MatchDataオブジェクトのmatchでキャプチャグループを取り出したりmatch_lengthでキャプチャ文字列の長さが取れるようになったのね」「Ruby 3.1は新機能を控えめにするということですが、こういう機能も入るんですね」

# 同記事より
result = /\$(?<dollars>\d+)\.(?<cents>\d+)/.match("$1.95")
#=> #<MatchData "$1.95" dollars:"1" cents:"95">

result.match(0)
#=> "$1.95"

result.match(1)
#=> "1"

result.match(:dollars)
#=> "1"

result.match(:cents)
#=> "95"

result.match_length(:cents)
#=> 2

🔗 Primitive.mandatory_only?でRuby組み込みメソッドを高速化


つっつきボイス:「ruby-jp Slackでたまたま見かけたんですが、Rubyの組み込みメソッドで上のような改修をやってくれる方を気長に募集しているそうです」「どれどれ、RubyのPrimitive.hogeなどを使っている組み込みメソッドで、キーワード引数のすべてにデフォルト値がある場合に、そのメソッドがキーワード引数なしで呼ばれると少し遅くなる、へ〜」「iSeqレベルの話なので細かそう」「以下のようにPrimitive.mandatory_only?を使って変更することで、キーワード引数なしで呼び出しても遅くならないようにできるのね: 小さな改修でも呼ばれる回数が多ければ改善は大きそう」「貢献するチャンスですね」

# 2a3d5d6より
# timev.rb#L270
  def self.at(time, subsec = false, unit = :microsecond, in: nil)
-   Primitive.time_s_at(time, subsec, unit, Primitive.arg!(:in))
+   if Primitive.mandatory_only?
+     Primitive.time_s_at1(time)
+   else
+     Primitive.time_s_at(time, subsec, unit, Primitive.arg!(:in))
+   end
  end

後で気づきましたが、以下のコミットログに詳しく書かれています。

🔗 Rubyコンパイラのリスト(Ruby Weeklyより)


つっつきボイス:「以下の記事↓を翻訳させていただいたShopifyのChris Seatonさんが、Rubyのコンパイラにどんなものがあるかを調べてみたそうです」「いろんなコンパイラやJITがあるな〜」「@tendeloveさんのTenderJITもありますね」「YJITはリストの下の方に載ってる」「こういうサーベイをやれるところがShopityの強さですね」

Rubyオブジェクトの未来をつくる「シェイプ」とは(翻訳)

🔗 pru: コマンドラインでRubyを手軽にパイプでつなぐ(Ruby Weeklyより)

grosser/pru - GitHub


つっつきボイス:「これは?」「以下みたいにpruを呼び出すことでRubyをsedやawk的なフィルタとして手軽に使えるようにするそうです」「お〜なるほど、Rubyを-eオプションで使おうとすろとPerlのperl peよりコマンドラインが長くなりがちなので、なかなか便利そう👍」「pru -i Gemfile 'sub /ruby/, "foo"'perl -i的なインライン置換もできるんですね」

# 同リポジトリより
# count letters of each line
ls -1 | pru size

# select lines longer than five letters
ls -1 | pru 'size > 5'

# 2nd to last character
ls -1 | pru self[2..-1]

「このpruのシングルバイナリ版が欲しいですね: gem installできない環境でも使えるようになるので」「それ欲しいです」「例のBusyBox↓にpruもで入ってくれたらとても嬉しい」「BusyBoxはよく使うコマンドがシングルバイナリになっているんでしたね」

参考: BusyBox - Wikipedia

🔗 その他Ruby

つっつきボイス:「今年のRuby PrizeはYJITでRubyに貢献したShopifyのMaximeさんでしたね」「YJITをここまで作り上げたMaximeさんとShopifyの人たちはホント凄い」「MaximeさんがPhD論文で提案したBasic Block Versioning(BBV)をRubyのYJITに応用したそうです」

YJIT: CRuby向けの新しいJITコンパイラを構築する(翻訳)


「チェリー本の改訂第2版がいよいよ先行発売開始🎉」

🔗クラウド/コンテナ/インフラ/Serverless

🔗 厚労省の「偽装請負」に関する疑義応答集の解説(Publickeyより)


つっつきボイス:「Agile Japan 2021でIPA専門委員の弁護士が厚労省の関係疑義応答集を解説してくれたのを記事にしたものですね: 自分の理解が概ね合っていたことがこの記事で確認できました」

参考: Agile Japan 2021 | The Heart of Agile

「そういえばBPSは客先常駐を基本的に行っていませんけど関連はあるんでしょうか?」「発注元が受注先の指揮系統を通さずに受注先の作業者に直接指示を出すことが違法になるので、常駐やリモートの有無にかかわらず関連はあります」「なるほど」「発注元が受注先の作業者に直接指示を出すなら派遣の形にする必要があります(発注前に作業者を面談・試験したりするのは派遣でも違法です)」

「いわゆる準委任型の開発を受ける側はこういう点に気をつける必要があるんですが、受注側が守りに入りすぎると今度はアジャイル開発のよさが失われてしまって、たとえばアジャイルでよくあるスタンダップミーティングすらできなくなってしまったりします」「あ〜たしかに」

参考: アジャイルソフトウェア開発 - Wikipedia

「話そのものは新しくはありませんが、これまでグレーになりがちだった部分についてIPAの弁護士が事例込みで詳しく解説してくれたのはありがたい」「ちゃんと読んでおこうっと」


後編は以上です。

バックナンバー(2021年度第4四半期)

週刊Railsウォッチ: フォームヘルパーの改修、Railsの監査ログgem比較、DHHとimport-mapほか(20211129前編)

今週の主なニュースソース

ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。

Ruby Weekly

Publickey

publickey_banner_captured


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。