Hard work by INTERNET

ベンチャーで働くひとりぼっちWEB開発者が頑張るブログ

rubyweekly#483

rubyweekly.com

Ruby 2.7 Commentary from Two Ruby Core Team Members

クックパッドのフルタイムで働くrubyコミッター2人による解説記事を英訳した記事。英語の鍛錬のついで読みたい。 この英訳記事を投稿した人が CTO Cookpad Ltdらしい。CTOはパンダの人では?と思ったけど海外の子会社なのかな。

sourcediving.com

The Ruby Reference (Now Updated for Ruby 2.7)

ruby2.7のドキュメント。https://github.com/rubyreferences/rubyref がソースになってる。 2.7のことしか書いていない!

How Well Do You REALLY Know Ruby's Exception System?

例外の実装について書かれた本。無料って書いてあったのでダウンロードしてみた。 ダウンロードには名前とメールアドレスの入力が必要でメールにダウンロードURLがついている。ただし、メーリングリストへの登録される。 全ページ43枚の英語で書かれてた。

Ruby 2.7.0's Rails Ruby Bench Speed Unchanged from 2.6

2.6から2.7へはパフォーマンスは変わらなかったよ。安定している。という記事。

Ruby 2.7 Reverts The Deprecation of The 'Flip-Flop' Operator

2.6から非推奨になったflip-flop 構文を2.7では非推奨を扱いをやめたよ、という記事。 warning: flip-flop is deprecatedがでなくなった。

誰も使っていないから消そうぜって書いたら実は使われていた、というのが取りやめの理由みたい。 Feature #5400: Remove flip-flops in 2.0 - Ruby master - Ruby Issue Tracking System 僕もflip-flop構文を知りませんでした。

Jobs

Software Engineer, Full-Stack (Ruby/Rails/JS)

ヘルスケア系会社の求人って書いていた。フルスタックエンジニアを求めているらしい。 サンフランシスコかリモートワーク。 海外の求人おもしろい。

Senior Rails Developer - Amsterdam (Netherlands)

これも求人。アムステルダム。バックエンドがメインでフロントエンドの知識もあるといいかもって。 競争力のある給与と無期限の有給休暇、つよい。

Find a Job Through Vettery

独自のマッチングアルゴリズムを使って企業と労働者を直接繋げる求人サイト。 NETFLIXの求人もありそう。

Articles & Tutorials

On Ruby 2.7 Pattern Matching After 10 Months of Elixir

エリクサーのパターンマッチングとRuby2.7から入ったパターンマッチングを比べる、という記事。 結論だけ読んでみたけど、そこそこ好評っぽい。

More Fiber Benchmarking

Fiberのパフォーマンスを調べたって記事。

直接Fiberってそんなに使うことってある??? 僕は並列処理したいと思ったらparallel(gem)使っている。。。

How to Migrate Large Database Tables Without Headaches

巨大テーブルをmigrateする方法が書いてる。 alter tableを使うと内容によっては書き込みロックするから、トリガーを使って新しく挿入する行は新しいテーブルにも挿入する。 既存データはバルクインサートする感じのスクリプトが書いている。 で、行のコピーが完全に終わったら一瞬ダウンした後にテーブルを入れ替える、みたいな感じっぽい。 ペルコナツールやんけ

Extracting a Tidy PORO From a Messy Active Record Model

リファクタリングの話。ActiveRecordを継承したクラスにベタッとメソッドを定義するんじゃなくて、Plain Old Ruby Object(PORO) に切り出そうぜって記事。

書いていることは下記とだいたい似ていると思う。

tech.medpeer.co.jp

Why Rails' default_scope Bad?

どうしてdefault_scopeは悪いのか、というRailsエンジニア誰が同意するであろう事実を言語化していう記事。 僕はアップグレードでいつも挙動が変わっていて近寄りたくない、みたいな印象でした。 この記事で書いている本当にそうで、検索条件が競合するので、associationを使えなくてバグの温床になってました。

Inheritance and Abstract Class Pattern for Rails Controllers

controllerで継承を使ってシンプルにしよう、という記事。 管理画面とかであたりまえに使っているので、はい、という感じがした。

Five Rails Performance Tips for Performance 'Noobs'

パフォーマンス改善の話。ほとんどの原因がデータベースだよねぇ、、、。

An Introduction to Ruby's 'Fibers'

Filberの解説記事。Theadとの対比している。 記事にも触れらているけどアプリケーションでは使わないライブラリだよって書いてあって「わかる」ってなった。

Code and Tools

ActiveRecord Adapter for Amazon Aurora Serverless

名前の通り、サーバレスAurora用のActiveRecord。 mysql2は不要。utf8mb4使える。サーバレスAuroraはMySQL5.6互換のみなんだよな。 今はPostgeSQLのAuroraには未対応らしい。 今後の動向に注目。

jetsというLambdaで動くrailsライクフレームがあるんだけど、それとは繋がるのかねぇ。

Forme: HTML Form Generation Library

他のライブラリに依存していないフォームビルダー。

Rack::Cache: Drop-in HTTP Caching for Ruby Webapps

rack層でキャッシュできるgemらしい。

CDN使っていれば不要なやつか?いまいちピンと来ていない。

Down: Streaming HTTP Downloads using net/http, http.rb or wget

ストリーミングでダウンロードするgem。 どんな感じで使うのかいまいち想像できないけど、フロントエンドにデータの断片を継続して送る時に使うのかな?

FString: Python-esque 'F-Strings' for Ruby

Pythonみたいな文字列展開ができるようになるgem。 内部でevalしているし、遅くなるしれないし、十分テストはしていないよってREADMEに書いてあった。

所感

多かったので大変でした。

ActiveRecordのorderメソッドで is null を使いたい

github.com

SQLのorder by句にActiveRecord経由で is null を使っていて、バージョンを6に上げたら警告が出てきた。よくわからん。

DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): "\"psets\".\"order\" is null, \"psets\".\"order\"". Non-attribute arguments will be disallowed in Rails 6.1. This method should not be called with user-provided values, such as request parameters or model attributes. Known-safe values can be passed by wrapping them in Arel.sql(). (called from show at /Users/martijn/dev/course-site2/app/controllers/user_controller.rb:26)

そもそも、この方法はStackOverflowにも書かれていた方法で間違っていないと思う。 is null を使えるようにQueryクラスを拡張してほしい。

みたいなこと書かれた。

これに対して、その警告は Arel.sqlでラップすると収まるぜ。つまり、 Pset.order(Arel.sql("order IS NULL"), :order)`って書けばいい。というコメントが書かれた。

レスポンスへのコメントに対して>>1 が、いま出ている警告がよくわからないのでプルリクを投げたぜ。これはクローズするぜ。

github.com

そのプルリクでは、non-attribute argumentというキーワードを raw SQL as argumentに置き換えようとしており、オープンしてから17日経過しているが、レビューされる気配はない。

おわり

rubyweekly#482 Ruby2.7

rubyweekly.com 今回は先月リリースされたRuby 2.7.0特集です。

Ruby 2.7.0 Released

英語で書かれた公式サイトのリンク。

Digging Into Ruby 2.7's Changes

2.7の変更を深堀りするような記事名。公式サイトに書いていないような filter_map とかにも言及している。

Introducing Automated Postgres EXPLAIN Visualization & Insights

PostgreSQLのツール、pganalyzeの新機能の紹介みたい。 EXPLAIN Plan Visualizationよさそう。ちなみにMySQLにはworkbenchに Visualization explainがある。 EXPLAIN Insightsは時間のかかったレイヤー毎の時間を出すみたい。これすごくよさそう。 私はMySQL派だけどこれは使ってみたい。

An Update on Ruby's JIT Development Progress

「ruby2.7のJITrailsアプリのパフォーマンス改善に注力したけど、仮説が間違っていた。改善はしなかった」と、要約に書いている。 冒頭を少し読んだ感じだと、リリース日であるクリスマスに合わせるために時間とJITで苦戦している感じが伝わりました。Rubyの実装は一切わからないのですが大変そう。 ありがたくRubyを使わせてもらいますm( )m

Pattern Matching: The Big New Feature in Ruby 2.7

ツジモトさんによるRubyConfの発表動画です。 今度見る。

A Practical Demo of Ruby 2.7's Pattern Matching Features

これは解説動画。今度見る。

Ruby 2.7's New ... Shorthand Syntax for Argument Forwarding

2.7から... operatorという構文が追加されたことを紹介する記事。 メソッド引数を別のメソッドにフォワードするための構文みたい。 使いみちが想像できないけど、引数をそのままフォワードする実装をしたことがある気がする。

What's new in Interactive Ruby Shell (IRB) with Ruby 2.7

  • シンタックスハイライト
  • マルチライン
  • 補完
    • デフォルトでインストールされるRDocを元にTABキー入力で補完するとのこと
  • オートインデント機能
    • 2.7からデフォルトで有効になっている。無効にしたいならirbrcに書くことで無効にできる
  • 入力履歴がデフォルトで有効に
    • これも2.7からデフォで有効になった

所感

2.7の次は3.0なんですね。頑張ってほしい!

railsのactivejobアダプターのAsyncAdapterって何?実装は?本番に使える?実用性は?調べてみました。

はじめに

AsyncAdapterってのは、activejobアダプターの1つでオンメモリで完結するジョブキューワーカー。 config.active_job.queue_adapter = :async 「即時実行」と「指定した時間の経過後に実行」が選べる。 ミドルウェアなしで非同期ジョブを実現できて開発環境やテスト環境での使用が推奨されている。本番で向かない理由は後述する。

実装は?

このオンメモリでのジョブキューは、concurrent-rubyのScheduledTaskで実装されている。

github.com

実装シンプルで、AsyncAdapter内にSchedulerとJobWrapperクラス内でScheduledTaskのメソッドで構成している。

本番で使えるの?実用性は?

結論は本番では使ってはいけない。

メール送信とかログ的な記録が向いている、とAsyncAdapterと同様なアーキテクチャhttps://github.com/brandonhilkert/sucker_punch のREADMEに書いているが、AsyncAdapteのソースコードには本番での使用は非推奨と書いている。なぜなら、オンメモリなのでキューをロストする可能性があり、実行される保証がないからである。

これは僕の経験なんですが、非同期処理およびマルチスレッドはエラートラッキングサービスに送信されずに失敗しているということがあったり、WEBプロセスのスレッドとして実行していると、WEBのログに非同期ジョブのログが混ざるわけなのでエラー発生時の検出が非常に困難。それと、WEBと非同期ジョブが1プロセス上でリソースを共有しているため不具合時の切り分けができない、などの運用時の欠点がある。 9割くらいは成功するだろうけど、残りの1割での失敗が許容されるなら採用してもいいと思う。

運用面ではnotコンテナ運用でのデプロイ時だけにジョブが失敗するとかも可能性もあるし、データストアを使っていないので実行したジョブの一覧を画面から見る事もできない。メールの送信可否を確認することが難しい。

繰り返しになるけど、どうでもいい処理だったら使ってヨシ。

おわり。

MySQL5.6をソースからインストールする

dockerの中で作業します。 docker run -it debian:sid bash

環境

root@c12674db7ecf:/mysql-server/bld_debug# cat /etc/debian_version 
10.0
root@c12674db7ecf:/mysql-server/bld_debug# gcc --version |grep gcc
gcc (Debian 9.2.1-21) 9.2.1 20191130

sidなので、、、。

作業ログ

apt-get update
apt-get install build-essential git cmake cmake-gui libssl-dev bison libncurses5-dev
git clone --branch '5.6' --depth 1 https://github.com/mysql/mysql-server
cd mysql-server

ここからは公式ドキュメントに従って進めます。

dev.mysql.com

https://dev.mysql.com/doc/internals/en/cmake-howto-quick-debug-configuration.html

mkdir bld_debug
cd bld_debug
cmake .. -DCMAKE_BUILD_TYPE=Debug
make

cmakeは成功したんですが、makeでエラーになりました。

root@c12674db7ecf:/mysql-server/bld_debug# make
[  0%] Built target INFO_SRC
[  0%] Built target INFO_BIN
[  0%] Built target abi_check
[  2%] Built target zlib
[  5%] Built target edit
[  6%] Built target event
[  8%] Built target event_extra
[ 10%] Built target event_core
[ 13%] Built target strings
[ 19%] Built target mysys
[ 19%] Built target dbug
[ 20%] Built target mysys_ssl
[ 20%] Built target comp_err
[ 20%] Built target GenError
[ 20%] Building CXX object storage/archive/CMakeFiles/archive_embedded.dir/ha_archive.cc.o
In file included from /mysql-server/sql/table.h:40,
                 from /mysql-server/sql/field.h:27,
                 from /mysql-server/sql/unireg.h:179,
                 from /mysql-server/sql/log.h:26,
                 from /mysql-server/sql/sql_class.h:35,
                 from /mysql-server/storage/archive/ha_archive.cc:27:
/mysql-server/sql/table_id.h: In member function 'Table_id Table_id::operator++(int)':
/mysql-server/sql/table_id.h:64:12: error: implicitly-declared 'constexpr Table_id::Table_id(const Table_id&)' is deprecated [-Werror=deprecated-copy]
   64 |     return id;
      |            ^~
/mysql-server/sql/table_id.h:47:8: note: because 'Table_id' has user-provided 'void Table_id::operator=(const Table_id&)'
   47 |   void operator=(const Table_id &tid) { m_id = tid.m_id; }
      |        ^~~~~~~~
In file included from /mysql-server/sql/unireg.h:179,
                 from /mysql-server/sql/log.h:26,
                 from /mysql-server/sql/sql_class.h:35,
                 from /mysql-server/storage/archive/ha_archive.cc:27:
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_num::Field_num(const Field_num&)':
/mysql-server/sql/field.h:1461:7: error: implicitly-declared 'constexpr Field::Field(const Field&)' is deprecated [-Werror=deprecated-copy]
 1461 | class Field_num :public Field {
      |       ^~~~~~~~~
/mysql-server/sql/field.h:463:8: note: because 'Field' has user-provided 'void Field::operator=(Field&)'
  463 |   void operator=(Field &);
      |        ^~~~~~~~
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_real::Field_real(const Field_real&)':
/mysql-server/sql/field.h:1572:7: note: synthesized method 'constexpr Field_num::Field_num(const Field_num&)' first required here
 1572 | class Field_real :public Field_num {
      |       ^~~~~~~~~~
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_decimal::Field_decimal(const Field_decimal&)':
/mysql-server/sql/field.h:1598:7: note: synthesized method 'constexpr Field_real::Field_real(const Field_real&)' first required here
 1598 | class Field_decimal :public Field_real {
      |       ^~~~~~~~~~~~~
/mysql-server/sql/field.h: In member function 'virtual Field_decimal* Field_decimal::clone(MEM_ROOT*) const':
/mysql-server/sql/field.h:1626:46: note: synthesized method 'constexpr Field_decimal::Field_decimal(const Field_decimal&)' first required here
 1626 |     return new (mem_root) Field_decimal(*this);
      |                                              ^
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_str::Field_str(const Field_str&)':
/mysql-server/sql/field.h:1501:7: error: implicitly-declared 'constexpr Field::Field(const Field&)' is deprecated [-Werror=deprecated-copy]
 1501 | class Field_str :public Field {
      |       ^~~~~~~~~
/mysql-server/sql/field.h:463:8: note: because 'Field' has user-provided 'void Field::operator=(Field&)'
  463 |   void operator=(Field &);
      |        ^~~~~~~~
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_null::Field_null(const Field_null&)':
/mysql-server/sql/field.h:2102:7: note: synthesized method 'constexpr Field_str::Field_str(const Field_str&)' first required here
 2102 | class Field_null :public Field_str {
      |       ^~~~~~~~~~
/mysql-server/sql/field.h: In member function 'virtual Field_null* Field_null::clone(MEM_ROOT*) const':
/mysql-server/sql/field.h:2142:43: note: synthesized method 'constexpr Field_null::Field_null(const Field_null&)' first required here
 2142 |     return new (mem_root) Field_null(*this);
      |                                           ^
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_temporal::Field_temporal(const Field_temporal&)':
/mysql-server/sql/field.h:2155:7: error: implicitly-declared 'constexpr Field::Field(const Field&)' is deprecated [-Werror=deprecated-copy]
 2155 | class Field_temporal :public Field {
      |       ^~~~~~~~~~~~~~
/mysql-server/sql/field.h:463:8: note: because 'Field' has user-provided 'void Field::operator=(Field&)'
  463 |   void operator=(Field &);
      |        ^~~~~~~~
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_temporal_with_date::Field_temporal_with_date(const Field_temporal_with_date&)':
/mysql-server/sql/field.h:2363:7: note: synthesized method 'constexpr Field_temporal::Field_temporal(const Field_temporal&)' first required here
 2363 | class Field_temporal_with_date :public Field_temporal {
      |       ^~~~~~~~~~~~~~~~~~~~~~~~
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_temporal_with_date_and_time::Field_temporal_with_date_and_time(const Field_temporal_with_date_and_time&)':
/mysql-server/sql/field.h:2437:7: note: synthesized method 'constexpr Field_temporal_with_date::Field_temporal_with_date(const Field_temporal_with_date&)' first required here
 2437 | class Field_temporal_with_date_and_time :public Field_temporal_with_date {
      |       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_timestamp::Field_timestamp(const Field_timestamp&)':
/mysql-server/sql/field.h:2551:7: note: synthesized method 'constexpr Field_temporal_with_date_and_time::Field_temporal_with_date_and_time(const Field_temporal_with_date_and_time&)' first required here
 2551 | class Field_timestamp :public Field_temporal_with_date_and_time {
      |       ^~~~~~~~~~~~~~~
/mysql-server/sql/field.h: In member function 'virtual Field_timestamp* Field_timestamp::clone(MEM_ROOT*) const':
/mysql-server/sql/field.h:2582:48: note: synthesized method 'constexpr Field_timestamp::Field_timestamp(const Field_timestamp&)' first required here
 2582 |     return new (mem_root) Field_timestamp(*this);
      |                                                ^
/mysql-server/sql/field.h: In copy constructor 'constexpr Field_bit::Field_bit(const Field_bit&)':
/mysql-server/sql/field.h:3663:7: error: implicitly-declared 'constexpr Field::Field(const Field&)' is deprecated [-Werror=deprecated-copy]
 3663 | class Field_bit :public Field {
      |       ^~~~~~~~~
/mysql-server/sql/field.h:463:8: note: because 'Field' has user-provided 'void Field::operator=(Field&)'
  463 |   void operator=(Field &);
      |        ^~~~~~~~
/mysql-server/sql/field.h: In member function 'virtual Field_bit* Field_bit::clone(MEM_ROOT*) const':
/mysql-server/sql/field.h:3756:42: note: synthesized method 'constexpr Field_bit::Field_bit(const Field_bit&)' first required here
 3756 |     return new (mem_root) Field_bit(*this);
      |                                          ^
cc1plus: all warnings being treated as errors
make[2]: *** [storage/archive/CMakeFiles/archive_embedded.dir/build.make:76: storage/archive/CMakeFiles/archive_embedded.dir/ha_archive.cc.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:496: storage/archive/CMakeFiles/archive_embedded.dir/all] Error 2
make: *** [Makefile:163: all] Error 2

私はgccコンパイラ事情についてを疎く、 https://github.com/rails/rails/issues/38087 あたりを見るとgcc9特有の出力みたいです。 gcc8にすればmakeが成功するだろうか。

続く。

rails6にしたらTransactionというクラスが見つからなくなったのだが。

github.com

rails6にするまでは動いていたんだけど、Transactionクラスのメソッド呼び出しで undefined method がでるようになったんだけど、 Transactionクラスを持つことはrails6からは許可されていませんか?というissueというか完全なる質問。

これについてコメントが1件ついた。 コメントにはコマンドラインでTransactionモデルを作成するという完結な再現するはずのコードが寄せられた。しかし再現しなかったので、再現コードを提供できますか?という質問がついた。

$ rails new blabbedy --skip-javascript
$ cd blabbedy
$ rails generate scaffold transaction
$ rails db:migrate
$ rails runner 'Transaction.create!'

rails6からクラスロードが変わったので、その Transctionクラスのロードができていないとかだと思うなー。いずれにせよ、英語ネイティブの人はissueをポンポン作るという印象がある。それだけ活気があり、打ち返すだけの意欲のある人々がコミュニティにいるということなので、これはこれですごい。

etagに関するドキュメントの変更

github.com

etagに関するドキュメントで誤りがあって、それを修正プルリクエスト。

  • fresh_when etag: @article # correct
  • fresh_when @article # incorrect

最終的にはマージされたものの、マージした人いわく、このドキュメントを変更したところであまり変わらないだろう、とのこと。 僕はetagの実装がわかっていないので深くは踏み込まないんですが、何か事情ありの実装らしい。

  • After reading through~
    • ~を読んだ後
  • side-effects
    • 副作用
  • subtle
    • 微妙
  • event
    • でさえ