- Ruby / Rails関連
週刊Railsウォッチ: rubygemsに「scoped gems」の提案、RSpecのブロック構文ほか(20220517後編)
こんにちは、hachi8833です。
🔗Ruby
🔗 scoped gemsの提案(Ruby Weeklyより)
つっつきボイス:「scoped gemsという名前の提案がRubyGemsのRFCsに上がっているそうです」
RubyGemsチームおよびこれを読んでる皆さんへ。
このプルリクには、「scoped gems」と呼ばれる機能の提案が盛り込まれています。要するに、gemの命名仕様を拡張して、関連するgemを特定の組織で予約したサフィックスでグループ化する新しい
@
を含めようという提案です。
命名パターンはgem名@スコープ名
に沿います。
最初のgemをプッシュ(新規レコード)では、そのgemがこのパターンに沿ってscopedになっていれば、そのgemのスコープは、そのスコープを予約した組織のユーザーによって作成されたことが検証されます。scoped gemは、現在の通常のgemと同様にインストールすることもrequire
もできます。たとえば、aws-sdk-s3というAWSのS3 gemで考えてみましょう。
このgemがscopedだとすると、s3@aws-sdk(一般化するとサービス名@aws-sdk
)という形で公開されます。s3@aws-sdkは、AWSというorganization(ここがaws-sdkというスコープを予約する)に所属するユーザーだけが作成できます。
一般ユーザーは、gem install s3@aws-sdk
でこのgemをインストールしてrequire 's3@aws-sdk'
することになります。scoped gemsの主なメリットは、organizationが独自のgemグループを公開できること(つまり複数のorganizationが"コンフィグ"gemを持てる)、組織がgem名を予約できること(
@スコープ名
を予約済みプレフィックス的に使う)です。
開発者は、たとえば新しいnew-cool-feature@rails
がRails公式のgemであることや、new-s3-service@aws-sdk
が公式のAWS SDKクライアントであることや、socket@ruby
がRuby公式のstdlib gemであることを合理的に確信できます。
この予約システムは、個人情報を盗み出そうとする"フェイク"gemが紛らわしい名前によって公式扱いされないようにするための対抗手段です。
お気づきの点があれば喜んで手法や設計を見直しますので、フィードバックをお願いします。
同PRより
「gem名@スコープ名
か、なるほど」「現在のRubygemsはgem名がグローバルなので、gem作者にとっては名前が衝突しないようgem名が長くなりがちですし、使う側にとっても違うgemを取ってきてしまったりという不便な点があるんですよ」「rubyzipとziprubyが同じ::Zip
という名前空間を使っていて衝突するみたいなことが実際起こってますよね」
「問題はどういう仕様にするか」「👎を押してる人も数人いるぐらいなので、それぞれ意見はあるでしょうね」「スレッドを見るといろんな案がある↓」「スコープを前に置くか後ろに置くかとか」「ネストをどうするかも考えないといけないでしょうし」「@
を使うとメールアドレスと間違えそうというのもちょっとわかる」
gem_name@scope
scope/gem_name
@scope/gem_name
--
で区切る(rails--activerecord
など)- etc
「gemを作るようになってくると、こういう仕組みを整備しておくのはとても大事👍」「gem作者にとっては欲しい機能」「まだ議論中なので最終的にどうなるかは今後の流れ次第でしょうね」
🔗 Ruby 3.1の非互換変更がPsych 4に与えた影響(Ruby Weeklyより)
つっつきボイス:「Ruby 3.1でPsych 4に非互換が生じた件は、以前も話題にしたかな(ウォッチ20210518)」「少し前のRails 7.0.2でもPsych 4関連の修正が入ってましたね↓」
🔗 RSpecのブロック構文でメッセージのexpectationを書く(Ruby Weeklyより)
つっつきボイス:「RSpecのブロック構文?」「引数のチェックに便利みたいなことが書かれてるようです」
「お〜、こういうふうにreceive
のブロック(do
〜end
)の中に通常のexpect
を書くのね↓: たしかにあまり見かけない方法かも」「なかなかよさそう👍」
# 同記事より
expect(@dummy_client).to receive(:create) do |headers, body|
expect(body[:name]).to eq "apollo creed"
…
end
「最終的にこんな感じになるのね↓」
# 同記事より
require "./user_builder"
RSpec.describe UserBuilder do
before :each do
@dummy_client = double("api client", {
create: "Done",
get_token: "90809080"
})
@params = {
api_client: @dummy_client,
name: "Apollo Creed",
shoe_size: 11
}
end
…
describe "instance method" do
before :each do
@builder = UserBuilder.new(@params)
end
describe "#build" do
it "should call the API client" do
expect(@dummy_client).to receive(:create).and_return("Done")
@builder.build
end
describe "API client call" do
it "should set headers appropriately" do
expect(@dummy_client).to receive(:create) do |headers, _body|
expect(headers["Content-Type"]).to eq "application/json"
expect(headers["Authorization"]).to eq "Bearer 90809080"
end.and_return("Done")
@builder.build
end
it "should set the body appropriately" do
expect(@dummy_client).to receive(:create) do |_headers, body|
expect(body[:name]).to eq "apollo creed"
expect(body[:shoe_size]).to eq 11.5
end.and_return("Done")
@builder.build
end
end
end
end
end
参考: Support expect(object).to receive(xyz).with_block(block) · Issue #1182 · rspec/rspec-mocks
「ところで、例外を拾うテストはブロックでないと書けないみたいな話はありますね↓」「そうだったかも」
参考: RSpec でエラーを捉えらんないアレなミス - Qiita
🔗 その他Ruby(Ruby Weeklyより)
I'm really excited about Ruby supporting WASM because it means we can finally run Rails in the browser and React on the server as was intended
— Aaron Patterson (@tenderlove) May 4, 2022
つっつきボイス:「珍しくRuby Weeklyで引用されていた@tenderloveさんのツイートです」「なるほどWasmでRailsをブラウザ内で動かしたいと」「Reactはサーバー側ですか😆」「続きのスレッドも盛り上がってる」「こういう夢は昔からみんなが見てましたね」
🔗 モバイルエージェント
「1990年代頃から研究されていたモバイルエージェント↓もそのひとつで、たとえばコードをユーザー側でも動かして、処理結果および処理内容が改ざんされていないかとうかを保証する研究などが行われています」「今だとブロックチェーンにも関連しそうですね」
参考: PDF モバイルエージェント技術と研究動向(2001年)
参考: ブロックチェーン - Wikipedia
「この分野の理論はいろいろ発達していて、改ざん防止もそうですけど、少し変わったものとしては、暗号化されている数値データを暗号化されたまま計算する一種のセキュリティ技術の研究を見かけた覚えがあります」「ということは...」「メモリ上に乗っている数値データが暗号化されたままなので、仮にメモリのデータを盗んでも読めない」「あ〜なるほど」(以下延々)
🔗DB
🔗 Cloudflare D1
つっつきボイス:「CloudflareのD1、話題になってますね」「SQLiteのDBファイルを使うんですか」
「D1は、Cloudflareが元々持っているファイル配布機能をSQLite DBファイルに応用したという感じですが、それをDBバックエンドとして使う点は新しいと思いました」
「せっかくなのでSlackに書いたコメントを引用しておきます↓」
発想としてはSQLite DBファイルを同じようにEdgeに載せるという話だとは思うけど、
- 更新系のリクエストでRDBMSを使わなくて良い(Dynamo他を使える、トランザクション不要)
- 更新系の変更が直ちにread系に反映されなくて良い
- readしたいデータのサイズが小さめ、または高いlocalityをもつ
あたりを満たしているのであればアーキテクチャ上はありかもですね。
集計系クエリ使いたいみたいな話も、最近はDatalake的なものに集約してやろう、みたいな風潮もあるので解決できるのかも(中小規模だとクッソインフラ&データ集約コストが上がるので僕は懐疑的ですが)
ノウハウが溜まってくるまではエンジニア工数の方が高そうという問題はあるけど、自社サービスとかなら半分技術開拓のつもりでやってみる、とかはいけるのかもしれない
CDN edgeのlocalityとDBとしてのlocalityがどれくらい一致するユースケースがあるのか疑問だけど、データ取ったり色々すると面白いテーマな気がするなー
参考: データレイクとは
「読み取りだけでいいなら便利そう」「SQLiteは1ファイル1DBなので、データのlocality(局所性)が高ければ分割して配布もできそうに見える」
🔗 CDNとデータベースのlocality
「自分が一般に気になるのは、CDNのEdgeのlocalityと、データベースのlocalityが実際のユースケースでどのぐらい一致するのかという点かな」「ふむふむ」「CDNのキャッシュの効き方もこういうlocalityに影響されるので、両者のlocalityが一致すればするほどキャッシュが効く可能性があるかもしれないと想像しています」「なるほど」
「Cloudflare D1を実際に使うかどうかはともかく、こういうのは研究向きのテーマだと思うので、実際にデータを取ってまとめたら面白いと思うんですよ」「なるほど」「個人的にはあまり効かないのではという気もしていますが、まだ知見が少ない分野ですし、やってみたらまったく違う結果になるかもしれないので、Cloudflareのような大手がデータを取ってくれたらありがたい」「クラウドの実験は大学の研究室より自前のインフラが使える大手が有利ですよね」「そうやって実用的なユースケースを明らかにして欲しい」
「ただCloudflare D1のようなものは、個人アプリレベルで使うならともかく、大規模な業務システムでいきなり導入すると、後から方向転換しにくくなる可能性があるかもしれない」「それはたしかに」
「更新がすぐに全体に反映されないという仕様は、要件定義や設計の自由度が下がるので、請負の案件で使うとなると顧客を説得しにくい場合もあるかもしれません: もちろん当日データの反映は翌日とする、みたいに要件をきちんと定義すれば十分可能ですが」
以下はつっつき後に見つけたツイートです。
sqliteに個人情報入れてしまって域外移転で引っかかる事例が出てきそう / 他70件のコメント https://t.co/pClbkO3JDp “Cloudflare D1 がヤバい” (646 users) https://t.co/ZwZLeBoyt9
— masa寿司 (@masa_iwasaki) May 12, 2022
🔗 Cloudflare R2ストレージ
「個人的にはD1も面白いけど、同じCloudflareのR2ストレージというS3クローン的なサービスの方がコスト面も含めて興味あるかな↓」「R2はいつの間にか正式にリリースされていますね」
マジでCloudflare R2を検討した方がいいかもしれん....https://t.co/f9IIbh3Vw3
— むらしゅん (@murashun) May 10, 2022
🔗 Railsで競合状態を回避する方法(Ruby Weeklyより)
つっつきボイス:「楽観的ロックや悲観的ロックの話が出てくるので、データベースの競合状態ですね」「こういうのをrace conditionって言うの知らなかった😅」
参考: 楽観ロック/悲観ロック(optimistic locking/pessimistic locking)とは - 意味をわかりやすく - IT用語辞典 e-Words
参考: 競合状態 - Wikipedia
「記事にもあるように、データベースのUNIQUEインデックスと、アプリケーション側のuniquenessバリデーションは違うことを知っておくのは大事」「Railsだと後者はActive Recordが行うものだから↓、前者の場合と結果が違ってくる可能性がありますよね」
# 同記事より
class User < ApplicationRecord
validates :phone_number, uniqueness: true
end
「sidekiq-unique-jobsというgemを使ってSidekiqのジョブに一意性制約を追加する↓: こういう話題は何度か取り上げたことがありますね」
# 同記事より
Sidekiq.configure_server do |config|
config.redis = { url: ENV["REDIS_URL"], driver: :hiredis }
config.client_middleware do |chain|
chain.add SidekiqUniqueJobs::Middleware::Client
end
config.server_middleware do |chain|
chain.add SidekiqUniqueJobs::Middleware::Server
end
SidekiqUniqueJobs::Server.configure(config)
end
Sidekiq.configure_client do |config|
config.redis = { url: ENV["REDIS_URL"], driver: :hiredis }
config.client_middleware do |chain|
chain.add SidekiqUniqueJobs::Middleware::Client
end
end
🔗 設計
🔗 オンライン投票と要件定義
というわけで、「オンライン投票はなぜ『難しい』のか」とか題しておきながら、全体の3分の2が現行のオフライン投票の話で埋まっている記事はこちらです https://t.co/i92k2X8A4B
— Dai MIKURUBE (@dmikurube) May 10, 2022
つっつきボイス:「これはいい記事: オンライン投票は一見すぐできそうに見えるけど、オンライン投票を要件定義すると実はいろいろ困難や課題があることが具体例を挙げて解説されている」「秘密投票とかそういう話題もあるんですね」「この記事でやっていることがまさに要件定義になっているのが興味深い: 良い要件定義の例として読むといいと思います👍」
参考: 秘密投票 - Wikipedia
後編は以上です。
バックナンバー(2022年度第2四半期)
週刊Railsウォッチ: Active Modelで属性のパターンマッチをサポート、猫でもわかるHotwire入門ほか(20220516前編)
- 20220511後編 Ruby 3.2.0devにRust版YJITがマージ、Docker Compose V2ほか
- 20220510前編 Active RecordにPromiseと非同期集計メソッドがマージ、climate_control gemほか
- 20220419後編 RubyのGCコンパクション改修、jemalloc、ReDoSの自動検出修正ほか
- 20220418前編 RailsConf 2022が5月17〜19日開催、認可機能解説記事ほか
- 20220412後編 HashieでRubyのハッシュを強化、最近のRubyコア解説記事ほ
- 20220411前編 Turbo Railsチュートリアル、Active Recordの「Leaky Abstraction」を削減ほか
- 20220406後編 RBS関連記事、Ruby formatterプロジェクト、Google Cloud Runほか
- 20220404前編 Ruby 3.2.0 Preview 1リリース、Rails向けDocker環境ジェネレータ、scientist gemほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。
週刊Railsウォッチについて
TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)