rastam on rails

東京在住のマレーシア人 Rubyist

Ruby Weekly #461: 日本語サマリー

rubyweekly.com

Highlights

Artichoke Ruby Playground: A New Ruby Interpreter

Artichoke という mruby ベースのインタープレターのコードをブラウザーで実行してみることができるページ。

Rails 6.0.0 RC2 Released

Rails 6 RC2 がリリースされた。ファイナルリリースは数週後の予定。

Articles & Tutorials

Consider Value Objects

ヘルパーからバリューオブジェクトを抽出する方法。

Infinity: How It Works and Why It Matters in Ruby

Ruby の Infinity オブジェクトいろいろ。

  • 0 で割った挙動いろいろ
  • 無限 Range(+ Ruby 2.6 の新しい表記)

Rails 6 Adds Support for Database Optimizer Hints

Rails 6 の ActiveRecordoptimizer_hints メソッドでクエリ軽量化ヒントを与えれるようになる。

Moving From Tagging with ActsAsTaggableOn to PostgreSQL Arrays

acts-as-taggable-on gem から PostgreSQL 配列カラムに移行した経験談。ネタバレ:migration だけでいけた!

Rails 5: Getting Started with Active Storage

Active Storage 導入手順。

3 Defensive Programming Techniques for Rails

デプロイ失敗の未然防止策。

  • concurrently オプションを指定しなかった add_index がエラーを起こすように prepend することで、DB をロックする migration 防止
  • rails server 起動時の FK チェックで、CASCADE による重大レコード削除防止
  • Net::HTTP への prepend で長い HTTP リクエストをタイムアウトさせる

Using Ruby's Array() and Array.wrap

配列であるかどうかの分岐を省略してくれる ActiveSupportArray.wrap

How Do You Tell Which Areas of a Project's Test Suite Need Attention?

所属していないプロジェクトのテストを重点的改善する方法。

  1. テストスメル特定
    • テストがない
    • 難解テスト
    • テストの重複
  2. チームに辛いところを聞き出す
  3. コード弄ってみる

Code and Tools

Geocoder: A Complete Ruby Geocoding Solution

位置情報用 gem。

Affect: Algebraic Effects for Ruby

関数型 Ruby の副作用を隔離してくれる gem。

Ruby Weekly #459: 日本語サマリー

rubyweekly.com

Highlights

regexp-examples: Generate Strings That Match a Given Regular Expression

正規表現に一致する文字列を生成する gem。Regexp#examples #random_example メソッドを生やす。

Goodbye ActiveRecord!

Rails モノリスを ROM マイクロサービスに分解した Aircall 社が ActiveRecord と ROM を比較した記事。

  • ActiveRecord の多岐に渡る責務 vs ROM の明確に分けた責務
  • ActiveRecord の疑問はググり放題 vs ほとんど ROM フォーラムで聞くことが多い

Lefthook, Crystalball, and Git Magic for a Smooth Development Experience

開発効率化案いろいろ。

  • lefthook で git hook 管理・チームと共有。push 前にテストを実行するフック登録。
  • crystallball で修正した差分のテストのみに絞る。
  • checkout 時に足りてない gem を自動的に bundle install するフック登録。
  • checkout 時に migration を自動的に実行するフック登録。

Articles & Tutorials

How We Migrated To Turbolinks Without Breaking JavaScript

メンテされなくなった PJAX を Turbolinks に移行した Honeybadger 社の注意点。

  • Turbolinks は SPA なので、遷移するたびに、ロードしたものをアンロードする必要がある
  • 破壊的リクエストを発行するたびにキャッシュをクリアする必要がある
  • 遷移した時点の DOM がその状態のままでキャッシュされるから、またそのページに戻ったら状態が初期化されてない覚悟を
  • <body> 内 JS を全部削除しないと、遷移するたびに実行されちゃう
  • 外部ライブラリを JS モジュールでインポートすること
  • デプロイを跨いだ遷移は古い JS・CSS に依存したままなので、 data-turbolinks-track 属性で強制リロード

Using strftime in a Rails View is a Mistake

Rails ビューで Date Time#strftime を直接呼ぶのをやめようという主張。 %Y-%m-%d 表記が読みにくいから。 #to_s(:symbol) で書こうと。 :symbolRails デフォのものからも選べれば、 Date::DATE_FORMATS[:symbol] `Time::DATE_FORMATS[:symbol] で独自定義もできる。

Minimum Viable Example of Calling Rust From Ruby without a Gem

RSpec コアチームの Sam Phippen 先生が gem なしで Rust を Ruby から呼んだ話。

Adding devise_token_auth to An Existing Rails App

既存 Rails アプリに devise_token_auth gem を導入する手順。

Rails 6 Adds ActiveRecord::Relation#annotate

SQL コメントを書く ActiveRecord::Relation#annotateRails 6 に登場。

Debugging MySQL Lock Errors in Rails Apps

Rails での Mysql2::Error: Lock wait timeout exceeded; try restarting transaction エラーの原因を突き止めた話。

50 秒以上かかるトランザクションがあるときに発生するエラーだが、そのトランザクションがどこにあるのかが謎。 ActiveRecord::Base.transaction のモンキーパッチで 50 秒以上かかるトランザクションをログに書き込むことで、犯人の正体が暴けた。トランザクション内でメールを送信する処理だった(非同期で送信してなかった)。

Dynamic Image Resizing with Ruby and the Serverless Framework

S3 上画像のサムネなどを Serverless フレームワークで生成する手順。Lambda 関数は Ruby、画像処理は MiniMagick gem で。

Code and Tools

Montrose 0.10: A Library for Defining Recurring Events

定期イベントを表すオブジェクト用 gem。オブジェクトをシリアライズすることで永続化できる。

Wasmer: A Ruby Library to Run WebAssembly Binaries

WebAssembly 実行用 gem。

Ahoy Email: Email Analytics for Rails

メールアナリティックス用 gem。送信・開封・クリック履歴、UTM タグ付けなどの機能付き。

Transproc: Transform Ruby Objects in Functional Style

proc を関数型っぽく書く gem。

A Bare Bones Starter Project for Sinatra Apps

Sinatra アプリの初期プロジェクト。clone して拡張していくもの。

pg_search: Build ActiveRecord Named Scopes using Postgres's Full Text Search

PostgreSQL 全文検索の複雑な SQLscope を生やしてくれる gem。なお Solr が提供してくれる機能もいくつか実装してる。 ü などの発音区別符号を無視する機能とか。

Ruby Weekly #458: 日本語サマリー

rubyweekly.com

Highlights

strong_password v0.0.7 Ruby Gem Hijacked

strong_password gem がハイジャックされた。メンテナが 2 段階認証を有効にしてなかったせいか、rubygems アカウントが乗っ取られちゃった。

問題の v0.0.7 は yank 済み。

TimeCalc: A Simple, 'Next Gen' Time Arithmetic Library

時間計算 gem。ActiveSupport と違って、Fixnum などをモンキーパッチしてなくて、依存が少ない。

Rails 6 Errors: The Good, The Bad, The Ugly

Rails 6 エラー画面の良いところ

  • 例外、絶対パス、エラーメッセージが分かりやすく表示される
  • 発生箇所のソースが分かりやすく表示される
  • スタックトレースが分かりやすく表示される
  • パラメータなど分かりやすく表示される
  • ブラウザー内 REPL!!!

良くないところ

  • Did you mean? が当たらないことがある。初心者がこいつに惑わされそう。
  • #<#<Class::0x000000000ed0aee0>:0x000000000ed110b0> といった出力が役立たず

Rails 6 Adds Hooks to Active Job Around Retries and Discards

ActiveJob の retry_ondiscard_on マクロに渡すブロックは、Rails 6 以降 ActiveSupport::Notifications フックで書けるようになる。

  • enqueue_retry.active_job
  • retry_stopped.active_job
  • discard.active_job

ApexCharts.rb: Interactive, Responsive Web Charts for Ruby Apps

JS チャート・グラフ用 gem。apexcharts.js ライブラリをラッピングしてるもの。

Articles & Tutorials

Discovering the Design Pattern at the Heart of Rack Middleware

Rack ミドルウェアデザパタとして定義してる記事。(GoF デザパタ本には載ってないので新規提案)

応用例:

My Experience Architecting A Software Development Stack with JRuby, OpenJDK, and Roda

JRuby + Roda + Sequel + Puma + H2 データベース + いろんな Java ライブラリでレトロゲーム管理システム開発経験談

JRuby メンテナー Charles Nutter 先生が「高スループット Ruby エンドポイントのベスト実装例」と賞賛するつぶやきでこの記事をバズらせた。

How to Deploy AnyCable with Capistrano and systemd

AnyCableCapistrano + systemd でデプロイする手順。

AnyCable はパフォーマンス・安定性・スケーラビリティが ActionCable に勝るが、Capistrano でデプロイすることは安易ではない。

Handling HTTP Headers in Grape with Rack and Rails

Grape vs Rack vs Rails の HTTP ヘッダー処理比較。

How to Store Secure Encrypted Data in Rails Without Gems

attr_encrypted などのデカい外部 gem に依存せずに、RailsActiveSupport::MessageEncryptor だけで機密情報を暗号化する方法。

10 Tips When Using the VCR Gem in Your Ruby Test Suite

vcr gem を効率よく使う豆知識 10 点。

  1. cassette 名自動生成しよう
  2. vcr_mode = :once。あとヘッダー無視しよう
  3. 外部へのリクエスト遮断しよう
  4. 環境変数で cassette 上書き
  5. VCR.current_cassette.file
  6. vcr を使ってるテストでは FactoryBot の sequence を必要に応じて固定化しよう
  7. cassette が何回でも作れるように、テスト冪等化しよう
  8. 実行順、キャッシュは要注意
  9. cassette 内 URL 正規化しよう
  10. cassette 変更時の差分は無視して良し

Building Messaging Between Ruby/Rails Applications with ActiveMQ

Rails の非同期処理を ActiveMQ で実装した経験談

STOMP プロトコルstomp gem で対応。本番は AmazonMQ で。

How to TDD When TDD Is Hard

TDD の壁とその乗り越え方。

  • 結合テストなどの高レベルテストが落ちる原因が分かりづらい場合は、モデルなどの低レベルテストでテスト書こう。
  • モックが多すぎるテスト = 関心ごとが多すぎるテストなので、高レベルテスト書いてから、リファクターしよう。
  • context などのネストが深すぎて読み解けないテストは、context・before・shared_context などのコードを it/specify で書き写そう。理解できたら、元のテスト or it/specify のみのテストのどちらかだけ採用。
  • テストがそもそもない場合は、現行挙動のテストを書こう。
  • テストをどう書くか分からない = 仕様を理解し切れてない。仕様を聞こう or 既存コード調査しよう。
  • テスト書く時間がない場合、正常ケースのテストとか低レベルテストだけでも重点的に書こう。

コードレビューで聞く質問集

コードレビュー中には、どこを見ればいいんだっけ、ってよくなりますので、 まとめておきました 英語でまとめたものを日本語に訳しました。

  • この PR の目的は何なの?
  • PR 作成者がこの PR に到るまでの調査結果・決定事項・仮説は妥当か?
  • もっといい解決方法はないか?コード修正以外の解決方法も検討。
  • この PR は根本的な解決?それとも暫定対応?暫定対応の場合は、PR 作成者に根本的な解決の計画を立ててもらう。
  • この変更点はステークホルダーにどんな影響を与えるか?ステークホルダーはエンドユーザだけでなく、チームメンバーとかも含まれてる。
  • その影響は最小限に抑えられないか?
  • 影響を最小限に抑えるには、具体的にどんなステップを取るか?
  • この PR の動作は正しいか?(言うまでもない)
  • 足りてないエッジケースはないか?
  • セキュリティの穴はないか?
  • コードをもっと読みやすくできないか?
  • コードをもっと簡潔に書けないか?
  • 削除できる不要なコードはないか?
  • PR 作成者にもしものことがあったら、レビュワーである あなた はこのコードを引き継ぐ責任は取れるか?
  • マージ前後にやることはないか?特に CI やチームメンバーの開発環境に影響を与える修正。
  • オンラインメンテでデプロイできそうか?
  • デプロイ前後にやることはないか?PR 作成者にチェックリストを書いてもらう。

下記項目は基本確認しないようにしている。

  • コード規約・フォーマット。Rubocop などのリンターに任せましょう。
  • テスト。上記項目の確認がぜーんぶ終わったら、テストまで確認する気がほとんど失せてるから。

ポジティブなコメントも欠かさず

レビューに慣れてない人は最初 レビュー = 間違い探し と思いがち、ネガティブな指摘しか書かない。問題点が見つからなかった PR も「何か書かなきゃ!」というプレッシャー感じて、些末な nits 書いちゃったりする。そういうときは

  1. どんな状態からどんな状態に変わったか?良い方向に変わった場合は褒める。読みやすくなったことだけでも。レビューしやすく工夫してくれたことでも。
  2. コード読んで理解したことを文章化する。理解に時間がかかったときは特に文章化する価値がある。認識の確認にもなる。

このレビュー術は、Aiming で培ってきたものです。

エンジニアの CS 対応メモ

この間、CS からのお問い合わせ対応のやり方について新卒に説教することになりました。 せっかくなので書き落としておきました。

手順は

  1. 何の問題なのか完全に理解すること
    • 不明な場合は、お客様に聞くように CS 担当者に依頼すること。
    • 必要があればスクショ撮ってもらう。
  2. 再現すること(できれば)
  3. リクエストログが追えれば、追うこと
    • 本当にその現象が起きた証拠を集めて参考にするために。その中にある情報で何かが分かるかもしれないから。あと人聞き悪いですが、クレーマーが嘘を付くことがたまにある。
  4. 原因調査すること
  5. 解決すること
  6. CS 担当者に連絡すること
    • 砕けた文章で OK。お客様向け文章を書くのは CS 担当者の仕事なので。
    • 五月雨式の連絡を避けて、出来るだけ連絡内容をまとめてから投げる。
      • お客様に何回も連絡すると、お客様がめんどくさくなる。
      • CS 担当者の負担を増やさないように。エンジニアを理不尽なクレーマーから守ってるのは CS 担当者だから。

Rails Needs Active Deployment: 日本語サマリー

先週の Ruby Rogues ポッドキャストで取り上げられた熱い記事。

medium.com

Active Storage、Active Job、Action Cable、Action Mailbox で超楽になってきたが、デプロイという難関が未だに残ってる。Heroku だと簡単に出来ちゃうけど、それ以外はハードルがかなり上がる。

初心者がやり方ググっても、大量のチュートリアルが出て来て、どれも微妙に違ってて結局自分で大量の決断をすることになり、標準化されてなくて保守しづらいインフラが生まれてくる。

Docker は一見簡単だけど、チュートリアルが大量にありすぎて、ほとんど中途半端かつ開発環境に特化した手順にすぎない。

社内にインフラのプロがいなくても、エンジニアが一人で簡単に本番環境構築できるのは Rails 流ではないでしょうか?Convention over configuration で標準化したデプロイできる Active Deployment 的なものニーズは十分ある。コミュニティで実装方法を議論しましょう。

という主張論の記事。

インフラが怖いと思っている僕はものすごく同感。非現実的だという反論はあるとはいえ。(Ruby Rogues でも実際この点でプチ喧嘩にもなった)

Growing Rails Applications in Practice: 日本語サマリー

leanpub.com

読破しましたのでサマリー書いておきました。

  • コントローラの設計を標準化せよ
  • ユーザーの各インタラクションをCRUDリソースで表現せよ
  • コントローラの責務は4つのみ
  • モデルのAPIをvalidation、コールバックで表現
  • ActiveModel のモデル積極的に作れ
  • クラス切り出してロジック整理せよ
  • ファットモデルをダイエットさせてスリムモデル切り出せ
  • インタラクションロジックをフォームオブジェクトに切り出せ
  • 他オブジェクトモデルから呼ばれる、Active Recordを必要としない単一責務POROのサービスオブジェクトをきり出せ
  • モジュールの使い道はファイル構造化のみ
  • モデルを積極的にネームスペース・サブフォルダに配置せよ
  • CSSはBEMで整理せよ
  • 生きたスタイルガイドを用意せよ
  • Railsバージョンアップせよ
  • Edgeは2〜3パッチレベル成長するまではバージョンアップするな
  • モンキーパッチ、gemが多ければ多いほどバージョンアップのコストが高くなる
  • 単体テスト結合テスト書け
  • テスト駆動設計せよ