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

週刊Railsウォッチ: Ruby 3.1にYJITマージのプロポーザル、Rubyのmagic historyメソッド、JSのPartytownほか(20211012後編)

こんにちは、hachi8833です。

週刊Railsウォッチについて

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

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

🔗Ruby

🔗 YJITマージのプロポーザル(Ruby Weeklyより)


つっつきボイス:「YJITをRubyにマージしようというプロポーザルにMatzが+1付けていました」「YJIT凄い」「Shopifyのような強い会社が集中的に作るのでないと短期間でマージ可能なところまでなかなかこぎつけられないでしょうね」「たしかに」「Shopifyが社内で使っているというのは、GitHub内部で使われているというのに匹敵するぐらい大きなアピールになりそう」「MJITを手掛けてきたk0kubunさんも早速YJITを詳しくチェックしていますね」「YJITマージ、いい流れだと思います👍」

参考: YJIT - Building a new JIT Compiler inside CRuby by Maxime Chevalier-Boisvert - RubyKaigi Takeout 2021

YJIがマージされたら3.1.0-preview1を出すとnaruseさんがコメントしてました」「お〜」

「MJITはプラットフォーム互換性は高いけど効率を上げにくいところがありましたが、YJITの実装はCPUアーキテクチャに依存する分効率を上げやすいようなので、JITの目指す方向としては好ましいかも」「そういえばYJITは対応プラットフォームがまだ少ないとissueの冒頭に書かれていました」「そうそう、MJITはプラットフォーム互換性を優先する設計になっています」

🔗 もっとRubyのマジックを


つっつきボイス:「記事ではproject.1.day.ago1_business_day_agoみたいな書き方をmagic historyメソッドと呼んでいますけど、これは他の言語からRubyに来た人が驚くもののひとつでしょうね」

project.1.day.agoみたいな書き方は初めてみたときにちょっと不思議でしたけど、今では普通に使っています」「特に英語圏の人にうれしみがありそう」「英語圏でなくても便利だと思いますよ」「Rubyはこうやって直感的に書けるのが便利ですよね」「記事にもあるように、project.one_day_agoのようにドットの代わりにアンダースコアでつなげる書き方もできます↓」

# 同記事より
  describe "magic history" do
    let(:team) { build(:team) }
    let(:project) { build(:project, team: team) }

    before do
      travel_to(Date.parse("Sep 23, 2021"))
    end

    it "handles date travel correctly" do
      expect(project).to receive(:at).with(Date.parse("Sep 23, 2021"))
      project.at(Date.current)
    end

    it "can go back one day" do
      expect(project).to receive(:at).with(Date.parse("Sep 22, 2021"))
      project.one_day_ago
    end

    it "can go back two days" do
      expect(project).to receive(:at).with(Date.parse("Sep 21, 2021"))
      project.two_days_ago
    end

    it "errors on nonsense" do
      expect { project.banana }.to raise_error(NoMethodError)
    end
  end

「記事ではis_magic_history_method?というメソッドを書いて、あるメソッドがマジックで生成されたものかどうかを確かめたりしてる↓」「なるほど」「メソッド名をアンダースコアでsplitして、呼べるかどうかをチェックしてるんですね」「これはたしかにマジック🧙」

# 同記事より
  def respond_to_missing?(method_name, include_private = false)
    is_magic_history_method?(method_name)
  end

  def is_magic_history_method?(method_name)
    number, duration, time = method_name.to_s.split("_")
    return false if NumbersInWords.in_numbers(number).zero?
    return false unless duration.in?(%w[day days])
    return false unless time == "ago"
    true
  end

  def method_missing(method_name)
    super unless is_magic_history_method?(method_name)
    number_string, duration, _ = method_name.to_s.split("_")
    number = NumbersInWords.in_numbers(number_string)
    date = number.send(duration).ago
    at(date)
  end

「記事では『無用なのはわかってるけどいろいろ楽しい』とあります」「やっぱり楽しさ大事: 自分が普段使っているコードが裏でどのようになっているのかを知るのは、コードを早く書くとかにすぐ役立つわけではなくても、Rubyについてより詳しく知ることができますよね」

🔗 Rubyの整数演算オーバーフローチェックを「スタンプ」で削減する(Ruby Weeklyより)


つっつきボイス:「RubyKaigi Takeout 2021で例のオブジェクトシェイプ↓について発表したShopifyのChris Seatonさんが、今度はTruffleRuby内部にスタンプという概念を導入してVMの整数演算オーバーフローチェックを削減する記事を書いてました」

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

「TruffleRubyとその中にあるGraalVMの機能を使って最適化しているようですね↓」

def add_stamps(a, b, c)
  a = Truffle::Graal.inject_stamp(a, 0xff)
  b = Truffle::Graal.inject_stamp(b, 0xff)
  c = Truffle::Graal.inject_stamp(c, 0xff)
  a + b + c
end

oracle/truffleruby - GitHub

参考: GraalVM

「図の左が最適化前、右が最適化後だそうです」「お〜、右の最適化後は短く並列なパスになってて依存も少なさそう: 左の最適化前は必ず通らなければならない箇所がたくさんありますね」「ざっと見ただけですがいろいろ凄いことやってそう💪」「こういう概念と実装をきちんと解説してくれる人がいるのは頼もしい」


同記事より(編集部で合成)

🔗 code2flow: コールグラフのビジュアライズgem(Ruby Weeklyより)

scottrogowski/code2flow - GitHub


つっつきボイス:「なるほど、呼び出しのパスを解析してこういう感じのコールグラフを生成するんですね↓」「Ruby以外にも複数の言語に対応しているそうです」

「この種のグラフ生成といえば、Graphvizがもう何十年と使われ続けていますよね」「そうそう、Graphvizは定番: 前職でシェルの呼び出しをGraphvizでこんなふうにビジュアライズしたのを思い出しました」

「ところで、Graphvizで生成したグラフは複雑になってくると密集して手に負えなくなってきますね」「そうそう、仕方ないとは思いますけど」「このcode2flowはなかなかいい感じに出力できてるように見える」「おや、code2flowはGraphvizを使わずにやっているのかと思ったら、インストール要件にGraphvizが書かれている」「やっぱりGraphviz使ってるんですね」

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

🔗 書籍『AWSコンテナ設計・構築[本格]入門』


つっつきボイス:「はてブで話題になっていました」「このコンテナはどのコンテナを指しているのかな?」

「Amazonのページなども見た限りでは、ECSやFargateのコンテナを対象にしていて、Lambdaのコンテナは含まれていないように見える」「なるほど、コンテナといってもいろいろあるんですね」「FargateもECSのサービスのひとつなので、おそらく広義のECSのコンテナを指しているんじゃないかな」

参考: Amazon ECS(Docker コンテナを実行および管理)| AWS
参考: AWS Fargate(サーバーやクラスターの管理が不要なコンテナの使用)| AWS

🔗JavaScript

🔗 Partytown


つっつきボイス:「これもはてブで話題になっていました」

「記事冒頭は、外部のスクリプトを手元ではなるべく隔離された環境で動かしたい、しかしscriptタグで読み込むと全コンテキストを触れるので強すぎる、それを避けるにはiframeで読み込むことで実質コンテナ的に動かせる、またはWeb Workerで動かせばメインのコンテキストから分離できる、という感じの流れですね」「ふむふむ」

「ShadowRealm↓というプロポーザルは、1個のJS実行系の中にShadowRealmを置いてグローバルオブジェクトに触らせないようにするというものらしい」

tc39/proposal-shadowrealm - GitHub

// 同リポジトリより
declare class ShadowRealm {
    constructor();
    importValue(specifier: string, bindingName: string): Promise<PrimitiveValueOrCallable>;
    evaluate(sourceText: string): PrimitiveValueOrCallable;
}

「ShadowRealmは同一プロセス内で動くのでSpectre↓のような攻撃が心配されると書かれてるけど、CPUの脆弱性まで気にするときりがなさそう」「Spectreは脆弱性の名前なんですね」

参考: Google Developers Japan: Spectre の影響を受けないウェブを作るための概念実証について

「Web Workerは別スレッドで動くので比較的わかりやすくて、ホスト側と非同期メッセージ通信もできるしプロセス分離も可能になる、その代わりDOMプロパティへの同期アクセスは難しい、たしかに」

「Web Workerはセキュリティ的には望ましいけど使いにくいということでしょうか?」「Web Workerは独自のコンテキストで動くもので、非同期メッセージ通信しかできないので、メインスレッドにあるDOMを直接触るのが難しいんですよ: なのでメインスレッドのDOMを更新するような処理はWeb Workerに投げにくい」「DOMを触らない純粋な計算処理ならWeb Workerでやれるけど、DOM更新には不向きということなんですね」

「WebAssemblyはメモリも別環境で動いて同期アクセスも可能なのか、へ〜」

「そしてPartytown: サードパーティのコードを別プロセスで動かしたいけどブラウザのDOMにもアクセスしたい、document.body.clientWidthみたいなものにアクセスしたくても、同期DOMを前提とするライブラリはそのままではアクセスできない」「ふむふむ」「Partytownではそのために同期的なXMLHttpRequest呼び出しを使うのか!なつかしいものが登場した」

参考: XMLHttpRequest - Web API | MDN

「Partytownでは、Worker内に仮想的なDOM環境を置いてプロパティアクセスを同期的なXMLHttpRequest呼び出しに変換する、でもそのままではXMLHttpRequestでURLにアクセスできないのでService Workerでインターセプトする: これはなかなかのハックですね」

🔗 Web WorkerとService Worker

「Web WorkerとService Workerの違いがわかってなかった...」「Web Workerはスレッド的に動作する普通のワーカーで、Service WorkerはMDNにもあるようにイベント駆動のプロキシサーバー的なワーカー」「なるほど」「Service Workerは使ったことがありませんが、イベントフックに似ているかも」

参考: Web Worker の使用 - Web API | MDN
参考: サービスワーカー API - Web API | MDN

「JavaScriptの呼び出しの多くが非同期に向かう中、残された同期的なXMLHttpRequest呼び出しを使ってPartytownを実現しようとしているということかなと思いました」「なるほど」「その呼び出しをうまく隠蔽して、あたかもWeb WorkerがDOMに同期アクセスしているかのように振る舞わせることができる、そしてサードパーティのJSからDOMへのマッピングを行う部分でアクセス制御可能なので、そこで分離しようと思えばできる、という感じ」

🔗 古い機能がよみがえるとき

「こういう無理矢理感は面白いですね😆」「こんなふうに、昔登場したけどあまり使われていなかった機能が、後に思いもよらぬ方法で使われるようになってよみがえるというのは言語の歴史でときどきありますね」「たしかに」「XMLHttpRequestも実はそうで、Ajaxでとても有名になりましたけど、もともとの仕様策定でこういう使い方は想定されていなかったはず」「へ〜!」「その意味でAjaxは既存技術の組み合わせに過ぎないとも言えますね」

参考: Ajax - Wikipedia

🔗CSS/HTML/フロントエンド/テスト/デザイン

🔗 SPAセキュリティ入門


つっつきボイス:「PHPカンファレンス2021やっていましたね」「徳丸先生のプレゼン冒頭でTechRachoの翻訳記事が引用されていると知りました↓」「よくランキングに上がってるLocal Storage記事ですね」

HTML5のLocal Storageを使ってはいけない(翻訳)

「結論としては、Local Storageだから即危険とは限らないそうです↓」「JWTが当初と違う使われ方をするようになってきたのはしょうがないのかなという気もしますけど」「そうかもですね」「JWTは開発者にとっては使いやすいんですよ、それもあってついLocal Storageに入れてしまうのかもしれませんね」

🔗 その他HTML


つっつきボイス:「お楽しみ画像です」「お〜ネコ画像🐈‍⬛」

202 Accepted」「304 Not Modified、そう来たか」「406 Not Acceptable、ネコ嫌がってるのが感じ出てる😆」「408 Request Timeout」「414 Request-URL Too Longは昔出回ってたコピペ画像ですね」「599 Network connect timeout errorツボった」「5xx系にあるとは思わなかった」「418 I'm a teapotは有名なジョークプロトコルですね↓」「HTTPステータスコードの数だけネコ画像集めたの凄い」

参考: Hyper Text Coffee Pot Control Protocol - Wikipedia


後編は以上です。

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

週刊Railsウォッチ: ServerTimingミドルウェア追加、paramsで数値キーを許可、Railsで多要素認証ほか(20211011前編)

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

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

Ruby Weekly


CONTACT

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