Ruby Weekly #375: 日本語サマリー
職場の Slack の #ruby 窓で Ruby Weekly メルマガが毎週配信されます。その中から面白そうなものをピックアップして、日本語で簡単なサマリーを書くようにしています。そのサマリーをここでまとまさせていただきます。くだけた日本語で失礼いたします。
Highlights
Net::HTTP、Typhoeus などの HTTP リクエストを JSON でロギングしてくれる gem。
DHH いろいろ。
- 元々はプログラミングに興味がなかった。
- 高校で運営していたゲームレビューサイトが数千もの読者がいた。
- サイトの機能追加で PHP 覚えた。
- ブログ上の PHP 相談で Jason Fried と知り合い、37Signals 入社。
- 好きなエディターは TextMate。
- 趣味は写真、機械式腕時計、自動車競技、旅行。
- 時間節約の裏技は、依頼をほとんど断ること。
- 仕事は 4〜5 時間集中して、それ以上仕事しない。
Celluloid、Concurrent Ruby のような Worker Pool パターンを TDD で一から実装してみた話。
- ワーカー数上限が指定できる
WorkerPool
- メモリパンク防止用のジョブ数上限が指定できる
SizedQueue
WorkerPool
に注入できるスケジューリングアルゴリズム
Gemfile 内 gem の定期アップグレードを SaaS として提供してる depfu。各 gem のバージョンを上げる試行錯誤を繰り返し、互換性を検証する仕組み。ある日 ActiveSupport のバージョンアップでメモリパンクしちゃった。原因は bundler が依存関係を Array#combination
で掛け合わせてるところ。配列の重複してる様子を排除する PR 出して緩和。
Waterfall gem でコントローラのサービスオブジェクトをロールバック可能なチェーンで連携する活用例 2つ。
コメントは必ずしもコードスメルだとは限らない、という主張。コメントは2種類ある:
Tutorial
プロキシパターン(別名サロゲートパターン)解説。
- 重い処理をラッピングして遅延評価などで時間稼いでくれる活用例。
- 認可層の活用例。
- RPC での活用例。
- メモ化用の活用例。
Octopus gem で Heroku の PostgreSQL 上レプリケーション実装手順。
PostgreSQL の Advisory Lock 解説。テーブルロック・行ロックと違って、DB 層ではなくアプリ層で管理。例えば、バックグラウンドジョブのワーカーだけでロックをかけても、UI からの CRUD 操作ではロックがかからない。
フィーチャーフラグ用 Flipper gem の新機能。
- 初期設定のデフォ
Flipper
クラスメソッドからシングルトンのインスタンスへデリゲートget_all
preload_all
で全フィーチャーフラグ取得- フィーチャーフラグ
import
機能 - redis、ActiveSupport キャッシュ用アダプター追加
- flipper-api gem でフィーチャーフラグを HTTP API に
Hash の デフォ値設定方法。
Hash.new
Hash#default
Hash#default_proc
case
文を Hash でリファクターすることも提案してる。
Rubyist 向け Atom パッケージ、キーボードショートカット、スニペットなど。
3 週間前にリリースされた Faktory バックグラウンドジョブシステムのインストール手順。
Opinion
ちゃんと書かれた describe
文を推薦する RSpec コアチーム方針への反論。メンテされなくなると。なぜならプログラマーがメンテしたいのは書くのが楽しい、カスタムマッチャーを活かした、テストコードを読むだけでもわかる spec。
出力が読みづらいという指摘を覆す例も挙げた。
Code
Rails、Sinatra などから静的コピーを生成してくれる Rack ミドルウェア。
SVG チャート生成ライブラリー Frappé Charts をラップした gem。
Karafka 1.1: Work with the Kafka Streaming Platform from Ruby
Ruby Weekly #374: 日本語サマリー
職場の Slack の #ruby 窓で Ruby Weekly メルマガが毎週配信されます。その中から面白そうなものをピックアップして、日本語で簡単なサマリーを書くようにしています。そのサマリーをここでまとまさせていただきます。くだけた日本語で失礼いたします。
Highlights
下記理由で Sprockets から Webpack に移行した LearnZillion 社。
- Sprockets が重い。
- ES6 欲しさ(Sprockets にもあるが、未だに experimental)。
- Sprockets が提供してくれない機能欲しさ。
- Webpack が Rails Way となった。
移行計画
- 準備フェーズ
- Webpacker 追加
- 環境構築
- Nginx、capistrano 設定
- デプロイ
- 移行フェーズ
- Rails asset 用 gem を NPM パッケージで置換
- アピリコードを Webpack に移行
- 必要に応じて Webpack 設定修正
- クリーンアップフェーズ
- Rails asset 用 gem 削除
- Sprockets 設定削除
- Webpack バンドル最適化
問題点
- JavaScript 単体テストの二重メンテ
- 依存していたグローバル変数の維持が大変(ライブラリなど)
- Sprockets バンドルから Webpack バンドルに移行するのが安易ではなかった
コード豊富なので原文参照。
9 年ものレガシー Rails アプリを Rails 5 にバージョンアップした Kickstarter 社。
- 段階的アップグレード
- リリースノートに従った修正
- gem を v5 にアップグレード
- Rails 5 専用ブランチで
- 依存問題で落ちる他 gem をまず修正(Ready4Rails 超便利)
- Rails アップグレードスクリプト実行
- Rails 4.2 にマージできる修正を master ブランチにマージ
- Rails 5 専用ブランチを CI グリーンに
- Rails 5 専用ブランチの deprecation 忠告撲滅
- Rails 5 専用ブランチを手動で動かす
- テストでカバーできてない問題特定のため
- master ブランチで今までの修正をバックポート
- 各機能の開発チームに自分の機能をテストしてもらう
- staging 環境にデプロイ
- 本番デプロイ
- カスタマーサポートからのバグチケ消化
- 振り返り
結果
- 見積もりどおりの 3 ヶ月で完了
- 大規模ダウンタイムなし
- カスタマーサポートのバグチケ対応計画たてとけばよかった
- いろいろ学習できた
- 影響範囲の最も広かった変更点は
HashWithIndifferentAccess
を継承しなくなったActionController::Parameters
。Hash
を継承していることを前提にしたコードがいっぱいあったから。 - モバイルアプリへの影響は少なかったが、予想しなかった。ネイティヴチームのエンジニア巻き込んどけばよかった。
API の重いリクエストで悩まされた Kollegorna 社は、フレイムグラフ見てもネックが特定できなかった。そこでクラス単位でメソッドをベンチマークしてくれる ClassProfiler gem を作ることに。%の最も高いメソッドの中で呼ばれるクラスを次々とベンチマークすることで、やっと犯人に辿り着いた。
先週サービスオブジェクトの使いすぎを否定した Avdi Grimm 先生への反論。
- モジュールメソッドだとどんどん増えていき、結局 junk drawer になる。
- 筆者の経験では、サービスオブジェクトが統一したコードへと繋がった。
- サービスオブジェクトを支える ActiveInteraction gem まで作った。
Rails アプリの多数データベース用 gem。
News
Semaphore CI ユーザが採用している Ruby バージョン別分布。
JRuby 9.1.14.0 リリース。
RubyGems 2.7.2 リリース。
bundle gem
コマンドで新規 gem 生成できなくなっていたバグ解消。- git がインストールされていない環境でエラっていたバグ解消。
Tutorial
インタラクターデザパタ用 interactor gem の紹介。
- Fat Controller の各工程をそれぞれサービスオブジェクトに抽出して、
Interactor
モジュールをinclude
。 Interactor::Organizer
をinclude
したオブジェクトでサービスオブジェクトの呼び出し順番を定義。Interactor
が提供してくれるbefore
around
after
フックでトランザクションを張ったりする。- gem は非常に計量(ソースが小さい)。
Interactor::Organizer
に並べたサービスオブジェクトは Context オブジェクトを共有するのがちょっとグローバル変数っぽくて要注意。- gem は validation 仕組みを提供してくれないので、筆者が validation 用
Interactor
を提案した。
$LOAD_PATH
に載っていないのに gem を require
できるようにしてくれる RubyGems コードリーディング。Kernel#require
のモンキーパッチで、LoadError
発生時の rescue
ブロックで、インストール済み gem の中から探す。見つけた場合、$LOAD_PATH
に追加し、require
再挑戦。
Rack::Deflate
ミドルウェアで Rails レスポンスを gzip 圧縮してサイズを 80% 減らした Richard Schneeman 先生。
&.
演算子の罠。<
などの評価順番が変わっちゃうから要注意。(原文コード参照)
数百万行もの PostgreSQL テーブルをパーティション分割した Evil Martians 社。
- 親テーブルをクローン。
- 子テーブル + 親テーブルの PK をマッピングするビュー作成。
- 子テーブルを作成・更新するストアドプロシージャ作成。
- ストアドプロシージャを呼ぶトリガーをビューに張る。
- ActiveRecord モデルがビューを見るように設定。
- 既存データはビューに
INSERT
することで移行。
Array#transpose
いろいろ。
- 二次元配列で行と列を入れ替えてくれる。
- 三目並べゲームの勝利判定ロジックを例に挙げた。
Rails 3.2 アプリを 4.0 にアップグレードするための豆知識。移行してない人がまだまだいるから。
- Ruby 1.8.7 を使っていれば、1.9.3 にアップグレード。
- rails4_upgrade gem を Gemfile に追加して、アップグレードの必要な gem を特定。
rails:update
Rake タスクで不要な設定・モンキーパッチを削除。- RailsDiff で予想された差分を確認。
- activerecord-deprecated_finders gem で
.find_by_hoge
メソッドを洗い出し・撲滅。 - scope は全部 lambda 表記に。
protected_attributes
撲滅。あるいは protected_attributes gem 導入。Strong Parameters に移行することがベスト。ActiveRecord::Observer
撲滅。あるいは rails-observers gem 導入。wisper gem または Rails Concerns に移行するのがベスト。ActiveResource
は active_resource gem に移行。caches_page
caches_action
は actionpack-action_caching gem に移行。Test::Unit
は test-unit gem に移行。match
式 route は HTTP メソッド要指定。- プラグインを使っていれば gem に移行。
Code
Alpha Vantage API を叩く両替 gem。Alpha Vantage 以外でも拡張可能。キャッシュ期限設定可能。他 gem への依存が一切ない。
ActionCable など WebSocket サーバテスト用 CLI ツール gem。データ送受信スクリプトを YAML で定義してから wsdirector
コマンドで実行。ApplicationCable::Channel
の単体テストと思えば良さそう。(RSpec・MiniTest・Test::Unit とは別物)
Ruby Weekly #373: 日本語サマリー
職場の Slack の #ruby 窓で Ruby Weekly メルマガが毎週配信されます。その中から面白そうなものをピックアップして、日本語で簡単なサマリーを書くようにしています。そのサマリーをここでまとまさせていただきます。くだけた日本語で失礼いたします。
Highlights
どんな Fat Controller でもサービスオブジェクト抽出で片付けちゃうのを否定する Avdi Grimm 先生。
- 多くの場合はプロシージャー型モジュールメソッドのほうが適切だと
- 間違ったオブジェクトを抽出よりも、オブジェクトを抽出しないほうがマシ
- サービスオブジェクトは依存し合いがち
- サービスオブジェクトはビジネスドメインよりも、インフラ層に相応しい(DDD 本もこう書いてある)
- ビジネスドメインのサービスオブジェクトがあったとしても、インフラ層のサービスオブジェクトから分離すべき
Bundler 1.16 リリース。
- 依存関係解決の新規アルゴリズムに切り替えたことでパフォーマンス向上・バグ解消。
bundle install
のeval
回数を減らしたことでパフォーマンス向上。
次のリリースは Bundler 2!
- master がすでに Bundler 2 となった。
- Bundler 2 機能は 1.16 にも入ってて、feature flag で無効となっている。Bundler 2 を試したい方は、ぜひ有効化を。
ランダムフォレストアルゴリズムで手書き数字の OCR を実装する手順。PyCall gem で Python の scikit-learn ライブラリーに投げてる。
メモリを意識した Ruby。
nil
true
false
はメモリを確保しないため、考慮しなくてもいい。-2^62
〜2^62-1
の整数もメモリを確保しないため、考慮しなくてもいい。Array
Struct
は要素 3 つまでは最低メモリの 40 バイトで収まる。- 空っぽの
Hash
は最低メモリの 40 バイトで収まる。 String
は 23 バイトまで最低メモリの 40 バイトで収まる。- オブジェクトはインスタンス変数 3 つまでは最低メモリの 40 バイトで収まる。
メモリ最適化の工夫:
- 上記ルールと
ObjectSpace.memsize_of
でメモリ計測していき、最も効率の良いデータ構造を選択。 - オブジェクトをできるだけ再利用する。
Array#map!
など破壊的メソッドでオブジェクトのインスタンス化を避ける。- allocation_tracer、memory_profiler などの gem でメモリ計測。
Rails トランザクションの罠いろいろ。全文日本語訳あり!
gem update --system
でバージョンアップしようぜ!
- 同梱 bundler を 1.16.0 にバージョンアップ。
- Bundler が
Gem.use_gemdeps
を使うように。 gem
CLI にsignin
コマンド追加。gem
CLI にログアウト機能追加。
News
Ruby 2.5 パフォーマンス向上。
- 文字列 interpolation が 72% 速く!
String#prepend
が 42% 速く!Enumerable#sort_by
Enumerable#min_by
Enumerable#max_by
が 50% 速く!String#scan
の文字列パターンは 50%、正規表現パターンは 10% 速く!Range#min
Range#max
が 60% 速く!
Tutorial
AWS 上の Sidekiq を自動スケーリングしている Honeybadger.io 社。
- Sidekiq 作業量が増えたら、CloudWatch アラームで新しいインスタンスを起動。
- 作業量が元に戻ったら、インスタンスを殺す。
実行中ジョブが完了するまで、インスタンスを殺すのを遅らせる、という要件を、原文のスクリプトで実装した。
よくある before_validate
コールバック悪用パターンと代替案。
- データフォーマット・正規化。
attr_writer
をオーバーライドしよう。
- データ設定。
- 例えばアソシエーションから取得した値をカラムに設定して非正規化。
- コールバックなしで普通に設定しよう。
linter で JSON API の RSpec テストを綺麗に。リクエストとレスポンスの
Content-Type
チェック- スキーマチェック
を JsonApiLint
オブジェクトに抽出して、
request spec の #app
を置き換えることで、
spec に残るのは
- HTTP ステータスチェック
- JSON 内容チェック
のみになった。
1 it
1 expect
ルールを厳守する Victor Shepelev さんの、引数パターン別メソッドの戻り値をテストする裏技。
subject
はObject#method
で取得したMethod
オブジェクト。its([引数])
で引数パターンを指定。
WEBrick・Rack・Sinatra のそれぞれの役割を分かりやすく描いた図。
Stripe で決済処理を行っている Rails アプリのテストを支える stripe-ruby-mock gem。StripeEvent gem で実装した Stripe Webhook の受信までテストできちゃう。
simplecov gem でテストのカバー率を測る手順。
Story
"".split("-")
は Ruby と Python で挙動が異なっている。
Python は
[""]
を返す。- Java、JavaScript、Elixir、Go、Haskell、PHP、Scala 同様。
Ruby は
25.hours.from_now
で日付が変わることを期待していたテストが落ちた話。実行したのは夏時間に切り替えた日。
Code
関数型 HTTP クライアント gem。
Rack::Session::SmartCookie: Smarter Session Cookies for Rack 2 Apps
Rack 2 セッションクッキーの問題点を解消してデフォにした gem。
Kaminari: A Powerful, Customizable Paginator for Ruby Webapps
松田明先生のアノ有名なページング用 gem。
SNS 投稿を一本化した gem。
Ruby Weekly #372: 日本語サマリー
職場の Slack の #ruby 窓で Ruby Weekly メルマガが毎週配信されます。その中から面白そうなものをピックアップして、日本語で簡単なサマリーを書くようにしています。そのサマリーをここでまとまさせていただきます。くだけた日本語で失礼いたします。
Highlights
Ruby 2.5 新機能まとめ。
begin
明示しなくてもdo/end
ブロックのrescue
else
ensure
ができるようになった。- 同一ネームスペース内で見つからなかった定数をルートネームスペースから探すのがなくなった。
- bundler 同梱。
- バックとレースのエラー発生行番号を一番下に出力するようになった。
yield_self
新規追加。String#delete_prefix
String#delete_suffix
新規追加。Array#unshift
の alias としてArray#prepend
新規追加。Array#push
の alias としてArray#append
新規追加。Hash#transform_keys
Hash#transform_keys!
新規追加。.
..
を除外したDir.children
Dir.each_child
新規追加。- ERB に binding を渡す手間を省いた
ERB#result_with_hash
新規追加。
Faktory バックグラウンドジョブ用サーバデーモンとそのワーカー用 faktory_worker_ruby gem リリース。Sidekiq 同様にウェブ UI とジョブ永続化(Facebook 製 RocksDB)機能付き。
FactoryGirl と FactoryGirlRails gem が FactoryBot と FactoryBotRails に改名。ユーザに不快感を与えないように、ジェンダー的に中性なネーミングにした。その裏に、Uber や Google のセクハラ・差別スキャンダルで非難を浴びてきた近年のシリコンバレーの影響があると思われる。
Configuration オブジェクト戦略いろいろ。
Hash
- YAML
OpenStruct
ActiveSupport::Configurable
知見
ミュテーションテストでより深く理解した絶対テストと相対テスト。
- 絶対テスト: 定数・リテラルと比較した
assert_equal
- 相対テスト:
<
>
<=
>=
や変数と比較したassert_equal
絶対テストは省略しがちだが、あったほうがミュテーションテストに強い。 例えば
#hash
をオーバーライドしたアルゴリズムは、assert_equal(object1, object2)
だけだと、アルゴリズムの固定値が書き換えられても、テストが落ちなくなる。ハッシュ値を固定値と比較した絶対テストがあるべし。- AUTOINCREMENT カラムでソートした scope は、
assert_equal([record1, record2], records)
だけだと、初期値が予期せぬ負の数値に書き換えられても落ちない。 id
カラムでソートした scope は、assert_equal([record1, record2], records)
だけだとorder(:id)
が書き換えられても落ちない。欠番を再利用する DB では不具合が起き得る。SQL 文の固定値と比較した絶対テストがあるべし。
モックは下記問題点がある。
expect
→allow
(setup
) →実行
順番が普段のsetup
→実行
→expect
と異なってて非直感的。- モックしたクラスと密結合。
- 再利用性が低い。
お手製 double
で全部解消。spy
はなおよし。
News
Ruby 2.5 以降は begin
明示しなくても do/end
ブロックの rescue
else
ensure
ができるようになった。
RSpec 3.7 Released: Now Integrates with Rails 5.1 System Tests
RSpec 3.7 は Rails システムテストに対応してる。これからは Feature スペックよりもシステムテスト推奨。Feature スペックと違って
- database-cleaner が不要。
- デフォ Selenium。
Rails の PhantomJS がようやく廃止となった。代わりに Selenium/Chrome Headless 導入。
Tutorial
プログラミング言語バージョン管理ツール asdf のインストール手順を紹介した、ブラジル RubyConf 元主催者 Fabio Akita 先生。rvm・rbenv と違って Elixir、Go、Node.js など多岐にわたる言語も一括管理。
Rails システムテストに移行した Table XI 社 Noel Rappin 先生。
- システムテストは Capybara でブラウザーを操作したテスト。
- Capybara の既存 RSpec テストも、システムテストに移行すれば、色々楽になる。Rails と同じプロセスで動くようになるから。
- 移行手順
- 各テストに
type: :system
メタデータ追加。 - テストファイルを spec/system フォルダーに移す。
- 原文の configuration 設置。
- 各テストに
- Circle CI 2.0 用設定は原文参照。
Rails アプリに Google reCAPTCHA 2 を設置する手順。
- Google reCAPTCHA 2 取得サイトでアプリを登録。
- ビューで reCAPTCHA の JavaScript ライブラリをロード。
<script>
要素のonload
コールバックで reCAPTCHA ウィジェットをロード。- コントローラの
before_action
で reCAPTCHA を承認。再利用できるように、concerns モジュールにて実装。 RecaptchaVerifier
サービスオブジェクト実装して、注入したGoogleRecaptcha
クラスに承認させる。GoogleRecaptcha
が Google reCAPTCHA API を叩くように実装。
React + Rails アプリを開発した Reverb 社は、クラサバ二重実装を避けるべく、React コンポーネントを Node.js で生成することになった。Rails ⇔ Node.js 通信は元々パフォーマンスの良い Unix ソケットだったが、各アプリサーバに React Rendering Engine (RRE) をデプロイする必要はあった。その手間を省くように gRPC + protocol buffer に移行することにした。
- .proto ファイルでインタフェース定義。
- protoc コンパイラーをインストール。
- grpc-tools gem で Ruby クライアント生成。
- Node 用 grpc ライブラリをインストール。
- Node 側サービス実装(原文コード参照)。
- Unicorn・Puma を使っている場合は、
after_fork
フックでクライアントを生成するように設定。
Rails バージョンアップ手順。
- 新規 Rails アプリ作成。
- 既存アプリで新規ブランチ切る。
- 新規 Rails アプリの gem を既存アプリの Gemfile にコピペ。既存 gem は必要に応じてバージョンアップ。
rails app:update
実行で config・bin ファイル更新。- テストのエラー修正。deprecation 忠告は無効にしておくこと。
- deprecation 忠告を有効にして、ひとつずつ解消。
- main ブランチにマージ。
Rails 5.1 アプリを作ってみた、ブラジル RubyConf 元主催者 Fabio Akita 先生。
- 新規 Rails アプリ生成手順
- webpack 採用手順
Rails 5.1 の大きな特徴はモダンな JavaScript・CSS への対応。
2 Ways to Test Eager Loading of ActiveRecord Associations in Rails
eager loading のテスト方法 2 つ。
association(:name).loaded?
ActiveSupport::Notifications
で発行クエリ数取得
Story
6 年ものレガシー Rails アプリに React を導入した話。
- モダンな JavaScript UI が必要となったのがきっかけ。
- jQuery でもできたが、React のほうがメンテしやすいし、ES6・ES5 相互対応でブラウザ間互換性が魅力的。
戦略。
- React 層をなるべく薄くし、routing は Rails に任せっきり(ページ間遷移は従来の HTTP)。
ActiveModel::Serializer
フル活用。モデルのデータだけでなく、ActiveRecord メソッドまで呼べて便利。
Opinion
何でもかんでも「魔術」と呼ぶのをやめよう、という主張。コミュニティの創造力の妨げになるから。
- 初心者には分からないからって「魔術」と呼んじゃダメ。
- モンキーパッチは良くない場合もあるが、「魔術」とはいえない。
- メタプロは「魔術」ではない。
これなら初めて「魔術」といえる。
class LandCruiserJ200Car end car = LandCruiserJ200Car.new # => #<Car model="Land Cruiser J200"> car.drive! # "wroom! wrrroooom!"
何も継承してないのにどこかから挙動を継承してる。つまりソースの追いようがないコード。
Tools
ActionCable テスト用 gem。Rails への PR としても出されてるが、Ruby Weekly 投稿時点では未マージ。
- 継承用
ActionCable::TestCase
とActionCable::Channel::TestCase
have_broadcasted_to
broadcast_to
RSpec マッチャー- Generator
Rails コード可読性向上 gem 集。
- サービスオブジェクト用 interactor
- デコレーター用 draper
- フォームオブジェクト用 virtus
- ビューモデル用 cells
- 例外発生時リトライ用 retryable
- Controller ボイラープレート隠蔽用 decent_exposure
- 日時グルーピング scope 用 groupdate
Code
Hanami 1.1 リリース。
belongs_to
has_one
has_many through:
アソシエーション- CLI は thor から hanami-cli に切り替えた
Hanami::Entity
のカスタムスキーマ定義- ブートするアプリを
HANAMI_APPS
環境変数で指定 - パスワードなどがログに残らないようにフィルター
rom-factory gem 新規リリース。FactoryBot(旧名 FactoryGirl)より 1.5 倍速く下記機能提供。
- 動的
sequence
- faker 同梱
- アソシエーション対応
- factory 継承
Ruby Weekly #371: 日本語サマリー
職場の Slack の #ruby 窓で Ruby Weekly メルマガが毎週配信されます。その中から面白そうなものをピックアップして、日本語で簡単なサマリーを書くようにしています。そのサマリーをここでまとまさせていただきます。くだけた日本語で失礼いたします。
http://rubyweekly.com/issues/371rubyweekly.com
Highlights
Configuring Puma, Unicorn and Passenger for Maximum Efficiency
Puma、Unicorn、Passenger を効率よく設定する方法。
- サーバ毎に 3 子プロセス以上。上限は
(合計 RAM / (あなたのウェブアプリのプロセスの 12 時間経過後の RAM * 1.2))
で計算。 - MRI はサーバ毎に 5 スレッドで良い。JRuby は子プロセス数同様に計算。
- とりあえず preloading オンにしようぜ。
- サーバは RAM 1GB 以上。正確には
5 スレッドの 1 ワーカの 12 時間経過後の RAM * 3
で計算。
時間経過とともに膨らんだ Puma ワーカー。
先月発表された macOS High Sierra 上の Puma 不具合解説。
- macOS が許可している fork 後処理が変わった。
- 許可されてない処理を踏んだアプリサーバが Objective-C エラーを起こす。Objective-C に一切依存していないのに。
- Apple 社が High Sierra の fork 挙動を変えたのは、Objective-C の fork 対応をやりやすくするため。
- Puma などアプリサーバ開発者は、Ruby 言語レベルで対応すべきだと主張してる。
- ワークアラウンドを実装したのは Passenger のみ。
- Puma、Unicorn、iodine ユーザは環境変数指定で一応対応できる。
Ruby メソッドの最も軽量なプロファイリング方法。
- 時間計測は
Time.now
ではなくProcess.clock_gettime(Process::CLOCK_MONOTONIC)
。 - メソッドのパッチは
prepend
ではなくalias_method
。 - スレッドセーフにする必要がある場合は、
Thread.current["hoge"]
でデータ保存。
Passenger 5.1.11 リリース。
「重いよ!」と訴えるユーザに応じて、Jupyter Notebook で Rails ログ可視化手順。
- lograge logstash-event logstash-logger gem でログのフォーマットを JSON に。
- ユーザ ID をスレッドのローカル変数に持たせる。
- Jupyter Notebook の
json_normalize()
関数で Pandas Dataframe にログをインポート。 Dataframe.head
で全体データをサニティーチェック。異常なし。Dataframe.describe
で全体データを集計チェック。異常なし。- 全体データのヒストグラム生成。異常なし。
- ユーザのデータに絞ったヒストグラム生成。異常なし。
- ユーザの 1 秒以上かかったコントローラ・アクションの棒グラフ生成。異常あり。
ROM 4.0.0 リリース。
- rom-repository gem のスキーマ自動マッピング(カラム情報を DB から読み込む機能)が ROM コアにて実装された。
- rom-repository gem の
auto_struct
マッピング(データを Struct に設定する機能)が ROM コアにて実装された。 - カスタム Struct が定義可能に。
changeset
が rom-changeset gem に抽出された。
News
GCP でも AWS でも使える stackdriver gem を紹介した Aja Hammerly 先生。
- Stackdriver Debugger デバッグツール
- Stackdriver Error Reporting 例外モニタリングツール
- Stackdriver Trace パフォーマンスモニタリングツール
- Stackdriver Logging ログ管理ツール
Tutorial
rescue
では例外をちゃんと指定しようぜ、という催促。
rescue Exception
だと、SignalException::Interrupt
までrescue
され、強制終了できなくなっちゃう。rescue => e
だと、予期せぬバグが隠蔽されちゃう。
Using JSON Web Tokens for Authentication in Distributed Systems
分散システム(マイクロサービスなど)の共通認証を JWT で実装する方法。Devise と jwt gem を採用した例。
オブジェクト指向で Rails システムテストを整理する方法。gem なしでページオブジェクトパターンを実装し、partial など共通 UI をモジュールに抽出している。
MongoDB が用途に合わなくなった Contractually 社がダウンタイムなしで PostgreSQL にデータを移行した 3 ステップ戦略。
- 第 1 デプロイ:稼働中のデータを MongoDB にも PostgreSQL にも WRITE。READ は MongoDB から。
- Mongoid のコールバックで PostgreSQL に書き込むバックグラウンドジョブをキューに積む。
- 12〜36 時間で移行完了の想定。
- 第 2 デプロイ:稼働中のデータの READ も WRITE も PostgreSQL から。
- NewRelic でパフォーマンス・エラー発生率監視。
- 第 3 デプロイ:Mongoid、MongoDB 削除。
- 予めバックアップ。
Array#zip
活用案いろいろ。
- 2 つの配列を比較する。
- 2 つの配列の各インデックスの最大値を取得する。
- キーの配列と値の配列を結合してハッシュを作る。
Enumerable#count
とチェーンして同一要素を数える。- シーザー暗号を実装する。
ホテルを例に挙げたコマンドパターン解説。
- 宿泊客がルームサービス、ランドリー、観光地パンフレットをコンシエルジュに注文。
- コンシエルジュが注文を厨房、クリーニング作業員、ベルボーイに依頼。
そのまま実装すると Concierge
オブジェクトにキモい case
文ができてしまう。各注文をコマンドオブジェクトにすることで、Concierge
がロジック分岐せずに実行できるようになる。おまけに
Concierge
以外のオブジェクトにも引数として渡せる。- 注文をキューに積むことができる。
- 注文をログに残すことができる。
- 注文を巻き戻すことができる。
Virtus gem のフォームオブエクトでデータをサニタイズする例で、Virtus::Attribute#coerce
でホワイトスペースを文字列から消してる。
プロジェクト管理ツールの UI をリアルタイムで更新するための ActionCable 実用ガイド。Build A SaaS App in Rails 5 本の抜粋。
関数型プログラミングをずっと警戒してた Rubyist をやっと説得できたリンク 3 つ。
- Ruby のオブジェクト指向と関数型プログラミングを融合した、dry-rb コアチームの Piotr Solnica 先生のトーク
- dry-rb コアチームの Tim Riley 先生のブログシリーズ
- Hanami 作成者 Luca Guidi 先生のトーク
Code
請求書 PDF 生成用 InvoicePrinter gem。 見辛い Prawn コードをカプセル化したのが売り。
Hanami v1.1.0.rc1 リリース
Ruby Weekly #370: 日本語サマリー
職場の Slack の #ruby 窓で Ruby Weekly メルマガが毎週配信されます。その中から面白そうなものをピックアップして、日本語で簡単なサマリーを書くようにしています。そのサマリーをここでまとまさせていただきます。くだけた日本語で失礼いたします。
Highlights
do; end
ブロック内rescue
対応。yield_self
新規追加。- bundler 同梱。
- 同一ネームスペース内で見つからなかった定数をルートネームスペースから探すのがなくなった。
RubyGems シリアライゼーション脆弱性を解説した Aaron Patterson 先生。 gem のチェックサムが YAML で保存されているのが原因。 RubyGems.org はこの脆弱性で攻撃された痕跡はない。 シリアライズ可能なオブジェクトをホワイトリストすることで解消済み。
レポート用 Rails engine。
Introducing hanami-cli: A New Framework for Command Line Tools
hanami-cli を紹介した、Hanami 作成者 Luca Guidi 先生。 thor では実装しづらい下記機能がある:
- サブコマンド。例えば
$ hanami generate action
のgenerate action
。 - 拡張性。外部 gem が Hanami にサブコマンドを追加できるようになった。
Hanami じゃなくても使えるので、thor の代替案として考えれば良い。
同一ネームスペース内で見つからなかった定数をルートネームスペースから探すのが Ruby 2.5 からなくなった。その経緯を語る Redmine チケット。
Surrealist gem に対応するように、Array
と ActiveRecord::Relation
のモンキーパッチを検討した話。
下記条件全部満たせなければ、モンキーパッチやめたほうがいいと。
- これ以上のモンキーパッチはない。
- モンキーパッチしたコードに依存しているものが壊れない。
- モンキーパッチ以外の選択肢がない。
- 新しいインタフェースが作れない。
カンファレンスを初めて主催した経験談。地方カンファレンスがなくなってきたのがきっかけ。
- 昔あったナッシュビル市の Ruby Hoedown カンファレンス主催者から許可を得た。
- ドメイン取得(自腹)。
- 会社設立(自腹)。
- ロゴ発注(自腹)。
- キーノート登壇者を招待した。
- CFP を 1.5 ヶ月開催。もうちょっと長くすればよかった。
- 予算計算。$199 のチケットを 175 枚売れば黒字。
- 会場探し。
- スポンサー探し。大変だったため、プランはもうちょっと安くすればよかった。
- 登壇者宿泊 + 交通費負担することにした。
- チケット発売。SNS + Ruby Flow + Reddit で宣伝。87 枚売れた。
- カンファレンス 3 日間開催。
赤字だったが、Ruby コミュニティに貢献できた充実感で、来年も開催予定!
News
Rails 5.2 では、暗号化・署名付きクッキーの有効期限が設定可能に。
台北の RubyElixirConf Taiwan 2018、CFP 開始。
Mastering Ruby: Strings and Encodings 本発売。
Tutorial
Receiving and Parsing Email in Rails 5 Using Griddler and Mailgun
Build a SaaS App in Ruby on Rails 5 本の抜粋。Rails 5 + Griddler + Mailgun でメールを受信・パースする手順。
- ngrok で手元マシンへの URL を用意。
- Mailgun で受信したメールを ngrok URL に転送するように Mailgun を設定。
- Griddler gem を Rails アプリにマウント。
EmailProcessor
オブジェクトでパース・処理を実装。
Rails 5.2 の HTTP2 Early Hints を発表した Eileen Uchitelle 先生。Rails がレスポンスを 2 つ返すようになる:
- Early Hints(HTTP ステータス 103)
- 通常のレスポンス(HTTP ステータス 200、404、500 など)
Early Hints はブラウザーが優先的にダウンロードするファイル(JavaScript、CSS など)の指定。Rails での検証手順も記載されてる。
Ruby 2.5 スタックトレースの見た目改善。エラー発生行番号が一番下になった。長いスタックトレースの上までスクロールすることがなくなって便利。しかし Rails・RSpec では効かない。
巨大メソッドをクラスに抽出した話。
Ruby のよく知られてないメソッド。
Integer#digits
(Ruby 2.4 以降)#tap
Array#values_at
Hash#transform_values
(Ruby 2.4 以降)Kernel#itself
(Ruby 2.2 以降)Array#count
Enumerable#cycle
Paperclip で Rails GraphQL API から画像を S3 にアップロードした話。REST アプリならドキュメンテーションはいっぱいあるが、GraphQL アプリは一切ない。画像を Base64 文字列に変換してから mutation の引数として Paperclip に渡した。
HexaPDF gem の PDF ファイル読み込み処理解説。
- PDF ファイルは不特定多数のストリームで構成されてる
- 各ストリームには不特定多数のフィルターが指定されてる
- フィルターはストリームデータの解読方法を定義している(例:JPEG 画像は
DCTDecode
フィルター、ASCII 文字列はASCIIHexDecode
フィルター) - フィルターはそれぞれ
HexaPDF::Filter::ASCIIHexDecode
のようなモジュールで実装されてる - ストリームは
HexaPDF::StreamData
オブジェクトでカプセル化 - ストリームのデータは非同期で読み込むため、Ruby の Fiber 採用
Rails フォルダー構造まとめ。
RSpec で深階層の nested attributes を指定した話。手で組み立てるのが大変だった。先輩に相談したら、ログからコピペすることになった。
Tools
nullalign: Generate Warnings for Missing Not-Null Constraints
NOT NULL
制限のない validates presence: true
を検知してくれる nullalign gem。
Code
ActiveRecord + PostgreSQL 10 パーティション管理用 gem.
Ruby Weekly #369: 日本語サマリー
職場の Slack の #ruby 窓で Ruby Weekly メルマガが毎週配信されます。その中から面白そうなものをピックアップして、日本語で簡単なサマリーを書くようにしています。そのサマリーをここでまとまさせていただきます。くだけた日本語で失礼いたします。
Highlights
Symbol
と String
の不一致がバグの根源なので、Ruby から Symbol
を捨てないかという提案。
- 下位互換性を維持するには、
Symbol
を#freeze
したString
にすれば良い。 Symbol#to_s
から#freeze
されてないString
を返すようにする。#hash
を同等にする必要がある。Symbol#hash
計算が 2〜3 倍速いから、String#hash
計算もSymbol#hash
に合わせたい。
Fixnum
Bignum
捨てたし、Symbol
も捨てれるのでは?と。
Ruby Rogues の Charles Max Wood 先生主催の Ruby Dev Summit 分散型カンファレンス(物理的開催地はなく、参加者はみんな動画配信やチャットで交流・登壇)。
get_schwifty: Render Portions of Rails Views in a Background Job Queue
重い partial を ActiveJob で render、ActionCable でブラウザー上非同期描画する gem。
株式会社デジカの Chris Salzberg 氏が RubyKaigi でトークを発表した話。たまたま Matz のキーノートと同じく、モジュールを題にしてた。しかし「モジュールはクラスではない」と言わんばかりの Matz 発言が Salzberg 氏のトークと矛盾してたのでちょっと困った。Module
は Class
だからこそ Ruby ならではの Module Builder パターンが可能。
-rubygems
に対応するための ubygems.rb
が削除された、というちょっと面白いコミット。
Gusto 社の給与システムが関数型 Ruby になるようにリファクターした話。
- PFaaO パターンで純粋関数オブジェクトを実装した。給料計算関数オブジェクトを例として挙げた。
- 純粋関数オブジェクトなので、メモ化していても参照透過性が維持されてる。
- 給料計算関数オブジェクトの中の税金計算メソッドを税金計算関数オブジェクトに抽出した。
- ActiveRecord モデルそれぞれに対して immutable な Value Object を切って、純粋関数オブジェクトにValue Object のほうを渡すようにした。
News
Hanami v1.1.0.beta2 リリース翌日に、バグ解消で v1.1.0.beta3 リリース。
Tutorial
Surrealist: A Gem to Serialize Ruby Objects According to a Defined Schema
シリアライズ用スキーマ定義 surrealist gem の紹介。データ型定義やキー camelize 機能など込み。
- Angular プロジェクトの該当 directive ファイルを開く関数
Ruby コアの delegate.rb をコードリーディングした話。
Delegator
が継承しているのは、不要なメソッドを省略されたKernel
。#initialize
#method_missing
メソッドはDelegator
にて実装されている。- デリゲート先オブジェクトの accessor は
SimpleDelegator
など子クラスで実装されている。 #method_missing
がチェックするのはデリゲート先オブジェクトと一部省略したKernel
。
Hash#fetch
でデフォ値を返すようにする。ブロック渡せば遅延評価もできる。
筆者著作の Domain-Driven Rails 本の抜粋。メソッドを 2 つのメソッドに分解することで Event Sourcing するというルールの解説。2 つのメソッドとは:
- イベントを発行するメソッド
- イベントの効果を適用するメソッド
Ruby 配列いろいろ
#initialize
方法いろいろ#slice
方法いろいろ#insert
方法いろいろ<=>
挙動|
挙動&
挙動
Ruby 2.4 では Enumerable#min
Enumerable#max
Enumerable#minmax
が速くなった!
validate uniqueness:
使用時の高速化案。
筆者作品の UniqueValidationInspector gem では、インデックスのない validate uniqueness:
を検知できる。
Ruby バージョン確認方法まとめ
環境 | 確認方法 |
---|---|
irb | RUBY_VERSION |
rvm | rvm current |
rbenv | rbenv version |
コマンドライン | ruby -v |
コマンドライン | which ruby |
コマンドライン | gem env |
Story
A Reddit AMA with the Authors of 'Effective Testing with RSpec 3'
Effective Testing with RSpec 3 著者たちの質疑応答 Reddit スレ。
Python コードのパフォーマンスを最適化した Richard Schneeman 先生。
Ruby との共通ルール:
- ダブってるロジックを省けば軽くなる。
- オブジェクトのインスタンス化を省けば軽くなる。
- オブジェクトのシリアライズを省けば軽くなる。例:シリアライズした配列を引数として渡すよりも、要素を渡したほうが軽い。
- ループ内のリテラルを省けば軽くなる。リテラル=オブジェクトのインスタンス化なので。
- 不要なロジックを省けば軽くなる。あり得ない
if
文の分岐点など。 - メソッドを省けば軽くなる。効果はそんなに大きくないので、このルールに関しては無理しなくて良し。
- ベンチマーク必須。
- キャッシュするなら、オブジェクトのインスタンス化ルールは破って良し。
レガシー Rails アプリに呆れて、18 ヶ月も Rails を避けていた経験で得た知見。
- 悪いのは Rails 自体ではなく、Rails の用途に合わないアプリ
- 何でも gem に依存させるのも良くない
- Rails はドキュメンテーションが充実してる
Opinion
default_scope
ではなく明示的に scope
使おうという主張。
new
したモデル属性はdefault_scope
で設定されちゃうのが予期せぬバグの元。default_scope
を外すことは辛い。unscoped
だとアソシエーションのスコープまで外れちゃったりするから。
Tools
Ruby 上級者向け書籍。
- オブジェクト指向設計実践ガイド ~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方
- Rubyのしくみ -Ruby Under a Microscope-
- Effective Ruby
- Ruby Way 第2版 (Professional Ruby Series)
- Mastering Ruby Closures: A Guide to Blocks, Procs, and Lambdas
- Rails, Angular, Postgres, and Bootstrap: Powerful, Effective, Efficient, Full-Stack Web Development
- Service-Oriented Design with Ruby and Rails (Addison-Wesley Professional Ruby Series)
Code
render_async 1.0: Render View Partials Asynchronously via Ajax
Rails ビューの partial を AJAX で非同期ロードする gem。
Bing Maps API クライアント用 gem。