Quantcast
Channel: Ruby on Railsの記事一覧|TechRacho by BPS株式会社
Viewing all 1383 articles
Browse latest View live

週刊Railsウォッチ(20200317後編)Strangler Figパターンでリファクタリング、ペアプロ実践記事、イミュータブルデータモデルほか

$
0
0

こんにちは、hachi8833です。以下は東京都の対策サイトをforkして構築したそうです。

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

⚓お知らせ: 出張!Railsウォッチ@銀座Rails#19、来週のRailsウォッチお休み

今週木曜19:00よりZoom経由で開催される「銀座Rails#19」に、TechRachoでお馴染みのmorimorihogeが『出張!Railsウォッチ』枠で今回もZoom登壇します。私もZoomで観るつもりです。


ginza-rails.connpass.comより

また、来週の週刊Railsウォッチはお休みをいただきます🙇

⚓Ruby

⚓Strangler FigパターンでRubyコードをリファクタリング(Hacklinesより)

Martin Fowler先生が発祥のようです↓。

参考: StranglerFigApplication


つっつきボイス:「ストレンジャー?」「私も最初同じに読み違えてスペルミスしてしまったんですが、1文字違いのストラングラー(strangle: 絞め殺すの名詞形)でした」「すげー名前😆」「Shopifyの記事なんですね」「Strangler Figか、Martin Fowler先生のところにそんなパターンがあったとは😳」「記事のヘソの部分を取り急ぎ訳してみました↓」

Strangler Figパターンは、コードのリファクタリングにインクリメンタルかつ信頼できるプロセスを提供します。これは、古いシステムの上に新しいシステムをゆっくり成長させ、古いシステムが”絞め殺されて”簡単に除去できるようになるまで新しいシステムを成長させるという手法を表します。このアプローチの良い点は、変更がインクリメンタルであり、常に監視下に置かれ、何かをうっかりぶっ壊す機会が比較的低いことです。新しいシステムが期待どおり動いていることが確信できるまで、古いシステムは温存されます。その後のレガシーコードの削除はシンプルです。

同記事より抄訳

「お〜、移行するときのアプローチとしては昔からあるかな☺」「お金かかりそう😆」「古いシステムをゆっくりと絞め殺していくと😇」「古いAPIをどう殺していくかみたいな🔪」「strangler figで検索したらこんなのが出てきました↓」

参考: 絞め殺しの木 - Wikipedia


その昔にいたStranglersというパンクバンドでこの単語を覚えました。実はちゃんと聴いたことがなかったのですが、腕っぷしの強そうな見た目とうらはらに、やけにピコピコした80年代なサウンドですね。

参考: ストラングラーズ - Wikipedia

⚓Railsで'string'.truncateするよりいい方法(Hacklinesより)


つっつきボイス:「ERBでRubyのtruncateで文字を詰めるよりいい方法があるという小ネタです」

.truncate-title {
  width: 50%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

「CSSのoverflow: hidden;text-overflow: ellipsis;とかでtruncateしようぜと☺」「width指定やwhite-space: nowrap;も全部動員するヤツですね」「やるかどうかは文字数によるかな」「記事のコメントに『Bootstrapにもそれ用のtext-truncateクラスがあるよ』ってありますね」

参考: Text · Bootstrap

「自分もCSSでやるのがいいと思います: これでtruncateした文字はブラウザのCtrl-Fでも検索できますし😋」「あ〜たしかに!」「HTML上には文字が存在してるからか」「AWSのコンソールでは長い文字の...がこのやり方になってるので、隠れた文字も検索できます😎

「ただし、これがうまくいくのは文字列が1行に収まっているときだけ: 2行以上になるとtext-overflowがどのブラウザでも1行の省略にしか効かなくて、それを承知で対応したことあります😢」「なるほど〜」「なんとかclampというのも使ってみたんですけど、どのブラウザでも動きませんでした😇

こちらかどうかわかりませんが参考までに。

参考: -webkit-line-clamp - CSS: カスケーディングスタイルシート | MDN

「ところで今見ているDev.toの記事の埋め込みカードにも...があるけど、CSSでやってくれてるかな?😆」(ブラウザでinspectしてみる)「おや、HTMLの時点で文字列が切り落とされてる😆」「惜しい、記事で言うところのUsual Way止まり😆」「Dev.toのこの部分は2行になってるから元から断つしかないんでしょうね😆

⚓Rubyのビット演算(RubyFlowより)

# 同記事より
# AND
25.to_s(2)           # 11001
30.to_s(2)           # 11110
(25 & 30).to_s(2)    # 11000

# OR
25.to_s(2)           # 11001
30.to_s(2)           # 11110
(25 | 30).to_s(2)    # 11111

つっつきボイス:「Honeybadgerの記事で、教科書どおりかなと思いつつ」「まさにビット演算」

「Rubyでビット演算ってあんまり使いませんけどね☺」「ぱっと思いつかないですね🤔」「もちろんビット演算はプログラマーが常識的に知っておくべきことではありますけど、Rubyで書くかというと書かないかな〜😆

「この間mrubyの勉強会に参加してきたんですけど、そこではビット演算書きまくりでしたね😋」「mrubyみたいな世界だとメモリのフットプリントを増やさないためにビット演算多用するのはありそう」

Rubyのビット演算子でarrayを操作する

⚓その他Ruby

つっつきボイス:「Rubyにfinalがあったらそうでしょうね〜」「てっきりRubyにfinalが入るのかと思って探しちゃいましたが、どこにもなかったので、もしfinalがあったらというもしもの世界の話だったようです😅」「もし入ったらいろんなものが壊れすぎますし😆」「出てきたのはJavaの記事ばかりでした😆

⚓DB

⚓イミュータブルデータモデル


つっつきボイス:「はてブでバズってた記事です」「おぉ、この視点↓は普遍性があっていいですね👍: 何が同じなのか、どういうときに同じと言えるのか、というような視点」「なるほど!」「こういうエンティティの感覚って人によってブレることがあるんですよね…」

  1. 単一性 (Oneness) 「何が1つのものであるか?」
  2. 同一性 (Sameness) 「2つのものが同じであると、どういうときに言えるのか?」
  3. カテゴリ (Category) 「それは何であるか? どんな分類で識別されるか?」
    同記事より

「自分が昔やってたときは、『もの』と『こと』で分類せよっていう教えられてた気がしますけど、今はリソースとイベントなんですね😆」「言葉はどちらでもいいといえばいいんですけど、日本語の『もの』と『こと』だと意味が広がりすぎるかもしれませんね🤔」「ああたしかに」


「記事では『マスター』『トランザクション』の分類は使わないという記述もありますけど、この分類って、大昔のバッチ処理中心のシステムなら割とマッチしてたんですよ」「そうですね」「そういう世界では、マスターを更新するのは洗い替えのときか、更新されるとしてもせいぜい1日1回ぐらいでしたけど、今はたいていのものがトランザクション的にガンガン更新されるようになってきてますし、『マスター』『トランザクション』分類でやろうとしても結局全部トランザクションになっちゃったりしますし😆」「そういう悩みポイントがこの記事にいっぱい載ってますね😅


Step3. イベントエンティティには1つの日時属性しかもたないようにする

「イベントエンティティの日時属性は1つにする↑、ああなるほど」「これはまさにアップデートを避けるための手法で、データをイベントごとに分けるという感覚ですね」「テーブルにステータスフィールドを増やすとつらくなるのにも通じる」

なんとか日時みたいなフィールドを複数持って更新するんじゃなくて、可能な限りイベントごとに別テーブルにしようという考え方: これはSQLアンチパターンなんかでもよく指摘されていますね☺」「うう、実際にやりがち😅」「実際にやりがちですし、それでOKな場合もないわけではないんですけど、だいたい破綻するんですよね😇」「1つのレコードにいろんな日時が入ってきたりするとわけわからなくなってしまいがち」「取り消し機能を付けた後に取り消しの取り消しをやろうとしたら破綻したり😆

「なので、この記事でやってるように日時ごとにテーブルを分けるのが理想ではありますね」「テーブルをばらした上で必要なときにくっつけると😋

「その一方で、テーブルとして見るときには複数の日時がまとまっている方が見やすかったりするんですよ😆」「システムがどのぐらい複雑になるのか、どのぐらい長く使われるのかにもよりますけど、感覚としてアップデートはよくないというか避けたいというのがテーブル設計のアンチパターンでよく言われてますね」「うんうん」「どんなDBMSを使っていてもアップデートすればフラグメンテーションしちゃいますし」「イミュータブルがアップデートを避けるという意味なら記事タイトルのイミュータブルデータモデルというのは腑に落ちますね😋」「インサートオンリーで考えるとかも」

「この辺のテーブル設計回りのスライドは以前のウォッチでも見たような気がしますね☺」「後で探してみます👀」「記事としてはそれほど目新しくはなさそうでしたが、テーブル設計で何をするとまずいかという点を最初に押さえてから設計を進めるというアプローチはありだと思います: 最終的には同じテーブル設計になるとしても、こうやって着目点を変えてみるのはいいかも👍

後で探しましたがうまく見つけられませんでした。

⚓ユニケージ開発手法

「ユニケージ強者にお尋ねしますけど、『マスター』『トランザクション』分類はユニケージとかなら割とマッチします?」「いえいえ、私ユニケージさんざんやってましたけど、そこは普通のシステムと一緒ですよ😆」「ああやはり: 現代的なシステムだとマスターといえどもいつ更新されるかわからなかったりしますよね😆」「はいそのとおりです😆」「ユニケージでバッチ処理が中心になるのであれば多少整理しやすくなったりします?」「まあユニケージのコマンドの中ではマスターとトランザクションを組み合わせて処理することが非常に多くて、仕様レベルでもこの2つをきっちり区別しておかないといけないんですけど、するとどれがトランザクションなのかというさっきと同じ議論になっちゃいますね」「なるほど」

参考: ユニケージ開発手法 - Wikipedia

「結局『マスター』『トランザクション』分類は不毛ということで: マスターに決めたからといって1日1回しか更新しないかというとそうはなりませんし😆」「そうなんですよ😆

⚓設計・運営・DevOps

⚓ペアプログラミングについて


つっつきボイス:「Martin Fowler先生のサイトに掲載されたかなり長いペアプロの記事で、今翻訳を進めています(近日公開予定)」「なるほど長い😆」「1冊の本になりそうなぐらいペアプロのススメ方についてすごく具体的にみっちり書かれています」(翻訳ドラフトを一同で眺める)

「ペアプロのやり方のひとつとしてストロングスタイルというのも紹介されてて、これは要するに二人羽織だなと思いました😆」「ストロングスタイル😆

「ペアプロはお互いにある程度の信頼関係が必要とか、ペアプロに適した粒度のタスクを選ばないといけないとか、いろいろありますよね☺」「つい長々とペアプロしちゃったりとか」「やってみたけど誰が書いても同じようなものになっちゃったとか」「時間を決めてペアプロするのはありだと思います😋」「記事でも8時間ぶっつづけでペアプロするなと注意してました」

「あとはペアプロで何を得るのかも大事でしょうね☺」「記事の後半でも、ペアプロの目的を見失わないようにときどき思い出せと強調してますね」「誰とペアを組むかも目的によりますし」

「自分はペアプロする機会はあんまりなかったかな」「自分もちょっとやってみたことありましたけど、何かを得たという手応えがあったかというとどうだろう😅」「人がコードを書いているところを横から見て驚いたりそこから学んだりというのはときどきしますけどね☺」「2人で黙々と同じ課題を進めるのは、どちらかというと設計でやる感じかなと」

「一方的に教えるみたいになってもいけないでしょうし」「記事には新人を引き上げるときにはありだって書かれてますね」「あとプロジェクトに新しく加わったメンバーにプロジェクトのルールやツールの使い方を説明しながらリードしていくのにペアプロするとかもありでしょうし」「ツールの使い方とかは横で見せてもらう方が早いし😆」「どこかでやってみてもいいかも😋」「私もペアプロされてみたいです😆」「😆

同記事で以下の記事やツールも紹介されていました。

⚓WIP数に上限を設けることの重要性

上のOn Pair Programmingで紹介されていた記事です。

見出しより:

  • WIPの上限とは
  • WIPの上限が重要な理由 — 非効率な個人マルチタスクを減らすため
  • ScrumでもWIPの上限は使えるか
  • WIPの上限を取り入れてみる

つっつきボイス:「WIPで止まるときってレビュー待ちになることが多いですけど😆」「😆」「WIP塩漬けの件数を超えたらアラートを出すようにするといいかも」「WIPで止まるときは、その本人の問題というより他の問題で止まることが多いですし☺

「自分はカンバン系ツールでタスク管理してますけど、待ち状態になったときは待ち用の板に置いて、本当に作業中のものだけIn Progress板に置いたうえでWIP数を管理するというのは、それはそれでありかなと思います」「ああ、本当の作業中と待ち状態を分けるということですね☺」「In Progress板に置いたものが質問待ちになっちゃったりして😆」「そのときは待ち板にどんどん移動すると😆」「でも待ち板に入ったものって実質WIPじゃありません?😆」「たしかに😆」「脳内からスワップアウトされたタスクをもう一回読み込むのが大変なんですよね😅

「ともあれWIPの数に上限つけるのが重要なのはたしかで、何らかの形でアラートを出すようにして、進めるのか取り下げるのかを相談するとかがいいでしょうね」「ですね」

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

⚓sshuttle: 貧者のためのVPN

つっつきボイス:「リモートワークの友として社内Slackで話題になってたツールです」「そうそう、この中にもsshuttle使っているメンバーがいて、ただそれだけだと外部からのブラウザ表示がうまくいかないときがあるのでSOCKSプロキシを使うといいよという話でしたね」「ずっと前にSOCKSプロキシを使ったのをかすかに覚えてます」「sshでdynamic forwardingできればSOCKSプロキシ使えますし、SOCKSはHTTP以外にも何でも通せるのがいいところ😋」「おぉ〜」

「SOCKSがsocketsの略語って初めて知りました😅」「この文脈だとsocketsぐらいしかありませんし😆

以下の記事もはてブで盛り上がってました。

「テレワークでVPNを使わない😆: ゼロトラストの話とか、言ってることはもっともだけど」「日経の記事ってたいてい有料だから途中までしか読めない…😢」「大学にいた頃はボリュームライセンスでバックナンバーも含めて読めましたね😆」「そうそう😆」「いいな〜😭

⚓その他インフラ


つっつきボイス:「Bottlerocket、スリム化したLinuxか」「Amazon Linuxとは別物なんですね」「この記事で言ってるコンテナはDockerコンテナのことでしょうね: EKSのこととか書いてるし」「GoogleのContainer-Optimized OSのアマゾン版という感じ」

参考: Container Linux - Wikipedia
参考: コンテナ最適化 OS  |  Container-Optimized OS  |  Google Cloud

「サポートは3年間か〜😅」「ちょっと短い😆」「こういうのは頻繁に更新したくないし😆

⚓Amazon Linux 2とDockerで構成をシンプルにする

「最近チーム内でよく使う構成は、Amazon Linux 2を使って、amazon-linux-extrasでDockerを入れる、そしてそれ以上のツールはなんにも入れない😆」「なるほど!」「こうすればパッケージ管理でAWSのパッケージしか使われなくなりますし、アプリケーションで必要なものは全部コンテナに入るので、仮にサーバーを再構築しないといけなくなったときにもあんまり怖くない😋」「余計なもの入れないの大事ですね」「ホストOSに何かインストールしちゃうとアップグレードとかセキュリティ対応とかやらないといけなくて、そういうのを考えたくない😆」「😆」「余分なものは極限まで削ぎ落としたいし、そのためにDockerを使う意味がすごくありますね😋

参考: Amazon Linux 2(セキュアなLinux環境でアプリを実行)| AWS
参考: amazon-linux-extras - Qiita

⚓CSS/HTML/フロントエンド/テスト

⚓UXのビジュアルデザイン5つの法則

  • 1. スケール: 相対的な大きさの違いで重要さを表す
  • 2. 階層の「見える化」: 要素が重要な順に並んでいることをひと目でわからせる
  • 3. バランス: 要素が均等であることを示す(あえてバランスを崩してダイナミックにすることも)
  • 4. コントラスト: 文字どおり「対比」で違いを強調
  • 5. ゲシュタルト: 個別の要素の集まりが全体として別のものを表す(だまし絵的)
    同記事より抜粋

つっつきボイス:「BPSデザインチームのチャンネルで話題になってました」「ゲシュタルト😆」「めちゃ堅苦しい言葉ですけど、部分が集まって全体の意味を作るみたいなニュアンスで使ってますね: このNBCのロゴマークに孔雀が隠れてるみたいな↓」


同記事より

参考: ゲシュタルト - Wikipedia

「自分たちエンジニアはこれだけ読んでもデザインはできないけど、他人のデザインにフィードバックするときにはこういう法則ってとっても役に立ちます😆」「😆」「雰囲気でフィードバックするとあやふやになりがちですけど、イケてないデザインはだいたいこういう法則に何かしら違反してたりするので、フィードバックに根拠を与えるという意味でこういう法則を知っておくのは大事ですね☺」「5つなら覚えられそうですし」「あえて法則を外しているのかどうかをデザイナーに問い合わせるときにも使えますし😋

「似たような話は、これまでも何度か話したNon-Designer’s Design Book↓にもあります❤」「へぇ〜😳

⚓その他フロントエンド


つっつきボイス:「フロントもマシンパワー必要なんですね」「もう今はめっちゃ必要😆

「Webpackはファイルアクセスもネットワークアクセスも多いし、動きの多いものを作ってるなら表示が遅いとダメだし」「なるほど」「とはいうものの、あまりハイスペックのPCで作ると、現場の遅いPCで当てが外れることもありますけど😆」「それもありそう😅」「といって遅いマシンで作れとは思いませんし😆

「昔、SSDが今ほど普及してなかった頃って、MacのSSDだとアプリがむちゃくちゃ速く動くのに、デプロイ先のハードディスク環境だとめちゃ遅くなったことが結構ありましたね😆

⚓言語・ツール

⚓repl.it: GitLabリポジトリをブラウザIDEで操作

st0012さん経由で知りました。
たとえば以下を開くとkognise/water.cssをブラウザIDEで開けます。


つっつきボイス:「ありがちかなと思いつつ、GitHubリポジトリをローカルに持ってこないで直接やれるのが面白いかなと思って」「ブラウザIDE的なものはいろんなものが出ては滅びたりしてますけど、その間にちょっとずつ進化してたりするので、追っておくのはいいと思います😋」「repl.itがそのまま使えるプロジェクトならいいけど、うまく動かないプロジェクトがあるかもしれませんし」

「最近社内で新人が使っているCloud9を横から見てると、自分が使ってたしょぼい時代よりだいぶ良くなってるなって思いましたし☺」「おぉ」「いつの間にかERBも補完できるようになってましたし👍

追いかけボイス: 「repl.itでRails引っ張ってみたらデカすぎるってエラーになりました」

参考: AWS Cloud9(Cloud IDE でコードを記述、実行、デバッグ)| AWS

;⚓WebTransport over HTTP/2


つっつきボイス:「HTTPプロトコルの強い人の記事です」「WebTransport over HTTP/2?」「まだ策定中みたいですね」

「へぇ、優先順位やフロー制御がビルトインで使えるのか: これはいいな〜❤」「WebSocketだと自分でやらないといけないんでしょうか?」「WebSocketにそんな機能はありません😇」「あぁやっぱり😅

  • HTTP/2上でWebTransportセッションが確立したあと、クライアントとサーバのどちらからでもWebTransport用ストリームをオープンできる。
  • WebTransport用ストリームでヘッダー圧縮、優先順位付け、フロー制御 の機能が利用できる
  • 中継者がいてもWebTransport用ストリームのデータを正しい相手に配送できる
  • WebTransport用ストリームをグループ化できる
    WebSocket over HTTP/2とは異なり、セッションが確立したあとにサーバ側からWebTransport用ストリームをオープンできる。そのデータをただしくクライアントに配送するための工夫が入っている。
    同記事より

「WebSocketって本当に昔ながらのソケットという感じで結構機能が少ないんですよ😢: 記事にもある『そのデータをただしくクライアントに配送する』なんてまさにWebSocketにない機能」「そんなにプリミティブだったなんて…」「WebSocketはソケットをオープンする以上のことはあまりできないので、WebSocketをつないだ上で、その上にチャネルとかメッセージングプロトコルとかを実装しないとマルチストリームみたいなことができないんですよ」「うーむ」

参考: UNIXドメインソケット - Wikipedia
参考: WebSocket - Wikipedia

「WebTransportはネゴシエーションとかヘッダーみたいな地道にやるのが面倒な機能もあるらしいのがいいですね😍」「しかもWebTransportでは中間装置(プロキシ)も使えるし!」「これでようやっと使えるものになりそう😂」「まあ世の中のブラウザがすべて対応するまではWebSocketもやらないといけませんけど😅

⚓その他

⚓リモートワーク、はかどるのかな?


つっつきボイス:「今流行りのようつべASMR😆」「ASMRって、自分より皆さんの方が詳しいかなと思って」「まあ存在は知ってますけど、自分が見るのはゲーム関係なんで😆」「ASMRのどの辺がリモートワークに関係あるのかと😆」「意味わからん😆」「ASMRって睡眠導入とかそっち方面じゃありませんでしたっけ?」「睡眠導入もありますけど他にもいろいろありますね😆」「睡眠導入しか知らなかったな〜😴

参考: ASMR - Wikipedia

「料理動画なんかで音響がバイノーラル的にすごくリアルになってるのがあったりしますけど、ああいう感じ?」「まあそんな感じ: 人間の頭の形したマイクとか使ったり☺」「今すごく適当に話してますけど😆、卵を割る音とかリアルなの面白いですよね」

参考: バイノーラル録音 - Wikipedia

⚓番外

⚓未来っぽい


つっつきボイス:「まだ光沢平面上ですけど😆」「これまで出てきた光学立体ディスプレイってSF感はあるけどイマイチ流行ってないですね😆」「あとちょっとなのかな〜って」「いろいろ出てきてますけど、表示だけじゃなくてインタラクションや触感なんかも含めた決定版が出てこないと趣味で終わっちゃうかも☺」「やっぱりキラーアプリか」「触ったり掴んだりできるぐらいにならないと」「まだ要素技術研究の段階かな〜」

「こういうのは10年ぐらい前からやってて、Kickstarterかどこかで商品化もやってましたね」「ガラスの中に映すのか〜、スター・ウォーズみたいに何もないところに映せるのが欲しいです👽

参考: まるで光速船、ヘッドギア不要の3Dディスプレイ – Kickstarterで25万ドル集めたチームが挑戦 | TechWave(テックウェーブ)記事内リンク先のプロジェクトドメインはNot Foundでした…

こういうのがやれるのはいつでしょうか。


後編は以上です。

バックナンバー(2020年度第1四半期)

週刊Railsウォッチ(20200316前編)Webpackerの対抗馬Simpackerはいかが、Hanami::APIは高速性をフィーチャー、N+1と戦うgemほか

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

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

RubyFlow

160928_1638_XvIP4h

Hacklines

Hacklines


Rails 6/5とRubyのJSON gem向けセキュリティ修正がリリース

$
0
0

当初同じ内容かなと思ったら、RailsとJSON gemのセキュリティ修正は別物でした。

Railsセキュリティ修正

影響を受ける可能性があるのはActionViewヘルパーのescape_javascriptメソッドとそのエイリアスであるjメソッドとのことです。変更点を見た限りでは、バッククォートと$がエスケープされていなかったのを修正したようです。

RubyのJSON gemセキュリティ修正

Rubyそのものではなく、RubyにバンドルされているJSON gemの追加修正です。以下のバージョンが影響を受ける可能性があるとのことです。昨年12月12日にリリースされたJSON gem 2.3.0(Ruby 2.0以降が対象)では修正済みとのことなので、この日より後にJSON gemを2.3.0にアップデートしたかどうかをチェックしてみましょう。

  • JSON gem 2.2.0およびそれ以前のバージョン

おまけ: Rails 5アプリをアップグレードした

オレオレRailsアプリを5.2.4.1から5.2.4.2にアップグレードしました。

アプリのJSON gemは既に2.3.0になっていたのでこちらは変更しませんでした。

  • GemfileでRailsバージョンを5.2.4.2に変更

  • bundle installを実行

実際はbundle installすると依存関係でいくつかつっかかったので以下を実行しました。これはアプリによって異なると思います。

$ bundle update activemodel actionpack railties activerecord

関連記事

Railsアプリで実際にあった5つのセキュリティ問題と修正方法(翻訳)

銀座Rails#19でZoomによるイベント視聴を体験しました

$
0
0

こんにちは、hachi8833です。先週の銀座Rails#19が、リモートイベント視聴初体験でした。

Zoom開催: 【オンライン開催】銀座Rails#19 @リンクアンドモチベーション - connpass


ginza-rails.connpass.comより

Zoomでイベント視聴に参加してみて

Zoomはここ数か月BPS社内で普及しつつあるので、慣れている分使いやすいですね。銀座Rails#19では少なくとも50人以上(一説には80人ほど)がZoomで視聴していましたが、やはり安定性と品質(特に音声)は驚異的でした。終了間際にごくわずか音声が乱れただけで、トラブルらしいトラブルはありませんでした。

Zoomの有料プランでは、たとえば「プロ」なら100人まで参加でき、それ以上はさらに別料金で開催できるようになっています。今回はこれを用いたとのことです。

参考: プランと価格 - Zoom


zoom.usより

発表者の方はだいたいZoomのバーチャル背景機能を使っていました。部屋の中が丸写しにならずに済みますし、視聴者の側も「部屋見えてますけど大丈夫ですか?」と気を遣わずに済むのがいいですね😋。「自分は部屋見られても一向に構わない」という方も、さしあたってバーチャル背景はオンにしておくといいかもと思えました。

銀座Rails#19ではさらにComment Screenというコメントツールも併用されていました。Comment Streenを別タブで開いてコメントを入力すると、ニコ動的にコメントが右から左に流れます。👍❤といったボタンを押せば絵文字が下から花を散らすように漂います。

このときは、Zoomのチャット機能を「発表者や主催者からのお知らせやURL共有」に、視聴者のコメントはComment Screenにという使い分けをしていたようです。Zoomのチャット機能に入力したメッセージにはユーザー名が表示されますが、Comment Screenにはユーザー名が表示されていなかったので、うまい使い分けだと思いました。

自分はこうしたライブものの視聴が初めてだったので、セッション開始で「8888888」がいくつも流れてきたとき何だろう?🤔と思ったのですが、どうやら拍手を表していることにやっと気づきました。そっち方面の文化知らなかった…😅

こうしたビデオカンファレンスでは、発表者の方が「ひとりで喋っていると届いているのかどうか不安になる」という話もちらほら見かけますが、Comment Screenのリアクションがあることで、発表者の方々も視聴者の反応が目に見えてやりやすそうでした😋

なお、20:30にセッションが終わってZoomの会議が閉じられた直後、Comment Screenの方で「しまった、アンケートのURLを開くの忘れてた!」という叫び声を目にしました。アンケートURLはZoomのチャット機能で知らされていたので、Zoomの会議が閉じられると開けなくなってしまうんですね😳

開催スポンサーのリンクアンドモチベーション様、オンライン開催スポンサーのForkwell様とSONY株式会社様、今回オンライン開催で惜しくも出動できなかったビールスポンサー予定のScoutAPM様、ありがとうございました!。

当日発表より

出張!Railsウォッチについては別記事でお送りします🙇

Rubyでバイナリをパース(小林ノエル)

こちらは今のところサンプルコードが公開されていますね。ここでは詳しく述べませんが、バイナリデータを体当たりでパース、考えるだけで恐ろしい…😱

The Majestic MPA(@f_subai)

@f_subaiさんのセッションは、Railsの非SPAをどうやってよくするかというテーマでした。「フロントエンドエンジニアが多い」「アプリごとにさまざまなバックエンド/フロントエンドフレームワークが用いられている」環境では、WebpackerのようにRailsに寄せるしくみだとやりづらくなることが実感できました。

参考: 今日から簡単!Webpacker 完全脱出ガイド - pixiv inside

次回銀座Rails#20

週刊Railsウォッチ(20200330前編)Active Record Doctorで診断、Webpacker 5、GitHubのViewComponentとRails 6.1の3rd-party component frameworkほか

$
0
0

こんにちは、hachi8833です。

つっつき前ボイス:「このところフルリモートで自宅作業していると、つい人と口をきくのを忘れちゃいそうになるので、つっつき会参加します😆」「そんなに😆」「ゴミ捨て以外まったく外に出ませんでした😆」「ほぼパーフェクト😆

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

⚓Rails: 先週の改修(Rails公式ニュースより)

今回はコミットリストから見繕いました。

⚓PartialRendererをリファクタリング

今回のコミットリストでtenderloveさんのコミット数がやけに多いと思ったら、これでした。


つっつきボイス:「以下の❌マークの組み合わせはありえないので削除したということのようです」「お〜これは頑張った感ある💪」「パフォーマンス的には速くなった部分と遅くなった部分でプラマイゼロに近いようですが、コードはだいぶすっきりしたようです」

diffがかなり増えて申し訳ない。
PartialRendererが複雑でこのところつらかったので、意を決して手を入れることにした。
ビュー内部で誰かがrenderを呼ぶときにいろんな組み合わせのオプションが渡されるが、PartialRendererはそれらを一手に引き受けていたので、まずはいろんなシナリオを表にまとめてみた。

修正前はPartialRenderer❌も含めて全部やっていたので、ObjectRendererCollectionRendererを切り出した。
同コミットより

「今までPartialRendereroptionsで何でも受けられるようになってて組み合わせが爆発していたのを整理したということかな: renderにパーシャル名を渡す場合、コレクションを渡す場合、オブジェクトを渡す場合…みたいな」「renderにコレクションとオブジェクトを両方渡すとか全然意味わかんないし🤣」「それが❌の場合か」「パーシャル名を渡す場合は普通にレンダリング、パーシャル名とコレクションを渡す場合はコレクション内のオブジェクトをeachで回して云々、パーシャル名とオブジェクトを渡す場合はこう、コレクションだけを渡す場合はこう…というふうに上の表で整理したということですね」

「プルリクにも、optionsハッシュがいろんなケースに対応しすぎてたり使われない組み合わせをわざわざチェックしてたりしたみたいなことが書かれてますね↓」「そういう余分な処理を枝刈りしたということか」「こういうリファクタリングは全容を把握してる人じゃないと大変そう😲」「コミット数45は大きいですね」「これでいいんだろうかと首を傾げながら修正してそう」

名前でわかるように、CollectionRendererはコレクションのレンダリングを担当し、ObjectRendererはオブジェクトのレンダリングを担当する。これで各クラスの実装がシンプルになって理解しやすくなった(し、最適化もしやすくなったと思いたい)。そのためにスタックを少々複雑にせざるを得ず、前述のoptionsハッシュを分解してどのレンダラーで使うか決められるようにする必要もあった。
同コミットより

⚓lookup_storeの互換性が壊れていたのを修正

# activesupport/lib/active_support/cache.rb#L57
      def lookup_store(store = nil, *parameters)
        case store
        when Symbol
          options = parameters.extract_options!
          retrieve_store_class(store).new(*parameters, **options)
+       when Array
+         lookup_store(*store)
        when nil
          ActiveSupport::Cache::MemoryStore.new
        else
          store
        end
      end

つっつきボイス:「これは@kamipoさんによる修正ですね」「lookup_storeって何だっけ?」「ああ、キャッシュストアに入ってるオブジェクトを引っ張ってくるのか」「Active Supportのキャッシュなんですね」

lookup_storeは、シングルトンメソッド的に任意の箇所でキャッシュストアの内容を引っ張ってくるのね」「つまりこのメソッドはシングルトンだからどこからでも呼べる」「なるほど」「Railsでコンフィグされていればそれを取れるし、されてなければメモリストアが取れるみたいな」

「Railsでは、こういうグローバルコンテキストから持ってくるみたいな書き方ってあんまりしませんけど、何かで必要になったら使うのかも🤔

⚓insert_allがenumを型キャストしない問題を修正

# activerecord/lib/active_record/insert_all.rb#L178

          def extract_types_from_columns_on(table_name, keys:)
            columns = connection.schema_cache.columns_hash(table_name)
            unknown_column = (keys - columns.keys).first
            raise UnknownAttributeError.new(model.new, unknown_column) if unknown_column

-           keys.index_with { |key| connection.lookup_cast_type_from_column(columns[key]) }
+           keys.index_with { |key| model.type_for_attribute(key) }
          end

つっつきボイス:「insert_allがenumで型キャストしない、そういえばそうなってたような覚えが🤔」「まだinsert_all使ったことない😆」「これとかupsert_allってRails 6からでしたっけ?」「そうですね」

「たぶんバグかな」「今まではinsert_allでenumをサポートする気があんまりないのかと思ってました🤔」「お?」「だってcreated_atとかも作ってくれないですし😆」「あ〜そういうことか、insert_allって結構挙動違うのかも😳」「もしかすると最新のRails 6のmasterでは作るのかもしれませんけど、少なくとも自分のプロジェクトではcreated_atとかも全部書きましたし、そういうものなのかなと思ってました😆」「とりあえずAPIdockでinsertを見た感じでは、created_atとか設定しなさそうだけど🤔」「コールバックやバリデーションはトリガしないけど、enumをキャストしないとは書いてませんね😆」「どっちなんだろ😆

単一のINSERT文で単一のレコードをインサートする。モデルはインスタンス化されず、Active Recordのコールバックやバリデーションもトリガされないが、渡された値はActive Recordの型キャストとシリアライズ処理を通る。
apidock.comより大意


「今回の修正の方向を今後も推し進めていったら、例のactiverecord_import gem↓とだんだん似てきたりして😆」「ありそう😆」「activerecord_importならやれるんだったかな…?あれはオブジェクト自体を渡すからやれると思います☺」「insert_allではオブジェクトじゃなくてハッシュを渡しますから😆」「activerecord_import gemは結構使ってきたけど、ほぼActive Recordと同じように使えましたし、特に困ることもありませんでしたね😋」「その代わりactiverecord_importはレコードの数だけインスタンスを作るから、困るとすればそこぐらいかなと」

「activerecord_importでActive Recordのバリデーションをスキップしてもスピードが足りなくなったときに、Active Recordを使うのを諦めるという選択肢を取ったことありましたよ😆」「insert_allを使いたい場面ってだいたいパフォーマンスと隣り合わせのタイミングになってるはずだし」「Active Recordを使うのを諦めたときは、ああユニケージのアプローチは正しかったんだなって思いましたし😆」「ユニケージということは私に振ってます?😆」「つまりオブジェクトを作るとか無駄なことするより、テキスト処理でズゴっとやるのが一番速いなと😆」「まあ状況によってはそうかもしれませんね😆」「TSV作ってMySQLのトランザクションをオフにしてcopy fromで突っ込むと、ディスク読み出しと変わらないぐらい爆速になりましたし🚀」「🤣

⚓normalize_keysを高速化

# actionpack/lib/action_controller/renderer.rb#L103
    private
      def normalize_keys(defaults, env)
        new_env = {}
-       defaults.each_pair { |k, v| new_env[rack_key_for(k)] = rack_value_for(k, v) }
        env.each_pair { |k, v| new_env[rack_key_for(k)] = rack_value_for(k, v) }
+
+       defaults.each_pair do |k, v|
+         key = rack_key_for(k)
+         new_env[key] = rack_value_for(k, v) unless new_env.key?(key)
+       end
+
        new_env["rack.url_scheme"] = new_env["HTTPS"] == "on" ? "https" : "http"
        new_env
      end

      RACK_KEY_TRANSLATION = {
        http_host:   "HTTP_HOST",
        https:       "HTTPS",
        method:      "REQUEST_METHOD",
        script_name: "SCRIPT_NAME",
        input:       "rack.input"
      }

-     IDENTITY = ->(_) { _ }
-
-     RACK_VALUE_TRANSLATION = {
-       https: ->(v) { v ? "on" : "off" },
-       method: ->(v) { -v.upcase },
-     }

      def rack_key_for(key)
        RACK_KEY_TRANSLATION[key] || key.to_s
      end

      def rack_value_for(key, value)
-       RACK_VALUE_TRANSLATION.fetch(key, IDENTITY).call value
+       case key
+       when :https
+         value ? "on" : "off"
+       when :method
+         -value.upcase
+       else
+         value
+       end
      end
  end

つっつきボイス:「1.24倍速くなってますね」「何のキーだろう?」「コントローラがリクエストするときのキーとかそのあたりかな🤔」「rack_value_forがあるからRackとかenvがらみっぽい」「プルリク↓に書いてあるように、毎回defaults.each_pairで全部引っ張ってたら遅いから、先にenv.each_pairしてからdefaults.each_pairで必要なものだけ設定するように修正したということか」「なるほど😋

このPRでは以下の2つを行う:
* defaultsをすべて新しい環境ハッシュに設定してからenvのエントリでオーバーライドするのをやめて、envの値をすべて設定した後は既に設定済みのdefaultsの値の設定をスキップする。
* case文でlambdaのハッシュを切り替える
同PRより大意

⚓ドキュメント修正

DEPRECATION WARNING: Dangerous query method (method whose arguments are used as raw SQL) called with non-attribute argument(s): “DATEDIFF(updated_at, created_at)”. 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().


つっつきボイス:「1つ目は、pluckのAPIドキュメントの書き方が古くて、そのとおりにしたらwarningが表示された↑ということみたいです」「ああなるほど、pluckに直接文字列を渡したらいかんと🚫」「Arel.sqlを通しなさいと」「へ〜、pluckにも文字列渡したらダメなのか😳」「orderとかに文字列渡してはいけないというのが入ったのは何となく覚えてますけどいつだったかな〜?🤔」「同じぐらいのタイミングでpluckもそうなった気がする🤔」「別々に対応する理由もなさそうですし☺」「とにかくSQLインジェクション対策のためにはArel.sqlを使う必要がありますね」

# activerecord/lib/active_record/relation/calculations.rb#L177
-   #   Person.pluck('DATEDIFF(updated_at, created_at)')
+   #   Person.pluck(Arel.sql('DATEDIFF(updated_at, created_at)'))

後で調べるとRails 6から文字列を渡せなくなったんですね↓。


# guides/source/asset_pipeline.md#L44
Using the `--skip-sprockets` option will prevent Rails from adding
-them to your `Gemfile`, so if you later want to enable
-the asset pipeline you will have to add those gems to your `Gemfile`. Also,
+this gem, so if you later want to enable the asset pipeline
+you will have to add it to your `Gemfile` manually. Also,
creating an application with the `--skip-sprockets` option will generate
a slightly different `config/application.rb` file, with a require statement
for the sprockets railtie that is commented-out. You will have to remove
the comment operator on that line to later enable the asset pipeline:

「2つ目はアセットパイプラインのガイドの文面がいろいろイマイチだったので修正したということだそうです↑」「修正も英作文レベルみたい」「ついにCoffeeScriptの記述も消されてる😆」「さらばCoffeeScript👋

⚓Rails

⚓Webpacker 5.0がリリース(RubyFlowより)

必要な最小バージョンがNode.js 10.13.0、Rails 5.2、Ruby 2.4になりました。


つっつきボイス:「Webpackの現在のバージョンは4.42.1ですし、WebpackerはWebpackとバージョン合わせる気なさそう」「Webpackも頑張って更新しないといけないうえにWebpackerまで気にしないといけないのって、どうもね…😭」「Webpackerの5を見た感じでは、必要なRubyやRailsやNodeのバージョンが上がったぐらいで、そんなに大きく変わってなさそうでした」「Multiple files per entryってどういう感じなのかな?🤔」「ファイル名が同じjsやcssごとにバンドルするようになったということのようで、以下で言うとhome.jsとhome.cssは同じhomeにバインドされるということみたいです」

# app/javascript/packs

accounts.js
application.js
home.js
accounts.css
home.css

extract_cssについて書かれてるけど、そもそもextract_cssが何をするのかを知らないと意味わからないでしょうね😆」「😆」「Webpackerのオプション以前にWebpackのプラグインとしてcss extract的なものがあるんですよ」「あ、そういうことですか😳」「Webpackで使うプラグインまでRailsと密結合しにいくのって、それはそれでひとつの未来かもしれないけど、それってどうなのかな〜😅

config/webpacker.ymlのextract_cssオプションもtrueに設定しなければならない。
extract_cssは、出力ファイルをCSSパックごとに分割して生成するようWebpackに指示する。このオプションはdevelopment環境ではデフォルトでfalseなので、development環境でCSSバンドルを生成するには明示的にtrueに変更する必要がある。
同記事より

おそらく以下がそれのようです。

参考: webpack-contrib/mini-css-extract-plugin: Lightweight CSS extraction plugin

⚓Webpackerのあり方

「もしかするとRailsとしてはそういう方向に持っていきたいのかも: Railsとして推奨するWebpackプラグインをバンドルして、みんなこれを出発点にしてくれみたいな🤔」「それありそうですね」「Railsって元々そういうところありますし、レールを敷きたいわけだし」「今まで使われてきたSASSがWebpackerでデフォルトで入っているあたりにそれを感じますね☺」「そうそう、Railsが推奨するWebpackの機能は最初からバンドルして便利に使えるようにしとくから、という世界を目指している感じはちょっとある🤔

「そのレールがいい感じのレールになるなら、Rails専門エンジニアにとってはWebpackerでいいかという気持ちになれるかも」「実際その辺のこと考えたくないですし😆」「考えたくない😆」「ゴリゴリのフロントエンド案件ならともかく、管理画面程度だったら、何を入れるかあれこれ考えるよりデフォルトの組み合わせでいこうぜみたいな」「よほど特殊なプラグインが組み込まれるとかでなければ」

「どっちにしろjavascript_pack_tagとかは自分たちでやらないといけませんし、manifest.jsonまでつながる何かを一気通貫で用意しとかないといけないというのは、そのとおりだと思います☺」「そのあたりが事前に決まっていれば細かいエラーに遭わなくて済みますし」「その分フロントエンドエンジニアにはキラワレそうですけど😆」「まあWebpackerは剥がせるようになってますから☺」「たしかに」

⚓ViewComponent: GitHubのViewComponent(Ruby Weeklyより)

ViewComponentの設計哲学: 「驚き最小の原則」に従ってRailsへのシームレスな統合を目指す
同リポジトリより


ViewComponentは、React Componentsにインスパイアされたビューレンダリングクラスであり、データを受け取って出力安全なHTMLを返す。PresenterやDecoratorやViewModelパターンの進化系と思えばよい。
コンポーネントは、ビューのコードが再利用されるほとんどの場面で効果を発揮し、直接テストできるというメリットもある。
同リポジトリより

ViewComponentは、次に取り上げる「3rd-party component framework」とも互換性を保つそうです。

以下の動画が資料として紹介されていました。


つっつきボイス:「GitHubがガンガン使っているというViewComponentと、次の3rd-party component frameworkについて見落としてたので😅、ViewComponentがどういうものなのかとりあえず上に軽くまとめました」「文字どおりビューのコンポーネントか: inspired by React Componentとあるぐらいだから、Reactと同じぐらいのコンポーネント粒度ということなのかな🤔」「こういうふうに↓renderにコンポーネントを書いて使うと」「なるほど」

<!-- 同リポジトリより -->
<%= render(ModalComponent.new) do |component| %>
  <% component.with(:header) do %>
      Hello Jane
    <% end %>
  <% component.with(:body) do %>
    <p>Have a great day.</p>
  <% end %>
<% end %>

「ViewComponent、入れるのには相当抵抗あるけど、もしかするといいものなのかもしれない🤔」「ビューをコンポーネント単位で単体テストしたいというのが開発の動機だったのね」「たしかにこうなっていればコンポーネント単位で試験できる: フロントエンジニアはこういうのをフロントでコードを書いてテストするけど、同じことをRailsのレイヤでやろうとするとこうなるでしょうね🧐」「やろうとしてることは理解できるけど、これを導入するのは勇気が要るというか、フロントエンドに戻れなくなりそうではありますね🤔」「導入するなら今後すべてRailsでやるという不退転の決意が必要ということになりそう」

「Reactにインスパイアされたんだったら、ERBじゃないスタイルにして欲しかったなんて思ったり😆」「まあERB以外でもできるみたいだし😆」「content_tagとかtag.divとか書く↓みたいですけど、書きたくないというか、ここに生HTML書けるならワンチャンあるかなと思ったり😆」「プロジェクトメンバーが全員Railsエンジニアで、フロントエンドにあんまり興味ないという編成なら、ありかも☺」「GitHubはそういう立ち位置なんでしょうね」

# 同リポジトリより
class TestComponentPreview < ViewComponent::Preview
  def with_default_title
    render(TestComponent.new(title: "Test component default"))
  end

  def with_long_title
    render(TestComponent.new(title: "This is a really long title to see how the component renders this"))
  end

  def with_content_block
    render(TestComponent.new(title: "This component accepts a block of content") do
      tag.div do
        content_tag(:span, "Hello")
      end
    end
  end
end

Q: ERB以外のテンプレート言語も使えるか?
A: ERB、haml、slimでテスト済みだが、ほとんどのRailsテンプレートハンドラーをサポートしているはず。
同リポジトリより

「おそらくGitHubはプロダクトが大きくなりすぎて、JSでテスト回すのがつらくなったのかも: ViewComponentならそれだけ読み込めばテストできるけど、フロントだとひととおり全部読み込まないとテストできないものが多いとか🤔」「次のトピックでそこに言及されてました↓」

⚓Rails 6.1で入る「3rd-party component framework」とViewComponent

Rails 6.1で入る「3rd-party component framework」機能に今頃気づきましたが、これも主にViewComponentのためのようです。以下の2つのPRは昨年のです。

このプルリクでは、ViewComponentを含む「3rd-party component framework」のサポートが導入される。
GitHubには4000テンプレートがあるため、Railsビューで以下のつらみがある:
* テストがつらい: 現在のRailsではビューのテストを結合テストかシステムテストでやることを推進しているが、そのためビューだけをテストすればよいというわけにいかず、ルーティングやコントローラ層のオーバーヘッドがあるためにビューのフルテストがつらいことになっている。それによって同じパーシャルがビューごとに何度もテストされるので、ビューをDRYにしたメリットが帳消しになってしまう。
* カバレッジ: ビューのカバレッジが多くのRubyコードで正しく扱われていないためにテストの監査が難しく、テストスイートとのギャップが開いている。
* データフロー: ビューでは、オブジェクトでのメソッド宣言と異なり、受け取ることを期待する値が宣言されない。そのため、レンダリングに必要なコンテキストを判定するのが難しくなり、1つのビューを複数のコンテキストで使い回すと微妙なバグをしょっちゅう踏むようになる。
* 標準的なRubyコードでもつらい: GitHubのビューは、Rubyクラスで期待される標準的なコード品質であっても、ほとんどがメソッドが長いだの条件ネストが深いだのでfailする。
同PRより大意


ViewComponentのメリット:
* ビューを単体テストできる。単体テストならだいたい25ミリ秒、結合テストでも最大6秒。
* カバレッジ: 少なくともカバレッジツールと一部互換性があり、SimpleCovでは一部うまくいっている。
* データフロー: コンポーネントのレンダリングに必要なコンテキストを明確に定義できるので、パーシャルよりも再利用が楽になった。
同PRより

つっつきボイス:「GitHubのビューテンプレートが4000超えてて、テストが重くてつらくてしょうがなかったそうです」「上の『ルーティングやコントローラ層のオーバーヘッドがあるためにビューのフルテストがつらいことになっている』とか、きっとフロントエンド勢から『フロントとAPIの構成にしとけばよかったのに、密結合してるからそういうことになるんじゃぁ😇』って言われそう😆」「😆」「『そんな無理しなくてもFirebaseでも使えば、フロントエンドでテスト書いてテストできるよ😋』って言われたりして🤣」「🤣

「カバレッジを改善したいという意図、理解できる」「これもフロント勢に言わせれば…(ryってなりそうですけど😆

「まあRailsのビューにもうひとつ別のソリューションが入ることは悪くないと思いますね☺」「言えてる」「3rd-party component frameworkでやれば新しい言語覚えないで済むし😆」「ただGitHubがもし仮に最初からやり直せるとしたら、果たしてViewComponentを選んだだろうかって思ったり🤣」「それな🤣」「歴史的な理由でこれになったんじゃないかと😆

「もしかすると3rd-party component frameworkって、いわゆるActiveとかActionが名前に付かないコンポーネントを導入できるという意味なんだろうか??🤔」「今でもgemを使えば入れられますし😆」「そういえば何が違うんだろう?」「そういう位置づけは詳しく見ないとわからないな〜🤔

「とりあえず#36388の『いいね👍』数がめちゃくちゃ多いし期待されてそうではありますね」「Railsの最大手ユーザーのひとつであるGitHubが使ってるから、という勢いで押されてたりして😆」「サードパーティといいつつ今のところGitHubぐらいしかなさそうですけど😆」「とりあえずViewComponentそのものは、コンポーネント単位でテストできますし、自分は割とキライじゃないですね👍」「今の世の中でスクラッチからRailsプロジェクトを立ち上げるときに使うかというと、ちょっと考えますけど😆

「以下もViewComponent的なものらしいです↓」「コンポーネントを組み合わせてビューを作るという考え方は、それこそいにしえの昔からあるヤツですね: それこそPHPでSymfonyのバージョン0.x系使ってた頃から、コンポーネントを作ってその中にコンポーネントスロットを作ったりとか、そういう名前でありましたし🧐」「いわゆるビューモデルというヤツ」「概念としては新しくない」「まあそんなにキレイに作れるかどうかはまた別😆

参考: ビュー・モデル - Wikipedia

⚓🌟Active Record Doctor: ARの問題を診断🌟Ruby Weeklyより)

Active Record Doctorでやれること:

  • インデックス化されてない外部キーのインデックス化
  • 不要不急なインデックスを検出する
  • 外部キー制約付け忘れを検出する
  • 未定義テーブルを参照しているモデルを検出する
  • uniqueインデックスがないuniquenessバリデーションを検出する
  • non-NULL制約付け忘れを検出する
  • 存在バリデーション付け忘れを検出する
  • booleanカラムに誤って付けられた存在バリデーションを検出する

つっつきボイス:「Active Record周りをチェックしてくれるのね😋」「なるほど😋」「これは何も考えずに入れておいていいgemかな👍」「CIに入れてもよさそうですね😋」「指摘もらって、それが正しいかどうか確認するだけでも意義ありそう」「単にやり忘れてたとか、そのうちやるつもりでそのままになってたなんてことはいつでもありますし」「外部キーを付けることも面倒で忘れやすい😆」「こういうのに怒られたらしょうがないという気持ちになれますし」

「uniquenessバリデーションあるのにuniqueインデックスが張られてないって😆」「ありがち😆」「もう正しさしかない😆」「う、やっちゃってるかも😅」「モデルのバリデーションって、一種気休めというか、本質的じゃないですし」「uniquenessチェックで毎回SELECTするのにuniqueインデックスないのはヤバい😆」「本当に信じられるのはunique制約エラーぐらい: create_or_find_byというメソッドがRailsに生えてるぐらいですし」「下手するとそこでINSERTが詰まる😆

久しぶりに🌟を進呈いたします。おめでとうございます🎉

⚓Facadeパターンでパフォーマンスとメンテナンス性を改善(Ruby Weeklyより)

# 同記事より
module Books
  class IndexFacade
    attr_reader :books, :params, :user

    def initialize(user:, params:)
      @params = params
      @user   = user
      @books  = user.books
    end

    def filtered_books
      @filtered_books ||= begin
        scope = if query.present?
                  books.where('name ILIKE ?', "%#{query}%")
                elsif isbn.present?
                  books.where(isbn: isbn)
                else
                  books
                end

        scope.order(created_at: :desc).page(params[:page])
      end
    end

    def recommended
      # ネストしたfacadeがここにある。
      # ビューの`Recommended Books`の責務は1つなので
      # これを切り出すことでカプセル化とテストしやすさが改善される
      @recommended ||= Books::RecommendedFacade.new(
        books: books,
        user: user
      )
    end

    private

    def query
      @query ||= params[:query]
    end

    def isbn
      @isbn ||= params[:isbn]
    end
  end
end

つっつきボイス:「普通のFacadeパターンかなと思いつつ」「普通にFacadeパターンですね😆

「Facadeって、GoFのデザインパターンの中でも『これってパターンというほどのものかしら、ただの切り出しでは😆?』という気持ちになりますね」「😆」「『ここはFacadeパターンでやりました』とか言うとスゴいことやってるような響きありますけど😆」「オブジェクト指向というほどでもない感☺

[保存版]人間が読んで理解できるデザインパターン解説#2: 構造系(翻訳)

⚓その他Rails


つっつきボイス:「『ロード・オブ・ザ・リング』のセリフなどをいろいろもじってたのが楽しかったので🧝‍♂️」「普通にRuboCopでレガシーコードと戦う記事💣」「3306 files inspected, 12418 offenses detectedとか見るとドキドキする😆」「やべえ😆

「Todo or not Todo😆」「You shall not passはガンダルフの『ここは通さぬ!』↓ですね😆」「😆

参考: ガンダルフ - Wikipedia

つっつきボイス:「*_previously_changed?きたー😆」「dirtyってどこまで使えるのかドキドキしちゃう😆」「from: nil, to: "Tesla"とか書けるようになるとは」

# 同記事より
car = Car.new
car.changed?                                      # => false
car.company = "Tesla"
car.changed?                                      # => true
car.company_changed?                              # => true
car.company_changed?(from: nil, to: "Tesla")      # => true

「何のpreviousなんだろ?🤔」「値がnilから"Tesla"に変わったということか」「dirty絡みっていろんなメソッドがあって覚えにくい😆」「changed?は保存するとfalseに変わるようになったんですね↓」「サンプルコードでfrom:to:付けても付けなくてもbooleanが同じだと違いがわからん😆」「ちょい見づらい😆」「reloadするとクリアされるということか」「reloadに対応するのは無理そうかな☺

# 同記事より
car.save
car.changed?         # => false
car.company_changed? # => false

car.reload
car.company_previously_changed?                               # => false
car.company_previously_changed?(from: nil, to: "Tesla")       # => false

「自分はDocker for Windowsは普通に使う分には今のところそんなに苦労してないかな〜😋


「チュートリアルにさらに解説動画があるという😆」「Railsチュートリアル大きいから😋」「こうやって裾野が広がっていくのはいいですね👍


前編は以上です。

バックナンバー(2020年度第1四半期)

週刊Railsウォッチ(20200317後編)Strangler Figパターンでリファクタリング、ペアプロ実践記事、イミュータブルデータモデルほか

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

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

Rails公式ニュース

Ruby Weekly

RubyFlow

160928_1638_XvIP4h

週刊Railsウォッチ(20200331後編)Ruby製プロセスマネージャOvermind、pgsyncで手軽にワンショットDB同期、DeepLの機械翻訳を試すほか

$
0
0

こんにちは、hachi8833です。リモートワークもさまざまですね。


つっつきボイス:「リモート環境は人それぞれ☺」「家族と住んでいると制約が発生しがち」「あ〜たしかに」「自分は独り者なのでリビングをオフィス環境にしてます😋」「こうなってくると、家賃が高くて狭い都内より、家賃も安くて広々した地方に引っ越す方がよかったりして😆」「伊豆あたりとかよさそう♨」「家にいる時間が長いと都心に住む意味あんまりないですし😆

「以下のツイート写真はちょっと前に話題になったDHHのリモート環境で、この記事でBasecampの他のメンバーとともにリモート環境を晒してます」

「記事に載ってる皆さんお部屋が随分広そうですけどご自宅なんでしょうか?」「はい、皆さんご自宅でらっしゃるようです🏠」「勇気あるな〜😆」「晒したい人はいますし☺」「日本人でも晒してる人いますヨ😆」「こういうジャンルありますし」「(ここでつっつきに参加)Jason FriedとDHHがいるからBasecampの記事ですか☺」「名前知ってるとはスゴい」「その2人だけですけど😆

このお部屋とかめちゃ狭くてトイレかと思っちゃいました😆」「左右のイボイボは防音材か何か?」「マイクが据え付けてあるし、画面もDTMっぽいからそういうのをやってるのかも🎵」「DHHのところに取り消し線でshow offってあるのは『見せびらかす』という意味です😆」「うらやましい😆」「融通利きやすくなってきてますし、地方ならやれますよ😋」「温泉のあるところにしたいです」

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

⚓Ruby

⚓RubyGems.orgが統計情報を公開(Ruby Weeklyより)


stats.rubygems.orgより


つっつきボイス:「RubyGems.orgの統計情報って前から出してたような?」「あ、そんな気もしてきました😅」「ダウンロード数とかはあったと思うので情報が増えたのかも🤔

「Ruby 2.3が一番多いんですね😳」「bundlerで取ってきた数とgemコマンドで取った数とか」「CI vs non-CIはnon-CIが圧倒的に多いけど、これは単に検出できてないのではという気もしますね☺」「野良gemも含めるとnon-CIが多いのかも🤔

⚓Overmind: Evil Martians製プロセスマネージャ(Ruby Weeklyより)

tmuxを用いたプロセスマネージャです。冒頭の記事ではForemanからOvermindに乗り換えたそうです。

参考: tmux - Wikipedia


つっつきボイス:「デバッグに便利という触れ込みみたいです」「tmuxに依存してる?また不思議なものを😆」「ああ、tmuxにアタッチすればいつでも見えるから楽だよという話か」「なるほど〜」「docker logsみたいなことをtmuxでやろうとしてるのかな、なんて😆」「たしかにdocker logsでやると全ストリームが表示されてうんざりしそうですし😆」「ローカル環境前提であれば、これはこれで思い切ったやり方としていいかも😋

「もしかしたら意外と使いやすいかも?」「ほんとに使いやすいかも😍」「ワンチャンあるかも😆」「でも自分の環境は残念ながら未だにGNU screenでやってるからtmux入れてない😇」「😆

参考: 作業がグッと楽になる screen を使おう! - bacchi.me

「この間dev環境staging環境本番環境でまったく同じコマンドを入れようとしてそれぞれの環境変数まで設定し終わってから、こういうときに何かうまいやり方あったよなと思ったら、それはscreenじゃなくてtmuxの機能だったということに気づいてシュンとなっちゃいましたし😭」「それできないとつらいっすね😅

「記事ではForemanからOvermindに乗り換えたとありました」「Overmindはたぶんtmuxがないと実行できなさそう」「インタラクティブなシェルが使えなかったりするとtmux動かないかもしれない😅」「Heroku環境なんかはそうかも🤔」「おそらくですけど、tmuxセッションを使うにはターミナルの環境変数とかを拾えて、cursesでカーソル移動とかを制御できる端末が必要なんじゃないかな〜」「なるほど」「実行環境がそういうのを返せない端末だとtmuxの起動が失敗しそうな予感: まあ普通のローカル環境ならまず大丈夫ですけど☺

参考: curses - Wikipedia


なおOvermindといえば、アーサー・C・クラークの最高傑作との呼び名も高い『幼年期の終り』に登場する、一種の神のような存在の名前です⛩。古典SF好きのEvil Martiansらしいですね😋

参考: 幼年期の終り - Wikipedia

⚓春のコード掃除(Ruby Weeklyより)


つっつきボイス:「Spring cleaning、ちょっとカッコいい❤」「たまにはbundle cleanしようぜと」「yarn autocleanは最近見かけますね☺」「gitのpruneも」「たまにはお掃除してさっぱりしよう☺

「そういえば、gitのマージ済みブランチを削除しないでずっと残しているプロジェクトでgit branch -aしたときの絶望感はヤバい😆」「😆」「あ、ブランチ表示が大量になるんですね😅」「ブランチ残されたまんまはツラい😢」「残すならタグにしましょうと」「最近うちのチームではGitLabでマージリクエストするときにdelete branchesチェックボックスをオンにしてますけど☺


見出しより:

  • 依存関係をお掃除
  • gitブランチをprune
  • 使われてないルーティングやビューを削除
  • 使われてないテーブルやカラムをチェック
  • バリデーションや制約に抜けがないかをチェック
  • migration/フォルダをお掃除
  • ツールでさらにお掃除

なお以下はつっつき後に見かけたツイートです。

⚓str_metrics: Rustも用いた文字列メトリクスgem(Ruby Weeklyより)


つっつきボイス:「何のメトリクスだろう?」「Sørensen–Dice…だと?」「いかにもスウェーデンの人名ですね」「(ググって)ソーレンセン-ダイス係数か!」「統計の手法でしたか😳」「文字列同士の評価方法として、こうした距離とか類似度とかを出せるということみたいですね😋」「レーベンシュタイン距離ってあったわそういえば」「なるほど、そういうメトリクス」

# 同リポジトリより
StrMetrics::SorensenDice.coefficient('abc', 'bcd', ignore_case: false)
 => 0.5

StrMetrics::Levenshtein.distance('abc', 'acb', ignore_case: false)
 => 2

「機械学習とかで使う感じでしょうか?」「統計や自然言語処理なんかでも使うヤツでしょうね」「最初数値の意味がぜんぜんわからなかったけど、そういうことでしたか😳」「文字列と文字列がどのぐらい似てるかを調べられるライブラリということで☺

⚓その他Ruby


つっつきボイス:「これはツボる🤣」「最大10年延ばせる🤣」「そういえばいらすとやさんが早速TOKYO 2021のイラスト出してましたし😆↓」「仕事速!」「商標申請とかされる前に仕上げちゃってるという😆

参考: TOKYO 2021の検索結果 | かわいいフリー素材集 いらすとや

「いらすとやがスゴいのは、TOKYO 2020のイラストがないところ」「ああっ😆」「そうかっ😆」「2020だとたぶんオリンピック委員会の許可が必要でしょうし☺」「実際のオリンピックはTOKYO 2020の名前のままやるらしいですけど」「まあこの先どう変わるかわかりませんし☺


つっつき後に見つけた、今週土曜開催の「Online Ruby Wine」カンファレンスです↓。参加費5ドルで、「ワイン片手に参加しよう🍷」だそうです。レジュメのあちこちにロシア語があったりしますが、「Work language: English」だそうです。

⚓DB

⚓pgsync: PostgreSQLデータベースを同期(StatusCode Weeklyより)

WebOps Weeklyマガジンが、いつの間にかStatusCode Weeklyと名前を変えていました。ツールを紹介するオンラインマガジンという触れ込みです。

よく見たらRubyで書かれていました。ankaneさん作です。


つっつきボイス:「普通のツールかなと思ったんですが、★が1,500個とかなり多かったので」「syncとあるからレプリケーションするのかと思ったけど、どちらかというとrsync的なバックアップとかに使うワンショット同期ツールっぽいですね」「名前のとおりぽすぐれ専用」

「synchronizationという言葉をデータベースの文脈で使う場合、普通は常に同期しっぱなしにすることを指すと思うんですけど、このツールはワンショット的にデータを取るのがメインのようです☺」「ふむふむ」

# 同リポジトリより
groups:
  product:
    products: "where id = {1}"
    reviews: "where product_id = {1}"
    coupons: "where product_id = {1} order by created_at desc limit 10"
    stores: "where id in (select store_id from products where id = {1})"

「こういう設定↑ができるようなので、たとえば最新の本番データを元にステージング環境のデータを整えるときに使うといいかも😋: 特定のデータをスクランブル化するみたいな作業もyamlで書けるみたいですし↓」「おぉ〜😍」「なかなかよさそう👍: こういうツールは書式がきちんと決まっていて誰でも安心してデータを作れるのが大事ですね☺

# 同リポジトリより
data_rules:
  email: unique_email
  last_name: random_letter
  birthday: random_date
  users.auth_token:
    value: secret
  visits_count:
    statement: "(RANDOM() * 10)::int"
  encrypted_*: null

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

⚓書籍『Docker/Kubernetes開発・運用のためのセキュリティ実践 ガイド』

https://twitter.com/akihirosuda/status/1242662941331050497


つっつきボイス:「NTTの人が書いたDocker/Kubernetesセキュリティ本で、かなり詳しい目次が記事に載ってました」「たしかにDockerやKubernetesについては基本的なところは固まってきていますし、そろそろ書籍を買って読んでもいい頃かも😋」「セキュリティの話のためにDockerやKubernetesを解説するところから始めてるみたいですね」「必要と思う人なら買ってもいいと思います👍

⚓Lamby: RailsとLambdaを統合(Ruby Weeklyより)


lamby.custominktech.comより


つっつきボイス:「LambdaだからLambyでそのまんま羊の絵というか」「AWSにある公式のインテグレーションツールを使わない理由ってあるんだろうか?🤔」「それもそうですね😳」「デプロイ方法を見た感じではAWSのSAM(Serverless Application Model)でやってるし、独自ツールでやらなくてもよさそうな気がしますけどね☺

# 同サイトより
#!/bin/bash
set -e

export RAILS_ENV=${RAILS_ENV:="production"}
export AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION:=us-east-1}
export CLOUDFORMATION_BUCKET=${CLOUDFORMATION_BUCKET:="lamby.cloudformation.$(whoami)"}

./bin/build

sam package \
  --region ${AWS_DEFAULT_REGION} \
  --template-file ./.aws-sam/build/template.yaml \
  --output-template-file ./.aws-sam/build/packaged.yaml \
  --s3-bucket $CLOUDFORMATION_BUCKET \
  --s3-prefix "APPNAMEHERE-${RAILS_ENV}"

sam deploy \
  --template-file ./.aws-sam/build/packaged.yaml \
  --stack-name "APPNAMEHERE-${RAILS_ENV}-${AWS_DEFAULT_REGION}" \
  --capabilities "CAPABILITY_IAM" \
  --parameter-overrides \
    RailsEnv=${RAILS_ENV}

参考: AWS サーバーレスアプリケーションモデル - アマゾン ウェブ サービス

「もしLambdaでRailsをやるとすると、リクエストのたびにコンテナが起動することになりそう😆: Rails.applicationあたりに流し込むLambdaコードを書くとかすればやれるでしょうけど」「リポジトリを見るとRails & AWS Lambda Integrationって書いてあるから、本当にやってるのかも」「ホントだ」「Quick Start↓を見た感じだと、普通にRailsのルーティングとコントローラを書いて…と、Rails.applicationに流し込むみたいなことをこのLambyがやってくれるということかな?」「じゃコードはRailsのでいいんだ😳」「めちゃ重そうだけど😆」「こういうのを最短でやれる方法がどこかにあるのかもしれませんね」「Railsのフットプリントを相当小さくしないといけないでしょうけど」

# 同サイトより
Rails.application.routes.draw do
  root to: 'application#index'
end

class ApplicationController < ActionController::Base
  def index
    render html: '<h1>Hello Rails</h1>'.html_safe
  end
end

「だからskipをいっぱい付けて少しでも軽くしてるのかも↓」

$ rbenv shell 2.5.5
$ gem install rails
$ rails new my_awesome_lambda \
  --skip-action-mailer --skip-action-mailbox --skip-action-text \
  --skip-active-record --skip-active-storage --skip-puma \
  --skip-action-cable --skip-spring --skip-listen --skip-turbolinks \
  --skip-system-test --skip-bootsnap --skip-webpack-install
$ cd my_awesome_lambda

「ちなみに、LambdaはAWS上で起動するたびにコンテナのデータを取りに行くところから始めてるわけではなくて、ウォームアップさえしてあれば2回目以降は同じコンテナを使うような実装になってます」「なるほど」「この場合ウォームアップって何でしょう?」「ああ、ウォームアップはHerokuとかでやってるようなのと同じで、最初に起動するときは遅いけど、2回目以降は前回のコンテナを破棄していなければ再利用するというモデルですね」「そうでしたか!」「なので最終的に読み込むファイルサイズが大きくても、OSのファイルキャッシュがふんだんに効く実装になっていれば2回目以降は初回起動よりは速いはず🧐

「ただ、Rubyで読み込む処理は速くならないはずなので、DSLみたいに読み込んで処理してから動かすコードをなるべくなくして、ファイルに入っているコードをそのまま読み込めば動くような形にしておいて、OSのファイルキャッシュが効きやすくする方が、おそらく速くなるでしょうね☺」「なるほど!」「そういう工夫をしないと速くならなさそう🤔」「どっちにしろ遅いんじゃないかという気もしますけど☺

「そもそもActive Recordなんかも、キャッシュがない状態でアクセスが始まるとスキーマチェックとかが走り出すから、何をするにも遅くなりがちですし」「ですね」「そういう部分をなるべくスキップするなどの細かいチューニングをしないとなかなか速くならないでしょうね」

「お、Lambyのデータベースコネクションのところを読むとDynamoDBを強くおすすめしてるし😆」「そういう面倒を避けたいんでしょう、きっと😆」「RailsはもともとLambdaで動くように作られていませんけど、データベースアクセスが不要またはデプロイしたSQLite3データにしかアクセスしないような、うんと小さいRailsコードならLambyは案外うまくはまるかも知れませんね☺

⚓その他インフラ


つっつきボイス:「ザンジバルってこういうスペルなんだ」「アマチュア無線でしか見かけたことない地域名🗺」「ガンダムで見たかも」

参考: ザンジバル - Wikipedia
参考: ザンジバル (ガンダムシリーズ) - Wikipedia

「このZanzibarは許認可系を扱うみたい」「Googleの共通認可基盤って、それだけで普通じゃない響き👽」「きっとヤバい😆」「この間のGCPの話に通じてそうですね(20200309)」「秒間100万リクエストをさばくって…😅」「こういうものが既にあるならそれに乗っかりたい😆」「記事は論文を解説してるんですね☺」「大量のリクエストをさばかないといけない認証基盤みたいなものは他にもあって実装もいろいろあるので、論文を見ればどういう部分が難しいのかみたいなことがまとまってそう😋

⚓JavaScript

⚓MicrosoftのReact Native for Windows


つっつきボイス:「BPS社内Slackで盛り上がってましたね」「WindowsのReact Nativeって誰が使うんだろうというのはさておき😆」「マイクロソフトがVSCodeでTypeScriptを推してる流れなのかなと」

「そういえばXamarinってどうなったんでしょうね」「たしかにXamarinどうなったんだ!」「技術的に筋悪じゃなさそうだったけど」「人気の違いなのかな?🤔

参考: Xamarin ドキュメント - Xamarin | Microsoft Docs

「React Native for Windowsも先のことはわかりませんけど☺」「Electronだとちょっと機能が足りないみたいなときにReact Native for Windowsを使うという感じなんだろうか?🤔」「最終的にUWPアプリという位置づけになるのかなという気がしてます」「JavaScriptの共通フレームワークと、プラットフォーム独立のインターフェイスがある、でもあくまでネイティブで動かす、というのがReact Native for Windowsなのかな〜」「Electronだと結局ブラウザエンジンを使ってるだけだから、ネイティブのReact Native for Windowsとは違うんでしょうね🤔

参考: Electron | Build cross-platform desktop apps with JavaScript, HTML, and CSS.
参考: ユニバーサル Windows プラットフォーム (UWP) アプリとは - UWP applications | Microsoft Docs

⚓言語・ツール

⚓DeepL: Google翻訳のライバル登場か


同サイトより

英文を入力すると自動で日本語文が出力され、日本語文を入力すると自動で英文が出力されるなど、細かな点もよくできてますね😋


つっつきボイス:「最近話題のDeepL」「機械翻訳がこうやって進化すると、英語が苦手という人の障壁が下りそうでいいですね😍

「DeepLを試そうと思って、この間出した記事原文の中から、これは難しいだろうと思えるパラグラフを機械翻訳させてみたら、案の定ひっかかりました↓」


deepl.comより

「vulnerabilityは普通ほぼほぼ『脆弱性』と訳されますけど、人間を形容するときは『ガードを下げる』とか『隙や弱みを見せる』とか『いじめられやすい』みたいなニュアンスになります」「ははぁ、しかも原文にProgrammersという言葉も入っているからよけい判定難しそう😆」「invulnerabilityもこの場合は『不屈の精神』というより『弱みを隠そうとする』という流れかなと😆」「こうやってコンテキストから意味を読み取るのはどうやっても難しいでしょうね😆」「まあ変だと思ったら原文見ればいいし😆」「私もDeepLといういいセカンドオピニオンができてうれしいです😋

DeepLに限りませんが、ときどき原文の一部が訳文ですっぽ抜けることがありますね。

「ほほぅ、DeepLに『数え役満』食わせてみたらbeing worthy of the countになった😆」「😆」「以前Google翻訳で『数え役満』を食わせたらcounting officer Mitsuruって出たんですよ🤣」「(爆)」「スゴい🤣」「さすがに今は変わったみたいですけど🤣」「サイコーでした😆」「そういう意地悪問題を思い付ける人もスゴい😆

参考: 麻雀の役の英語一覧はこれだ! | 調整さん

「ディープラーニングの機械翻訳は辞書に載ってない用法も扱えるから、ローカリティの高い文章はむしろ強そうですけどね」「それはありますね: 過学習(overfitting)になることもありますけど」「こういうツールは、自分が6割ぐらいわかっているものを翻訳させる分にはよくて、逆にまったく知らない分野の文章を翻訳させるとドハマリしそう😆」「やっぱり訳文を自分が吟味できないとつらいですね😅」「機械翻訳が一番向いてるのはやっぱりマニュアルかな〜」「業務で使う分にはいいと思います😋

参考: 過剰適合 - Wikipedia

⚓アルゴリズムビジュアル大事典


つっつきボイス:「アルゴリズムビジュアル大事典はどこで見かけたんだっけ…😅」「お、『アニメーション』をクリックするとアニメーションページが表示された」「お〜面白い😋」「よくぞここまで作ったと思います😍


yutaka-watanobe.github.ioより

「こうやっていろんな人があの手この手でアルゴリズムを頑張って説明してくれているんですけど、こくたまにどんなに頑張って説明してもわからない人はどうしてもわからないことがあって、一種思考の断絶みたいなものを感じることはありますね😅」「どちらかというと意欲の方が影響しそうな気がしますけど」「まあそういう人の方が多いですし、そういう人にこういうアニメーションを見せれば多少なりともわかってもらえますし☺

「このアルゴリズムアニメーションは、わかっている人がわかってない人に説明するにはよさそう👍」「後は本人の意欲と😆」「そして本買えと😆

⚓その他言語


つっつきボイス:「プログラミング言語系のSNSで見かけました」「OCaml使ってるのが京大らしいというか」「opamっていうのがOCamlのパッケージマネージャみたい」

参考: OCaml - Wikipedia
参考: opam - opam

⚓その他

⚓ワンツイートでコードを書く(StatusCode Weeklyより)


つっつきボイス:「ワンライナーのTwitter版みたいな感じですね」「140文字縛りでコードを書くのね☺」「140文字でライフゲームってスゲエ😆

「その@bbcmicrobotっていうボットにコードを投げつけると動かしてくれるとかそういう感じなのかな?」「あ、そういうサービスか!」「かなと思って: タイムライン見るとピンク・フロイドのアルバムみたいなドット絵出してたりするし↓」「コードを投げるとGIFアニにして返信してくれるってことかな😋」「いい感じの遊び場🪁

⚓番外

⚓睡眠の科学


つっつきボイス:「いやぁ〜リモートワークの何がいいって、睡眠時間をたっぷり取れること❤」「ホントにホント😍」「今日なんか9時半まで寝てたし😆」「人生における幸福感がしみじみ😂

「自分は意外にも起床時間変わってませんね😋」「何と人間的な😆」「普段でも電車の中でポッドキャストとか聞いてましたし、いつものようにやってるといつの間にか始業時間になってるんですよ😆」「自分は明日何時に起きないといけないときこそ攻めてますけど😆

「記事のアドバイスは『いつもより30分余分に寝てみましょう』でした💤」「あとは運動とかもそうですけど、サウナに行って代謝を促進させるのが効く〜💪」「たしかに😋」「不調だった頃にサウナ行ったら感動的なぐらい体調すっごくよくなりましたし🥰」「デトックスが大事ということですね😋」「何というか体内の水が入れ替わってなかった感じだったし」「サウナ行くと500mlぐらい汗かきますし」


後編は以上です。

バックナンバー(2020年度第1四半期)

週刊Railsウォッチ(20200317後編)Strangler Figパターンでリファクタリング、ペアプロ実践記事、イミュータブルデータモデルほか

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

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

Ruby Weekly

RubyFlow

160928_1638_XvIP4h

StatusCode Weekly

statuscode_weekly_banner

週刊Railsウォッチ(20200406前編)Ruby 2.7.1セキュリティ修正、RailsビューHTMLにテンプレート名を出力、Action Mailboxテスト用フォーム改良ほか

$
0
0

こんにちは、hachi8833です。オードリー・タン氏の次なる快挙です。

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

⚓臨時ニュース: Ruby 2.7.1などがリリース(セキュリティ修正)

以下でお知らせした3月のセキュリティ修正↓とは別の修正です。

Rails 6/5とRubyのJSON gem向けセキュリティ修正がリリース


つっつきボイス:「RubyのJSONに別の修正が入ったそうです」「お、これはアップグレードすべき」「手元ではアップグレード完了しました😋」「Ruby 2.7〜2.4まで対象か😳

⚓Rails: 先週の改修(Rails公式ニュースより)

今回はコミットリストから見繕いました。

⚓en_US.UTF-8環境を指定しない場合のバイトシーケンスエラーを修正

# guides/Rakefile#L14
- task :encoding do
-   %w(LANG LANGUAGE LC_ALL).each do |env_var|
-     ENV[env_var] = "en_US.UTF-8"
-   end
- end
-
  namespace :generate do
    desc "Generate HTML guides"
-   task html: :encoding do
+   task :html do
      ENV["WARNINGS"] = "1" # authors can't disable this
-     ruby "rails_guides.rb"
+     ruby "-Eutf-8:utf-8", "rails_guides.rb"
    end

    desc "Generate .mobi file. The kindlegen executable must be in your PATH. You can get it for free from http://www.amazon.com/gp/feature.html?docId=1000765211"
-   task kindle: :encoding do
+   task :kindle do
      require "kindlerb"
      unless Kindlerb.kindlegen_available?
        abort "Please run `setupkindlerb` to install kindlegen"
      end
      unless `convert` =~ /convert/
        abort "Please install ImageMagick"
      end
      ENV["KINDLE"] = "1"
      Rake::Task["guides:generate:html"].invoke
    end
  end

つっつきボイス:「Railsガイドをジェネレートするrakeコマンドの修正か」「Rails本体ではないと」

「ははぁなるほど、ロケールにen_US.UTF-8がない環境で動かすと死ぬということね😆」「これって一般的でないロケールなんでしょうか?」「いえいえ一般的なロケールです☺

「Linuxシステムに入っているロケールはOSの環境に依存します: プルリクにもあるようにコマンドプロンプトでlocale -aと打つとロケールのリストが表示されるんですけど、そこにen_US.UTF-8が入っていなければ、それに依存するコードは当然死にます🧐」「なるほど!」「やってみたら出た出た😋」「ロケールに縛りかけられている環境ってたまにありますし☺

「逆にロケールに縛られないコードを書きたければロケールにCを指定すればOK」「LANG=Cはよく使います😋」「sshした先でコンソールに日本語を出してぐちゃら〜っと文字化けしたときなんかにexport LANG=Cしたり😆」「😆」「en_USなのにUTF-8を指定する必要ってあるのかという気持ちはワカル😆

⚓新機能: previously_new_record?が追加

# activerecord/lib/active_record/persistence.rb#L431
    # オブジェクトが作成されていたときにtrueを返す。ただしsaveする前で
    # オブジェクトがデータベースに存在せず、かつ`new_record?`がtrueを返した場合。
    def previously_new_record?
      sync_with_transaction_state if @transaction_state&.finalized?
      @previously_new_record
    end

つっつきボイス:「previously_changed?になぞらえたメソッド名にしたそうです」「おっとActive Recordのdirty関連ですね😆」「また増えた😆」「普通に考えるとpreviously_new_record?ってぱっと意味わかりにくいし😅」「直前がnew recordだった場合か🤔」「ちょっと微妙な響き😆」「こういうのが欲しいときがあるのか😅

Active Recordモデルにpreviously_new_record?メソッドを追加した。これはモデルが新しいレコードで、最後に保存する前の状態の場合にtrueを返す。x_previously_changed?メソッドになぞらえてpreviously_new_record?という名前にした。

「今日は新メンバーもつっつき会にROM参加しているので、もしわからなければ”active record dirty”で検索してみるといいと思います😋」「ソースコードはだいぶ泥臭いと思いますけど😆」「たまにバグってたりしますし😆」「dirty周りの直しって割とよくありますね」「シンプルに使えばいいと思うんですけど、極まった使い方をする人がいたりしますし😆

参考: 1.4 Dirtyモジュール — Active Model の基礎 - Railsガイド

⚓Base64のstrict_decode64urlsafe_decode64に変更

# actionpack/lib/action_controller/metal/request_forgery_protection.rb#L394
      def real_csrf_token(session) # :doc:
-       session[:_csrf_token] ||= SecureRandom.base64(AUTHENTICITY_TOKEN_LENGTH)
-       Base64.strict_decode64(session[:_csrf_token])
+       session[:_csrf_token] ||= SecureRandom.urlsafe_base64(AUTHENTICITY_TOKEN_LENGTH, padding: false)
+       Base64.urlsafe_decode64(session[:_csrf_token])
      end

Base64 strict-encoded CSRFトークンはwebsafeを継承していないので扱いが難しかった。たとえばCSRFトークンをクライアントリーダブルなcookieでブラウザに送信するのによく使われる方法が簡単には使えない。無事に送信するには値がurl-encodedかつurl-decodedでなければならない。
今回Base64 urlsafe-encoded CSRFトークンを生成するようにした。これは送信への継承が安全である。後方互換性のためバリデーションはurlsafeトークンとstrict-encodedトークンの両方を受け取れる。
同コミットより大意


つっつきボイス:「strict-encodedなCSRFトークンってそもそも何だろう?🤔」「そういえばBase64そのものは特殊文字も含めてエンコードできるんだった」

strict_encodedstrict_decode64のRuby APIを見ると『このメソッドは [RFC4648] に対応しています』とある」「そしてurlsafe_encode64urlsafe_decode64は、URLでも使われる+/を別の文字に置き換えてエンコードするのね😳

このメソッドは [RFC4648] の “Base 64 Encoding with URL and Filename Safe Alphabet” に対応しています。 “+” を “-” に “/” を “_” に置き換えます。
同APIより

「そしてRFC 4684の5章を見ると『ファイル名セーフなアルファベット』にするとある、ははぁこれか!」「ファイル名セーフにしたいときはたしかにある」「~なんかも置き換えられると」「おぉ」「RFCで定義されてるなら大丈夫そう😋

参考: RFC 4648 - The Base16, Base32, and Base64 Data Encodings


RFC 4648より

⚓さまざまなBase-nエンコーディング

「どうやらBase32なんてのもあるらしいし😆」「おほ、数字の1とかがないのが面白い↓」「不思議😳」「何か意図があるんでしょうね〜」「アルファベット大文字のアイIと紛らわしくないようにとか?」「それあるかも!」「ゼロ0がないのも大文字のオーOと紛らわしくならないようにということだったりして🤔」「よくそんなの気づきますね👍」「いえいえ😅」「言われてみればプリンタブル&ビューマンリーダブルなエンコードっぽい」


RFC 4648より

「Base16もある〜😆」「これはそのまんま16進数か😆」「さすがにBase8はない😆」「プルリクと関係ない話になったけど学びある🧐」「ともあれCSRFトークンにurlsafeを使うべきというのもごもっとも👍


RFC 4648より

⚓新機能: Action Mailboxで受信メールをフォームのsourceに貼ってテスト配信

# actionmailbox/app/controllers/rails/conductor/action_mailbox/inbound_emails/sources_controller.rb#L3
+module Rails
+ class Conductor::ActionMailbox::InboundEmails::SourcesController < Rails::Conductor::BaseController
+   def new
+   end
+
+   def create
+     inbound_email = ActionMailbox::InboundEmail.create_and_extract_message_id! params[:source]
+     redirect_to main_app.rails_conductor_inbound_email_url(inbound_email)
+   end
+ end
+end

emlファイルを貼り付けてテストするのに便利。
同PRより大意

DHH自らのプルリクです。


つっつきボイス:「テストでうれしい改良みたいですけど、sourceっていうのが何を指すんだろうと思って」「Action Mailboxみたい」

「あ〜そういうことか!: Action Mailboxのデフォルトのジェネレータで生成されるフォームにこれがあるんですよ」「おぉ?」「Action Mailboxはメールの受信をトリガとして動くんですけど、ローカルテスト用に受信メール送信フォームがscaffoldで作られます」「ふむふむ」「これはRailsの普通のscaffoldと同じようなフォームになっていて、Newを押してsubjectとbodyを入力できるようになっているんですけど、このsourceというのはいわゆるメールのemlファイルをそこにべたっと貼り付けられるようになっているということですね🧐」「あ〜そういうことですか!😳」「コミットメッセージに書いてあったemlってタイポかと思ったらファイル形式でしたか😅

「じゃテストでうれしいというのは…」「今までのAction Mailboxのフォームだと、たとえば添付ファイルが複数あるメールとか、HTMLメールとプレーンテキストメールの組み合わせとかを送信できなかったんですよ: そういうのはMultipart形式でboundaryとかを書かないといけないので」「はぁ〜なるほど」「そういうメールを生でフォームにコピペできるようにしたということですね😋」「これはたしかに欲しい😋」「任意の添付ファイルチェックみたいに、これがないとテストできないケースはたしかにありますね☺

以下は銀座RailsでのAction Mailbox解説スライドです(発表: morimorihoge

⚓Active SupportのRange#cover?の挙動をRubyに合わせて修正した

# activesupport/lib/active_support/core_ext/range/compare_range.rb#L66
    def cover?(value)
      if value.is_a?(::Range)
+       is_backwards_op = value.exclude_end? ? :>= : :>
+       return false if value.begin && value.end && value.begin.send(is_backwards_op, value.end)
        # 1...10 covers 1..9 but it does not cover 1..10.
        # 1..10 covers 1...11 but it does not cover 1...12.
        operator = exclude_end? && !value.exclude_end? ? :< : :<=
        value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
        super(value.first) && (self.end.nil? || value_max.send(operator, last))
      else
        super
      end
    end

つっつきボイス:「Rubyのcover?とActive Supportのcover?の挙動が違ってたのを修正したそうです」「cover(6..3)みたいに逆順に書けるって知りませんでした😳」「そんな書き方したことない〜😆」「手元でirbしてみるとたしかに逆順で書ける!」「こういう書き方がありだったとは😆」「よくぞ見つけた😆」「===include?も同様に更新されてますね😋

# Rubyの場合
(1..10).cover?(6..3) #=> false

# Railsコンソール(Active Suport)の場合
(1..10).cover?(6..3) #=> true

⚓ビューのHTMLにテンプレート名を含められるようにした


同PRより


つっつきボイス:「ビューにテンプレート名を表示?」「おぉぉなるほど、こういうコンフィグ↓でテンプレート名を表示できるのか、これいいじゃん❤❤」「おお喜びに満ちてる🥰

config.action_view.annotate_template_file_namesを設定すると、各テンプレートの開始位置と終了位置を示すHTMLコメントがレンダリング出力に追加される。@jhawthornが#35407で導入したステキなActionView::Template#short_identifierが使われる。
(メモ: ChromeはHTMLタグの外にあるHTMLコメントをbodyの内側に移動する。<!-- END app/views/layouts/application.html.erb -->が本来ドキュメント全体の閉じタグであるにもかかわらずbodyの内側にある理由はこれ。)
本PRは@tenderloveとの共作。
同PRより抜粋・大意

「どこからどこまでがテンプレートなのかわからなくなるので入れたんですね」「これはデバッグ用にとっても欲しい😘」「今までは自分でテンプレート名を入力してたりしましたし」「自分で書いたビューならまだしも、他人の書いたビューのコードでパーシャルが大量に使われていたりするとつらいんですよ😢」「とくに複数のパーシャルの出力が互いにとってもよく似てたりするとなおさら😭

「さらに厄介なのはパーシャルのパスの解決順序: 基本的には今いるディレクトリから近いところを探すんですけど、ない場合は親ディレクトリをたどったりするので、そこにあるパーシャルの出力がほとんど同じだったりすると、今ここで出力されているのはいったいどっちのパーシャルなんだ?ということになったりしますし😡」「あああ😅」「こういうことが割と普通によく起きるんですよホント😇」「ビューのこういう調査ってしんどい😭

「とにかくこれはいい機能👍👍」「ローカルのdevelopmentだけで使うんですよね?」「もちろんローカルとかstagingとか限定で☺

⚓番外: 存在しないenumがクエリにある場合にエラーを出すようにした(revertされました)

アプリにこの挙動を入れるとびっくりさせすぎるので取り消した。デフォルトでraiseするより先に振る舞いを非推奨化する必要がある。
@f3dfed7より

# @f3dfed7より
# activerecord/lib/active_record/enum.rb#L142
      def serialize(value)
-       assert_valid_value(value)
        mapping.fetch(value, value)
      end

つっつきボイス:「存在しないenumをクエリで使った場合のエラーか」「びっくりさせすぎるということでコミットが取り消されてました」

⚓データベースのenumは考えてから使おう

「ちなみに自分はenum好きじゃないのであんまり使わない😆」「😆」「もちろん好みはあると思うんですけど、enum使うとデータベースの出力がわかりにくくなるんですよ😅

参考: 8.7. 列挙型 — PostgreSQL 11

「自分はバグ修正とかするときには、Railsコンソールでやるよりも昔ながらのSQLを最終的に書きたいタイプなんですけど、enumを使われると、値の意味を知るのに毎回ソースコードを見にいかないといけなくなる😭

参考: RailsのEnum: 諸刃の剣(1) from Viblo | Framgia Journal

「まあ最近のRailsだとenumを参照すると一応Rails側のキーの文字列で取れるんですけど」「ひどいときはテーブルAでは0がactiveなのにテーブルBでは1がactive、なんていうプロジェクトがあったり😭」「あぁ…😅」「そういうプロジェクトで障害調査のためにSQLを書くと結果のenumのところでマジわからなくなりますし😤」「お察しします😅」「enumを使われるとSQLで調査したいときにSQL出力がリーダブルにならないのがホント困る😢

参考: Rails5でenum定義したカラムの元の値を取得 - Qiita
参考: ActiveRecordのEnumの取り扱い方 - Qiita

「まあデータベースの管理権限があれば、最悪の場合enumを展開したデータベースビューを定義してそっちをSELECTする手が使えるんですけど、それもできないときはCASEとWHENをひたすら使ってenumを文字列に戻す神SQLを書いたりしますし」(一同ソースを見て)「うぅ、これはつらそう😅」「こうしないとヒューマンリーダブルにならないのってつらすぎるし」「戻すときの対応関係を間違えたりするとさらに地獄👿」「正直、よほどでかくない限りenumにしても大して速くなりませんし😆」「😆

⚓Rails

⚓DID.appでパスワードレス認証(RubyFlowより)


did.appより


つっつきボイス:「このdid.appというのがパスワードレス認証サービスをやってるそうです」「こういうふうに↓認証部分をdid.appにリダイレクトできるということか」「あとはルーティングにちょっと手を入れてコントローラにコールバックを追加すればいいと」「Railsでこうやれば私たちのサービスで認証できますよと」「OmniAuthとかに近そう😋

<!-- 同記事より -->
<form action="https://auth.did.app/oidc/authorize" method="get">
  <input name="client_id" value="<%= ENV["CLIENT_ID"] %>" type="hidden" />
  <input name="redirect_uri" value="<%= callback_url %>" type="hidden" />

  <button type="submit">Sign in</button>
</form>
# 同記事より
require 'faraday'
require 'json'

class SessionController < ApplicationController
  def callback
    response = Faraday.post(
      "https://auth.did.app/oidc/token",
      client_id: ENV["CLIENT_ID"],
      client_secret: ENV["CLIENT_SECRET"],
      code: params["code"]
    )
    data = JSON.parse(response.body)

    session[:current_user_id] = data["userinfo"]["sub"]
    redirect_to root_path
  end
end

「いわゆるCRM(Customer Relationship Management)系のサービスなんでしょうね☺」「ユーザー管理以外にもいろいろやってくれるんでしょうきっと」「1000ユーザーまでは無料か🤔」「なるほどそういうサービスですか」

参考: CRMとは何ですか? ~メリットデメリット & 活用と運用のコツ~

「こういう部分の実装は面倒なので、外に出したい気持ちはありますね」「たしかに」「1つのアプリだけメンテするならともかく、自分でホスティングしている認証サービスを他のアプリでも共用するようになってくると、その認証サービスが落ちた瞬間に他のアプリが全部動かなくなりますし」「あ、そうか😳」「そういう状態になってしまうと、計画メンテがとてもやりにくくなってしまう😅」「ですね…」

「結局システム間依存が増えれば増えるほど容易に止められなくなってしまうんですよ: たとえばあるシステムは夜中ならほぼ誰も使っていないからと思って夜中にデカくて重いバッチを走らせてみたら、そこに依存していた他のシステムが止まったなんてことになりかねませんし😇」「う〜む」「そういう依存度を下げるためにこういうサービスを使うのはひとつの方法になると思います☺

「まあGoogle認証とかOAuth 2とかでもいいと思いますけど😆」「自分もそれにしようかな…」「ただそういうサービスは認証しかやらないので、計測みたいな他の便利な機能はありません🧐」「あ、そうか」「まあ単なる認証と目的が違うので: このdid.appがやっているようなカスタムブランディングとかアクティブユーザーインサイトみたいな情報はOAuth 2とかだけでは取れませんし」「そういうのがやりたいときにはいいんじゃないでしょうか☺

参考: Google 2 段階認証プロセス
参考: OAuth 2.0 — OAuth

⚓Railsでマルチステップのフォームを作る方法(Ruby Weeklyより)


つっつきボイス:「いわゆるウィザード的なフォームをRailsでやる記事です」「こういうマルチステップフォームってRailsのCRUDと相性が悪いんでしたっけ?」「まあマルチステップフォームは既にCRUDじゃないので😆

「こういうのはForm Objectを作ればだいたいやれますけど」「そういえば今日はいませんけど、kazzさんが以前こういうフォームは面倒じゃ〜って言いながら作ってました」「マルチステップのフォームは、フロントエンドでやるのかバックエンドでやるのかを決めるのも含めて、いろいろ面倒😆」「ですね😆

「マルチステップのフォームをフロントエンドでやるならRails側は基本的にCRUDでいいんですけど、Rails側も多少マルチステップを意識した実装にしないと親切なフォームを作るのは難しいんですよ😅」「うーむ」「たとえばマルチステップの第一段階でサーバーサイドでのバリデーションが必要なチェックが入ると、結局ステップ1用のバリデーションを用意しないといけなくなりますし」「なるほど」「よくあるのが、ユーザーアカウントを作成するときのアカウント重複チェックなんですけど、そういうふうに項目がまだ全部入力されてないけどバリデーションしたいことも多いですし」「バリデーションを個別のAPIにバラしてフォーム送信前にチェックする方法も考えられますけど、今度は複数項目を組み合わせてバリデーションしたくなることもありますし😆

「マルチステップフォームはどうやっても面倒になりますし、結局この面倒臭さをフロントとバックエンドのどちらで巻き取るかでしょうね☺」「どちらかに寄せるのがいいと思います」


記事要点:

  • 各ステップが単独のActive Recordモデルにだけ関連する分にはやりやすい
  • 各ステップとモデルが1対1対応しないと面倒になる
  • wicked gemを使う手もあるが、自分は外部ライブラリに依存しない方法を選んだ
    • マルチステップフォームは案件に固有なものが多いのでgemがうまくはまるとは限らないと思った
  • session storageに保存しておいて最後にまとめる方法は必ずしも必要とは限らない
  • 大事なのは、マルチステップフォームをわかりやすいコードで書いてメンテ可能に保つこと
    • 名前空間を使うなど

⚓Railsのセキュリティベストプラクティスと脆弱性リスト、そしてRails脆弱性の賞金サイト


同記事より


つっつきボイス:「今回はこれも含めて長い記事が多くなりました😅」「なるほど、こういう賞金を稼げるサイト↓も紹介されてますね😋」「おぉ💰」「Railsのクリティカルな脆弱性を見つけると15万円もらえる😆」「😆」「😆


hackerone.com/railsより

「こうやってセキュリティに賞金をかけるのは最近一般的になりましたね」「インセンティブで釣るのが大事😋」「賞金だけで食べてる人はそんなに多くはないようですけど、実際にいるみたいですヨ❤」「こういうのはだいたいドルベースなので、物価の安い国なら一発当てるとしばらく暮らせたりするようですし🏝」「むふふ😋」「日本でもこれで生活してるっぽい人が何人かいるようですし、まあどこかに所属してる人も多いんでしょうけど😆

「それこそ今話題のZoomも賞金かけるんじゃ?😆」「😆」「例のZoomの声明↓でも、たしかその辺の対応を始めるって載ってたと思います☺」「賞金を拡充するってありますね」「HackerOneにはまだZoomはないっぽいですけど😆

参考: A Message to Our Users - Zoom Blog

「まあRailsの場合はとりあえずセキュリティ系のgemを入れておくことでしょう☺」「あとRailsセキュリティガイドも読んでおくと」「こういうのは世の中でよいとされているものを入れておくのが好き🥰」「こういうドキュメントを読み込むのはとても勉強になりますね👍

参考: Rails セキュリティガイド - Railsガイド

なおOWASP.orgのRailsのセキュリティ項目はなぜかなくなっていました↓。

参考: 404 - Not Found | OWASP — リンク切れ

⚓時刻を丸めるときのちょっとしたテクニック(Hacklinesより)


つっつきボイス:「すごく小ネタなのでコードは引用しませんが、Railsで時刻と時刻の差を丸めたいときにActive SupportのTime#changeでやれば割り算しなくていいよという記事でした」「なるほど😋」「これは使ったことなかったな〜」

参考: Time の一部を自由自在に改変したい - Qiita

⚓その他Rails


つっつきボイス:「今年のRailsConfは、Couch Editionという名称でオンライン開催を目指しているそうです」「おおDHHにGitHubのUchitelleとAaron Patterson、錚々たるメンツ👍」「オンライン開催になったことで日本人としてはむしろ参加しやすくなった感ありますね🥰」「もちろん現地に飛んで会うからこそ得られるものもありますけど😆」「そこですよね…😅


前編は以上です。

バックナンバー(2020年度第1四半期)

週刊Railsウォッチ(20200317後編)Strangler Figパターンでリファクタリング、ペアプロ実践記事、イミュータブルデータモデルほか

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

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

Ruby 公式ニュース

Rails公式ニュース

Ruby Weekly

RubyFlow

160928_1638_XvIP4h

Hacklines

Hacklines

週刊Railsウォッチ(20200407後編)RubyのTracePointでデバッグ、Rubyとモナド、Gitノウハウ集、リモートワークほか

$
0
0

こんにちは、hachi8833です。リモートワークでは、高品質のマイクの他に高品質の椅子も重要ということが判明しつつあるようです。

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

⚓Ruby

⚓TracePointで変わるRubyのデバッグ


つっつきボイス:「st0012さんがあのAppSignalに書いた記事です」「RubyのTracePointはデバッグの奥の手になりそうですね😋

「今日Webチーム内発表でRailsとOracleでつらい目に遭った話があったんですけど、ああいうキツいデバッグをやるときにTracePointを知ってるかどうかで違いが出るんじゃないかなと思います☺」「そうですね」「よくわからないライブラリやものすごく巨大なライブラリと戦うときは、こういうのを知らないと手当り次第のアプローチになってしまいそうですし😆」「自分は今は別チームなので発表のスライドだけ見ましたけど、Oracleと戦うのがツラいことだけはとってもよくわかりました🤣」「🤣」「まあOracleの問題というよりはアプリの設計がね😆


記事要点:

  • バグの発見より、しくみを理解する方が大変
  • メソッド呼び出しレベルまで掘り下げて調べるのは時間がかかる。
  • デバッグとは「プログラムと設計を理解すること」
    • 期待される動作を設計から学ぶ
  • いい情報はお高い
  • TracePointが味方になってくれる

⚓TruffleRubyの最適化を解除する(Hacklinesより)


同記事より


つっつきボイス:「ShopifyがTruffleRubyを最適化した記事です」「最適化を一部解除するというのはありそう☺」「大変そうですね😅」「TruffleRubyはJVMに何とかしてもらえますし😆」「JVMってやたらスピード速いですし」「あの進化の早さはヤバい💪

参考: Java仮想マシン - Wikipedia


記事要点:

  • Shopifyは1年ほど前からTruffleRubyの改良を手掛けている
    • TruffleRubyはoptcarrotでCRubyの9倍もの速度を叩き出している
  • Rubyのlazy初期化とは
  • Rubyの慣用的な用法を分析する
  • TruffleRubyでコンパイルする
  • 「最適化解除」を実装する
  • ベンチマークがどのぐらい改善されたか
    • コンパイル速度は6%、メモリ上のマシンコードは63%削減
  • Truffleは実は「トリュフチョコレート」から命名された(チョコの箱のモジュラリティーの高さから)
  • Shopifyは本番アプリケーションでのTruffleRuby利用実験をリードし、CRuby/MRIやSorbetにもコントリビュートしている

⚓Rubyにモナドは必要なのか?


つっつきボイス:「長い記事ですが、最近kazzさんがモナドやってるので拾ってみました」

「記事は、モナドは本当に要るのか?静的型付けの世界じゃないとうまくハマりにくいのでは?みたいなことを書いてますね」「モナドにしたことで本当にうまくいくケースもあれば、趣味以上のものにならないことも大いにありますね😆」「😆

「kazzさんがこの間Webチームで発表したときのモナドの使い方は、まさにモナド向きのケース👍」「そう思いました😋」「いろんな計算式の仕様が今後どんどん変わる可能性があるときに、ある計算式がその後の計算式に影響するのをなるべく柔軟に扱いたいという、要するにExcelシート的なことがやりたい😆」「😆

「原文で面白かったのがThe beef with monadsという言い方で、beefは『不満のポイント』というニュアンスだと初めて知りました」「へぇえ😆」「美味しいポイントかと思ったら『ここがイヤだ』だったという😆

「モナドは作ってるときが一番楽しいのでオーバーエンジニアリングになりがち☺」「使い所を間違えると単に遅くなったりとか😆」「モナドは使い所を気にしておかないと読みにくくなって遅くなったりしますけど、効果的な場所に用いればよいものですね☺」「なるほど」

参考: モナドの意味 - Hexirp’s Blog


記事要点:

  • モナドの実用的かつ情緒的な側面を記事にしてみたいと思った
  • モナドとは
    • 「モナドは単に自己関手の圏におけるモノイド」という説明は網羅的だがよくわからん
    • むしろ「特定の方法」による抽象を表す数学的な名前と考えたい
  • 自分が聞いた「モナドのここがイヤだ」説
    • 静的型付けでしか有用でなく、Rubyではトラブルの種にしかならない
    • 関数型プログラミングはRubyに似合わない
    • モナドはRubyに似合わない
    • Resultは単にifとelseのシンタックスシュガーだろう
    • Rubyには例外があるじゃないか
    • モナド信者がカルトっぽい
    • RubyにHaskellを持ち込むのってどうよ
  • Rubyはモナドにふさわしいか
  • Rubyでのモナドコード例
    • 基本
    • 複数の操作のコンポジション(2例)
    • 計算結果を利用する(4例)
  • Rubyでモナドを使うとこうなる
    • ブロックの利用頻度が増える
    • 不要なネーミングをしなくて済む
    • オブジェクトをnewでビルドしなくて済む
    • 欲しい抽象化をつまみ食いできる
    • include一発で欲しいものをつまみ食いできる
    • 条件ロジックで述語が使われる
    • caseやパターンマッチングで大きなサポートを得られる
    • ライブラリがyieldに新しいセマンティクスを持ち込む
    • 「関数型」プログラミング部分は純粋に有用
  • Rubyの例外とは
  • 自分の考え
  • チームをどう説得するか
  • 「Rubyにモナドは必要なのか?」への回答
  • まとめ

⚓その他Ruby

⚓DB

⚓PostgreSQLのインデックスメンテナンスで便利なクエリ集(Postgres Weeklyより)


つっつきボイス:「Perconaブログの記事です」「ぽすぐれのDDLからデータを引っ張ってくる方法とかですね☺」「is_uniqueなんてのがあるのか」

-- 同記事より
SELECT    i.relname AS index_name,
          indisunique is_unique
FROM      pg_class c
JOIN      pg_index x ON c.oid = x.indrelid
JOIN      pg_class i ON i.oid = x.indexrelid
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE     c.relkind = ANY (ARRAY['r', 't'])
AND       c.relname LIKE 'pgbench_accounts';
       index_name       | is_unique 
------------------------+-----------
 pgbench_accounts_pkey  | t
 pgbench_accounts_index | f
(2 rows)

後で見つけましたが、PostgreSQLのWikiにも有用な日本語情報がありますね。

「この記事は、いわゆるDBアドミニストレータ(DBA)向けの記事という感じですね: どのデータにどういうインデックスを効かせるかというのはアプリエンジニアもやりますけど、実際に大量のデータが入ってきたときにどうするかという話がメイン」「ぽすぐれをディープにやりたい人にいいと思います😋」「なるほど!」


掲載されているクエリの概要

  • テーブルにインデックスがいくつあるかを調べる
  • uniqueインデックスかそうでないかを調べる
  • インデックスのサイズを簡単に調べる
  • テーブルサイズとインデックスサイズを表示する
  • インデックスを作成したときのクエリを取得する
  • テーブルをブロックせずに再インデックスするコマンド
  • そのインデックスでサポートされているデータ型のリストを取得する
  • 使われていないインデックスを調べる
  • インデックスが重複しているかどうかを調べる

⚓リモートワーク

⚓Zoom騒動

Zoomについては続報が大量に出ていますが、ここではつっつき時点のものを中心にメモしました。


つっつきボイス:「そうそう、さっきBPS社内Slackのzoomチャンネルにも貼りましたけど、Zoomが反省文出してましたね↓」「90日間は新規開発を止めてセキュリティ対応と既存問題の修正に集中すると」

「まあZoomの問題はかなりヤバい😆」「実際セキュリティが厳し目の会社だと割とZoom禁止にしてたりしますし🚫」「機能リストで『End to Endエンクリプション』を謳っていたのに実際はそうではなかったという😆」「それは痛い😆」「仕様に記載されてない部分に穴があるのも十分困るけど、機能として謳っているのに実はできませんでしたというのはいくらなんでも🤣」「ひどい🤣

「End to Endエンクリプションが実はユーザーとZoomのサーバーの間のことだったって、そういうのはEnd to Endとは言いませんし😆」「しびれる😆」「実際End to Endエンクリプションをやってたらクラウド録画とかできないはずだし」「あ〜たしかに!」「やるとしても一度ユーザーのローカルに保存してから送るとかしないといけないでしょうし、というふうにいろいろ思い当たる😆」「ともあれZoomがこうやって批判にさらされて改良されていくプロセスは健全だと思いますね☺

ミーティングには少なくともパスワードを設定しておきたいですね。

⚓リモートワークツールの期間限定無料化続々


つっつきボイス:「AWS WorkSpaces無料化の話ありましたね」「AWS WorkSpacesはWindowsのインスタンスとかを立ててVNCでデスクトップ環境につなげるサービスだったと思います」「一時期流行ったVDI」

参考: Amazon WorkSpaces(セキュアな仮想デスクトップ(VDI)サービス )| AWS
参考: デスクトップ仮想化 - Wikipedia

「WorkSpacesって重そうですけど」「自分もだいぶ前に使ってみたことありますけど重くてちょっとな〜と思った覚えあります😅」「デスクトップ環境をインターネット越しに使えば遅いのは当たり前😆」「どうやっても遅そう😆

「セキュリティを気にする組織にはいいんでしょうね」「端末にデータが残らないので安全度は高まりますし、何かあったらアカウントロックしちゃえばいいし🗝」「ですね」「コントロールできないということが一番怖いですし」「まあこういう環境で仕事しろと言われたらおさらばするかな🤣」「🤣」「🤣」「やるならお金うんと摘んでもらって🤣」「迷惑料欲しいレベル🤣

「環境を作るのに20万円以内に収めないと消耗品扱いされなかったりしますけど、20万円だと基本的人権が満たされないのではって思いますし🤣」「🤣」「まあThinkPadに移行してからは20万以内でもやれる感じになりましたけど、Macbookで20万円以内はキビシイ💵」「Macbookキビシイです😭」「まあちょっと前までは8GBぐらいしか積めなかったのが、今は20万円以内でもメモリ16GB積めるようになりましたけど」

「WorkSpacesみたいなのは自分は使いたくないけど😆、セキュリティという面で必要になることはありますし、端末を相手に預けるのはいろいろリスキーでもあるので、ひとつのやり方ではあると思います☺

「NutanixのXi Frameは同じようなヤツかなと思ったらブラウザで上で仮想デスクトップやれるのね😳」「Adobeもビデオ会議やってるとは知らなかった😳」「こうしてみるといろんなところが参入してますね」

「今Zoomがああだから他のビデオ会議はチャンスとばかり力入れそう😆」「それはあるでしょうね☺」「Zoomがいち早くセキュリティ何とかする声明を出したのもその対策でしょうし」「今ユーザー企業はどこも『自分たちの業務が止まらないこと』という視点でビデオ会議システムを血眼で比較していますし」「Zoomがあのままだと企業のシス管から一番ダメだしを食らいそうなので、Zoomとしては現在のチャンスを逃さないために何としてもここで的確に対応して巻き返しをはかりたいところでしょうね」「せっかく株価も爆上げしてるし、ここで頑張らないと」「まさにビデオ会議戦国時代」

⚓その他リモートワーク

つっつきボイス:「そのMicro Sniffは今自分のMacに入れてみてます」「ああ、マイクが知らないうちにオンになってたらわかるヤツ」「そういえば最近だとノートPC内蔵のカメラは使用中にランプ点きますし、シャッターで閉じられるようになってますね」「自分も外付けでシャッターつけてます」「へぇ〜、あるけど使ったことなかった(シャッター閉めてみる)、お消えた消えた」「今どきはいろんなソフトがカメラやマイクにアクセスしようとするので、自分も基本閉じてます☺


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

⚓Rails 6アプリをAWS Elastic BeanstalkとRDSに置く理由(Ruby Weeklyより)


つっつきボイス:「細かいことができないのけど楽にやれるHerokuを選ぶか、つらみもあるけどフルフィーチャーのElastic Beanstalkを選ぶかみたいな感じでした」「自分はElastic BeansTalkでRailsをやるのがいい選択肢とはあんまり思わないかな〜😆

参考: AWS Elastic Beanstalk(ウェブアプリの実行と管理)| AWS

「まあElastic BeansTalkはわかりやすいというメリットはありますね: Elastic BeansTalkはAWSのEC2連携サービスとしては割と歴史が長くて、普通にEC2のインスタンスを起動する以外に、所定のスクリプトを動かすことができます🧐」「おぉ」「言ってみればVMのオーケストレーション的なことができる🎻

「ただやってることはシェルスクリプト動かすのと大差ないので泥臭いんですけど😆」「ホント😆」「あと起動時に変数を流し込むことができるので多少それで制御できる、ただしそのスクリプトは自分で書け、という😆」「😆」「なので自分はElastic Beanstalkで構築するのはダルい😆」「自分はHerokuのままでいいかな…」「HerokuはHerokuで独自ルールありますけどね☺

「記事にもありますけど、Elastic Beanstalkにはテンプレートもいろいろ用意されています: でもこういうのってだいたいそうなんですけど、Railsでやる場合このテンプレートに乗せるという前提でRailsアプリを開発することになりますね」「なるほど」「アプリを作った後でテンプレートに乗せるのは面倒😆」「ただ最近だと状況は違うのかもしれませんね: 自分が新規でRailsアプリ作るならHerokuは選ばないと思いますけど」「Herokuはスケールしにくいという話もありましたね」「どんなふうに育つかわからないアプリは、Herokuに乗せると後になって『Herokuではできません』になりそう😅」「まあ最近のHerokuはコンテナでやれるのでまた違うかなと思います☺

⚓その他インフラ

  • サイト: Netflix Party — ねとふりを複数で見るChrome拡張

つっつきボイス:「この間BPS社内Slackに貼っていただいたヤツです」「そうそう、これなかなか良さそう❤」「これは何でしょう?」「複数人でNetFlixの同じ動画を再生できるんですよ」「あ〜つまりリモートで同じ映画を見られるんですか😳」「しかも再生の一時停止とかも含めて連動するみたいですよ」「じゃ『今のシーンちょっと巻き戻すね』とかがやれるんですね🎬」「それそれ😋」「今期アニメの第一話鑑賞会とかやるのにいいんじゃねってこの間話題にしました😆」「なるほど〜、いいユースケースですね😋

「全員NetFlixに加入してないとやっぱりダメでしょうか?」「そりゃ当然: 誰かのアカウントだけで配信したら完全NGでしょう🤣」「🤣」「これはNetFlixとは別のサードパーティなのかな?」「だと思います」

「昨今リモート飲み会みたいな話もよく出ますけど、あれって意外と盛り上がりづらかったりするじゃないですか: むしろこうやって同じ動画を見ながらそれを肴に盛り上がる方がやりやすいのではと🍶」「言えてますね😋」「やってみようかな〜😋

⚓JavaScript

⚓Leaky Abstractionとは


つっつきボイス:「この記事をどこに置くか迷ったんですがJavaScriptに置いてみました」

「カプセル化とかのおかげでとても簡単にやれるようになったはずなのに内部実装の都合とかで遅くなったりするという、よくある話みたいですね☺」「たしかによくある話😆」「でもレイヤ化するとどうしてもそうなっちゃうんですけど😆」「例に出されているのもTCP/IPとかRPCとかコンテナとか、たいていのものが該当してますし」「そしてうんと速くなければいけない場合には、下のレイヤも覗けるインターフェイスを用意しようということになって、そのうちクロスレイヤアプローチみたいになってわけわからなくなったりしそう🤣」「🤣」「でせっかくレイヤ化してたのがお漏らししちゃったり😆

「結局レイヤを新しく再編成しておしまいというオチになったりしそうですけど😆」「ネットワークカードのドライバなんかは、概念上はTCP/IPがあってMACがあって…みたいにレイヤ化されていますけど、実際にはそういうふうになっていなくて、一度メモリに乗せたものをパケットに転送するんじゃなくて、いきなりデバイスのメモリ領域に突っ込んだりすることで、メモリコピーをできる限り減らすようになってるんですよ」「そういえばそうですね😳」「そういうデバイスドライバが特定のパターンでお漏らしするような問題があったりすると、デバイスドライバのバグをアプリケーション層から叩けるなんてことがごくまれにあったりします🤣」「🤣

「ともあれLeaky Abstractionという言葉があるのは初めて知りました」「概念の範囲がめちゃ広くてちょっと戸惑います😅」「潔癖といえば潔癖かも」「こういうのは抽象化につきものですし☺」「ですね☺

「上のスライドを作った新山さんという方のブログを昔ずっと読んでたことがあって、研究者らしいということ以外よくわかっていないんですが😆」「設計する人ならこういうLeaky Abstractionみたいなところを押さえておくといいでしょうね☺

参考: Leaky abstraction - Wikipedia
参考: たべすぎ・ねっと (tabesugi.net)

⚓RubyのEnumerableの抽象化

「そういえばRubyのEnumerableとかもピュアに使うと遅くなるんですよ」「ありそう😅」「本来はeachだけ定義してからEnumerableをincludeすれば他の機能も使えるようになるんですけど、コレクションの型によってはすごく重くなるので、そういうのはもっと速い実装でオーバーライドして特異メソッドを作ったりしますよね😆」「気持ちはわかります😆」「そういう話がぱっと出てくるようになれば、とりあえずいいんじゃないかなと思います☺

⚓その他JS

つっつきボイス:「Matzがリツイートしてたので、『型宣言が必要なときなんてない』が刺さったのかなと」「まあどんなシステムも作っているうちに確実にでかくなってきますし、最初から使い捨てのつもりだったらあえてJSでやるという選択肢もあるかなと思いますけど」「大きくなるかどうかわからないシステムはたいてい大きくなる😆」「😆」「わからない場合はたぶん育つからTypeScriptにしとく方がいいのかな〜とは思いますね☺

⚓CSS/HTML/フロントエンド/テスト

⚓vm/vh/vmin/vmax

参考: CSS には vw, vh, vmin, vmax という単位がある | Developers.IO


つっつきボイス:「この辺の長さの単位は、マイクロソフトの認定試験↓で出た覚えある😆」「😆」「vhとかは今は割と普通に使いますよ😋」「この方面はあんまり…😆」「こういうvhとかvmとかでないと書くのが難しいものってそこそこあります🧐

参考: 試験 70-480: HTML5 と JavaScript および CSS3 との組み合わせによるプログラミング

⚓ブラウザのviewport

「いわゆるviewportのサイズなんかがそうなんですけど、皆さんviewportはわかります?」「あんまり😅」「あんまり😅」「今見ているブラウザの、画面で今レンダリングされている部分がviewportです」「今見えている部分でしょうか?」「たとえば画面を拡大するとviewportが小さくなりますし、縮小するとviewportが大きくなります🧐」「ははぁなるほど!」「スクロールするとviewportが移動するということでしょうか?」「スクロールしてもviewportのサイズは変わらないので、スクロールはまた別だと思います☺」「あ、そうでしたか😅

参考: meta要素でビューポートを指定する-ウェブ制作チュートリアル

「いわゆるレスポンシブの設定でこういうの↓をmetaタグに書きますけど、これがまさにviewport」「なるほど!」「ここでは横幅はdevice-widthがあればその値を使うんですけど、これがあると横スクロールしなくなります」「ふむふむ」「initial-scale=1.0がないと4倍ディスプレイとかでおかしくなった覚えがあります: viewportは組み合わせで挙動が変わるので全部は把握してませんが😅

<!DOCTYPE html>
<html lang="en-US">
<head>
  <meta charset="UTF-8">
  <title>週刊Railsウォッチ(20200407後編)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社</title>
  <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=yes">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">

「話を戻すと、vhとかはviewportに対する相対サイズなので、現在レンダリングされているviewportからしか算出できません」「ふ〜む🤔」「だからレスポンシブでよく使われるのか😳」「viewportの幅に応じて要素の幅を変えたりするデザインは最近よくありますね☺

⚓言語・ツール

⚓git-flight-rules: Gitノウハウ集


つっつきボイス:「これもBPS社内Slackに貼られてた膨大なGitトラブルシュート集で、日本語版も出てました」「こういうのはありがたいっすね👍

「Gitで何かやらかすと、たいていググって探しまくりますし」「Gitを多少わかってきた人にはこういうのがいいと思います😋」「逆にGitの初心者は今自分がどういう状態なのかがそもそもわからなかったりしますし😆」「あるあり😆

「rebaseしてコンフリクトするとrebaseモードになりますけど、未だにrebaseモードに入るとわからなくなったりする🤣」「ああ🤣」「rebaseモードでコンフリクトを解決してcontinueすると次のrebaseが始まったりしますけど、rebaseモードのときのカレントブランチっていったいどういう状態なんだ?って思ったり」「う…わかんない🤣」「そうそう混乱するんですよそこで🤣」「カレントブランチでgit pushしたのに入らなくて、おかしいな〜と思ったらrebaseモードだったり😇」「あぁぁ😅

「rebaseモード怖いからなるべく早く終わらせたい気持ち😭」「自分も基本的にJetBrains IDEでしかGit操作しないんですけど、Windowsだと思い通りに動かないことがちょいちょいあるんですよ😇」「きっとWindowsのファイルシステムが悪い😆

「それにしてもこのノウハウ集、マジいいですね❤」「だいたいググっても見つけられますけど、その記事が正しいかどうかを吟味する時間を考えたらこういうのを使いたいですね👍」「同意」「同意」

Creative Commons Attribution Share Alike 4.0 Internationalというライセンスを初めて知りました。

参考: git-flight-rules/LICENSE at master · k88hudson/git-flight-rules
参考: Creative Commons — Attribution-ShareAlike 4.0 International — CC BY-SA 4.0

⚓slackdeck-proto: SlackチャンネルをTweetDeck風に表示

つっつきボイス:「これもBPS社内Slackに貼られてました」「ああ、TweetDeckみたいにSlackチャンネルを表示するヤツ」「欲しい人いるのかしら?」「お…お…これちょっと便利かも❤」「やった刺さった😋」「チャンネル以外に別のワークスペースも並べられたらいいなと」「multiple workspacesってありますヨ😋」「おぉ〜😂」「ま自分は見てるチャンネルの数が膨大なので横に並べる意味ありませんけど😆」「あとで遊んでみます🪁

以下はつっつき後に見つけたスライドです↓。

⚓その他言語


つっつきボイス:「Cマクロを使って爆発させるヤツ😆」「なんと邪悪な😆」「100回表示せよとしか言ってないから、まあ正しい💯」「hello worldを100回書いたりして😆」「手書き回答で100回はツラいでしょ🤣」「そうか手書きか😆

⚓その他

⚓スマホとポケコンの合体?


つっつきボイス:「こういうの好きそうな人が今日いるので😋」「要するにスマホに外付けキーボードを付けた感じ?」「昔からあるやん😆」「最近はありませんよ😆」「そりゃま最近は😆」「こういうのがあったら一も二もなく買いたいですよ私は❤」「また刺さった😋

「こういうの絶滅しちゃいましたし🦕」「やっぱNokiaとかBlackberryが凋落しちゃいましたから😆」「好きだったのに😢

参考: BlackBerry - Wikipedia

「ちょうど昨日エンジニア仲間とそういう話になって、うちに転がっているその手のデバイスの写真撮りましたよ📸」(写真を見ながら)「お、Clieだ」「最初にClieに喰い付いた😆」「フルキーボード付きのガラケーも」「フリック入力出るまではPalmグラフィティの文字入力が最強だと思ってた😆」「いろいろ懐かしい〜」(以下延々)

参考: グラフィティ (Palm) - Wikipedia

⚓番外

⚓右と左


つっつきボイス:「右脳左脳って前からどうなのって気持ち😆」「自分も半分も信じてないです😆」「脳の機能が局在化してるのは確かだと思うけど🤔」「ある程度証明はされてると思いますけど因果関係の方向が謎ですし😆

参考: 脳機能局在論 - Wikipedia


後半は以上です。

バックナンバー(2020年度第2四半期)

週刊Railsウォッチ(20200406前編)Ruby 2.7.1セキュリティ修正、RailsビューHTMLにテンプレート名を出力、Action Mailboxテスト用フォーム改良ほか

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

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

Ruby Weekly

Hacklines

Hacklines

Postgres Weekly

postgres_weekly_banner

Publickey

publickey_banner_captured

RailsをHerokuにデプロイするときのBundlerバージョン(2020年版)

$
0
0

小ネタで恐縮です。HerokuにRailsアプリをデプロイする場合やRubyバージョンをアップグレードする場合、Bundlerのバージョンで罠を踏まないためにどうしたらよいのかを自分用にまとめました。以下は2020年4月時点の情報です。

最近のBundlerとHerokuの事情

まず現状がどうなっているかをまとめました。

参考: 週刊Railsウォッチ(20200121後編)

BundlerはRuby 2.6から組み込みになった

Bundlerは、元々追加でインストールするgemでした。かつてはRubyの新しいバージョンをインストールするとgem install bundlerを実行してからRailsなどで作業するというのが定番でした。

しかしその後、Ruby 2.6.0-preview3でBundler 1.17.1が組み込まれ、Ruby 2.6.0正式版ではBundler 1.17.2が組み込まれました。

Ruby 2.7ではBundler 2.1.2が組み込まれています。


バンドルに使ったBundlerのバージョンは、Gemfile.lockのBUNDLED WITHに刻まれます。

ローカル環境で以下のように実行すれば他のバージョンのBundlerを追加インストールすることはできますが、組み込みのバージョンのBundlerは削除できません。

$ gem install bundler:1.17.3

Bundlerバージョンが複数共存するとややこしくなりそうなので、自分は避けています。

HerokuではBundlerのバージョンを指定できない

上のヘルプの冒頭に「Herokuで使われるBundlerのバージョンは変更できない」と記載されています。次を参照してください。

RubyとBundlerのバージョン

Herokuにデプロイすると、使うRubyのバージョンに応じて、自動的にBundlerのバージョンが以下のように決定されます。これは変えられません。

Gemfile.lock末尾のBUNDLED WITHでBundler 2.xが指定されているアプリ
Bundler 2.0.2が使用される
Gemfile.lock末尾のBUNDLED WITHでBundler 1.xが指定されているアプリ
Bundler 1.17.3が使用される
Gemfile.lock末尾のBUNDLED WITHでBundlerのバージョンが指定されていないアプリ
Bundler 1.17.3が使用される

Gemfile.lockのBUNDLED WITHは削除されるようになった

現在のHerokuではエラー抑制のため、デプロイ時にBundlerのバージョンを検出した後で、Gemfile.lockのBUNDLED WITHを削除するようになりました。

結局どうすればよいか

原則として、Rubyに組み込みのBundlerをそのまま使うことになります。

自分が一番気になったのは、ローカルでbundle installしたときのBundlerのバージョンと、Herokuで使われるBundlerのバージョンが違っていたらおかしなことになりはしないかというものでした。

しかし上にあるように、Gemfile.lockのBUNDLED WITHはHeroku側で削除されるので、ローカルで使ったBundlerのバージョンに関係なく、Heroku指定バージョンのBundlerが使われます。

つまりローカルで使うBundlerのバージョンは基本的に何でもよい(は言い過ぎですが)ということになります。

実際、ローカル開発環境のBundlerが2.1.4(Ruby 2.7に組み込み)のRailsアプリをHerokuにデプロイすると、上の表のとおり、Heroku側ではBundler 2.0.2が使われ、Railsアプリは問題なく動作しました。

もちろんBundlerのバージョンがローカルとHerokuで微妙に変わることで何か起きる可能性はなきにしもあらずですし、今後変わる可能性もありますが、基本的にこうすることにしました。

古いBundlerを使いたい場合

アプリのRubyが2.6より古い場合などはそうもいかないかもしれません。

以下のヘルプには「もっと古いバージョンのBundlerを使う場合の方法」も記載されていますが、あくまで一時的なものであって将来にわたって保証されるわけではないと断り書きがあります。古いBundlerを無理やり使うよりは、新しいBundlerに乗り換える方が後々無難かと思いました。

おまけ

DockerでHerokuにRailsをデプロイできる

まだ試していませんが、最近のHerokuではDockerでRailsをデプロイできます。

最近のBundler

将来Bundler 3.0でbreaking changesが入ることがこのスライドで予告されています。

関連記事

ちょっと待った! Railsでgitリポジトリから除外すべきでないファイル:Gemfile.lockとdb/schema.rb


Rails: webpack(er)に乗り換える25の理由(翻訳)

$
0
0

概要

原著者の許諾を得て翻訳・公開いたします。

webpack/Webpackerで使える有用なツールも本記事で多数紹介されています。
画像は元記事からの引用です。

Rails: webpack(er)に乗り換える25の理由(翻訳)

最近こんなことをよく聞かれます。「webpackとかWebpackerで頑張る価値ってあるの?」

よい質問だと思います。そして私の短い回答は「イエス」です。

近年JavaScriptコミュニティにおける認知度が急上昇していることで、フロントエンド開発用のツール、開発エクスペリエンス、最適化に巨大なイノベーションが続いています。

Railsはかつて最前線に躍り出ていました。登場した当時のRailsアセットパイプラインは大きな進歩でしたが、今やその方面の最前線ではありません。JavaScriptやCSSの依存関係の管理をアウトソースして、アセットをバンドルする手法は、当時としては経済的にスマートな方法でした。

本記事では、アセットパイプラインからWebpackerへの乗り換えが賢明な判断であると私が考える理由について詳しく述べたいと思います。ただしそのためには、いくつかの前提条件があります。言い換えれば、Webpackerに乗り換えずに、Railsアセットパイプラインを使い続けるかもしれない理由について最初に考えてみたいと思います。

WeboackerをRailsで使うことについて詳しくはニュースレターの購読をお願いします。

⚓乗り換えない理由があるとすれば

あなたがRails開発者で、現在のRailsアプリでアセットパイプラインが使われているのであれば、webpackおよびWebpackerへの乗り換えがうまくいかない可能性もあります。以下でいくつか理由をご紹介します。

⚓1. アプリケーションが乗り換えに向いてない

アプリケーションでJavaScriptがあまり使われていないのであれば、おそらく乗り換える価値はないでしょう。JavaScriptに充てている時間は、総開発時間の5〜10%を下回っていますか?その場合、そのアプリはwebpackのような実質的なツールを必要としていないかもしれません。

⚓2. 時間がない

まず述べておきたいのは、webpackを初めて導入する場合、辛抱が求められるのは確かだということです。Sprocketsでやるのとは勝手が違いますし、新しいパラダイムを習得する時間に投資する必要も生じるでしょう。webpackやnpmの依存関係はハイペースで更新されるので、常にアップグレードを繰り返す必要があります。さらに、JavaScriptの「モジュール」のしくみについても理解する必要があるでしょう。ここでよいお知らせ: ここで学んだスキルは他でも応用が効きます。

⚓3. 心の準備が整っていない

はい、webpackはたしかに複雑です。多くの開発者がwebpackの複雑さについて不満たらたらです。あなたがそうした開発者のひとりであれば、おそらくwebpackを導入するプロセスを楽しめない可能性もあります。ただしフラストレーションの大半は学ぶことで和らぎます。やるなら前向きな態度で取り組むことをお忘れなく。


いろいろ申し上げましたが、Webpackerに割けるささやかな時間と必要性、そして心構えがあるのであれば、きっとWebpackerへのアップグレードは成功するでしょう。Webpackerで得られるメリットのリストを以下でご紹介します。

⚓1. WebpackerはRailsの未来の姿

Webpackerは、新しいRailsアプリでデフォルトのJavaScriptコンパイラになっています。Rails 6アプリにはCSSや画像を管理するためのSprocketsの引き続き含まれますが、JavaScriptの依存関係はWebpackerによってバンドルする前提です。Railsのデフォルト設定は、BasecampがWebアプリケーションを構築するときの設定に沿っています。「多数派に合わせる」ことでRailsの先端技術に肉薄し、より高度なツールで開発したいと考える開発者を惹きつけて採用につながれば、チームにとってメリットとなる可能性もあります。

⚓2. Sprocketsと共存できる

Sprocketsの開発速度は近年落ちているようですが、すぐに消えることはないでしょう。Sprockets 4はRichard Schneemanの献身的な努力のおかげで最近リリースされました。デフォルトのRailsセットアップでは、Webpacker(JavaScriptのコンパイル用)とSprockets(CSSや画像用)の両方を使うことが奨励されています。

同じアプリケーションで2つのコンパイラを同時に利用できることで、チームが乗り換えるときに実際に役立ちます。段階的な移行への道が残されるので、移行リスクを軽減するうえで望ましいといえるでしょう。

⚓3. よりよいJavaScriptの書き方が変わる

RailsがWebpackerを介してwebpackをサポートする前、私がGitHubで直接目にしたりチュートリアルやプレゼンで目にしたほとんどのRailsアプリは、以下のいずれかに分類できました。

  1. jQueryスパゲッティ
  2. 特注のモジュールを実装
  3. 1と2の組み合わせ

このアプローチのどこがまずかったのでしょうか?

  1. JavaScriptコードが何かのはずみでグローバルスコープにお漏らしする
  2. コードの共有が難しい
  3. コードをrequireする順序にがっつり依存する
  4. 暗黙の依存関係グラフの理解が極めて難しい
  5. コードを非同期に読み込むのが極めて難しい

JavaScriptソースコードをモジュールシステム内で書けば、ファイル単位のモジュールスコープを利用できるようになります。すなわち、コードがうっかりグローバルスコープにお漏らしすることもなくなり、特注のモジュールも不要になります。

⚓4. ESモジュールのパワーの恩恵を受けられる

ESモジュール(ECMAScriptモジュール)がJavaScriptの未来であることを疑う人はほぼいないでしょう。ESモジュールは、最終的に新しいECMAScript標準として、ブラウザでもNode.jsなどのサーバーサイドランタイムでも利用できるようになります。同期importと非同期importを両方ともサポートしているので、CommonJSAMD(Asynchronous Module Definition)といった従来のモジュール仕様は最終的にことごとく消えてなくなるでしょう。

ひとつ強調しておきたいのは、ESモジュールがライブバインディングを採用している点です。つまり、exportしたモジュールで何らかの値を変更すると、モジュールをimportするときにその値が読み込まれます。この機能は、アプリケーションロジックで有用となる可能性があるのみならず、ESモジュールで循環依存をサポートできるようになります。

ESモジュールについて詳しくは、こちらの図解入り記事をどうぞ。

⚓5. $JAVASCRIPT_FRAMEWORKは必須ではない

一般に広く信じられているのとは逆に、ReactやVueやAngularやSvelteといった人気のフレームワークを使わなくても、Webpackerが提供する機能を利用できます。Webpackerは、Vanilla JSはもちろん、jQueryベースのアプリでも問題なく利用できます。

私は、いわゆるSPA(Single Page Application)で余計な苦労を背負い込む価値があるとは思っていません。SPAはCRUD(Railsの核心)ベースのアプリの大半にとって複雑すぎます。2020年においても「JavaScript-sprinkled Rails Applications」を採用する意味は大いにありますし、webpackは利点と捉えるべきです。

⚓6. 別のファイル構造を利用できる

webpackによって、JavaScriptのソースファイルの構造をうまくカスタマイズする方法への道が開かれました。おそらく最も人気の高いJavaScriptフレームワークであるReact.jsによってJSXというものが導入されました。JSXではHTML的なJavaScriptを書くことでコンポーネントのHTMLコードとJavaScriptコードを共存させられるので、開発者が昔ながらのテーゼである「関心の分離」にチャレンジできます。

Vue.jsはSingle File Componentsをサポートしていることでも有名です。これはHTMLとCSSとJavaScriptを、1つのファイル内の異なるセクションに分離しつつ共存させることができます(例↓)。

<template>
  <div>Hello, {{ name }}!</div>
</template>

<script>
export default {
  data() {
    return {
      name: "World"
    }
  }
}
</script>

<style scoped>
div {
  background-color: aliceblue;
  padding: 1em;
  font-size: 2em;
  text-align: center;
}
</style>

私の知る限り、このアプローチをRailsアセットパイプラインで実現するのは容易ではありません。

⚓7. 依存関係の管理方法が改善される

Railsの「アセット系gem」は、いつも私にとって特につらくてたまらないものでした。アセット系gemは、ほとんどの場合npm(Node Package Manager)の依存関係に置き換え可能です。

npmは、オープンソースJavaScriptパッケージの主要な分散リポジトリになっています。当初の設計ではNode.jsランタイムでの利用が想定されていましたが、やがてブラウザベースのパッケージのデフォルトにもなりました。これはつまり、Node.jsで実行されるライブラリ(webpackなど)と、ブラウザ向けのライブラリ(ReactやVieなど)のどちらもnpmで配布できるということです。npmを利用すれば、主にRailsのアセットパイプライン向けのJavaScriptやアセットの共有で非常に大きなメリットが得られます。後者のアプローチにはひとつ問題点があり、それはRubyのバージョンをパッケージ化されたアセットのバージョンに合わせてメンテしないといけなくなる点です。この手法は常に面倒がつきまとうと感じられます。

ここでひとつ言及しておきたいことがあります。npmでアセットを管理しつつ、node_modulesをSprocketsの読み込みパスに追加することでRailsアセットパイプラインで利用することは引き続き可能だということです。繰り返しますが、この方法は面倒であり、対象によってはビルド時間に悪影響が生じる可能性もあります。

⚓8. jQueryプラグインをやめられる(やめたければ)

モジュールを採用する前の時代におけるjQueryプラグインのメリットのひとつは、グローバルスコープを汚染せずに機能を追加できることです。正しいモジュールシステムを使えば、webpackに慣れ親しむに連れてjQueryインスタンスに機能をアタッチしてアプリケーション全体で参照する必要はなくなってきます。

タッチレスポンシブなカルーセルプラグインのFlickityで考えてみましょう。Railsアセットパイプラインでは以下のように使うでしょう。

//= require flickity

$(function () {
  $('.main-carousel').flickity({
    contain: true
  });
})

FlickityはjQueryなしでの利用も想定されています。つまりFlickityモジュールをwebpack環境で実装することもできるということです。

import Flickity from 'flickity'

document.addEventListener('DOMContentLoaded', () => {
  const elem = document.querySelector('.main-carousel');
  const flkty = new Flickity(elem, {
    contain: true
  });
})

jQueryはこのやりとりから丸ごと除外できます。

⚓9. ES2015以降の構文をES5+Babelにコンパイルできる

CoffeeScriptが導入された当初は、クリーンかつRuby的な構文のおかげで人気を博しました。最近のECMAScriptには、CoffeeScriptのアイデアも多数導入されています。かつて私はCoffeeScriptで書くのが好きでしたが、ES構文でJavaScriptを書くのはさらに好きです。

ES2015以降の数々の大きな進歩を、以下の簡単なリストに抜粋してまとめました。

⚓10. 実験的なES機能をオプトイン/オプトアウトできる

Babelインテグレーションを用いることで、次世代の実験的なECMAScript構文を利用できます。

⚓11. 特定バージョンのブラウザを対象にできる

アプリケーションでサポートするブラウザの種類をコード化できたらどんなに素晴らしいか想像してみましょう。Webpackerならできます。

Babelインテグレーションにbrowserlistパッケージを併用することで、トランスパイルされたコードが対象とするブラウザをプロジェクトでコード化できるようになります。バージョンのリストはクエリの形で設定でき、特定バージョンのブラウザを指定することも、「最新の2バージョン」を指定して手動アップデートを回避することもできます。browserlistでは、Can I Useが提供するデータを用いて、より新しいフロントエンドAPIをサポートするブラウザを決定します。

これで、以下のように未来のJS構文で書けるようになります。

const array = [1, 2, 3];
const [first, second] = array;

BabelでEdge 16向けにコンパイルすると以下のようになります。

const array = [1, 2, 3];
const first = array[0],
      second = array[1];

⚓12. 新しいブラウザAPIをポリフィル化できる

上の11番では、自動ポリフィルで指定する新しいJavaScript APIをより簡単に指定するために、Webpackerで@babel/preset-envを用いています。

これは、依存関係グラフのトップに以下のコードを挿入することで実現されます。

import 'core-js/stable'

chrome 71がターゲットの場合、上は以下に置き換わります。

import "core-js/modules/es.array.unscopables.flat"
import "core-js/modules/es.array.unscopables.flat-map"
import "core-js/modules/es.object.from-entries"
import "core-js/modules/web.immediate"

これで、今までブラウザサポート用にテストに追加されていた条件を削除できるようになります。

⚓13. TypeScriptが使える

近年のTypeScript人気の高まりは著しいものがあります。

TypeScriptによって静的型付けがフロントエンド開発に導入されたことで、エラーをより効率的にキャッチできるようになり、VSCodeなどのJavaScript IDEをサポートするインテグレーションによって生産性が高まりました。TypeScriptは反復的に導入することも可能です。TypeScriptはJavaScriptのスーパーセットなので、JavaScriptとして正しいプログラムは、TypeScriptとしても正しいプログラムになります。Webpackerは、RailsプロジェクトにTypeScriptをより簡単に追加できるインストーラを提供しています。

⚓14. 新しいパワフルなツールを利用できる

webpackによるコンパイルやビルドのプロセスで提供される多数のフックによって、振る舞いをほぼあらゆる段階で変更できます。システムのニーズに応じてwebpackを拡張する方法を以下のリストに簡単にまとめました。

  • Railsアセットパイプライン経由の単体テストでは常に火の輪くぐりのように冷や冷やさせられていましたが、MochaJestといったJavaScriptの単体テストツールを自由に選べるようになりました。
  • eslint統合によるコードのスタイルや構文の標準化・自動修正
  • バンドルのサイズや内容を分析するプラグイン(WebpackBundlerAnalyzerなど)を追加できる
  • Rails i18n yamlファイルをパースしてWebpackerのJavaScriptモジュールにJSONとして提供するローダーを追加できる
  • バンドルの「フィンガープリントなし」クローンを生成するプラグインを追加できる(non-stupid-digest-assets

webpackと馴染みのよいアドオンであるStorybookは私のお気に入りです。これはRailsサーバーと独立してコンポーネントをビルドできる新しいツールであり、開発環境を実データで汚すことなく、さまざまなステートを持つUIを表現する優れた方法のひとつです。

⚓15. ソースコードをプログラムで変更できる

webpackは、モジュールからの出力を簡単に変更できるいくつかの設定オプションを提供しています。たとえば、jQueryのimportをソースファイルのあらゆるモジュールに「提供する」には、ProvidePluginを追加します。

これは、レガシーRailsアプリをwebpackにアップグレードするときに重要になってきます。たとえば、古いjQueryプラグインの多くはjQueryがグローバルスコープで利用できることを前提としています。ProvidePluginを以下のように設定することで、必要に応じてレガシーモジュールをrequire('jquery')ステートメントで「shimming(詰め物)」するようwebpackに指示します。

// config/webpack/environment.js

const webpack = require('webpack');

const {environment} = require('@rails/webpacker');

environment.plugins.append(
  'jquery', // arbitrary name
   new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    'window.jQuery': 'jquery'
   }),
);

module.exports = environment;

⚓16. 引き続きrequire_treeして一部を扱える

Sprocketsには、アセットバンドルにファイルをインクルードするのに便利な方法がいくつかあります(require_treeなど)。同様に、webpackにも複数のファイルを1つのファイルにインクルードするためのrequire.contextがあります。こちらの方が退屈ではありますが、強力さにおいても上回ります。require.contextはファイルをフィルタするオプションを提供しており、たとえば.svgファイルだけをimportしたりできます。戻り値を操作することも可能です。

構文:

require.context(directory, useSubdirectories = true, regExp = /^\.\/.*$/, mode = 'sync');

例: カレントディレクトリとその下のディレクトリにあるテストファイルをすべてrequireする場合

require.context('.', true, /\.test\.js$/);

例: カレントディレクトリにあるデフォルトのexportをすべてimportし、名前付きモジュールとして再度exportする場合

const requireModule = require.context('.', false, /.js$/)

context.keys().forEach(filename => {
  const moduleConfig = requireModule(filename)

  // filenameからモジュール名をパスカルケースで取得する
  const moduleName = upperFirst(
    camelCase(
      filename.replace(/\.\//, '').replace(/\.\w+$/, '')
    )
  )

  export {[moduleName]: moduleConfig.default}
})

⚓17. コードを自動で静的分割できる

Sprocketsでは、あらゆるベンダーコードを個別のバンドルに移動することで、バンドルサイズを削減してキャッシュが効きやすくする方法がよく使われます。

<!-- app/views/layouts.application.html.erb -->
<%= javascript_include_tag "vendor" %>
<%= javascript_include_tag "application" %>

この方法では、バンドルを頑張って手動で分割し、読み込み順序で問題を起こしたり重要な依存関係を取りこぼしたりしないよう、細心の注意を払わなければならないのが悩みのタネです。

webpackではソースコードを静的解析して依存関係グラフをビルドします。ベンダーコードやアプリケーションコードを自動的に個別のバンドルに分割生成する設定も使えます。つまり、webpackは1つのpackからベンダー用バンドルとアプリケーションバンドルを、webpack実行時に代わりに生成してくれるということです。この振る舞いを有効にするには、Webpackerヘルパーと設定を以下のように用います。

// config/webpack/environment.js

const { environment } = require('@rails/webpacker')

environment.splitChunks()

module.exports = environment
<!-- app/views/layouts/application.html.erb -->

<%= javascript_packs_with_chunks_tag "application" %>
<!--
<script src="/packs/vendor-16838bab065ae1e314.chunk.js"></script>
<script src="/packs/application~runtime-16838bab065ae1e314.chunk.js"></script>
<script src="/packs/application-1016838bab065ae1e314.chunk.js"></script>
!>

もう手動でコードを分割する必要はありません。

⚓18. コードを自動で動的分割できる

自分のJavaScriptコードを複数のファイルに分割するオプションとしては「動的import」がさらに優れています。ただしこのアプローチでは、設定を一切変更しないことが求められます。webpackの作者がwebpackを最初に作った動機は、まさにこのためでした。

webpackがアプリケーションで以下のような動的なimport関数を検出すると、そのimport向けの独立したバンドルを作成し、コードがブラウザで実行されるときに非同期で読み込みます。

import('pdfjs/webpack').then(({default: pdfjs}) => { // async import!
  pdfjs.getDocument('https://example.com/some.pdf')  // ...
})

この手法を用いることで、初期ダウンロードサイズを削減して不要なJavaScriptコードの読み込みを回避でき、TTI(time to interactive)メトリクスの改善にもつながります。

⚓19. 最新のCSSプロセッサを利用できる

Railsとの付き合いが長い方がこれまで採用していたSASSやSCSSなど、皆さんが好きそうなCSSプロセッサにもチャンスが与えられます。もちろん大丈夫!WebpackerではSASS/SCSSをデフォルトでサポートします。なおWebpackerにはPostCSSという新しいツールも統合されています。

PostCSSは比較的新顔のツールで、JavaScriptでCSSを変換します。PostCSSはプラグインで設定を拡張可能なので、さまざまな機能を利用できます。webpackでは、flexboxの一部のバグ修正を適用したり、(@babel/preset-envがJavaScriptで行うのと同様に)preset-envプラグインを用いて古いブラウザで新しいCSS機能をポリフィル化したりするのに、PostCSSを用いています。

PurgeCSSは私の好きなPostCSSプラグインのひとつで、自分のCSSをHTMLマークアップやテンプレートと比較することで、不要なCSSを削除します。こうしたツールは、本番コードでは使いそうにないユーティリティクラスを山ほど持ち込むTailwindCSSのようなフレームワークを採用する場合にとても重宝します。

⚓20. 開発時にアセットのコンパイルをRailsサーバーから切り離せる

development環境のSprocketsは、Railsサーバーで扱う静的アセットのコンパイルや再コンパイルを自動で行いますが、これによってRubyプロセスの仕事が倍増してボトルネックになることがあります。webpack-dev-serverなら、アセットのコンパイルは独立したプロセスに移動するので、Railsサーバーがリクエストのレスポンスを返すのとは独立にアセットがコンパイルされます。

webpack-dev-serverはシンプルなNode.js Webサーバーであり、ソースコードディレクトリ内のファイル変更を監視して変更が生じたらwebpackをトリガし、コンパイル済みアセットをメモリ上で提供します。アセットはwebsocketリスナー経由で自動的にブラウザに挿入され、必要であればオートコンパイルの完了時に開発用ブラウザウィンドウを自動で再読み込みします。

⚓21. 開発中にページを再読み込みせずにコードを更新できる

ブラウザ内にあるJavaScriptモジュールの実装を、ページをリロードせずに置き換えられるとしたらどうでしょう。これはHot Module Replacement(HMR)と呼ばれる機能です。コードが変更された場合にだけほぼ瞬時にページを更新できるだけでなく、アプリケーションやDOMのステートも維持されます。つまり、望みのUIステートを得るのに余分なクリックや入力を行う必要がないということです。このツールには利用上の注意点がいくつかありますが、一般に開発をスピードアップできる強力な方法のひとつです。

⚓22. source mapオプションを利用できる

自分の書いたJavaScriptやCSSのソースコードは、開発環境や本番環境でコンパイルされるとフォーマットが変わります。source mapはこのギャップを埋めてくれます。source mapの読み込みやレンダリングは、ほとんどのメジャーなブラウザにあるdev toolsでサポートされており、ブラウザに読み込まれているコードと、ソースファイルにあるコードを橋渡しできます。source mapは、ぜひ道具箱に常備しておきたい素晴らしいツールです。

Sprocketsは、最近Railsアセットパイプラインにsource mapを導入しました。webpackではsouce mapは最初からサポートされており、しかも高度にカスタマイズ可能です。webpackでは20種類以上ものsource mapがサポートされているので、ほぼあらゆるユースケースの攻略に使えます。source mapの種類がこれほど多い理由のひとつは、自分のバンドルとは別に1個のファイルとしてsource mapを生成しなければならないためです。そのため、ビルドによるパフォーマンス上のコストが発生します。時間を節約するか、それとも正確さを優先するかはトレードオフになります。

ここでのポイントは、webpackを使えば以下のように多数の選択肢が得られることです。

⚓23. 「パフォーマンスバジェット」を実装できる

最適化のルール第一条は「まず測定せよ」です。私がフロントエンドのパフォーマンスを最適化することになったら、いの一番にAddy Osmaniでアドバイスを探します。

フロントエンドのパフォーマンス測定における重要な戦略のひとつは「パフォーマンスを予算化する」ことであり、TTI(time-to-interactive)にも強く関連します。このように捉えることで、ユーザーによるアプリケーション操作のエクスペリエンスにおいて、TTIの値を求められるようになるでしょう。TTI値は、ユーザーのブラウザにダウンロードして実行させるJavaScriptコードの量と強く相関します。初回ダウンロードのペイロードサイズを抑えることで、TTI値を改善できるようになるでしょう。

それがwebpackと何の関係があるのでしょうか?webpackは上述したように自分のバンドルを簡単に分割できるだけでなく、パフォーマンスバジェットのサポートも組み込まれています。webpackをカスタマイズすることで、設定済みのmaxEntryPointSize値をバンドルが超えたときに警告を表示することもエラーを発生することもできます。

⚓24. バンドルの内部を詳しく調べられる

webpackのデバッグツールの中で私のお気に入りのひとつはwebpack-bundler-analyzerです。このツールを自分のビルドに追加すれば、以下のようなインタラクティブなツリーマップにバンドル内部の相対サイズや中身がビジュアル表示されます。たとえばlodashを追加するとバンドルサイズはどれだけ増えるかを知りたければ、このツールを使いましょう。依存関係やwebpack出力にバグの疑いがあれば、このツールが原因特定の助けになるでしょう。

⚓25. 「tree shaking」が使える

JavaScriptバンドル方面の流行りである「tree shaking」を忘れては手落ちになるところです。これは要するに、特定の条件が満たされた場合にwebpackが不要なコードをビルドから削除してくれるというものです。つまり削除の対象は基本的にESモジュールということになります。たとえばESモジュールを扱うようBabelが設定されていれば、副作用なしでそのモジュールをimportできます。

lodashはtree shakingのよいユースケースです。lodashが完全に読み込まれると、アセットバンドルに追加されるライブラリは75KBになります。

import _ from 'lodash' // または

import {map, uniq, tail} from 'lodash'

以下のように書くことで、webpackがファイルサイズを抑えてくれます。

import map from 'lodash/map'
import uniq from 'lodash/uniq'
import tail from 'lodash/tail'

⚓まとめ

webpack(er)に乗り換える25の理由は以上でおしまいです。本記事が、皆さんのRailsアプリでwebpackを採用するうえで、webpackの可能性やユースケースのよい紹介となることを願っています。繰り返しますが、webpackの導入は、webpackの仕組みを理解するという「参入障壁」を克服しながら多数の細かなJavaScript依存関係を管理する手間とのトレードオフです。

私自身は、このトレードオフに価値があったと感じています。

Twitterでの議論もお待ちしています。

関連記事

Rails 6+Webpacker開発環境をJS強者ががっつりセットアップしてみた(翻訳)

週刊Railsウォッチ(20200413前編)最近macOSでRailsが遅い、トランザクションでのreturnやbreakなどが非推奨化、Rails監視ツールリスト2020年度版ほか

$
0
0

こんにちは、hachi8833です。カレンダーのリマインダーで気づきましたが、本当なら今日(注: つっつきが行われた4/10木曜日)からRubyKaigi 2020だったんですね。


つっつきボイス:「そうかRubyKaigiのはずか〜」「もう入学式のシーズン🎓」「子どもの入学式とRubyKaigiとどっち取る問題ってありそうですね」

Rails: 先週の改修(Rails公式ニュースより)

今回もコミットリストから見繕いました。


つっつきボイス:「今の時期はコミットに使える時間増えそう😋」「そういえば今週は珍しく@kamipoさんの姿があんまり見えませんね👀」

.を含むテンプレート名でのレンダリングを非推奨化

# actionview/lib/action_view/template/resolver.rb#L229
      def find_template_paths_from_details(path, details)
+       if path.name.include?(".")
+         ActiveSupport::Deprecation.warn("Rendering actions with '.' in the name is deprecated: #{path}")
+       end
+
        query = build_query(path, details)
        find_template_paths(query)
      end

つっつきボイス:「テンプレート名で.を使って欲しくないということでしょうか?」「.は必ずフォーマット区切りだけに使うということでしょうね: まあ問題ないと思います☺️」「自分も.を名前に含めるのはイヤです😆」

テンプレート名で.の利用を許すと一部で曖昧さが生じる。たとえばindex.html.erbは「テンプレート名がindexでフォーマットがhtml」なのか、それとも「テンプレート名がindex.htmlでフォーマットは指定なし」なのか。人間ならたぶん前者だということはわかるが、Action Viewでindex.htmlをレンダリングすると、Templateで2つの組み合わせが取れることがある: index.htmlがバーチャルパス名になるが、htmlがフォーマットになる。
今回テンプレート名のどこかに.を含むことを非推奨化するにあたり、フォーマット指定用の文字を予約するべき。99%の人はindexではなくindex.htmlを指定するだろう。
実は以前にも3.xシリーズで非推奨化されたことがあり、6c57177で削除された。しかしこの8年間誰もこれを導入していないということを当てにしてよいとは思えない。
同コミットより大意

new_framework_defaults_6_1.rbでutc_to_local_returns_utc_offset_timesを設定できるよう修正

# railties/lib/rails/generators/rails/app/templates/config/initializers/new_framework_defaults_6_1.rb.tt#L27
-# Rails.application.config.active_support.utc_to_local_returns_utc_offset_times = true
+# ActiveSupport.utc_to_local_returns_utc_offset_times = true

つっつきボイス:「長い名前😆」「差分を見るとutc_to_local_returns_utc_offset_timesがActive Supportに引っ越したということみたい」「あ、そういうことですか😳」「Rails.application.configの下にあったのを書き直してますし☺️」

bf34c80の続き。
以前はこのオプションをnew_framework_defaults_6_1.rbで有効にしても反映されなかったのは、railtie初期化がアプリケーション初期化より先に動いていたため。
Active Support railtieに特殊なハンドリングを追加してこのオプションを他より後に適用する方法もあるが、5.0のto_time_preserves_timezoneと同様に直接設定する方が好ましいと考える。
同コミットより大意

「そういえばRailsをrails app:upgradeでアップグレードするときにnew_framework_defaultsなんちゃら.rbというファイルが作られますね」「そうそう、config/initializers/の下に」「どきどきしながら修正してエントリを1個ずつ消していく感じで」「まあ消さなくても残しとけば今までどおりに動いてくれますけど😆」

参考: フレームワークのデフォルトを設定する — Rails アップグレードガイド - Railsガイド

コールバックの:only:exceptに渡した条件を1度だけ算出するようにした

# actionpack/lib/abstract_controller/callbacks.rb#L71
      def _normalize_callback_option(options, from, to) # :nodoc:
-       if from = options[from]
+       if from = options.delete(from)
          _from = Array(from).map(&:to_s).to_set
          from = proc { |c| _from.include? c.action_name }
          options[to] = Array(options[to]).unshift(from)
        end
      end

つっつきボイス:「コールバックの条件は基本的に結果整合になるような形でしか書かないだろうから、こう修正しても大丈夫でしょうね」「バグでしょうか?」「これはバグとは言わないと思います😆」「あ、無駄な処理を減らしたという感じなんですね😅」「テストコードにCallbacksWithReusedConditionsというのがありますけど、only:とかexcept:に渡すブロックは、普通は2回評価しても同じ結果を返すように書きますよね😆」「あ〜😳」「だから『まともな』コールバックを書いている限りはこの挙動が正しいということになると思います😆」「たしかに、呼ばれるたびに結果が違うような条件を書いたらわかりにくくなりそう😅」「逆になぜ今までそうじゃなかったのかというのはありますけど😆」

# actionpack/test/abstract/callbacks_test.rb#L186
+   class TestCallbacksWithReusedConditions < ActiveSupport::TestCase
+     def setup
+       @controller = CallbacksWithReusedConditions.new
+     end
+
+     test "when :only is specified, both actions triggered on that action" do
+       @controller.process(:index)
+       assert_equal "Hello, World", @controller.response_body
+       assert_equal "true", @controller.instance_variable_get("@authenticated")
+     end
+
+     test "when :only is specified, both actions are not triggered on other actions" do
+       @controller.process(:public_data)
+       assert_equal "false", @controller.response_body
+     end
+   end

参照: #38323
修正: #38679
:only:exceptコールバックの条件を1度だけ計算する。
_normalize_callback_optionsはoptionsハッシュを改変するが、only:except:の条件を削除しない。
つまりbefore_actionを同じoptionsハッシュで繰り返し呼ぶと、最終的に完全に同一の:if procや:unless procインスタンスが複数できてしまう。
optionsハッシュは既に_normalize_callback_optionsで改変されているので、この道筋を変えずにonly:except:に渡す条件を削除して続行するよう変更することにした。
別の修正方法として、optionsハッシュが改変される前にdupする手もある。このハッシュはDSLからやって来るので改変しても問題ないと思うが、この別手段で実装するのもやぶさかではない。
同PRより大意

config.force_sslがオンのときにurl_forhttps://をデフォルトで使うようになった

# actionpack/lib/action_dispatch/http/url.rb#L140
          def normalize_protocol(protocol)
            case protocol
            when nil
-             "http://"
+             secure_protocol ? "https://" : "http://"
            when false, "//"
              "//"
            when PROTOCOL_REGEXP
              "#{$1}://"
            else
              raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
            end
          end

つっつきボイス:「Action Mailerは既にそうなっていたので、それをアプリ全体で効くようにしたそうです」「今どきはhttpsでしかホスティングしないのであんまり気にしませんけど😆」「ですよね😆」「今の時代にhttpとhttpsのハイブリッドサイトを新たに構築するとかほぼありえない😆」「つらくなるだけ😆」

Journey::Path::PatternのASTビルドのループを1回にして倍高速化

# actionpack/lib/action_dispatch/journey/path/pattern.rb#L43
        def ast
-         @spec.find_all(&:symbol?).each do |node|
-           re = @requirements[node.to_sym]
-           node.regexp = re if re
-         end
-
-         @spec.find_all(&:star?).each do |node|
-           node = node.left
-           node.regexp = @requirements[node.to_sym] || /(.+)/
+         @spec.each do |node|
+           if node.symbol?
+             re = @requirements[node.to_sym]
+             node.regexp = re if re
+           elsif node.star?
+             node = node.left
+             node.regexp = @requirements[node.to_sym] || /(.+)/
+           end
          end

          @spec
        end

つっつきボイス:「ネストしたループを浅くしたのかなと思ったら、前はfind_allのループを2回走らせてたのを1回にしたのね😳」「これで倍速くなったそうです」「こういう修正は地道に大事☺️」

IPS
Warming up --------------------------------------
                 ast     7.572k i/100ms
            fast_ast    16.195k i/100ms
Calculating -------------------------------------
                 ast     78.133k (± 2.1%) i/s -    393.744k in   5.041539s
            fast_ast    165.113k (± 2.5%) i/s -    825.945k in   5.005666s

Comparison:
            fast_ast:   165112.9 i/s
                 ast:    78132.7 i/s - 2.11x  slower

MEMORY
Calculating -------------------------------------
                 ast   240.000  memsize (     0.000  retained)
                         4.000  objects (     0.000  retained)
                         0.000  strings (     0.000  retained)
            fast_ast    80.000  memsize (     0.000  retained)
                         1.000  objects (     0.000  retained)
                         0.000  strings (     0.000  retained)

Comparison:
            fast_ast:         80 allocated
                 ast:        240 allocated - 3.00x more

returnbreakthrowによるトランザクション終了を非推奨化

このプルリクは以下の記事で知りました。よく見ると2017年のが最近マージされたんですね😳。

# 同記事より
def destroy_post_if_invalid
  Post.transaction do
    post = Post.find_by(id: id)
    return if post.valid?

    post.destroy
  end
end

つっつきボイス:「今まではトランザクション内でreturnするとコミットされてたのか😳」「えぇ!?😳」「そんな書き方普通しないから気にしたことなかったけど😆」

「Saelounブログによると、以下のコミットがRails 3.xのときに入ってたそうです」「トランザクションの中でreturnを書くことがそもそもあるんだろうか?って思いますけど、raiseすることはなくもないかな: 何にしろこれはdeprecateすべきでしょうね🧐」「普通じゃない書き方ですし」「何よりわかりにくいんですよ😅」

「この修正では振る舞いが変わるから、もしそういう書き方をしている人がいたら影響される😆」「そういう人にはbreaking changes😆」「こういう書き方をふんだんにやる人っているんだろうか😆」

# activerecord/lib/active_record/connection_adapters/abstract/transaction.rb#L292
      def within_new_transaction(isolation: nil, joinable: true)
        @connection.lock.synchronize do
          transaction = begin_transaction(isolation: isolation, joinable: joinable)
-         yield
+         ret = yield
+         completed = true
+         ret
        rescue Exception => error
          if transaction
            rollback_transaction
            after_failure_actions(transaction, error)
          end
          raise
        ensure
          if !error && transaction
            if Thread.current.status == "aborting"
              rollback_transaction
            else
+             unless completed
+               ActiveSupport::Deprecation.warn(<<~EOW)
+                 Using `return`, `break` or `throw` to exit a transaction block is
+                 deprecated without replacement. If the `throw` came from
+                 `Timeout.timeout(duration)`, pass an exception class as a second
+                 argument so it doesn't use `throw` to abort its block. This results
+                 in the transaction being committed, but in the next release of Rails
+                 it will raise and rollback.
+               EOW
+             end
              begin
                commit_transaction
              rescue Exception
                rollback_transaction(transaction) unless transaction.state.completed?
                raise
              end
            end
          end
        end
      end

Rails

enumerize: i18n対応のenum

enumerizeはだいぶ前のウォッチで一度取り上げましたが、以下のおたよりを見かけたので。


つっつきボイス:「enumerizeはどこかで使ったことあった気がする🤔」「i18nに対応したenumということですね」「誰もが考えるヤツ😆: Railsでi18nに対応していない部分はちらほらあるので、そういう部分をこういうgemでサポートしたいでしょうね☺️」

「enumrizeを使うということは、要するにRails標準のenumを使わないということね: 自分もRails標準のenumは使いたくない派なのでワカル😆」「クエリビルダの汚染というのがまだイメージできてなくて😅」「自分もそこの意図はよくわかりませんが😆、Active Recordのenumを使うとシンボルとかをenum値に変換するので、ソースコードと実際のSQLを比較したときにわかりにくいコードになるのは確か😭」「やりにくそう…😅」

参考: ActiveRecordのenumで気をつけたい3つのポイント - Misoca開発者ブログ

「次のツイートも見つけました」「別テーブルと外部キー、個人的にはあんまりやらないかな: なおDBアドミニストレータ(DBA)の立場ならenumにする方がインデックスサイズは小さくなるから当然速くなるというのはありますね☺️」「ふむふむ」

「PostgreSQLならデータベースレベルでenum型があるので、やるならそっちを使う方がいいかなとちょっと思います😋」

参考: 【Rails】5ステップでイケてる enum を作る(翻訳) - Qiita

RailsがmacOSだと最近遅いのはなぜ?(Ruby Weeklyより)


discuss.rubyonrails.orgより

samsaffronさんによると、ここ1年Mac上でRails specのベンチがLinuxネイティブやWSL2と比べてやけに遅いとのことです。MacのDocker上だとさらに遅いようです。


つっつきボイス:「やっぱりMacだと遅いのか😢」「今どきはほとんどの人がDockerでやってる気がしますね🐳」「DockerもMacだと遅いという説もありますし」「ファイルシステムアクセスが特に遅いですね🐢」

「MacのファイルシステムがLinuxと違うために、ファイル変更を検出して自動リロードするのがMacでうまくやれないのが悔しいです😭」「MacでDockerやるとHypervisorフレームワークの上でLinuxを動かすことになるのでそうなっちゃいますね☺️」「くすん😢」「そこを何とかするには、Hypervisorフレームワークを通して、Linuxで言うinotify的なMacのファイル更新通知を伝搬させないといけないんですよ🧐」「やっぱりそうなるんですね」「やってやれないことはないんでしょうけど、いろいろ面倒そう😅」「どうしてもダメならダサくpollingするしかないのかな…」「まあpollingは最終手段でしょう😆」

参考: inotify-toolsでファイルやディレクトリを監視する - Qiita
参考: ポーリング (情報) - Wikipedia

Docker for MacのEdgeリリースノートを見る限りでは、inotify周りがまだ不安定な印象です。

参考: Docker Desktop for Mac Edge release notes | Docker Documentation


「ところで、公式にこういうディスカッション場↓があることを今になって知りました」「へぇ知る人ぞ知る公式😳」「discussionというサブドメインがあるとは」「見た感じそんなにアクティブという感じではなさそうですけど😆」「初歩的な質問にピンポイントでレスが付いておしまいになってるのも多いみたいです」「まあ気軽に質問できそうでいいかも😋」


discuss.rubyonrails.orgより

indexページをページネーションしないとRailsが死ぬかも(Ruby Weeklyより)


同記事より


つっつきボイス:「ページネーションしないindexアクションはだいたい死にます、以上😆」「😆」「ものにもよりますけど普通にメモリ溢れたりしますし☺️」


記事概要:

  • Rails+Pumaが突然メモリを激しく消費し、20分おきにPumaプロセスがkillされた
  • メトリクス
  • 調査に便利なコマンド技
  • ページネーションしてれば問題はたぶん起きなかった
  • Pumaにはタイムアウトオプションがない(たぶん今後も)
  • 以下のバグを発見(id=nilで問題が発生する)
    • 今後のためにSorbetを入れようとしたけどレガシーアプリにつき無理だった
# 同記事より
class FeatureRepository
  def self.find(id)
    OtherApp::Clients::V1::Feature.find(id)
  end
end
  • ソースをロールバックすればもっと早く発見できたかも

Rails向け監視ツールリスト2020年度版(Ruby Weeklyより)


つっつきボイス:「いわゆるAPM(Application Performance Monitoring)ツール」「こうして見るとずらっとありますね」「エラー/例外監視なんかもあったりして範囲広いな〜」

「AirBrakeは無料トライアルもあるけど基本的には有料: AirBrakeのオープンソース版がerrbit↓」「そういえば以前も話題になりましたね(ウォッチ20170804)」「BPSでもかなり昔からerrbit使ってます😋」

Railsのエラー管理はこれでOK!オープンソースのAirbrakeクローン、errbitを使ってみた

「コメント欄に『Scout APMも載せるべき』とありますね」「今は『Rails APM』で検索すればScout APMが即出てきますヨ☺️」


scountapm.comより

optimism: Rails用リモートバリデーションgem(Ruby Weeklyより)


つっつきボイス:「デモサイトがそっけないですね😆」「Ajaxでやってるのかなと思ったら、ChromeのDevToolsで見るとどうやらAction Cableでやっているらしい↓」「ホントだ😳」

「つまりページ遷移する前にAction Cable経由でバリデーションを走らせてるんでしょうね🧐」「なるほど!」「このぐらいのバリデーションをgemでやるかどうかというのはありますが😆」「★も70個ぐらいだし割と新しいgemみたい」「productで使ってる人はまだ作者ぐらいかな?😆」

後で調べると、optimismでは以下のcable_readyというgemを使っていますね。

その他Rails

つっつきボイス:「新しい記事なんですがform_withがかけらも登場していなくておや?と思ったので」「form_forで書くのはさすがに古い😆」「ですよね😆 」「相当古いRailsをメンテしてるのかな?ネステッド周りは基本的にやり方変わってないからまあいいでしょう☺️」

参考: Rails5.1からのform_withでnested_formを扱う方法 - Qiita

Rails 5.1〜6: ‘form_with’ APIドキュメント完全翻訳


前編は以上です。

バックナンバー(2020年度第2四半期)

週刊Railsウォッチ(20200407後編)RubyのTracePointでデバッグ、Rubyとモナド、Gitノウハウ集、リモートワークほか

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

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

Rails公式ニュース

Ruby Weekly

週刊Railsウォッチ(20200414後編)Ruby 3で”endレス”メソッド定義構文が追加、ECMAScript 2020の新機能、紛失防止デバイスほか

$
0
0

こんにちは、hachi8833です。今日はMatzの誕生日と今朝Facebookが知らせてきました🎉

それはそうとZoom背景がすっかり大喜利化してますね。

今朝はジブリのかぐや姫にしてみましたが、やっぱりこっちにしました↓。

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

⚓Ruby

⚓monar: もうひとつのRubyモナド

# 同リポジトリより
class Just
  include Monad
  include MonadPlus
  include Monar::Maybe

  def initialize(value)
    @value = value
  end

  def fmap(&pr)
    self.pure(pr.call(@value))
  end

  def flat_map(&pr)
    pr.call(@value)
  end

  # このモナドが2種類以上のオブジェクトを返す可能性がある場合は
  # `monad_class`で親クラスを指定してください
  def monad_class
    Monar::Maybe
  end
end

つっつきボイス:「@joker1007さんがモナドのgemを作っていることを以下のツイートで知りました↓」「用法が今後変わる可能性があると書いてありますね☺

「実用というより、作ってみたかったから作ってみた感じかな」「そうかも」「これはflat_mapさえ実装すれば後はこのgemをincludeするだけでモナドを使えるようになるヤツですね: この間話したeachを実装すればRubyのEnumerableを使えるのと似たノリで(ウォッチ20200407)」「あ、そういうことですか😳」「とてもRuby的な実装だと思います😋

⚓提案: endレスなメソッド定義(Ruby Weeklyより)

# こういうふうに1行でメソッドを定義する新しい構文を入れたい
def: value(args) = expression

つっつきボイス:「@mameさんがRubyの新構文を提案していました」「エンドレスなメソッド定義?」「endlessはキーワードのendを書かなくて済むという意味か!😳」「endが省略可能なら省略したいというか😆

「これはまたlinterが苦労しそう😆」「大胆な提案ですね」「Matzは”totally agree”ですって😆」「Rubyは元々、書かなくていいものは書かないようにしようという文化がありますし☺」「そういえばreturnとかもそうですね」「以下のdef value { @val }みたいな書き方できるといいなと思うことはあります😆

# original
def value; @val; end

# proposed - is that conflicting one?
def value { @val }

「こういう書き方は主に作り捨てのスクリプトとかで使うのかな☺」「そんな雰囲気ですね」「def:で始まると文末までがメソッド定義になると↓」「どことなくPythonっぽい🐍」「パーサーでやれるんなら、そんなに無理な仕様追加ではないかなと思います🤔

def: fib(x) =
  x < 2 ? x : fib(x-1) + fib(x-2)

p fib(10) #=> 55

「『どこまで本気の提案なんだろうか』というコメントもありますね😅」「まあRubyを書けば書くほど、中身が1行しかないメソッドを書くことって増えてきますよね、rubocopのABCサイズで怒られないようにとか👮🏼‍♀️」「ああたしかに!」「エディタ画面が1行メソッドで埋まるのもあるあるですし😆

「それに従来のdef value; @val; endみたいに;endで書くやり方ってあんまり直感的じゃありませんし」「個人的にもRubyでセミコロンはない方が嬉しい😂」「より読みやすい構文が入るのはいいと思います😋

その後早々にこの機能がRuby 3.0(表示は2.8-dev)にマージされました。

⚓Rubyで「モンティーホール問題」を納得する(Ruby Weeklyより)

参考: モンティ・ホール問題 - Wikipedia


つっつきボイス:「数学ネタはkazzさんにと思ったんですが今日はお休みでした」「あまりに直観に反しているので発表当時に数学者も続々間違えたことで有名な問題ですね」「いわゆるベイズ理論を学ぶと必ずと言っていいほど出てきますけど、納得するのが難しい😆」「まさに😆」「扉が100個になったらどうなる😆」「扉を増やす方がわかりやすいという説明をどっかで見たことあった気がします🤔

参考: ベイズの定理 - Wikipedia

「でモンティーホール問題をRubyでやってみたら、たしかに扉を変える方が確率が上がると↓😆」「😆」「こうやってモンテカルロ法的にシミュレーションしてみるのはひとつのアプローチですね😋

# 同リポジトリより
ruby monty_hall.rb 1000
#=> {"stay"=>343, "switch"=>657}

参考: モンテカルロ法 - Wikipedia

⚓ruby.hを分割整理


つっつきボイス:「5000行削って6万行足す🤣」「思わず笑っちゃいました🤣」「がっつり整理した感」「プルリクのこの図がわかりやすいです↓」


同PRより

「この規模で大整理やったらこうなるでしょうね😆」「このグラフえらいことになってる😆」「maybe_unused.hとかサイコー🤣」「す、スゴすぎ🤣」「🤣」「Rubyはこんだけスゴいことになってるというのがよくわかる😆」「ある程度は自動化したんでしょうけど☺

こちらもその後マージされました。

⚓提案: Struct.newimmutable: trueオプションを追加(却下)

# #16769より
Post = Struct.new(:id, :name, immutable: true)

post = Post.new(1, "hello world")
post.id = 2 # NoMethodError (undefined method `id=' for #<struct Post id=1, name="hello world">)

つっつきボイス:「こちらは@k0kubunさんの提案です」「Struct.newimmutable: trueを付ける、なるほど😋」「今のStructは構造は変えられないけど値は変えられるか🤔」「Value Objectやるときにイミュータブルを保証したいことはあるのかも?」

「Structがイミュータブルかどうかをチェックする方法ってあるのかしら?」「@mameさんがコメントにも書いてますけど、freezeのメカニズムを流用すればfrozen?でチェックできますね」「たしかに!」

# #16769より
Post = Struct.new(:id, :name, freeze: true)

post = Post.new(1, "hello world")
p post.frozen? #=> true
post.id = 2 #=> FrozenError

なおこちらはその後rejectされ、以下に議論が移りました。

基本的な振る舞いを変えるキーワード引数は好きでない。#16122の方が好ましいので続きはそちらで。
Matz
#16769のコメントより

⚓リモートワーク

⚓COVID-19がネットに及ぼす影響


同記事より

イタリアのトラフィック上昇が突出してますが、全体にダウンロード速度の低下は持ちこたえてますね。公的機関のアナウンスがあるとトラフィックが増える傾向があるとのこと。


つっつきボイス:「BPS社内Slackに貼っていただいた記事です」「この記事を見たときに思ったんですけど、今リモートワーク関連特需でPCの納品が間に合ってなくて、各種部品の生産もゼロではないにしてもだいぶ落ちているので、この記事のようにインターネットのトラフィックもクラウドの利用も非常に増えているということは、もしかするとクラウド系の利用料金の上昇につながる可能性があるのではないかとちょっと思いました」「あぁ、それありそう!😳」「クラウド料金を現在の価格で試算しているとハマるかもしれないので、とりあえず料金上昇の可能性について警戒はしておこうかなと☺

「まあAWSあたりがいきなり爆上げするとは考えにくいですが😆、カツカツの料金で運営しているサービスなんかが上げてくる可能性はあるかなと: 上の記事はそのつもりで貼りました」「なるほど」「文字どおり自分らの業務に影響する話なので🧐

⚓その他リモートワーク

つっつき後のツイートです。

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

⚓AWS ECSやFargateでEFSファイルシステムをサポート


つっつきボイス:「これも社内Slackに貼っていただいた記事です」「うん、これはいいですね👍: AWSのECSがEFSをマウントできるようになったことで、ようやく共有ファイルシステムを触れるようになった😋

参考: Amazon ECS(Docker コンテナを実行および管理)| AWS
参考: Amazon EFS(EC2 用フルマネージド型ファイルシステム)| AWS

「今までだと面倒だったんでしょうか?」「ECSはEC2の上で動いているからやってやれないことはないんでしょうけど、公式にインテグレーションされていなかったので自分で頑張って設定しないといけなかったと思います🧐」「どちらかというとFargateでEFSが使えるようになったというのが目玉っぽいかな🤔

参考: 【全世界待望】Fargateから共有ファイルストレージのEFSが使えるようになりました! | Developers.IO

「Googleだとどのサービスが対応するんだろうという話にもなってましたね」「以下の記事↓にあるように、GKEのKubernetesには元々PersistentVolumeというものがありますが、GKEはKubernetesなのでそもそもECSとは違いますね😆」「そうでしたか😅」「AWSにおけるEFSに相当するのはGoogle Engineの永続ディスクでしょうね」「なるほど」

参考: 永続ディスクを使用した永続ボリューム  |  Kubernetes Engine のドキュメント  |  Google Cloud
参考: ストレージ オプション  |  Compute Engine ドキュメント  |  Google Cloud

⚓コンテナデザインパターン


つっつきボイス:「こちらは少し前の記事ですが、論文PDFを要約したものだそうです」「なるほど、GoogleがUSENIX↓に出した論文」「意外に短いですね」


usenix.orgより

「Googleが今まであったコンテナのパターンをまとめた感じで、2016年の論文だからDockerが流行り始めたぐらいの頃かな🤔」「そのぐらいですね」「まあGoogleはその前からKubernetesをゴリゴリ使ってたので、そういうコンテナパターンの走り的なものでしょうね☺

⚓JavaScript

⚓privateメソッドのテストは書かないものか


つっつきボイス:「はてブでバズってたt-wadaさんのブログで、サンプルコードがJSだったのでここに置きました」「ああこれ、privateなメソッドをテストしないかどうかはものによる気もしますけど😆」「基本的にはしないという感じでしょうか?」「privateなメソッドをpublicメソッド経由でテストするのは一見理にかなっているように見えなくもないんですけど、仕様変更によってパスしなくなる条件が出現する可能性は否定できないので、カバレッジの保証ができないという意味ではあんまりよくないとは思います🧐」「う〜む」「まあカバレッジにどこまで意味があるのかという話もありますけど😆

「実際記事で言っているとおりだと思いますし、privateなメソッドは、落ちても人が死なないようなシステムであれば普通テストは不要だと思いますが、とてもクリティカルな機能についてはテストを書きたいと思うこともあるんじゃないかなという気はしますね☺」「なるほど」「記事の『privateなメソッドのテストは内部の実装に対するテストになりがち』『構造的結合が強い』もそのとおりで、ただそれが必要になることがまったくないわけではないかなと自分は思います: まあWebシステムではほぼ要らないでしょう😆」「😆

⚓ECMAScript 2020の新機能


つっつきボイス:「似たような記事はちょいちょい見かけますが😆」「ECMAScript 2020はもう確定した?」「今release candidateだったと思います」

参考: Release ES2020 Candidate · tc39/ecma262

「お、Promise.allSettledでPromiseに対してまとめて処理できるようになってる: 速くなりそうなので速くなってるといいな😋

// 同記事より
const p1 = new Promise((res, rej) => setTimeout(res, 1000));

const p2 = new Promise((res, rej) => setTimeout(rej, 1000));

Promise.allSettled([p1, p2]).then(data => console.log(data));

// [
//   Object { status: "fulfilled", value: undefined},
//   Object { status: "rejected", reason: undefined}
// ]

「Nullish Coalescing演算子なんてのも」「??っていうのがそれですね」「なるほど、通常の||だと空文字""がfalseになるので”Anonymous”が返るけど、??だと少し型厳密に""はfalseじゃないという扱いになって""が返ると」「次の数値0も同じで、要は必ずtrue/falseで判定するのね」「??なんて記号が突然出てきたらこっちの頭がクエスチョンになりそう😆」「😆

// 同記事より
let person = {
  profile: {
    name: "",
    age: 0
  }
};

console.log(person.profile.name || "Anonymous"); // Anonymous
console.log(person.profile.age || 18); // 18

// 演算子でやる場合
console.log(person.profile.name ?? "Anonymous"); // ""
console.log(person.profile.age ?? 18); // 0

「Optional Chaining演算子?.はRubyの&.演算子と似たような動作😋」「Rubyのぼっち演算子でしたっけ」「その呼び方知らな〜い😆

// 同記事より
let person = {};

console.log(person.profile.name ?? "Anonymous"); // person.profile is undefined
console.log(person?.profile?.name ?? "Anonymous");
console.log(person?.profile?.age ?? 18);

Rubyのぼっち演算子はRailsの`Object#try`より高速(翻訳)

「そしてBigInt型」「およ、数値の後ろにnを付けるのか!😳」「これも実際に見たらビックリしそう😆」「たぶん使わないかな〜☺

// 同記事より
const bigNum = 100000000000000000000000000000n;

console.log(bigNum * 2n); // 200000000000000000000000000000n

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

⚓Chromeのデフォルトコントロール改善とSameSite Cookieの一時ロールバック


つっつきボイス:「またChromeの見た目変えるのね😆」「😆」「こういうコントロールは結局ブラウザ依存ですし、デザインにこだわる人たちはみんなCSSで上書きしてるので影響ありませんし」「たしかに」「ブラウザのスタイルシートをそのまま使っている人にとっては影響ありますけど☺


「2本目はSameSite Cookieの適用を先送りにしたという話」「COVID-19の影響か😳」「なるほど、SameSite Chookieに対応していなくても生活のために重要な情報を発信しているサイトはあるので、GoogleがSameSite Cookie適用を強行すると影響が大きいと見て先送りにしたということなんでしょうね☺」「これはたしかに」「SameSite Cookieに対応するリソースがないところもあるでしょうし」「Googleナイスプレイ❤

参考: 【一問一答】 Chrome の SameSite Cookie の変更とは? : Cookie への新たなアプローチ | DIGIDAY[日本版]

⚓その他デザイン


つっつきボイス:「画像や写真なしでレイアウトしているとBPSデザインチームがどよめいてたので」「英語圏だとそういうサイトがよくありますね☺」「このレベルまで完成させるのは大変そう😅」「本当の意味でフロントエンドエンジニアとUXデザイナーを兼任しているような人たちはこういうのが作れますしお金も取れますね💪」「あとコピーライティングも」

⚓言語・ツール

⚓Unixコマンドの名前由来事典(StatusCode Weeklyより)


つっつきボイス:「DebianのWikiに載っているコマンド名由来事典だそうです」「めちゃ大量😆」「aptが何の略かとか初めて知りました😆

「コマンド名は由来がいくつもあったりするものもありますけど😆」「古いコマンドとか特に😆」「dcってdesk-calculatorの略なのか〜」「bcは知ってたけどdc知らなかった😳」「cdをタイポしてdc動かしちゃうことがたまにあってですね😆

nethack-*はnot a net-hacking toolだぞと😆」「あれ、これは…?」「rogueライクなゲーム😆」「あ〜CLIゲームの!」「そうそう、自分のマークが@になるヤツ」

参考: NetHack - Wikipedia

tmuxとかあるぐらいなので割と新しそう」「メンテされてるのかしら?」「たぶん最近作ったんでしょう😆: インターネットミームまみれでもなくて割と真面目に書かれてるっぽい」「そんな感じですね」「まあトリビアですけど🤣」「年代別でも探せると嬉しいかも😋」「たしかに!」「最近はまともなコマンド名が増えましたけど、昔になるほど意味不明なコマンド名多いですし😆

「昔何かで読んだんですが、Unix古参の人がcreat()関数にeを付けなかったのは失敗だったと悔やんでたような覚えがあります」「昔のlibcとかにもそういうのありますね、strなんちゃら系で母音を削ったみたいな話😆」「😆

参考: C言語では、createではなく、creat

⚓その他言語

つっつきボイス:「COBOLはgotoありなのか」「はいありました😆」「Cのgotoは、gotoで書く方がシンプルになることもなくはないかも☺」「深いところから脱出するときとか😆」「まあ自分はやらないけど😆」「今のC言語ならgotoで書いてもよしなに最適化してくれるかな?ラベルにgotoするのは割とアセンブラに近いものがありますし、Cにgotoがあるのは自分的にはそれほど違和感はないかな〜☺

⚓その他

⚓LPWAとBLE対応GPSトラッカー

参考: LPWA (LPWAN) とは? Low Power Wide Area - IoT プラットフォーム 株式会社ソラコム
参考: 「そもそもBLEって何?」Bluetoothの技術概要 | 芳和システムデザイン


つっつきボイス:「LPWAとBLE周りがわかってなかったので😅」「全部入りな感じ😆

「こういうデバイスって昔から需要はあったんですけど、お値段がね…昔こういうデバイスを自転車に付けようとして探したんですけどなかなか手頃なものがなかったんですよ😅」「電波を発信するとどうしても電力使うから難しいですね💡」「電力は自分がバッテリー交換すればいいとしても、当時はやっぱりお値段というか運用費かかっちゃって😅」「ライセンス費用で値段下げにくいとかもあったんでしょうね」「そんな感じでした😢」「バイクにPHS仕込んで盗難防止にする記事を昔見ました」「そういう発想です☺

⚓紛失防止デバイス: TileとAirTag

「そういえば、手段は違いますけど最近Appleが似たようなサービスを始めようとしているニュースがありましたよね?」「というと?」「その前に説明しておくと、日本だとソフトバンクがやっているTileっていう探しものに便利な製品↓があって自分も使ってるんですけど」「え、これ知らなかった😅

「このキーホルダーみたいなTileはBLEと連携していて、スマホのアプリからTileを鳴らしたり、逆にTileのボタンを押してスマホを鳴らすこともできるんですよ😋」「へぇ〜!」「Tile自体はBluetoothの通信機能しかないので、本来だと遠くでなくしたら通信できないはずなんですけど、Tileがエラいのは、Tileアプリを入れている他人がたまたまTileの近くにいると、それを経由してTileの居場所をいわば共有することができるんですよ」「ははぁなるほど!」

「私、これに似た別の製品を昔持ってたんですけど、アプリのユーザーがあまりに少なすぎて役に立ちませんでした😆」「この手の製品で重要なのは圧倒的に売れて普及していることですね🧐」「おっしゃるとおりです😅」「自分が調べたときはTileが一番普及してたのでTileにしましたけど😋」「Tileを自分だけが使う分には問題ありませんね」「実際Tileの一番の使いみちは、自分の部屋の中で車の鍵とかをなくしたとき🗝

「で、AppleもAirTagという製品を出してこのアプローチをやることにしたとこないだ発表してたんですよ」「なんと😳」「Appleが公式にこれをやったらライバルを全部つぶせますから😇」「あ〜そういうことですか😳」「ユーザーとしてはそういうサービスがある方がありがたいんですけど😂」「でもこれだとビットコインみたく他人のリソースを使って商売することになるので、そこは超えないといけないハードルだと思います🧐」「米国はそういうのにうるさいですし😆」「まあでも便利なサービスには違いないですね」「自分もTile使っててそう思いますし☺

参考: Apple紛失防止タグ「AirTag」はコイン電池で動作。交換も可能か
参考: Apple、高精度な紛失防止タグ「AirTag」の発売は4月以降に?

「とにかく、こういうアプローチはやれるからやっていいというものではありませんし☺」「技術はあっても運用で揉めるパターン😅」「日本だと『見守り』とか『安心』をフィーチャーしないと😆」「海外だとだいたい軍事目的になりがちですね: 小隊の兵士全員に持たせて小隊の位置を把握するとか」

「まあ冒頭の製品みたいに自分で位置を検出する方が、他のユーザーに頼らなくて済むので当然いいんですけど」「でもお高いしエネルギーも使うし😅

⚓かるた


つっつきボイス:「関係ありませんけど、今任天堂Switchがものすごい勢いで売れてる一方でボドゲも結構売れてるみたいですヨ😆」「ボドゲ😆」「それこそ人が集まらないとできないんじゃ?」「いえいえ、家から出られない子どもにゲームばかりさせるのは後ろめたいけど、ボドゲなら親としても言い訳が立つじゃないですか😆」「なるほどそっち😆

「AIかるたはさすがに大人向けかな〜😆」「ゲームにすれば子どもはあっという間に覚えちゃいますから😆」「それもそう😆」「むしろ子どもほど、暇があれば意味わからなくても覚えちゃいますし☺」「百人一首全部覚えるみたいな😆」「自分も暇だったときにギリシャ文字全部覚えたりしましたし🇬🇷」「私もギリシャ文字とキリル文字を並べて覚えました🇷🇺」「子どもならやれる😆」「後で大学とかでμ(ミュー)とか知ってる文字が出てくるとうれしかったり😋」「ψ(プサイ)とか😋」「ξ(クサイ)とか😋

⚓番外

⚓感情操作


つっつきボイス:「知能をAIで云々はよくやりますけど、感情周りってあんまりフィーチャーされてなかったかなと思って」「どこまで本当なのかと思いますけど😆」「電気信号で恐怖とか快楽とかを味あわせたりできるってことですよね」「もう攻殻機動隊でやってたみたいな、パチンコやってる人に何かを打ち込んで操作してどうこうする世界😆」「😆」「うちの子が大人になる頃には実用化されるかしら」「もっと早いかもですよ😆

参考: 電脳化 - Wikipedia


後編は以上です。

バックナンバー(2020年度第2四半期)

週刊Railsウォッチ(20200413前編)最近macOSでRailsが遅い、トランザクションでのreturnやbreakなどが非推奨化、Rails監視ツールリスト2020年度版ほか

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

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

Ruby Weekly

StatusCode Weekly

Rails+Docker環境をbrowser-syncでオートリロードできるようにしてみた

$
0
0

例のEvil Martians流Rails + Docker環境でひとつ困っていたのが、ファイルを更新したときの自動ブラウザ再読み込みです。

今回は、Gulpなどの静的Webサイト開発などでよく使われるbrowser-syncをプロキシにしてオートリロードをやってみました。Chrome拡張をインストールせずにオートリロードできるのと、管理コンソールが使えるのが特徴です。


同リポジトリより

Dockerの外でbrowser-syncを動かす

主に以下の記事を参考にしました。

参考: Rails + BrowserSync でViewをシームレスに開発する - Qiita

環境

  • macOS Catalina
  • Docker for Desktop 2.2.0.5(43834)
    • Docker 19.03.8
    • Docker Compose 1.25.4
  • yarn 1.22.4(Dockerの外、つまりmacOSのシェル環境にインストールしておくこと)

前提

以下のEvil Martians流Rails + Docker + docker-composeをベースとします。

Rails 6のDocker開発環境構築をEvil Martians流にやってみた

自分は上に加えて以下のdipツールも併用していますのでdipコマンドで記述します。それ以外の環境では適宜docker-compose exec app bashdocker-compose upなどに置き換えてください。

docker-composeを便利にするツール「dip」を使ってみた

設定手順

下ごしらえ

  • macOSのシェルでyarn global add browser-syncを実行し、browser-syncをインストールする
  • プロジェクトのルートに移動する
  • dip browser-sync initを実行して初期化する(bs-config.jsが作成される)

コンフィグ1

  • 作成されたbs-config.jsを以下のように変更する
// 変更前
// (略)
module.exports = {
    "ui": {
        "port": 3001
    },
    "files": false,
    "watchEvents": [
        "change"
    ],
// (略)
    "server": false,
    "proxy": false,
// (略)
// 変更後
// (略)
module.exports = {
  "ui": {
    "port": 3001
  },
  "files": ["app/**/*.css", "app/**/*.sass", "app/**/*.html", "app/**/*.erb", "app/**/*.js", "app/**/*.rb"]          // ここを変更
  "watchEvents": [
    "change"
  ],
// (略)
  "server": false,
  "proxy": "localhost:3000",  
// (略)

コンフィグ2

  • package.jsonに以下を追加する
    • browser-sync start --config bs-config.jsを直接実行するなら不要
  "scripts": {
    "start": "browser-sync start  --config bs-config.js"
  }

自動リロードを動かす

  • ターミナルウィンドウを2つ開く
  • 1つ目のターミナルでプロジェクトに移動し、エディタを開いてからDockerを起動する

自分はdipを使っているのでdip rails sで起動しています

  • 2つ目のターミナルでnpm startを実行してbrowser-syncを起動する

これでブラウザでhttp://localhost:3001が自動的に開き、エディタでファイルを更新するとオートリロードされるようになります。

自分の場合、webpack-dev-serverによるWebpackerのリコンパイルはEvil Martians流docker-compose側でやってくれるので、元々手動でリロードすればWebpackerのコンパイルが走るようになっています。なのでbrowser-sync側でwebpack-dev-serverの設定は不要です。

ブラウザでhttp://localhost:3002にアクセスすると以下のコンソールが開きます。

BASIC認証を使う場合

自分のRailsアプリでは管理用画面にBASIC認証(実際はダイジェスト認証)をかけているのですが、そのままではBASIC認証がプロキシを通りません。

この場合はbs-authというプラグインを用いてBASIC認証が通るようにします。

設定

  • macOSシェルでbs-authを追加する
    • yarn global add bs-auth
  • bs-config.jsを以下のように変更する
    • process.envで環境変数からユーザー名とパスワードを読める
    • digestの場合もdigestなしのパスワードを環境変数から渡す
// 変更前
// (略)
    "plugins": [],
// (略)
// 変更後
// (略)
  "plugins": [
    {
      module: "bs-auth",
      options: {
        user: process.env.DIGEST_USERNAME,
        pass: process.env.BASIC_PASSWORD
      }
    }
  ],
// (略)

改良したい点

  • ターミナルを2つ開いて起動するのが面倒、しかもRailsが完全に起動してからbrowser-syncを起動する必要がある
  • bs-authの認証時にパスワードがコンソールに表示されないようにしたい
  • できればDockerの外でbrowser-syncを動かすのではなく、docker-composeのサービスのひとつとしてbrowser-syncを動かしたい

docker-composeのサービスでやれないか以下のように試してみましたが、まだうまくいかないので今後の課題とします。

  • ファイル更新は検出されるがブラウザに更新が届かない
  • サービスをctrl-cで止められず、ターミナルを閉じないと終了しない😢
# Dockerfile
FROM node:12-slim

RUN npm -g install browser-sync bs-auth

WORKDIR /app
# docker-compose.yml(抜粋)
  browsersync:
    build:
      context: .
      dockerfile: ./.dockerdev/Dockerfile_bs
    command: browser-sync start --config ./bs-config.js --tunnel
    env_file: .env
    volumes:
      - .:/app:cached
    ports:
      - "3000:3000"
      - "3001:3001"

最後に

browser-syncを使う場合、ブラウザに拡張をインストールせずにやれる点はありがたいです。今のところ管理コンソールでは特別な設定はしていません。

READMEによると、初回リクエスト時に<script async>...</script>という非同期スクリプトタグを<body>タグの直後に挿入することで実現しているとのことです。そのためHTMLに<body>タグがないと動作しません。自分のアプリでHTMLソースを見ると、たしかに以下が挿入されています。

<body><script id="__bs_script__">//<![CDATA[
    document.write("<script async src='/browser-sync/browser-sync-client.js?v=2.26.7'><\/script>".replace("HOST", location.hostname));
//]]></script>

とにかく、Docker上の開発環境(特にMac上)での定番のオートリロード方法が早く確立されて欲しいです。

週刊Railsウォッチ(20200420前編)anyway_config gemでRails環境設定、ShopifyのLiquidテンプレートエンジン、書籍『Beyond the Twelve-Factor App』ほか

$
0
0

こんにちは、hachi8833です。Gitをただちにアップグレードしてセキュリティ修正しましょう。リンク先に日本語の丁寧な説明があります🙇

また、OpenSSLのセキュリティ修正1.1.1gが明日リリースされるそうです。

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

⚓Rails: 先週の改修(Rails公式ニュースより)

⚓Rails.cache.clearが高アクセスで出すErrno::ENOTEMPTYを無視するようにした

# activesupport/lib/active_support/cache/file_store.rb#L36
      def clear(options = nil)
        root_dirs = (Dir.children(cache_path) - GITKEEP_FILES)
        FileUtils.rm_r(root_dirs.collect { |f| File.join(cache_path, f) })
-     rescue Errno::ENOENT
+     rescue Errno::ENOENT, Errno::ENOTEMPTY
      end

つっつきボイス:「ENOTEMPTY?」「あ、E NOT EMPTYか😆」「FileStoreを使っているときのエラーね☺」「単に無視することにしてるとは😳」「raiseするよりはということかな🤔

「他のキャッシュ操作ならともかく、キャッシュをclearするときだから、キャッシュがnot emptyになっても無視して別に大丈夫でしょうという感じですかね😆」「どうせ消すんだし😆」「正しいキャッシュの使い方をしていれば普通は問題ないはず😆

⚓Active Modelのerrorsメソッドの多くが非推奨化


つっつきボイス:「お、Enumerable系の操作の一部がdeprecateされてる😳」「そもそもerrorsって単純な配列やハッシュじゃなかったような覚えがあるので、そういう操作が対象になったということか: 気持ちはワカル」「おぉ」「インターフェイスは一応共通ですけど☺

「その後上のコミットで一部が差し戻されてました↑」「まあeachはなくさないでしょうけど😆valuesとかkeysぐらいはあってもいい気がしますが」「そうですね」「まあdeprecationはいったんマージされても後になってやっぱり必要なんじゃないかって取り消されることもちょくちょくありますけど😆」「たしかに😆」「従来のユースケースをハードに使ってる人たちがいそうな雰囲気ですし、このプルリクももしかするとまた差し戻されるかも?」

バリデーションエラーをErrorオブジェクトとしてカプセル化する
ActiveModelerrorsコレクションは、messages/detailsのハッシュではなく、これらErrorオブジェクトの配列になった。
それらErrorオブジェクトのひとつひとつにあるmessageメソッドやfull_messageメソッドはエラーメッセージの生成用。同じくdetailsメソッドは、従来のdetailsハッシュにあった追加のエラーパラメータを返す。
今回の変更ではできる限り後方互換性を保とうとしているが、errors#firstなどのerrors.messageserrors.detailsハッシュを直接操作する一部のエッジケースまではカバーしきれない。今後は、こういった直接操作ではなく、提供されるAPIメソッドに書き換えること。
今回非推奨になったメソッドや、次のメジャーリリースで振る舞いが変更される計画のあるメソッドのリスト:
* errors#slice!(削除される)
* errors#firstErrorオブジェクトを返すよう変わる)
* errors#lastErrorオブジェクトを返すよう変わる)
* errors#eachkey, valueを引数に持つブロックを渡す機能は動かなくなるが、errorだけを引数に持つブロックはErrorオブジェクトを返す
* errors#values(削除される)
* errors#keys(削除される)
* errors#to_xml(削除される)
* errors#to_h(削除される、errors#to_hashで置き換え可能)
* errors自体をひとつのハッシュとみなす操作は無効になる(errors[:foo] = 'bar'など)
* errors#messagesが返すハッシュ(errors.messages[:foo] = 'bar'など)への操作は無効になる
* errors#detailsが返すハッシュ(errors.details[:foo].clearなど)への操作は無効になる
#36125と@a4deb63より

⚓新機能: ActiveSupport::TimeWithZone#inspectに秒以下表示を追加

# activesupport/lib/active_support/time_with_zone.rb#L141
    def inspect
-     "#{time.strftime('%a, %d %b %Y %H:%M:%S')} #{zone} #{formatted_offset}"
+     "#{time.strftime('%a, %d %b %Y %H:%M:%S.%9N')} #{zone} #{formatted_offset}"
    end

つっつきボイス:「タイムゾーンのinspectに下の12345678みたいな秒以下が追加されたそうです」「inspectの挙動を直しただけみたいだけど、たしかに表示しないとキモチワルイし☺

# 同PRより
# before
Time.at(1498099140).in_time_zone.inspect
# => "Thu, 22 Jun 2017 02:39:00 UTC +00:00"
Time.at(1498099140, 123456780, :nsec).in_time_zone.inspect
# => "Thu, 22 Jun 2017 02:39:00 UTC +00:00"
Time.at(1498099140 + Rational("1/3")).in_time_zone.inspect
# => "Thu, 22 Jun 2017 02:39:00 UTC +00:00"

# after
Time.at(1498099140).in_time_zone.inspect
# => "Thu, 22 Jun 2017 02:39:00 UTC +00:00"
Time.at(1498099140, 123456780, :nsec).in_time_zone.inspect
# => "Thu, 22 Jun 2017 02:39:00.12345678 UTC +00:00"
Time.at(1498099140 + Rational("1/3")).in_time_zone.inspect
# => "Thu, 22 Jun 2017 02:39:00 1/3 UTC +00:00"

inspectの結果が等しいかどうかみたいなことは実装では普通やりませんけど、エラーログを調べているときなんかにはinspectしたときに中身が違っていたら表示も違ってて欲しいですよね😋」「あ、それはうれしい😂」「上のbeforeの2つ目と3つ目だと中身違うのに表示が同じになっちゃってますし😆」「今までだと、そういう知識がなかったらinspectしても違いが出ない理由が想像つかなくてハマったでしょうね😆」「これは理にかなった変更だと思います👍

「ところでTime.at(1498099140 + Rational("1/3"))って書いてますけど、RubyのタイムにはRational食わせられるのか🤣」「うぉ〜マジですか🤣」「出力もちゃんと02:39:00 1/3になってるし😳」「そんな書き方できるんかいっ🤣」「これは『今日のへぇ〜』決定😆

「どうやらRuby 2.7のTime#inspectがサブセカンドも表示するようになったので、今回の修正はそれに合わせたのかも↓」

$ docker run ruby:2.7.0-alpine ruby -e 'p Time.at(1498099140)'
2017-06-22 02:39:00 +0000
$ docker run ruby:2.7.0-alpine ruby -e 'p Time.at(1498099140, 123456780, :nsec)'
2017-06-22 02:39:00.12345678 +0000
$ docker run ruby:2.7.0-alpine ruby -e 'p Time.at(1498099140 + Rational("1/3"))'
2017-06-22 02:39:00 1/3 +0000
$ docker run ruby:2.6.5-alpine ruby -e 'p Time.at(1498099140)'
2017-06-22 02:39:00 +0000
$ docker run ruby:2.6.5-alpine ruby -e 'p Time.at(1498099140, 123456780, :nsec)'
2017-06-22 02:39:00 +0000
$ docker run ruby:2.6.5-alpine ruby -e 'p Time.at(1498099140 + Rational("1/3"))'
2017-06-22 02:39:00 +0000

参考: Ruby 2.7 の変更点 - Time / Date - @tmtms のメモ

⚓match_head_routesのループを減らしてアロケーションを1/3に

IPS
Warming up --------------------------------------
               match    52.685k i/100ms
          fast_match    60.366k i/100ms
Calculating -------------------------------------
               match    606.333k (± 4.4%) i/s -      3.056M in   5.050991s
          fast_match    743.192k (± 3.0%) i/s -      3.743M in   5.040465s

Comparison:
          fast_match:   743192.4 i/s
               match:   606332.8 i/s - 1.23x  slower

MEMORY
Calculating -------------------------------------
               match   120.000  memsize (     0.000  retained)
                         3.000  objects (     0.000  retained)
                         0.000  strings (     0.000  retained)
          fast_match    40.000  memsize (     0.000  retained)
                         1.000  objects (     0.000  retained)
                         0.000  strings (     0.000  retained)

Comparison:
          fast_match:         40 allocated
               match:        120 allocated - 3.00x more

Lazyはあまり効かなかったので使わなかったそうです。

# actionpack/lib/action_dispatch/journey/router.rb#L108
        def find_routes(req)
          routes = filter_routes(req.path_info).concat custom_routes.find_all { |r|
            r.path.match?(req.path_info)
          }

-         routes =
-           if req.head?
-             match_head_routes(routes, req)
-           else
-             match_routes(routes, req)
-           end
+         if req.head?
+           routes = match_head_routes(routes, req)
+         else
+           routes.select! { |r| r.matches?(req) }
+         end

          routes.sort_by!(&:precedence)

          routes.map! { |r|
            match_data = r.path.match(req.path_info)
            path_parameters = {}
            match_data.names.each_with_index { |name, i|
              val = match_data[i + 1]
              path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
            }
            [match_data, path_parameters, r]
          }
        end

        def match_head_routes(routes, req)
-         verb_specific_routes = routes.select(&:requires_matching_verb?)
-         head_routes = match_routes(verb_specific_routes, req)
-
-         if head_routes.empty?
-           begin
-             req.request_method = "GET"
-             match_routes(routes, req)
-           ensure
-             req.request_method = "HEAD"
-           end
-         else
-           head_routes
+         head_routes = routes.select { |r| r.requires_matching_verb? && r.matches?(req) }
+         return head_routes unless head_routes.empty?
+
+         begin
+           req.request_method = "GET"
+           routes.select! { |r| r.matches?(req) }
+           routes
+         ensure
+           req.request_method = "HEAD"
          end
        end

-       def match_routes(routes, req)
-         routes.select { |r| r.matches?(req) }
-       end

つっつきボイス:「スピードも速くなってアロケーションは3倍良くなってる🎉」「HTTPのHEADリクエストのルーティングのマッチを変えたのね😋

「HEADって結構使うんでしょうか?」「まあキャッシュを設定するとブラウザからちょいちょいHEADリクエストが飛んできますし」「そうなんですね!」「ETagの更新チェックなんかもそう🧐

⚓速いマシンはいい

「うむむ、変更量多いからGitHub diff画面をサイドバイサイド表示に変えようっと」「おや、そういえば今日は上下diff表示ですね」「いえいえ、今日Windows PCをギンギンに新しくしたばかりなのでその辺の設定をまだ移してなかっただけで😆」「そういえばRyzen 7にお引越ししてましたね」

「いやもう何が嬉しいって、マウスがちゃんと60fpsで動いて見えること😂」「そんなに違うとは😆」「新しい方はデスクトップPCですか?」「ですです😋、8コア16スレッド、特にメモリを64GBにしたらスラッシングが皆無になってもう神⛩」「😆」「やっぱメモリが足りてるのは大事って改めて思いましたよ: 今の時代に16GBは普通に足りなすぎ😆」「😆

⚓使われていないArel visitorsを削除

# activerecord/lib/arel/visitors.rb#L3
require "arel/visitors/visitor"
require "arel/visitors/to_sql"
require "arel/visitors/sqlite"
require "arel/visitors/postgresql"
require "arel/visitors/mysql"
-require "arel/visitors/mssql"
-require "arel/visitors/oracle"
-require "arel/visitors/oracle12"
require "arel/visitors/where_sql"
require "arel/visitors/dot"
-require "arel/visitors/ibm_db"
-require "arel/visitors/informix"

つっつきボイス:「@kamipoさんによる修正」「rbファイルが結構削除されてますね」「visitorsって何をやるんだろうと思ったら、まんまVisitorパターンなのか😆: Arelノードをなめる感じの」「既にどこかのタイミングでvisitorが廃止されてたんでしょうね」

既にコードベースで使われなくなったibm_db、informix、mssql、oracle、oracle12のArel visitorを削除する。
実際にはoracleとoracle12のvisitorは、sqlserverアダプタがそうであるように、アダプタのリポジトリに置いて専用Arel visitorにすべき。さもないと、自分たちにはOracleの知識がそこまであるわけではないので、#35838や#37646のようにoracle visitorのバグを見つけるのもプルリクをレビューするのもつらくなる。
同PRより

# 同コミットで削除されたactiverecord/lib/arel/visitors/ibm_db.rb
module Arel # :nodoc: all
  module Visitors
    class IBM_DB < Arel::Visitors::ToSql
      private
        def visit_Arel_Nodes_SelectCore(o, collector)
          collector = super
          maybe_visit o.optimizer_hints, collector
        end

        def visit_Arel_Nodes_OptimizerHints(o, collector)
          hints = o.expr.map { |v| sanitize_as_sql_comment(v) }.join
          collector << "/* <OPTGUIDELINES>#{hints}</OPTGUIDELINES> */"
        end

        def visit_Arel_Nodes_Limit(o, collector)
          collector << "FETCH FIRST "
          collector = visit o.expr, collector
          collector << " ROWS ONLY"
        end

        def is_distinct_from(o, collector)
          collector << "DECODE("
          collector = visit [o.left, o.right, 0, 1], collector
          collector << ")"
        end

        def collect_optimizer_hints(o, collector)
          collector
        end
    end
  end
end

参考: Visitor パターン - Wikipedia

「こうしてみると、Railsで使われているRDBMSっていっぱいありますね」「ibm_dbはきっとDB2」「DB2は試しにインストールしたことはあるけどproductionではやったことないな〜😆」「昔いた会社ではAS400でDB2を動かしてました」「DB2もSQLだから、複雑なことをやらなければ既に動いているものにアクセスする分にはたぶん大丈夫、かな😆」「😆

参考: DB2 と Ruby on Rails: 第 1 回 DB2 と Ruby on Rails の導入

⚓ルーティング探索の不要なパス情報取得呼び出しを削減

# actionpack/lib/action_dispatch/journey/router.rb#L108
        def find_routes(req)
-         routes = filter_routes(req.path_info).concat custom_routes.find_all { |r|
-           r.path.match?(req.path_info)
+         path_info = req.path_info
+         routes = filter_routes(path_info).concat custom_routes.find_all { |r|
+           r.path.match?(path_info)
          }

          if req.head?
            routes = match_head_routes(routes, req)
          else
            routes.select! { |r| r.matches?(req) }
          end
          routes.sort_by!(&:precedence)

          routes.map! { |r|
 -          match_data = r.path.match(req.path_info)
 +          match_data = r.path.match(path_info)
            path_parameters = {}
            match_data.names.each_with_index { |name, i|
              val = match_data[i + 1]
              path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
            }
            [match_data, path_parameters, r]
          }
        end

つっつきボイス:「これもルーティング系の更新」「無駄な呼び出しを削ったんですね」

👋自分はShopifyで働いているのだけど、最近自分らのメインアプリでproductionのリクエストをプロファイリングして、キャッシュヒットのサブセットで時間を食っている箇所について理解を深めようとしていたところ、通常で40〜50msかかっていた。自分たちのミドルウェアスタックで何が起こっているか、実際の「動作」の前の各リクエストで行われているすべてのものが特に気になった。
そして以下の結果にたどり着いた(Speedscopeのプロファイルより)。


Rack::Request::Helpers#path_infoへの呼び出し部分に少々驚かされた。コードを覗いてみると、同じ関数が無意味に繰り返し呼び出されていたので、ローカル変数に値を保持して再利用するよう変更した。
この変更は割とシンプルかつストレートなのと、ルーティング数の少ないアプリでは基本的にパフォーマンスは向上しないだろうと踏んで(アロケーションはある程度削減されるだろうが)、特にベンチマークは書かなかった。Shopifyほどのスケールになれば、イテレーションの必要なルーティング数が膨大になるので、この変更が効いてくるだろうと見込んでいる。
同PRより

「最近ルーティングの改修をそこそこ見かけますね」「ルーティングだと、パフォーマンスの最適化は比較的手出ししやすいかもしれないですね: 機能自体に手を入れなければ☺

「そういえばRailsのjourneyだったかな?、何かのコンポーネントでメインのメンテナーがいなくなってうかつに触れなくなったみたいな話が以前あった気がするけど、今はどうなっているんだろう?」「そういえばそんなような話した覚えが🤔」「journeyだったかどうかも定かでないけど😆」「う〜ん何だったかな〜😅

⚓Rails

⚓anyway_config: Evil Martiansの環境設定管理gem

以下の記事で紹介されていたgemです。


つっつきボイス:「今記事を翻訳し始めたところです」「これひとつで環境構築をまかなってやるぜ的な」「コンフィグ系のツール、いろいろあるな〜😆

「最近のRailsにあるsecretなんちゃらも対応してくれてるみたい」「コンフィグといえば昔から割と定番のconfig gem(旧rails_config gem)は今どうなってるんだろう: 最近も更新されてはいるみたいですね↓」「おぉ」

「anyway_configはそのオルタナという感じ: config gemはあくまでyamlで設定するけど、anyway_configはRubyのコードで設定することもできるみたい↓」「どっちもやれるんですね❤」「ちゃんと見ないとわからないけど、いろいろ高機能そうなツール😋: Rails標準のコンフィグだとかゆいところに手が届かなかったりもするので、こういうのを作る気持ちワカル」

# anyway_configリポジトリより
class MyConfig < Anyway::Config
  attr_config :host, :port, :url, :meta

  # 型強制を扱うためにライターをオーバーライド
  def meta=(val)
    super JSON.parse(val)
  end

  # または、値がない場合を扱うためにリーダーをオーバーライド
  def url
    super || (self.url = "#{host}:#{port}")
  end

  # v2.1まではインスタンス変数を読み取れる予定
  # つまり以下も動作する
  def url
    @url ||= "#{host}:#{port}"
  end
end

「今日はいませんがkazzさんはENVキライって言ってて、自分はどちらかというとENVの方が好きです」「ENVはENVで、万一プロセスを奪われると全部見えちゃいますけど😆」「それもそうですね😅」「まあ今はENVに入れるのが王道ですし、機会があったらanyway_config使ってみてもよさそう😋

「記事の方を見るとAWSコンフィグにも対応しているらしい↓」

# 同記事より
class AWSConfig < ApplicationConfig
  # attr_configでパラメータ設定用の
  # リーダーとライターを定義できる
  attr_config :access_key_id, :secret_access_key,
              :region, :storage_bucket
end

「そういえば、リポジトリでanyway_configを使っているものが紹介されている中にあるAnyCable、どっかで見たな〜」

この記事↓の著者がAnyCableやってるそうです。

Rails 6のB面に隠れている地味にうれしい機能たち(翻訳)

⚓RailsのMVCリファクタリングに役立つ7つのパターン


つっつきボイス:「ラインナップは特に目新しくはなさそうで以下の記事↓と基本的に変わらないんですが、短所や注意も書いてあるのがちょっとよさそうかなと思って」「こういうパターンはそうそう風化しないので、もし知らなければやってみればいいと思います😆」「エバーグリーンですね🌳

肥大化したActiveRecordモデルをリファクタリングする7つの方法(翻訳)

「自分はArelで書けるならQuery Object化しなくてもいいかな派だけど😆、ちっちゃいクラスを保ちたいときにArelでQuery Objectを書くのはそれはそれでありかも」「ふむふむ」「どちらかというとQuery Objectにするのは生SQLが必要になったときかなって自分は思ってます☺」「なるほど〜」

# 同記事より: Query Object
class Article < ActiveRecord::Base
    # t.string :status
    # t.string :type
    # t.integer :view_count
  end

 class ArticlesController < ApplicationController
    def index
      @articles = Article
                  .accessible_by(current_ability)
                  .where(type: :video)
                  .where('view_count > ?', 100)
    end
  end

「よく使われるパターンがひととおり載っているので、最近Railsを始めた人は読むといいと思います😋

見出しより:

  • Service Object(とIntaracter Object) — コントローラが太りやすい
  • Value Object — 変換や比較関連のロジックがコントローラに入りがち
  • Form Object — バリデーションロジックはモデルにあるので、Adminなど他のエンティティで再利用できない
  • Query Object — クエリの条件がコントローラに入るので再利用できずテストが面倒
  • View Object(Serializer、Presenter) — 計算ロジックがビューに入りすぎる
  • Policy Object — 作成ポリシーを知っているのはコントローラだけ、コントローラのロジックが増えがち
  • Decorator — 計算ロジックがビューに入りすぎる
  • まとめ

⚓書籍『Beyond the Twelve-Factor App』: あのTwelve Factor Appが15項目にリライト

参考: The Twelve-Factor App (日本語訳)


12factor.netより


つっつきボイス:「3月にはてブでバズっていたんですが、取り上げようと思って忘れていました😅」「12個から15個に🍫」「お〜、順番も少し変わってるし、『APIファースト』とかが加わってるあたりはマイクロサービスを意識している感じがしますね🔬

「credentialの話が入っているのもなかなかオモシロイ😋: デプロイ周りでは常にここが問題になってきますし」「前は『ENVでやれ。以上』みたいな感じでしたっけ?」「こちらではENVをどこに置くか、どのタイミングでロードするかみたいなところまで踏み込んでますね🧐」「おぉ」

「ぶっちゃけ開発者の環境なんかはどうでもよくて😆、production環境で本当に隠さないといけない情報をどう扱うかが重要: 記事にもあるようにcredentialをVaultとかに隔離してそっちから引っ張って来るなんてのは最近普通にやるようになってきましたし😎」「ヴォールトって記事にあるHashiCorpのVaultのことか😅」「TerraformだとVaultで鍵管理しますね🗝」「一般的には、マスターキーがないとコンフィグ自体にアクセスできなくする機能☺


vaultproject.ioより

「『Environment Parity(環境一致)』の概念か〜」「『Build、release、run』が1個増えて『Design、build、release、run』になってる😳」「テレメトリーはAPM(Application Performance Monitor)なんかも含むと」「authentication(認証)とauthorization(認可)なんかはサービスメッシュにやらせたい😂

authorizationは日本語訳が「認可」だったり「承認」だったりして、いつも迷います😅

「このBeyond the Twelve-Factor Appは詳細に読み込んでおく価値ありそう: Twelve-Factor Appが書かれた当時はまだ未来だと思われていたものがいろいろ出現しているのを反映しているし、とてもいいんじゃないでしょうか👍」「おぉ😋」「勉強会のお題にうってつけ❤


後でスライドを見つけました。

⚓AppSignalの「Citadelアーキテクチャ」(Ruby Weeklyより)


つっつきボイス:「Citadel(シタデル?)って知らない単語だったんですが、辞書で見てみると「要塞」とか「とりで」という意味で、周辺サービスをOutpost(前哨基地)と呼んでるようです」

参考: シタデル:永炎の魔法と古の城塞 | スパイク・チュンソフト

「どういう趣旨の記事かしら😆」「ざっと眺めたところでは、DHHが『Majestic Monolith↓パターン』に続く『Citadelパターン』という呼び名を考えたようなんですが、Majestic Monolithをまず知りませんでした😅

参考: The Majestic Monolith - bon’s bookmarks

「Majestic Monolithという言葉は今ひとつしっくりきませんけど😆、そういえばDHHは前からこういうことを言ってましたね」「基本はモノリスでという感じでしょうか?」「まあ上のリンク先で以下のようにまとめられているとおりですね: Railsもマイクロサービスに対応しないのかと聞かれるたびにDHHがこんな感じで答えてた覚えありますね☺」「そうでしたか!」「『マイクロサービスが流行っているから』『マイクロサービスだからいい』という理由で導入するのって違いますし😆

  • 組織の規模に合わせてマイクロサービス化する必要性は理解している
  • 組織の成長に合わないのであればマイクロサービスにする必要はない
  • モノリスであることを誇るのではなく、モノリスだからこそ保守性を上げる努力をする
    scrapbox.io/bon/より

「で記事ではOutpostという概念を持ち込んで幸せになったと」「とりあえず追っておくとよさそうな記事😋」「ですね😋

記事ではKafkaに対応するgemを作ることでOutpostを実現したそうです。

⚓liquid: Shopifyのマークアップ言語(GitHub Trendingより)


つっつきボイス:「liquidは随分前からあるみたいで★も多いんですけど、どこで使われているんだろうと思って」「{{ }}で囲んで記述するテンプレートエンジンか😳

<!-- 同リポジトリより -->
<ul id="products">
  {% for product in products %}
    <li>
      <h2>{{ product.name }}</h2>
      Only {{ product.price | price }}

      {{ product.description | prettyprint | paragraph }}
    </li>
  {% endfor %}
</ul>
# 同リポジトリより
@template = Liquid::Template.parse("hi {{name}}") # Parses and compiles the template
@template.render('name' => 'tobi')                # => "hi tobi"

「ははぁ、ノリとしてはSmartyみたいなヤツかな↓」「スマーティ?」「PHPのテンプレートエンジンですね🚗: READMEにも『Smartyスタイルのテンプレートエンジンがお好きならどうぞ』って書いてあるし😆」「おぉなるほど」

参考: Smarty マニュアル | Smarty

# smarty.netより
{if $name eq 'Fred'}
    Welcome Sir.
{elseif $name eq 'Wilma'}
    Welcome Ma'am.
{else}
    Welcome, whatever you are.
{/if}

「RailsのビューはERBの中でRubyのコードが直接動くので、どんなひどいコードでも書けちゃうんですよ: そもそもビューにそんな複雑なロジックを書くべきではないという話も昔からありますし」「たしかに」「こういうLiquidとかSmartyは特定のコードしか動かないようにすることで、何でもできるようにさせないというものです」「なるほど、テンプレート専用のDSLにすることでやんちゃさせないと😆」「そうそう、Rubyで言うDSL」「概念としては昔からこういうのがありますね☺

参考: ドメイン固有言語 - Wikipedia — DSL

「そういうふうにするともうひとつメリットがあって、キャッシュがよく効くようになります: 生Rubyコードを書くとどんなコードが来るかわからないので、うまくキャッシュに乗らなかったりプリコンパイルも限界があったりするんですけど、こういう機能制限した言語なら先にコンパイル済みキャッシュを作りやすいんですよ」「おぉ❤」「まあ新たにその専用言語を覚えないといけないのがしんどいですけど😆」「😆

「そういえば以下の記事なんかでエンドユーザーがLiquidのテンプレートで書けるようにしてますね」「そうそう、比較的安全度高いのでそういう用途に向いてますね😋: APIに載ってるものしか書けないので、lambda書いて動かすような無茶はできない😆」「😆

参考: Rails with Liquid - Qiita
* 元記事: 【Shopify②】テーマのカスタマイズ(Liquidコード編集)|Osamu Iwasaki|note

「まあ自分はたぶん使わないというか、エンジニアが書くならLiquidみたいなのは不要かなと思いますが」「やっぱりエンドユーザー向けでしょうか?」「エンドユーザーよりは管理者に使ってもらうのにいいでしょうね: たとえばメールテンプレートをカスタマイズできるようにするみたいなオーダーはよくありますけど、BPSでやっている入退くん↓のように複数テナントの管理者が個別に通知メールをカスタマイズするような案件では、管理者がRubyを生で書けてしまうと何が起きるかわかりませんし事前チェックもしづらいんですけど、Liquidみたいなものなら事前にコンパイルがとおるかどうかをチェックするようにもできますし😋」「なるほど!」

個別指導塾での「入退くん」の使い方

⚓その他Rails

つっつきボイス:「2本目は永和システムマネジメントさんの記事です」「リファ練はリファクタリングの練習か🤔」「リファクタリングは、やり方さえ間違ってなければ、チームの足を引っ張らずに練習できるという意味で新人に向いている作業ですね」「とっかかりによさそう😋」「最悪マージできなくてもロジックに影響しないので☺

「ただ、リファクタリングばかりするということだと業務としてはちょっと違うんですよね😅」「たしかに機能面での進捗ないですし🤔」「もちろんリファクタリングする人は必要ですし、いてくれることでコードの健康が保たれるんですけど売上に直接貢献する作業ではないので」「そうですね」

「自社システムをたくさん持っている大きな会社だったら、リファクタリングの鬼になって社内のあらゆるシステムのリファクタリングを一手に引き受けることで会社にもメリットがあると思いますけど、受託開発で案件もそんなにたくさんないような職場だとリファクタリング専任の社員を抱える余裕はそうそうないでしょうし☺」「ただ、本物のリファクタリングのプロになれば、たとえばフリーランスとして週2日とか週3日とかのペースでリファクタリングを請け負う人になれるでしょうし、実際そういう人がいてくれるとありがたいです😋」「😋


前編は以上です。

週刊Railsウォッチ(20200413前編)最近macOSでRailsが遅い、トランザクションでのreturnやbreakなどが非推奨化、Rails監視ツールリスト2020年度版ほか

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

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

Rails公式ニュース

Ruby Weekly

GitHub Trending

160928_1701_Q9dJIU

週刊Railsウォッチ(20200421後編)Ruby 2.4サポート終了、Ruby 3の右代入演算子、GitHubコア機能無料化ほか

$
0
0

こんにちは、hachi8833です。本日Python 2系の最終リリースが出ました。

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

⚓Ruby

⚓Ruby 2.4のサポート終了(Ruby公式ニュースより)

Ruby 2.4は今後セキュリティ修正が出なくなります。


つっつきボイス:「おぉ〜Ruby 2.4終わったか〜!」「発表は4/5だったんですが見落としてました😅」「Ruby 2.5もセキュリティメンテナンスフェーズ突入とは😳

「こういう情報見逃してると、いきなりAWSで新しくLambdaのレイヤを作れなくなったりしますし😇」「ああっ🤣」「それは痛いっ🤣」「おそらくですけど、AWSではサポート対象のRubyバージョンでないと出してくれないんじゃないかと: さすがに今動いているものは止めないでしょうけど☺」「これは気を付けないと😅

⚓Ruby 3に入る右代入演算子=>

参考: Ruby の開発版に右代入演算子とエンドレスメソッド定義構文が入った - Qiita


つっつきボイス:「先週のendレスメソッド定義の他にこれも入ってました」「おほ、右代入😆」「=>はキライじゃないけど、いきなり出てきたらビックリするかも😆

「いわゆる比較演算子と紛らわしくならないかしら?」「一応大丈夫みたい↓」

3 >= 5 # 比較演算子
3 <= 5 # 比較演算子
=>     # 右代入

「右代入演算子オモシロイけど、どこで使ったらいいんでしょうね?🤔」「lambdaチェインの長い処理をtapして、その最終処理を変数に入れたいときとか?😆」「変数名を冒頭に置かなければ処理を読み下しやすいからいい、とか?🤔」「ようわからん😆」「まだ自分は使わないかな〜🤣」「🤣

⚓比較演算子を英語の語順で覚える

=<>のどっちが先か割と忘れがちで😅」「Rubyに限りませんけど、自分はこういう演算子の順序を英語の語順と同じということで思い出しますね😋」「それだ!」「言われてみれば😳」「less than or equal toとかgreater than or equal toで思い出せばいいですし☺」「ほら、Perlの比較演算子にもleとかgeとかあるじゃないですか😆

なお英語的にはequal to or greater thanのようにequal toが先に来るのもありですが、コンピュータの文脈ではequal toを後ろに書く方が多いようです。

⚓Rubyコンカレンシーについての最終レポート


同記事より


同記事見出しより:

  • はじめに
  • 実装(自分たちの提案する設計では現状のマイナーチェンジが必要)
    • スレッドスケジューラ
    • ノンブロッキングFiber
    • ノンブロッキングスレッド
    • ノンブロッキングI/O
  • 今後のスケジュール
  • まとめ

つっつきボイス:「以前もお伝えした(ウォッチ20191225)、Rubyのコンカレンシーをこんなふうに改良しようじゃないかというレポートの最終版だそうです」「ファイバーとかコンカレンシー周りの話はこれまでもRubyKaigiでちょくちょく話されてましたね😋」「その一連の流れにつながっているみたいで、最終的に以下のissueを投げたそうです」

参考: まつもとゆきひろさん「Ruby3の目指す未来 –The Year of Concurrency–」〜RubyKaigi 2019 1日目 基調講演:RubyKaigi 2019 Keynote レポート|gihyo.jp … 技術評論社

⚓Rubyのコンカレンシーとリソース値上げ

「今はパンデミックの影響でクラウドの利用率が上がっているから、Rubyのコンカレンシーを改良しないとクラウドでのRubyが頭打ちになるかもってちょっと思いました」「おぉ😳」「先週もパンデミックがネットに及ぼす影響(ウォッチ20200414)で話しましたけど、今半導体の供給が追いつかなくなっているうえにネットのトラフィックが増加しているので、クラウドのコンピュテーションやネットワークのリソースが値上がりする可能性があるんじゃないかって」「そうでしたね」

「これまではフットプリントがでかくても動けばOKという富豪的な感じでやってきましたけど、リソースが値上がりしてくればフットプリントを小さくすることが直接コスト削減に結びつくようになるかもしれませんし」「ふむふむ」「そうなったら、コンカレンシーがうまく回らないと待ち時間にも課金されて残念みたいなことになったり」「う〜む😅

参考: 富豪的プログラミング

「そういう状況になったら、Go言語みたいなコンカレンシーに強くて起動時間も短いものが全面に出てくるかもしれないって、ちょっと思いました☺」「流れによってはそうなってくるのかも🤔」「JavaもGraalVMみたいのが出ていますし☕、最近はコンテナ向けのJavaもあるらしいので(ウォッチ20190218)、コスト面のためにもRubyのコンカレンシー周りがよくなって欲しいですね☺

参考: GraalVM


graalvm.orgより

⚓RubyMine 2020の新機能


つっつきボイス:「2020年最初のRubyMineアップデートか」「いろいろ機能増えてるっぽいですね」「Ruby 2.7のnumbered parametersを含む新機能がサポートされてるし」

参考: プロと読み解くRuby 2.7 NEWS - クックパッド開発者ブログ

「docker-composeをリモートインタプリタとして使えるようになった↓のが素晴らしい〜😂


同記事より

参考: RubyMine 2020.1 EAP is Open! | RubyMine Blog

「sshコンフィグUIが統一されてる」「sshといえば、Windows版でOpenSSH形式のコンフィグを読めるようになって欲しいな…」

「おぉ、この機能↓はきっとDataGripにも入るに違いない😋」「クエリの結果をエディタに出力できるようになったということでしょうか?」「クエリの結果は通常だとクエリビューに出力されるんですけど、クエリビューの結果と別の結果を比較したいということがよくあってですね😆」「あ〜」「クエリビューに出力されると前の結果が上書きされて比較できないので、こういう機能があると結構うれしい❤」「なるほど〜😋


同記事より

「とりあえず新しいRubyMineを使いましょうということで👍

⚓Rubyにおける「等値」とは

# 同記事より
class Message
  attr_reader :body, :subject

  def initialize(subject:, body:)
    @subject = subject
    @body = body
  end

  def eql?(other)
    other.class == self.class &&
      other.body == body &&
      other.subject == subject
  end
  alias == eql?

  def hash
    body.hash ^ subject.hash
  end
end

つっつきボイス:「Rubyのオブジェクト同士が等しいとは何ぞや的な記事みたいです」「ああeql?とかequal?とか==とかのね😆」「Ruby技術者認定試験に出るヤツ😆

参考: Ruby技術者認定試験


同記事では、既に同趣旨の記事があったことに気づいたとありました↓。こちらの方が読みやすいかも。

参考: Difference Between ==, eql?, equal? in ruby - Khalidh Sd - Medium

⚓その他Ruby


同リポジトリより


つっつきボイス:「Ruby製のゲーム作成キットだそうです」「なんだかとても懐かしげな画面😆」「昭和の匂い😆」「Rubyでゲームを作るのってもっと流行って欲しい気もするけど、ゲームを作るという目的でRubyを選ぶのってあんまりしないかな☺」「Rubyを勉強したいならいいかも😋

⚓DB

⚓ぽすぐれのここがキライ10連発(DB Weeklyより)


つっつきボイス:「PostgreSQLがキライな人もいるんだなと思って」「XIDってトランザクションIDか〜」「そのあたりでハマったことなくてわからないけど😆

「フェイルオーバーやレプリケーションの問題が挙がってるけど、どっちも自分で設定しないし😆」「随分コアな感じですね😅」「データベースをゴリゴリに使っているDB管理者の立場で書かれた感じがしますね: Oracle使ってたら困らないのにみたいな😆」「うんうん」「DB管理者はこのあたりを気にしておくといいと思います☺


見出しより:

  • トランザクションIDが一周すると危険(参考: PostgreSQLのトランザクションID周回問題を強制的に発生させる - Marlock Homes Diary
  • フェイルオーバーするとデータが失われる可能性
  • レプリケーションによってはデータの傷が拡散する可能性
  • MVCC(マルチバージョンコンカレンシー制御)のゴミが何かとつらい
  • 1コネクション=1プロセスはスケールするとつらくなる
  • 主キーインデックスが大飯食らい
  • メジャーアップグレードでダウンタイムが要求されることがある
  • レプリケーションがやや面倒
  • プランナーヒントを採用しない方針がイヤ
  • MySQLのようなブロック圧縮がない
  • といろいろ書いたけど、一般にはPostgreSQLから始めておいて、困ったときに調べることをおすすめする

⚓その他DB


つっつきボイス:「おぉ〜BigQueryにマテビューが❤」「内部的には今までもやってたんじゃないかという気もしますけど、結果を高速に得たいときにはあるとうれしいときもあるんでしょう☺

「BigQueryはどんな課金体系でしたっけ?」「ジョブの回数とI/Oアクセス量に対する課金ですね💰」「なるほど!」

参考: BigQuery の料金  |  Google Cloud
参考: マテリアライズドビュー - Wikipedia

⚓リモートワーク

⚓リモートワークさまざま


つっつきボイス:「1件目の記事は自分がSlackに以下を引用しながら貼ったんだったかな」「ですです」

 “Okay”はシンプルな同意で、“Okay.”は怒っているかもしれず、“Okay…”はためらいを表している。こうした違いが分からないのは、自社の公用語を読む能力がないに等しいとハシモト氏は話した。この違いが分からないからといって雇わないわけではないが、コミュニケーションの仕方と人の気持ちとの関係を理解することは不可欠。ハシモト氏はこれを「チャットリテラシー」と呼び、入社後できるだけ早く教えるようにしているという。
atmarkit.co.jpより

「リモートワークは、やっぱりリモートワークを前提として人を集めるのが大事だなって思いましたね: 出社して働くのが前提の人とリモートでもいいよという人が混じっているのが管理上いちばん調整しづらいので😅」「わかります」「うちのチームを半端にオンサイトに残さずにとっとと全員リモートに移行したのはそういう理由: ひとつのチームで両者入り交じるぐらいならそれぞれ別のチームにする方がいいと思います☺」「混じってると出社している人はリモートを気にしないといけないし、リモート側は取り残されてるんじゃないかという不安に駆られるし😅」「お互いの負担も大きくなる😢

「自分はリモート歴長いし性に合ってるからいいんですけど、出社前提で仕事のフォーメーションを構築した人は大変だろうなと」「あと職階や役職にもよるんですよね: 他のメンバーと連携するのが仕事の人が出社前提だとリモートで途端につらくなるでしょうし」「う〜む😅」「2件目の記事にあるリモートだと外出できないのがつらいという話もワカル」「リモート組と出社組がいるところでは、フルリモートへの移行で多少はパフォーマンスが落ちる可能性についてもたぶん覚悟が必要でしょう🧐

⚓その他リモートワーク

つっつきボイス:「この間も話しましたけど、ツイートにある『当初end-to-end encryptionしているような宣伝をしていたこと』がまさに問題😇」「ですね」「end-to-endでencryptionしてたら録画機能の提供が難しいのはたしかですけど」「できてないのをできてるかのように宣伝するのはマズい」


つっつきボイス:「ゴートを呼べるって🤣」「ヤギとはいえ知らない人をZoomに呼ぶのってどうよ🤣」「$100ってあるけど金取るとは😆」「そこがビジネスですよ🐐

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

⚓MinIO: S3 API互換のオブジェクトストレージサーバー


つっつきボイス:「MinIO、これは割と前からあるヤツです」「たしかに★もかなり多いですね」「要はオープンソースのS3互換ストレージサーバー」「これはdev環境とかテストで使う感じでしょうか?」「あとCIとかでも使いますね: S3 APIレベルにもテストをかけたいけどAWSへの通信を発生させたくないときなんかに、こういうのを使うとローカルで完結します😋」「なるほど〜」「Webチームでもどこかで使ってた覚えありますし」

「ミンアイオーって読むのかな?」「このスペルとロゴならきっとそうでしょう😆」「ミニオじゃなかった😆


同リポジトリより

⚓その他インフラ

つっつきボイス:「WSL2なかなかリリースされませんね😆」「😆」「さっきWindows Updateの再起動がなかなか終わらなかったんですけど、Insider Previewを入れてたせいだったという😆」「😆」「道理でWSL2が入らないと思った😆


つっつきボイス:「お😆、これは香川県のゲームパブコメのIPアドレスの件ですね」「この辺のニュースの元ネタがわかってなかったんですが、それでしたか😅

参考: 香川県ゲーム条例へのパブコメが192.168.7.21から大量に届いた状況を解説してくれる人々 - Togetter

「パブコメのメールが192.168.7.21というプライベートIPアドレスから来ていたということでツッコまれてたんですけど、ちゃんと技術をわかってたらこのIPアドレスだけで断定的なことは言えないはずなんですよ😆」「なんと😆」「それとは別に、パブコメに同じ誤字が大量にあったという報道もありましたね↓」「まあ組織票ぐらいあってもおかしくないですけど😆、庁内リバースプロキシがあるかもしれませんし、IPアドレスについてはもっと技術的な情報が出てこないと証拠にならないでしょう☺

参考: ゲーム条例パブコメに同じ誤字 「依存層」「条例にに」:朝日新聞デジタル

⚓JavaScript

⚓React HooksとRails APIでアプリを作る


同記事より


つっつきボイス:「React Hooksって最近のかな?」「Reactもいろいろ機能が増えてますし☺

参考: フックの導入 – React

フック (hok) は React 16.8 で追加された新機能です。state などの React の機能を、クラスを書かずに使えるようになります。
☄ja.reactjs.orgより

「記事はRailsアプリを作るところからやってみた感じ😋」「やってみた系記事😆

「まあこのぐらいシンプルなCRUDだったら、今だと『どうしてFirebase使わないの?』って言われて終わりそうですけど😆」「😆」「実際最近だとエンタープライズの複雑な用途でないとRailsを選ぶことがあまりなくなってきてますし☺

参考: Firebase


firebase.google.comより

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

⚓Chromiumのアーキテクチャ


つっつきボイス:「これもBPS社内Slackに貼っていただいたヤツです」「これは初心者向けにピッタリの超読みやすい記事👍」「とても優しく書かれている❤

「ちなみにGoogleスライドはパブリッシュ側で許可しないとスライドをブログに埋め込めないみたいなので、ツイートを見つけて埋め込みました😅

⚓言語・ツール

⚓GitHubコア機能が無料に

HackerNewsでもえらく盛り上がっていました。


つっつきボイス:「GitHubに日本語版ブログがあるとは😆」「私もこの記事で初めて気づきました😆

「今回のGitHub無料化では、オーガナイゼーションのprivateなコラボレーター数に制限がなくなったのがとっても大きいですね❤」「おぉ〜」「これでGitHub使う人が増えるでしょう😋

「今まではどういう価格体系だったんでしょう?」「これまでだと、チームのprivateなリポジトリーには、そのチームで購入したライセンス数までしかコラボレーターを追加できなかったんですよ」「あ〜」「なのでフリープランの人たちをいっぱい呼ぼうとすると人数がつっかえちゃったりすることがよく起こりましたし😇」「そういう理由でBitBucketのようなサービスを使ってた人たちがそれなりにいるはず」「あるいはBPSみたいにGitLabサーバーを自前で立てるとかですね↓」

GitLab自社運用のための注意点とノウハウ(2018/06版)

「BPSの場合は協力会社も含めた開発者の人数が多いから、以前の価格体系のGitHubでやろうとするとコストが大変だったんでしょうね😅」「今はGitHubのリポジトリ数の上限もなくなりましたし: でも自分たちの場合、協力会社はともかく社員のライセンスは全員分買わないといけませんし、これまでGitLab上に構築してきたCI環境などをGitHubに移行する手間もあるので、月4ドル✕社員数と移行のコストをかけてまでGitLabからGitHubに移行する価値があるかどうかでしょうね💰」「たしかに〜」「自分たちも既にGitLabにロックインされてますし🔐」「今の社内GitLab上にはSandStar(注: 内製のCIサーバー)↓も動いてますし」

GitLab 10.6以降でpushイベントのSlack通知が止まったときの対応方法

「GitLabを社内でホスティングするのはそれなりに手間ですけど、やっぱりメリットもあるんですよ😋」「ふむふむ」「特にBPSの場合、アプリチームがずっとやっている超縦書超教科書のような超シリーズ↓のコンパイル量がものすごいらしいので、たぶん社内GitLabからGitHubにそのまま移行しても超シリーズのCIが満足に動かない可能性あるかも😅」「あ〜たしかに!」

「超シリーズはChromeのビルドまで含んでてリソースを鬼のように食いますから💋」「Chromeのビルドって😆」「BPSみたいに特殊な要件を抱えているところなら社内GitLabでやる意味はそれなりにあると思いますね: 将来GitLabでやる理由が歴史的経緯ぐらいしかなくなればGitHubに移行してもいいと思いますけど☺」「なるほど!」

「とにかくGitHubは今回の価格改定で使う人が増えると思いますね😋」「もう使わない理由がありませんし😋」「個人的に持ってるGitHub有料ユーザーも解約しようかと思ってるぐらい😆」「😆

⚓GItHubの戦略

「GitHubはどの辺を狙っているんでしょうか?」「たぶんGitHubはエンタープライズプラン以上の顧客に狙いを定めているでしょうね☺」「もうチーム以下は別にいいよみたいなノリで😆」「😆

「結局エンタープライズプランで一番大きいのはSAML↓なんですよ: SAMLを導入するような大きな企業は人数も相当多いはずですし」「もっと小さいベンチャー企業もこれを機会にGitHubに完全に乗っかるためにエンタープライズプランにするところも増えるかも🏢

参考: Security Assertion Markup Language - Wikipedia

「想像ですけど、GitHubとしてはチーム以下の個人ユーザーはもうあんまり眼中にないのかなって😆」「そういう人たちはGitHubを無料でガンガン使ってGitHubの知名度を上げてくれればいいよという感じで😋」「最初はチームプランで無料で使ってもらって、規模が大きくなってきてSAMLが使いたくなったらエンタープライズプランに移行してもらう、というようなシナリオを考えてるでしょうね😎」「なるほど!」

「ちなみにSlackは相当大きな企業でも通常プランでやってるところが多くて、エンタープライズはよほど大きな企業ぐらいしかいないようです😎」「へぇ〜😳」「Slackはエンタープライズにするとワークスペースを複数作れるようになるので、人数がすごく増えてくるとそういうのが便利なんでしょうね😋

⚓その他

⚓吸気と排気


つっつきボイス:「ウィルスの病室内拡散をシミュレーションして最適な換気方法を導き出したそうです」「ほほぅ」「吸気口と排気口を部屋の対面に置くとかえってよくないのか😳」「パラメータ次第では逆にうまくいったりすることもありそうなので慎重にやらないと難しいかも🤔

「プレハブ診療所みたいな規格化された環境なら理論上は条件が揃うので、こういうシミュレーションの結果がとても効いてきそう👍」「おぉ😍」「逆にカスタマイズされている既存の病室とかだとかなり大変かも😅」「建築は動くお金が大きいから、この規模のシミュレーションでもペイするんでしょうね☺

⚓キーボード配列変換アダプター

つっつきボイス:「こういうの好きな人いるかなと思って😆」「とてもオモシロイと思いましたけど、最近ノートPCのキーボードを直接使ってるんで使う機会がなさそう😆」「こんな下のレイヤで変換かけてるんだ😆」「発想はオモシロイですよね😋

「カンファレンスのブースで配ったらウケそう」「ワンチップマイコン1個でおしまいな感じだし、大した値段じゃないかな?」「ぐぉ、12,800円😇」「「1,000円だったらな〜😆」「3〜4,000円だったらな〜😆

⚓その他のその他

つっつきボイス:「おニューのiPhone SE、誰か買う人います?😆」「たぶん私かな😆」「iPhone 8のリベンジ感あるというか、中身iPhone 8やんって思ったし😆」「スマホに11万円もかけられない😭」「4万円って安いかなぁ?😆」「今なら安い方だと思いますよ😆

⚓番外

⚓成功を祈りたい


つっつきボイス:「エサの金属って😆」「もろSFの世界👽

⚓Stephen Wolframが動いた


つっつきボイス:「あのMathematicaで有名なStephen Wolframという人が、『New Kind of Science』という本で物理学の基本法則はネットワーク理論とかセルオートマトンみたいな計算理論から導けるみたいなことをずっと前から主張してて、主流からは正直あんまり相手にされてなかったんですけど、このたびそれを本気で研究するためのプロジェクトとサイトを立ち上げたという記事です」「何かえらいこっちゃ😆」「しかもパンデミックにもめげずスタートしたそうです」「まあ統一理論は人類の夢ですけど🌠

「物理業界だと、それまで日の目を見ていなかった理論が突如脚光を浴びることもあったりするから油断なりませんし😆」「70年ぐらい経過した頃とかですね😆」「あ、リンク先の文章めちゃ長いです😅」「理解できる気がしない😆」「Wolframさんの本もむちゃくちゃ長くって😭

参考: スティーブン・ウルフラム - Wikipedia
参考: 新しい種類の科学 - Wikipedia


後編は以上です。

週刊Railsウォッチ(20200420前編)anyway_config gemでRails環境設定、ShopifyのLiquidテンプレートエンジン、書籍『Beyond the Twelve-Factor App』ほか

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

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

Ruby 公式ニュース

Ruby Weekly

DB Weekly

db_weekly_banner

Rails 6.1でreturnやbreakやthrowによるトランザクション終了が非推奨化(翻訳)

$
0
0

概要

原著者の許諾を得て翻訳・公開いたします。

Rails 6.1でreturnやbreakやthrowによるトランザクション終了が非推奨化(翻訳)

Railsには長年の間、トランザクションをひそかにコミットする機能が入っていました(fc83920)。トランザクションの内部でreturnを呼び出すと、コネクション上のトランザクションを開きっぱなしにしない形でreturnが実行されます。

この機能は、何らかの条件が満たされない場合にトランザクションから早々に抜け出すのにも使えます。

def destroy_post_if_invalid
  Post.transaction do
    post = Post.find_by(id: id)
    return if post.valid?

    post.destroy
  end
end

トランザクションが裏でコミットされるこの振る舞いは、Rubyのtimeoutメソッドと組み合わせたときに驚かされることがあります。

以下の例では、トランザクションが1秒以内に終了しなかった場合にもコミットされてしまいます。

Timeout.timeout(1) do
  Post.transaction do
    # 何か重たい処理を行う
    # post.time_consuming_task

    # ここで何らかの遅い動作をシミュレートする
    sleep 3
  end
end

このように動作するのは、klass引数が渡されない場合にtimeoutthrowでトランザクションブロックを終了するためです。

# throwとcatchでブロックを終了する
>> Timeout.timeout(1) do
     sleep 2
   end
Timeout::Error: execution expired

# ArgumentErrorをraiseする
>> Timeout.timeout(1, ArgumentError) do
     sleep 2
   end
ArgumentError: execution expired

このプルリクの作者は、この驚きの振る舞いを非推奨化するにあたって代替手段を設けなかったので、この問題に関する後方互換のソリューションはありません。

残念ながら、ensureブロックではブロックの終了がreturnで行われたのか、breakで行われたのか、throwで行われたのかを区別できません。このため、Timeout.timeoutで行われているようにthrowでこの問題を修正することができません。

ここでRails 6.1での以下の非推奨化warningを見てみましょう。

DEPRECATION WARNING: Using `return`, `break` or `throw` to exit a transaction block is
deprecated without replacement. If the `throw` came from
`Timeout.timeout(duration)`, pass an exception class as a second
argument so it doesn't use `throw` to abort its block. This results
in the transaction being committed, but in the next release of Rails
it will raise and rollback.

先に進めるソリューションは、以下のようにトランザクション内部でreturnではなくifunlessによる条件を利用し、timeoutメソッドを持つ何らかの例外クラスを用いることです。

def destroy_post_if_invalid
  Post.transaction do
    post = Post.find_by(id: id)

    unless post.valid? do
      post.destroy
    end
  end
end

関連記事

Rails: Active Recordメソッドのパフォーマンス改善とN+1問題の克服(翻訳)


週刊Railsウォッチ(20200427前編)Railsで避けたい8つのミス、ridgepole導入の注意点、RDS ProxyのPostgreSQL対応ほか

$
0
0

こんにちは、hachi8833です。

つっつきボイス:「近所のビアパブに注文しておいたビール取りに行ってた🍺」「お疲れさまです!」「最近酒類の販売免許が飲食店向けに割と簡単な手続きで申請できるようになったじゃないですか」「あ、酒の持ち帰りは居酒屋の免許とは別なのか😳」「持ち帰りだと販売として扱われるので☺️」「なるほど〜」「本来だと酒販免許を取るのはかなり面倒なんですけど、その店は5日ぐらいで取れたって😋」「そういえば都内で店やってる知り合いも2日で取れたって言ってました😋」「都内だと特に早いらしい」「ではつっつき始めましょう〜」

参考: 酒類のテイクアウト販売が可能になる「期限付酒類小売業免許」とは?─ 免許の概要から申請のポイントまで | 日本酒専門WEBメディア「SAKETIMES」

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

Rails: 先週の改修(Rails公式ニュースより)

Active Recordのremove_indexif_exists:オプションが追加

# activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb#L451
-       def remove_index(table_name, column_name = nil, options = {}) #:nodoc:
+       def remove_index(table_name, column_name = nil, options = {}) # :nodoc:
          table = Utils.extract_schema_qualified_name(table_name.to_s)

          if column_name.is_a?(Hash)
            options = column_name.dup
            column_name = options.delete(:column)
          end
          if options.key?(:name)
            provided_index = Utils.extract_schema_qualified_name(options[:name].to_s)
            options[:name] = provided_index.identifier
            table = PostgreSQL::Name.new(provided_index.schema, table.identifier) unless table.schema.present?
            if provided_index.schema.present? && table.schema != provided_index.schema
              raise ArgumentError.new("Index schema '#{provided_index.schema}' does not match table schema '#{table.schema}'")
            end
          end

+         return if options[:if_exists] && !index_exists?(table_name, column_name, options)
+
          index_to_remove = PostgreSQL::Name.new(table.schema, index_name_for_remove(table.to_s, column_name, options))
+
          algorithm =
            if options.key?(:algorithm)
              index_algorithms.fetch(options[:algorithm]) do
                raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}")
              end
            end
+
          execute "DROP INDEX #{algorithm} #{quote_table_name(index_to_remove)}"
        end

つっつきボイス:「remove_indexif_existsオプションを渡す必要のある巨大プロジェクトは大変そう😆」「😆」「本来ならRails標準のActiveRecord::Migrationを使うべきかなと😆」「ridgepoleみたいなものを使う方がいいのかなという気もするけど🤔」

if_existsを使うシチュエーションだとインデックス名が同じでオプション名が同じでないものについては管理できてないことになるだろうから、if_existsしたインデックスがMigrationで作られたインデックスと同一であることまでは保証しきれないんじゃないかという気がしますね😆」「付け焼き刃というか😆」「RailsのMigrationにSQL書いて追加したインデックスとかまでは検出できなさそうな予感😆」「むしろif_existsに頼る状況にならないようにしたい☺️」

「想像ですけどif_existsが欲しい理由ってもしかすると、db:migrateを含むコードが途中でコケるとインデックスだけ中途半端に作られてしまうからif_existsしたいということだったりして?」「あ〜😳」「それってRails開発中のあるあるなんですけど😆、本当ならMigrationがコケたときに安全にロールバックするようにすべきかなと思いますし☺️」「productionリリース後の方がif_existsつけたいかも🤔: remove_indexを2回叩いてMigrationが落ちたら手動で修正するしかありませんし」

このプルリクは、remove_indexif_existsオプションを渡すことで、インデックスが削除済みの場合に無視されるようにする。この動作は、カラムのif/if_not_exists(#38352)や、add_index:if_not_exists(#38555)の動作に合わせてある。
この改修はGitHubでのMigrationでインデックスが削除済みならraiseしたくない場合に有用であることに気づいた。このおかげでremove_indexのモンキーパッチを削除できる。
index_name_for_removeメソッド呼び出しの後でraiseすることも検討したが、こちらのメソッドだとインデックスが存在しない場合はメソッドが実行される前にraiseする。これをリファクタリングするコミットもやってみたが、熟慮の結果、他の実装よりもこちらの方がより明快で素直だと考えた。
今回の変更ではadd_indexのテストにバリデーションも少し追加してある。
編集したメソッドのnodocの修正をよろしく。
同PRより

ridgepoleの注意点

「…ridgepoleといえば、最近ridgepoleが入ってるプロジェクトをやったんですけど、それはそれはカオスでしたよ😇: 何も考えずにridgepoleが導入されてて、もう苦労しかないので何とかして消し去りたいけどめんどくさいのでそのままです🤢」

「ridgepoleのようなマイグレーターではup/down以外のデータのMigrationを扱えないのが面倒😅」「普通にMigrationしようとしたらridgepoleがいてできませんでした😇」「ridgepoleには特定の操作にフックを仕込むとかないですよね?」「はい、ありません😆: なのでわざわざデプロイしてrakeタスク叩いてもう1回デプロイして、というバカバカしい手順を踏むしかなくて😭」「ああ、たしかにそれしかできなくなりますね😅」「Rails標準のMigrationなら全部やれたのに…💢」「Migrationには時系列がありますけど、ridgepoleにはありませんし😆」「なので個人的にはridgepoleキライです」「自分も好きというほどではありませんが☺️」

「クックパッドさんはridgepole入れるにあたって『Migrationは行わない』と決めてますね↓」「困ったらデータを消しても良いようなプロトタイピングや小規模開発とか、Migrationに代わるデータの管理運用がちゃんとした確立されているプロジェクトで用途に合わせてridgepoleを使うのは別に良いと思うんですが、代わりの運用方法がないまま何も考えずにridgepoleが導入されてたのがつらかった😢」「Migrationが必要な案件にridgepoleが入ってたとは😳」「まあRailsのMigrationもひどいのを書かれたら同じくつらいので、チームメンバーのモラルが必要なのは変わりませんし、結局プロジェクトの方針次第ですね☺️」「db/schema.rbは大規模開発に完全に向いてないと思います😤」

「ところでMigrationだとGitの履歴とMigrationファイルの履歴が二重になるよねみたいな話をどこかで聞いたような気がします」「うぅんそれはちょっと違うかな: スキーマの履歴を管理するだけならridgepoleとGitでもいいんでしょうけど、Migrationはスキーマ履歴の管理だけじゃなくてスキーマ更新以外のデータ移行のような作業も含められますし、それがRailsのMigrationのメリットだと思うんですけどね🧐」「Migrationは履歴を知るためのものじゃなくてデータベースを運用するための機能ですから🧐」「う、失礼しました😅」

touch_attributes_with_timeがキーワード引数を取るよう修正

# activerecord/lib/active_record/counter_cache.rb#L52
          if touch
            names = touch if touch != true
-           updates.merge!(touch_attributes_with_time(*names))
+           names = Array.wrap(names)
+           options = names.extract_options!
+           touch_updates = touch_attributes_with_time(*names, **options)
+           updates.merge!(touch_updates)
          end

つっつきボイス:「@kamipoさんによる修正です」「例のキーワード引数関連の修正ですね☺️」「このテストだけtime: Time.now.utcが書いてある↓あたりが試行錯誤感」「キーワード引数対応はまだ先がありそう…」

# activerecord/test/cases/counter_cache_test.rb#L264
  test "reset multiple counters with touch: true" do
    assert_touching @topic, :updated_at do
      Topic.update_counters(@topic.id, replies_count: 1, unique_replies_count: 1)
-     Topic.reset_counters(@topic.id, :replies, :unique_replies, touch: true)
+     Topic.reset_counters(@topic.id, :replies, :unique_replies, touch: { time: Time.now.utc })
    end
  end

rename_columnするとMySQLのカラムコメントが消えるのを修正

# activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb#L663
        def rename_column_for_alter(table_name, column_name, new_column_name)
          column  = column_for(table_name, column_name)
          options = {
            default: column.default,
            null: column.null,
-           auto_increment: column.auto_increment?
+           auto_increment: column.auto_increment?,
+           comment: column.comment
          }


つっつきボイス:「コメントが消えてたとは😆」「rename_columnの実装レベルの話か: abstractのMySQLアダプタを修正しているし」「所定のオプションだけ通すようにしてたところに漏れがあったっぽい」「バグですね」

6.1でretry_jitter = 0.15がデフォルトで入る

# railties/lib/rails/application/configuration.rb#L159
        when "6.1"
          load_defaults "6.0"

-         if respond_to?(:active_job)
-           active_job.retry_jitter = 0.15
-         end
-
          if respond_to?(:active_record)
            active_record.has_many_inversing = true
          end
@@ -172,6 +168,7 @@ def load_defaults(target_version)
          end

          if respond_to?(:active_job)
+           active_job.retry_jitter = 0.15
            active_job.skip_after_callbacks_if_terminated = true
          end

          if respond_to?(:action_dispatch)
            action_dispatch.cookies_same_site_protection = :lax
          end

つっつきボイス:「前に話題にしたjitterがデフォルトで入るようになりました(ウォッチ20191216)」「こういうのはデフォルトがありがたい😋」「リトライのジッターだし大丈夫でしょう☺️」「これで困るようならたぶんアプリの設計の方がおかしい😆」

Webpackerのintegrityチェックが削除された

# lib/webpacker/configuration.rb#L66
  def check_yarn_integrity=(value)
-   data[:check_yarn_integrity] = value
- end
-
- def check_yarn_integrity?
-   fetch(:check_yarn_integrity)
+   warn "Webpacker::Configuration#check_yarn_integrity=(value) has been deprecated. The integrity check has been removed from Webpacker so changing this setting will have no effect."
  end

つっつきボイス:「Webpackerの修正で、昨日bundle updateした後でDockerのRails起動が急に速くなって気づきました」「yarnのintegrityをやめたということ?」「プルリクコメントに、yarnの作者自身がyarn checkは使うなと言ってるのが引用されてました😆」「しかもyarn 2.0でyarn check削除されてるからそれもあって削ったのね😆」「お前のせいで起動遅かったのかと😭」

番外: DHHが#38588をrevert

# actionview/lib/action_view/template/resolver.rb#L229
      def find_template_paths_from_details(path, details)
-       if path.name.include?(".")
-         ActiveSupport::Deprecation.warn("Rendering actions with '.' in the name is deprecated: #{path}")
-       end
-
        query = build_query(path, details)
        find_template_paths(query)
      end

つっつきボイス:「先週のウォッチ20200413取り上げた#38858のdeprecationをDHHがrevertしてました」「ああ、影響範囲割とでかいんじゃないのって話したヤツ?」「ですです」「deprecation自体を取りやめるということは、確実に検出できるまで差し止めるということでしょうね☺️」

文字列の式展開で誤ってdeprecation warningがトリガされるのが修正されるまでは#38858をrevertしておく。
同コミットより

Rails

Railsで避けたいありがちな8つのミス


つっつきボイス:「既視感ありまくりですけど、まとめてくれているのがいいかなと思って」「N+1問題にcredentialにファットコントローラもファットモデルもやめろ話とかね☺️」「別サービスを呼び出すときはなるべく非同期にと」「?付きの述語メソッドはtrueかfalseを返せというのは命名の話ね😆」「そうしない人がいるのか…😅」「メモ化を使うな、って書いてるのかと思ったらメモ化を使わないミステイクという話か😳」「この見出しの英文、統一感ないですね😆」「ミステイクにnotを付けるのはわかりにくい〜😆」「命名ルールに従う、にnotが付いてないとミステイクにならないんじゃ?」「こっちも整合してない😆」「ともあれ基本的な内容ですね☺️」「たぶん反論は出ないでしょう😆」


見出しを統一してみました。

  • ミス1: N+1クエリをチェックしない
  • ミス2: コンフィグが安全でない
  • ミス3: コントローラのロジックが多すぎる
  • ミス4: モデルのロジックが多すぎる
  • ミス5: 外部サービス呼び出しが非同期化されてなくてブロックされる
  • ミス6: 述語メソッド(?で終わるメソッド)がtrue/falseを返さない
  • ミス7: メモ化を使ってない
  • ミス8: Railsの命名ルールに沿ってない

Heya: Rails用キャンペーンメールgem(Ruby Weeklyより)


heya.emailより


つっつきボイス:「heyaはhey youのオーストラリア方言らしいという説があるようです🇦🇺」「.emailドメインなんてのを使ってる😳」

「どの辺が嬉しい感じでしょう?」「timed email sequenceとあるのでメールの順序が大事ということかな🤔」

# 同リポジトリより
Heya.configure do |config|
  # Heyaを使いたいモデル名を指定する
  config.user_type = "User"

  # キャンペーンのステップを処理するときのデフォルトオプション
  config.campaigns.default_options = {from: "user@example.com"}

  # キャンペーンの優先順位。ユーザーが複数のキャンペーンに加えられると、この順序で送信する。
  # 優先順位の設定がない場合は、ユーザーが追加された順でキャンペーンメールが送信される
  config.campaigns.priority = [
    "FirstCampaign",
    "SecondCampaign",
    "ThirdCampaign"
  ]
end

「なるほど、たとえばユーザー登録して1日後にこのメールを送信するみたいなことがやれるのか」「あ、それをユーザーごとにやれるんですね」「『このサイトの便利な使い方』みたいなメールを送り付けるヤツ😆」「たぶんこれに『登録後7日間ログインしていない場合』みたいな条件も付けられるんじゃないかしら、知らんけど😆」

# 同リポジトリより
class OnboardingCampaign < ApplicationCampaign
  default wait: 1.day,
    queue: "onboarding",
    from: "support@example.com"

  # support@example.comから1日後にメールを送信する
  step :welcome,
    subject: "Welcome to my app!"
end

「たしかにこういう処理はAction Mailer単体では定義不可能🧐」「そうか!」「Action Mailerはメール送信しかできませんし😆」「こういうのをキャンペーンメールと呼ぶのであれば、キャンペーンメールをとても積極的かつ複雑に使いたいときにこういうDSLを書くのかな〜☺️」「自分ならこういうのを実装するよりCRMツールに金払う方がいい気がしますけど😆」「😆」

参考: CRMツールとは?おすすめ14製品を紹介!選び方も併せて解説!|ITトレンド

「HeyaもそういうCRM路線だろうと思いますけど、たぶん世にあるCRMツールの方が遥かに複雑なことができますし😋」「おぉ」「たとえばメール開封率が一定以下の場合はこうする、みたいなことも普通はできますし🧐」「なるほど!」

「どうしても自分で実装したいとかRailsからメール送信したい人なんかはHeyaでいいと思いますが、自分ならCRMツールを統合するかな〜: wait: 1.dayみたいなコードをRailsに入れるのもちょっと心配ですし」「おぉ?」「この値を運用中に変えたときに同じメールがもう一回発射されるかもしれないじゃないですか😅」「なるほど」

tomo: capistranoのオルタナ(Ruby Weeklyより)


つっつきボイス:「capistrano的なデプロイツールみたいです」「tomoはそこそこ前からありますね: 以前検討した覚えあります☺️」「や、そうでしたか」「最近capistranoがあんまり更新されてなくて、capistrano的なデプロイツールないかな〜と探してて見つけた中のひとつにあった気がします👁」

# 同リポジトリより
# .tomo/config.rb

plugin "git"
plugin "bundler"
plugin "rails"
# ...

host "user@hostname.or.ip.address"

set application: "my-rails-app"
set deploy_to: "/var/www/%{application}"
set git_url: "git@github.com:my-username/my-rails-app.git"
set git_branch: "master"
# ...

setup do
  run "git:clone"
  run "git:create_release"
  run "bundler:install"
  run "rails:db_schema_load"
  # ...
end

deploy do
  run "git:create_release"
  run "core:symlink_shared"
  run "core:write_release_json"
  run "bundler:install"
  run "rails:assets_precompile"
  run "rails:db_migrate"
  run "core:symlink_current"
  # ...
end

参考: Capistrano - Wikipedia

「tomoってCapistranoよりは新しい気がするけどどうだったかな(リポジトリの履歴を遡る)」「ところでGitの履歴ってolderをクリックして1ページずつめくらないといけないのが面倒ですね」「まあ履歴の最終ページを算出しようとすると件数カウントが重たいので、それでこういうUIにしてるんじゃないでしょうか☺️」「あ、たしかに😅」「どうやらtomoの履歴の最初は2018年だから割と新しいかな: まあどのぐらい使われてるかも知りませんしまだ使ったこともありませんが😆」「😆」「コンテナ全盛の今、新たにDSL覚えるのもどうかと思いますけど😆」

Railsのコネクションとプールとハンドラ(Hacklinesより)


つっつきボイス:「コネクションとプールとハンドラの違いについての割と短い記事です」「そうそう、RailsにはRailsのコネクションプールがありますので🧐」「データベース側とは別にRailsにあるんですね😳」「たとえばPostgreSQLを使う大規模なプロジェクトだと、PostgreSQLに直接つなぐのではなくて手前にコネクションプールサーバーを配置するというモデルがあります🧐」「なるほど!」「まあアプリケーション側にも似たようなコネクションプールがありますよという話☺️」


記事見出しより:

  • コネクションとは
  • コネクションプールとは
  • コネクションハンドラとは

AWS RDS ProxyのPostgreSQL対応

「…コネクションプールといえば最近AWSのRDS Proxyで何かの機能がアップデートされてましたね: LambdaからRDSにつなぐためのプロキシがPostgreSQLに対応したとか何とか🤔」「へ〜、Lambdaから?」「LambdaからたくさんRDSにつなぐと溢れるからRDS Proxy通しますけど、それがぽすぐれに対応したらしいという話」「おぉ〜これか↓😋」「ごく最近ですね」「今までLambdaからコネクション張るのが地味に面倒だったんですよね😢」「たしかにLambdaからのコネクションはなかなか作れませんでしたね😅」

参考: PostgreSQL 互換の Amazon RDS Proxy (プレビュー)

「とまあこれはマネージドのコネクションプールなわけですが🧐: MySQL用は半年ぐらい前からあるんだったかな」「たしかにLambdaから接続するとコネクションがボトルネックになるので、これは欲しい機能😂」

参考: AWS LambdaでAmazon RDS Proxyを使用する | Amazon Web Services ブログ

「ほら、今までだとせっかくLambdaとAuroraがマネージドなのに、コネクションプールのためにEC2を立てるみたいなバカバカしいことをしないといけませんでしたし😭」「それはマジでバカバカしい😆」「😆」「そこがようやくまともになったという☺️」

「そもそもRDBMSってマネージドと相性があんまりよくありませんし😆」「とはいえ欲しいじゃないですかやっぱり😎」「欲しい😆」「絶対欲しい😆」「DynamoDBと戦うのイヤ😇」

参考: Amazon DynamoDB(マネージド NoSQL データベース)| AWS


「話を戻すと、アプリケーションサーバーは超々一般的にコネクションプールを持ちます、そしてRailsにはアプリケーションサーバーがあります、以上😆」「はい😆」

その他Rails


つっつきボイス:「Webpackerの挙動を追うためにWebpackの挙動を追ってみた感じですね☺️」


前編は以上です。

バックナンバー(2020年度第2四半期)

週刊Railsウォッチ(20200421後編)Ruby 2.4サポート終了、Ruby 3の右代入演算子、GitHubコア機能無料化ほか

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

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

Rails公式ニュース

Ruby Weekly

RubyFlow

160928_1638_XvIP4h

Hacklines

Hacklines

週刊Railsウォッチ(20200428後編)Rubyのバックトレース順序が戻る、KubernetesでRailsをスケール、セキュリティソフト入れますか?ほか

$
0
0

こんにちは、hachi8833です。ついさっき見つけた記事がよかったので貼りました。

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

⚓Ruby

⚓Rubyのバックトレース順序が戻る


つっつきボイス:「@kamipoさんが超喜んでますね」「そう、これこれ!以前バックトレースの表示順序が変更されてからマジでやりづらいと思ってましたし😭」「今回の改定を喜んでいる人は@kamipoさん以外にもきっとたくさんいる😂

以下は改定直前のツイートです。

「バックトレースの順序が変わることがあったんでしょうか?」「正確にはRubyのバックトレースが変わったけどRailsのバックトレースの順序は変わらなかった」「あ、そういうことでしたか😳」「Ruby 2.5の変更より前はバックトレースの順序は常に同じだったんですが、変わってからわかりにくくて😭

「『バックトレースの順序が反転するという画期的なギミック』って超ワナですよ😇」「まあちょっと読めば順番が変わっているのはわかるんですけど」「RubyとRailsで順序が違うのが痛い😇」「みんな困ってないんだろうかって不思議だったし😆

⚓提案: Struct#initializeでキーワード引数もデフォルトで取れるようにしよう

# 同issueより
Post = Struct.new(:id, :name)

# 以下に加えて
Post.new(1, "hello") #=> #<struct Post id=1, name="hello">

# 以下の初期化もできるようにしよう
Post.new(id: 1, name: "hello") #=> #<struct Post id=1, name="hello">

つっつきボイス:「あ、Struct.newした後のnewでということか😳」「まあ名前は付いてますし、使いやすさ的には全然いいかなと思うけど🤔

後で現行のRuby 2.7で実行すると以下のように引数が全部id:に入りました。

Post = Struct.new(:id, :name)
Post.new(id: 1, name: "hello")
=> #<struct Post id={:id=>1, :name=>"hello"}, name=nil>

「ちなみに自分はStructもOpenStructもあんまり使わない方で、Value Object作るならちゃんとクラス書きたい派😆」「😆」「今日はいないけどkazzさんが前にStructをちょくちょく使ってるのを見て『大変そうだな〜』って思いましたし😆

参考: class Struct (Ruby 2.7.0 リファレンスマニュアル)
参考: class OpenStruct (Ruby 2.7.0 リファレンスマニュアル)

⚓super_methodメソッドでRubyのDecoratorをテストする(Ruby Weeklyより)


つっつきボイス:「super_methodっていうメソッドがあるって知りませんでした😅」「途中の見出しが『The super super_method method』😆」「superで呼ばれるはずのメソッドをMethodオブジェクトにするみたいです」「Methodオブジェクトにsuper_methodメソッドがあるのは当然でしょうね☺」「リフレクションするのに必要でしょうし☺

self 内で super を実行した際に実行されるメソッドを Method オブジェクトにして返します。
ruby-lang.orgより

「そのsuper_methodでDecoratorをテストするという記事か」「えぇ?、described_class.new.method(:info).super_method.callみたいなテストって書くかなぁ?😅」「わざわざsupoer_methodしてからcallするって、どういう観点のテストなのかわからん😆」「継承とは何ぞやと😆

# 同記事より
RSpec.describe Address do
  describe '#info' do
    subject { described_class.new.info }

    it 'adds the phone number to the default address' do
      expect(subject).to include(phone_number: '123456789')
      expect(subject).to include(
        described_class.new.method(:info).super_method.call
      )
    end
  end
end

「呼べるか呼べないかで言えばたしかにsuper_methodは呼べますけど、こういうテストが欲しくなる状況がぱっと思いつかない😅」「記事はspecがシンプルになるということみたいだけど、ちゃんとテストできてるんだろうか🤔」「デバッグツールを作るのでトリッキーなことをしたいとかならともかく、普通のコードでsuper_methodを使うことはないんじゃないかな〜、普通は☺

⚓クロージャでRubyコードを読みやすくする(Ruby Weeklyより)

参考: クロージャ - Wikipedia


つっつきボイス:「f.call()のショートハンドがf.()というのも今頃知りました」「f.()はカリー化の文脈とかで割とよく見るヤツですね☺」「そうでしたか😅」「自分も見るたびに?って思いますし、あんまり好きな書式でもありませんけど、call()よりは短いですし😆

def bar(f)
  f.()
end
bar(method(:foo)) # => hello from foo

「記事にも『f.()はビジネスロジックではめったに見かけないがオープンソースではよく見かける』ってありますね」「カリー化がビジネスロジックでめったに使われないからでしょう、きっと😆」「まあ😆」「もちろんビジネスロジックでカリー化がふさわしいこともありますし、それなら別にいいんですけど、呼び出しが増えると遅くなりがちなので☺

参考: カリー化 - Wikipedia

「ともかく.()は随分昔からちゃんとしたRuby入門には書いてあると思いますヨ😋」「探します👁

ありました↓。

.()は、メソッド名のないメソッド呼び出しのように見える。これは定義できる演算子ではなく、callメソッドを呼び出すための構文糖である。この記法は、Proc オブジェクトに限らず、callメソッドを定義するすべてのオブジェクトで使える。
『プログラミング言語Ruby』(オライリー)p202より

⚓Rubyのlambda呼び出し

「…Rubyだとlambdaでインラインメソッド的なものを書くときに何だかキモチヨクナイ気がします😆」「はいわかります😆」「C++でもJavaScriptでもかっこ()だけつけて関数と同じように呼べるのに、Rubyはこの.()という書き方のせいで普通の関数とlambdaが区別されるので、一時的な関数を作る気力が削がれそう😇」「それはある😆」「すっごくわかる😆」「普通に()で呼びたいのに😢」「いろんな互換性に配慮した結果そうなっているのはわかるんですが😅」「言語仕様上しょうがないんですけど😅

後で自分でもやってみました。Rubyだと.()ですね。

// JavaScript
let foo = num => { return num * 2 };
foo(7);  // 14
// C++
auto foo = [](auto num) { return num * 2; };
printf("%d", foo(7)); // 14
# Ruby
foo = ->(num) { num * 2 }
foo.(7)  # 14

⚓RailsのHashWithIndifferentAccessがRubyにないのはなぜ?

参考: ActiveSupport::HashWithIndifferentAccess`


つっつきボイス:「Redditにあったスレです」「よく持ち上がる話😆」「昔Matzがその辺の理由についてコメントしてたような覚えがあります」「『RubyがPHPみたいになるから』だったりして😆」「文字列とシンボルは全然違うものなのに、そこがRails方面にうまく伝わらなかったとかそんな感じ🧐」「へ〜」

「プログラミング言語全般ではたしかに文字列とシンボルは違いますし、自分もそう思うんですけど、Webの文脈だとその辺が厄介なんですよね😅」「うんうん」「Webだとどんなパラメータもいったん文字列になってしまうので、そういうのが間に挟まってHashWithIndifferentAccessができたのかなと思ってます☺」「元PHPerとしてはHashWithIndifferentAccessって結構好きなんですけど😆、言語全般として考えたら一貫してないよねというのはワカル」

参考: Smalltalk と Ruby と LISP のシンボル - Smalltalkのtは小文字です

「でも最近のRubyだと文字列をfrozenにする動きがありますけど、それがデフォルトになったらHashWithIndifferentAccessと同じにしてもいいんじゃね?ってちょっと思いますね」「気持ちわかります」「もちろん文字列とシンボルは違うという主張はわかるんですけど、frozenがデフォルトの世界なら多少同一視してもいいのかなと😋」「探索速度とかを考えたら多少の同一視はありかも😋


「…さっきのMatzのコメントは、どうやら以下の記事↓の記憶が自分の中で改ざんされてたらしき🤣」「自分で訳してて忘れてた😆

Rubyのシンボルをなくせるか考えてみた(翻訳)

(Rubyの)シンボルはLispのシンボルを取り入れたもので、Lispのシンボルは文字列とは根本的に異なっていました。(Lispの)シンボルは文字列表現としてはイケてません(し速くもありません)が、Rubyはシンボルに関して独自路線を取ったため、シンボルと文字列の違いは(Rubyの)ユーザーからはそれほど認識されてこなかったのです。
同記事の引用より

「frozenなら事実上一意の値が与えられると考えてもいいんでしょうね」「frozenならそうだと思います☺」「unfreezeしなければ😆」「シンボルって要は整数の定数だから、frozenなstringのアドレスだと思えばいいっちゃいいかも😆」「シンボルはto_sできますし」「個人的にはfrozen string literalをオフにできないことを前提にできるのなら文字列とシンボルを同一視してもいいかなと思います: でも今のRubyだとファイルごとにfrozen string literalをオンオフできるから同一視するとマズいのかもしれないけど☺」「うーむ」

⚓Rubyで線形回帰(Ruby Weeklyより)


同記事より


つっつきボイス:「ruby-linear-regressionというgemで線形回帰やってみた記事だそうです」「自分ならExcelでやれるところはExcelでやって、ExcelでできないところはPythonとかRでやっちゃうかな😆」「たしかにExcelでもできますね😆」「回数が多すぎなければ☺

# 同記事より
require 'csv'
require 'ruby_linear_regression'

x_data = []
y_data = []
csv = CSV.read("top50.csv")
csv.shift

# Load data from CSV file into two arrays -- one for independent variables X (x_data) and one for the dependent variable y (y_data)
# Row[0] = title
# Row[1] = BPM
# Row[2] = Popularity
csv.each do |row|
  x_data.push( [row[1].to_i] )
  y_data.push( row[2].to_i )
end

# 回帰モデルの作成
linear_regression = RubyLinearRegression.new

# 訓練データの読み込み
linear_regression.load_training_data(x_data, y_data)

# 正規方程式でモデルを訓練
linear_regression.train_normal_equation

# 計算コストを出力
puts "Trained model with the following cost fit #{linear_regression.compute_cost}"

# ある曲の人気を250 BPMで予測
prediction_data = [250]
predicted_popularity = linear_regression.predict(prediction_data)
puts "Predicted popularity: #{predicted_popularity.round}"

参考: 線形回帰 - Wikipedia

⚓その他Ruby


つっつきボイス:「MatzのGitHub Sponsorsが今23人ぐらいになったそうです」「お、月10ドル払えばここのバッジに載せてもらえるのか🎫」「こういうのはいいですね〜😋

その後見てみたらスポンサーが65人に爆増してました🎉

なおRailsチュートリアルとRailsガイドでお馴染みのYasulabもGitHub Sponsorsの審査にパスしました🎉

⚓DB

⚓PostgreSQL 13のinsert-onlyテーブルautovacuumを改善(Postgres Weeklyより)


つっつきボイス:「insert-onlyテーブルなんてのがあるのか」「ぽすぐれ何でもある😆」「UPDATEしないテーブルという意味でしょうか?」「いわゆるappend-onlyテーブルでしょうね🧐」「昔からあるんですね」

参考: Querying Append-Only Tables | Stitch Documentation

「autovacuum自体はPostgreSQLに昔からあるけど、それをinsert-onlyテーブル向けに賢くチューニングしたということみたい」「おぉ」「そもそも最近のPostgreSQLはvacuumを手動で実行しなくてもそれほど遅くならなくなったはずなので☺

autovacuumはテーブルの特定の値が上回ると常に実行される。この値は“autovacuum_vacuum_insert_threshold(デフォルトは1000)とautovacuum_vacuum_insert_scale_factor(デフォルトは0.2)から以下のように算出される。
insert_threshold + insert_scale_factor * reltuples
reltuplesは、pg_classカタログから取得したテーブルの行数の見積もり。
同記事より


見出しより:

  • insert-triggeredでautovacuumが動くしくみ
  • ユースケース1: insert-onlyテーブルでの「anti-wraparound」vacuum
    • insert-onlyテーブルでVACUUMが必要な理由
    • insert-onlyテーブルのanti-wraparound vacuumが問題になる可能性がある理由
    • 破壊的なanti-wraparound vacuumから身を守る方法
  • ユースケース2: insert-onlyテーブルでのindex-onlyスキャン
    • PostgreSQLのindex-onlyスキャンのしくみ
    • insert-onlyテーブルでのindex-onlyスキャンの問題点
    • insert-onlyテーブルでindex-onlyスキャンを取得する方法
  • ユースケース3: insert-onlyテーブルでの「hint bit」
  • 今後の改良
  • まとめ

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

⚓KubernetesでRailsをスケールする(Hacklinesより)


つっつきボイス:「要はRailsをPodに押し込めろと😆」「ポッドというと…」「PodはKubernetesのコンテナの単位です🧐」「そういえばKubernetesを勉強中って話してましたね」「合間を見て、くばねて本をちまちまと😆

参考: Podとノードについて - Kubernetes

「最近BPSのWebチームもDockerやdocker-composeの運用が定着してきたので、そろそろ普通のコンテナオーケストレーションツールで包んじゃおうかなと構想中📈」「お、いよいよですね😋」「AWSのECSやFargateを見てくれているメンバーがいるので、じゃ自分はくばねて方面をやろうかなと思ってます☺」「なるほど〜」「BPS社内にあるDocker用のホスティングマシンが6個ぐらいできてきてそろそろややこしくなってきましたし😆」「前は4つだった気がしますけどさらに増えてるとは😳」「メモリが足りなくなると足す感じでやってます☺


見出しより:

  • スケールアップする
  • Autopilotでスケールする
  • タスクをJobsで実行する
  • productionのログファイルをinspectする
  • Podにログインする
  • その他の便利タスクたち

⚓GitHubとGitLab


つっつきボイス:「GitHubとGitLabの機能リリースがいくつか出てたので」「GitHubもGitLabも、リポジトリ管理ツールというよりは開発プロジェクトの管理ツール&オーサリングツールに変化してきた感じはありますね🧐」「ところで以下の記事の見出しにGitLabのカンバン表示が書いてありますけど、カンバン表示は前からオープンソース版のGitLabにもあるんですよね😆」「そうですね😆

参考: GitLab、有償版の機能をオープンソースへ移植すると発表。カンバン表示やカナリーデプロイ、複数のKubernetesクラスタの使い分けなど18機能 - Publickey

「まあGitLabは有料版とオープンソース版で元々そんなに違いはありませんでしたし、逆にオープンソース版にあるけど有償版の下の方にはなかった機能もあったりしましたし、一般に思われているほど差はないかなと思いますね☺」「へぇ〜😳


GitLab記事を見ると、以下のそれぞれのissueを足して18個になるようです。

  • 「Plan」「Create」「Verify」「Package」「Release」「Configure」「Defend」がオープンソースに移行した
    • Plan: 共同作業を同期する
    • Create: よりよいコードやブランチをビルドする
    • Verify: コードの品質をさらなる高みに
    • Package: パッケージのビルドや共有
    • Release: 継続的デリバリー(CD)をシンプルに
    • Configure: 複数のKubernetesクラスタをサポート
    • Defend: アプリケーションセキュリティ


about.gitlab.comより

GitLab自社運用のための注意点とノウハウ(2018/06版)

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

⚓Periodic Background Syncとは


つっつきボイス:「例のjxckさんの記事です」「PWA(Progressive Web Apps)に関連するブラウザとかWebの仕様の話のようで、Service WorkerのBackground Syncとは違うことをやりたいという感じ」

参考: PWAをもっと簡単に初めてみる - Qiita
参考: サービスワーカー API - Web API | MDN
参考: ServiceWorkerのBackground Syncでオンライン復帰時にデータ送信 - Qiita

「お〜、『Webをインストールする』という言い方をしてますね」「Webをインストール?」「おそらくですがローカルで動くものとWebで動くものを区別しないで実行できるというような意味合いだと思います: 以下にあるように、Webアプリは本来インストールなしで実行できるけど、特定の機能が必要なときはインストールしてパーミッションを与えないといけないという感じ」「おぉ〜」

本来 Web は、インストールのような操作なく、 URL にアクセスするだけでページが読み込まれ、スクリプトが実行される。
ここで強力な機能(Powerful Features)がユーザの同意なく実行されると、意図しない問題が発生する可能性がある。
そのため、ここまでの機能は、その API の重要性に応じて User Gesture, Feature Policy, Permission Prompt などを使い分けてきた。
一方、 Native App は、強力な OS 機能の利用を、ユーザによる明示的なインストールという操作(とそこで発生する認証や追加許諾)によって許可してきた。
この考え方に合わせれば、 「Web もユーザが明示的に Install すれば、 Native と同等の機能を許可できるのではないか」という発想に至る。
同記事より

「Webアプリもインストールという明示的な操作を経れば、ブラウザで冒頭のPeriodic Background Syncみたいな動作を許可してもいいのでは、ということですね」「おぉ〜」「Windowsにもアプリのインストールでroot権限取るときにダイアログが出てくる機能があったけど、あれ何て名前だっけ?🤔」「…Windowsでぽーんと出るのはUACですね」「それそれ😋、Webのインストールはそういうのに近い考え方なのかなと思って」「Webをインストールするという言い方は何となくいい感じな気がします👍」「ですね😋

参考: ユーザーアカウント制御(UAC) - Wikipedia

「ところで『Webをインストールする』って元記事の人独自の言葉なのかな?🤔」「引用されてるissue↓とかにもinstalled web appとかinstallableみたいな言い方があるから、そちらが元みたい」

「つい昔なつかしのActiveXみたいなものを想像してしまったんですが、たぶん違いますよね?😅」「Webをインストールするというのは、ブラウザの権限付与の文脈の中でインストールらしい動作を明示することで特定の操作の許可を得ることだと今のところ理解しているので、ActiveXでOSライブラリの実行を許可するのとは違うでしょうね🧐」「なるほど😅

参考: ActiveX - Wikipedia

「まあPeriodic Background Syncがどのぐらい大事なのかはわかりませんが😆、Webをインストールするという考え方はキャッチーだし、なかなかいいと思いました😋」「はい😋」「今のService Worker周りは正しく使われてない度が高い気はしますけど🤣」「通知許可したことないです🤣

⚓Webプッシュ通知よもやま話

「最近通知の許可を求めてくる新聞系のサイトが多くて嫌になるじゃないですか😆」「たしかに😆」「あれを自動でオフにするChrome拡張とかもあるぐらいですし、ユーザーが速攻不許可にする感じになってますよね😆」「😆」「なのでインストールという考え方に移行して、もっとtrustedなしくみを導入するのはありなのかなと思いました☺」「それはそれで悪用されたりして?😆」「まあ先のことはわかりませんが😆

「…Webブラウザは昔からブラウザを閉じればすべてが終わるという大前提でやっていますけど、Service Workerとプッシュ通知が入ってきたあたりから変わりつつありますね: でもそこで昔からやっている人たちの機嫌を損ねないように、ものすごく慎重にバランスを取りながらやってるという印象あります🧐」「それはある」「それに何がセキュリティホールなのかは最早感触でしかないという側面もあるので、仕様が不評を買わないための落とし所を慎重に探している感じですね☺

「あの手の通知許可ダイアログ、あちこちで出くわす😆」「しょっちゅう出てくるあのダイアログは単なる通知の許可だと思います」「あれはService Workerの許可とは別でしたっけ?」「ブラウザのプッシュ通知は専用のAPIがありますね🧐」「つまりService Workerは通知そのものとは別なのか」「オフライン対応で広く裏で使われているとは思います: オフライン対応するならService Workerは必須です☺」「なるほど」「たしかにそれがないと動かしようがないですし」

「実はあの通知がうざすぎるということでMozillaとGoogleがそれぞれ通知をおとなしくさせる予定になっていて、もうすぐアップデートが来るはずです」「それは大歓迎🎉」「プッシュ通知はフォーカスをダイアログに持っていかれるのが問題」「ほんとそれ!😤」「アンケート取ったらほとんどの人が読まずに通知のNoを押してることがわかったそうです🧐」「でしょうね🤣」「🤣

「今リンク貼りました↓🩹」「非常に不人気🤣」「やはり🤣」「実装した人たちは乱用されると思わなかったんだろうか🤣」「許可が1%程度で48%は明示的に拒否ということは、残り50%は単に離脱しているということでは🤣」「もう即閉じ🤣

参考: 非常に不人気な「Web Push通知」、Firefox 72以降ではポップアップを表示せずURLバーのアイコンで通知するのみに | スラド IT

「おとなしめの通知ではURLバーに通知が出るのか: それならまあいいかも☺」「Webをインストール、覚えとこう😋

⚓言語・設計・ツール

⚓セキュリティソフト入れますか?


つっつきボイス:「仕事のパソコンはセキュリティポリシー上の理由でウィルスチェッカー入れてるけど私物のパソコンはWindows Defenderで十分って徳丸先生が言ってますけど、そういうものなんでしょうか?」「あ、私もそうですよ: 私物PCはWindows Defenderだけです☺」「おぉ」

参考: Windows セキュリティによる保護 - Windows Help

「…セキュリティソフトなんてセキュリティホールを増やすためのソフトじゃないですか🧐」「なんと🤣」「🤣」「セキュリティソフトがウィルスソフトって言われるのは、あれ言い間違いじゃないと思ってますから🧐」「そこまで🤣」「🤣

「だいたいセキュリティソフトってセキュリティ上よくないことしかしないじゃないですか: 特権で勝手に動いてフルスキャンかけるし、SSLを通そうとして証明書のチェックをおざなりにしたりとか、そんなんばっかしです🧐」「お、おう😅」「まあそうですけど😆

「まあ自分たちが業務用PCにセキュリティソフト入れてるのも徳丸先生と同じで、取引上の理由しかありませんし😆」「はい☺」「セキュリティソフトに意味があるとすれば、うっかりミスを防ぐ効果でしょうね🧐」「あまり詳しくない人ほど効果が高い☺」「Webカメラ止めてくれたりするのは実際ありがたいですし😋

「でもセキュリティにこだわればこだわるほどセキュリティホールの比率は高まると思います😆」「セキュリティソフトがルート証明書入れてくる時点でどうかと思いますし🤣」「Windows Defenderで十分😋」「Macの場合どうしよう…😅


以下はつっつき後のツイートです。

⚓ソースコードブランチ管理のパターン


つっつきボイス:「Martin Fowlerさんの記事です」「この辺の図で何となくわかりそう😋


同記事より

「ポリシーとしては上図の左のようにブランチを管理したいけど、だいたい右みたいになるという😆」「右が現実😆」「左はGit-flow↓で言えば下の線がmaster、その上がdevelop、その上がfeatureブランチに相当するんですけど、縦の下矢印は必ずmasterに一方向に向かっているのがポイント🧐」「ふむふむ」「本来こうあるべきなんですが、現実には右の下みたいに別のブランチが生えてきて一方向にならなくなってしまう、ということが言いたい図だと思います☺」「なるほど!」

参考: git-flow cheatsheet

「どんなプロジェクトでもそうですけど、ブランチ管理はルールを制定することと、それを守らない人をリジェクトする強い心がないと徹底しないでしょうね🧐」「たしかに」

「以下の記事でもMartin Fowlerのfeature toggles(feature flag)を使ってやってるそうです」「feature flagも昔からあるやり方です😆」「ありゃ😅

参考: フィーチャートグル - Wikipedia

⚓Gitブランチ運用よもやま話

「ところで自分たちWebチームはGit-flow使ってますけど、アプリチームでは何を使ってます?」「…完全なGit-flowではないけどそれに近い使い方はよくやってます」「現行バージョンにでかい機能を入れるときは普通にfeatureブランチ切ります?」「メンテナンスブランチを伸ばしたくないので、master/develop/feature/hotfixで極力やりたいです☺

「クライアントごとにリポジトリを分けるとかはしませんか?」「極力やらないように努力してます😆」「納得😆」「やっちゃダメなヤツ😆」「そこが分岐してしまうと二度と元に戻れなくなると思うので、ソースは同じままでクライアントごとのソースを生成するビルドオプション作ってます」「なるほど」(以下延々)

⚓その他ツール


つっつきボイス:「TweetDeck風にGitHubリポジトリをブラウズできるツールだそうです」「リポジトリのコミットを表示してるみたい」「そこまで頻繁にコミットされるんでしょうか😅」「オープンソースのコミッターなら使うかな?」

「22ドルだそうです😆」「高っ😆」「オープンソースでこれがないと困る人はむしろ金もらえる立場だったりして😆

⚓その他

⚓古書通販


つっつきボイス:「古書店の人が本棚を動画撮影して、欲しい本を知らせてもらうという企画が評判よさそうなので」「たしかに書籍データを打ち込む手間を考えたら動画の方がラクですね😋」「カメラ移動をゆっくりで願いますという注文もありました😆

「古書の背表紙だと第何版なのかまではわからないか🤔」「あ、たしかに」「初版じゃないとイヤとか😆」「背取らーとかなら版数も気にするでしょうし😆」「うちのK&R本は第200うん十刷までいってたかな😆」「そんなに😆」「今なら300ぐらいまでいってたりして😆

参考: プログラミング言語C - Wikipedia

著者名の頭文字からしばしばK&Rと略される。
ja.wikipedia.orgより

⚓番外

⚓元素周期律表がリニューアル

以前からいろんな周期律表が考案されているようです。


後編は以上です。皆さまよい祝日を。

バックナンバー(2020年度第2四半期)

週刊Railsウォッチ(20200421後編)Ruby 2.4サポート終了、Ruby 3の右代入演算子、GitHubコア機能無料化ほか

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

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

Ruby Weekly

Hacklines

Hacklines

Publickey

publickey_banner_captured

Postgres Weekly

postgres_weekly_banner

Rails: Webpacker 5.1.0でcheck_yarn_integrityオプションが廃止された

$
0
0

小ネタかつRailsウォッチ20200427でも書いた話で恐縮ですが。

Webpacker 5.1.0でcheck_yarn_integrityオプションが廃止に

Docker上のRails 6アプリでgemを更新した後、develpment環境で起動したときに起動が露骨に速くなったことで、Webpackerの更新に気づきました。

問題

yarnのintegrityチェックはこれまで開発者を混乱・イライラさせてきた(#2517#2322#1568)。
integrityチェックはイニシャライザで実行されるので、その環境を起動するRailsコマンドを潜在的に邪魔し、多くの開発者をびっくりさせていた(1135)。
そしてYarnのメンテナー自身も利用はやめとけと言っている(yarnpkg/yarn#6427 (comment))。
yarn checkコマンドもYarn 2.0で削除された。

ソリューション

integrityのイニシャライザと設定オプションを削除する。開発者は、ローカル環境でyarn installを実行し、デプロイ時にyarn install --frozen-lockfileを実行するようにしていただきたい。
同PRより大意

おかげでRails起動が速くなってとても助かります😂

5.1.0より前の古いWebpackerを使っている方も、config/webpacker.ymlのcheck_yarn_integrity:行は遠慮なく削除しちゃいましょう。

参考: アップグレード前のwebpacker.yml

Webpacker 5.1.0へのアップグレード前の自分のconfig/webpacker.ymlは以下のとおりでした。

default: &default
  source_path: app/javascript
  source_entry_path: packs
  public_root_path: public
  public_output_path: packs
  cache_path: tmp/cache/webpacker
  check_yarn_integrity: false  # 削除した
  webpack_compile_output: true

# 略

development:
  <<: *default
  compile: true

  # Verifies that correct packages and versions are installed by inspecting package.json, yarn.lock, and node_modules
  check_yarn_integrity: true  # 削除した

関連記事

以下の記事でもyarnのintegrityチェックはオフにしているそうです。

Rails 6+Webpacker開発環境をJS強者ががっつりセットアップしてみた(翻訳)

週刊Railsウォッチ(20200511前編)Rails 6.0.3リリース、rails newに–masterオプションが追加、system specとfeature specの違いほか

$
0
0

こんにちは、hachi8833です。『みんなで筋肉体操』を今頃知って、軌道に乗せようと試行錯誤中です。


つっつきボイス:「筋肉体操一時期流行ってましたね💪」「当時まるで気づいてなくて、『筋肉は裏切らない』の出どころもやっとわかりました😅」「おうちでやる版が出たのね☺️」「今や空前の筋トレブーム」「みんな家にいますし😆」

「ジムによってターゲットの客層がそれぞれ違うんですけど、ゴールドジムはガチの筋トレ勢向けらしい」「ボディビルダーとか」「一般向けとかスタジオレッスン中心ではないと😳」「行ったことありますけどガチ勢多かった😅」(以下延々)

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

今回のつっつき会は、試験的にZoomで外部ゲストをお迎えして小規模に開催しました。ご参加ありがとうございました!🙇

Rails: 先週の改修(Rails公式ニュースより)

4/27の更新情報を中心に見繕いました。

GW中は@kamipoさんによる修正がかなり増えていました。


つっつきボイス:「Railsの公式更新情報ってウィークリーでしたっけ?」「自分はいつもチェックしてますけど平気で2か月とかインターバルあります😆」「ですよね😆、そんなしょっちゅう出てた気がしない」「公式が毎週やってたらRailsウォッチでそんな頑張らなくていいでしょうし😆」「😆」

「@kamipoさん、めっちゃアクティブにやってる」「すげ〜、毎日コミット!」「今の時期ライブが開催されていないからかも😆」「こんなにアクティブになれる秘訣が知りたいです」「あとお知らせにもありますけど、Railsのメーリングリストが以下のDiscourseに統合されたそうです↓」

rails new--masterオプションが追加


つっつきボイス:「--masterとは?」「どうやら--devとか--edgeというオプションは前からあったみたいです」「知らな〜いこれ🤣」「何に使うんだろ🤣」「rails newするときに最新版を取ってきたりできるということ?」「だと思います」

「たぶん業務では直接使わないでしょうね😆」「gemを作ってる人がこれをCIに仕込んで常にedgeでテストできるようにするとか?」「普通にgitでブランチ指定すればよさそうですけど😆」「同じこと思いました😆」「これがどうしても欲しい理由はよくわからん😆」「手っ取り早くmasterでnewしたいとか?」「グローバルgemを汚さずにedgeを取って来たいとか?」「それならrbenvとかでやればよかったりして😆」「rbenvならグローバルgemは汚れないけどCIだとうまく動かなかったりするんですよね😅」「ああたしかに」「この機能がrails newコマンドに入っていれば、不自由な環境でもrailsコマンドさえ動けばやれるから、そういうのが欲しい人もいるのかなと」「まあ--dev--edgeが前からあるなら--master足してもいいかも☺️」

背景

現在のrails newジェネレータでサポートされているオプションは--dev--edge
--devはローカルのRailsセットアップを指し、--edgeはRailsの最新stableブランチを指す。
しかしRailsコミュニティでedgeと言えば最新のmasterだと考えることが多く、Shopifyの以下の素敵な記事で最新のmasterを指す方法が書かれているほど。
Living on the Edge of Rails – Shopify Engineering
本来ならedgeがmasterを指す変更をおすすめするところだが、利用が多すぎて詰まった。

変更

現在のedgeの機能を変えるよりは、欲しいものを足そうかと思う。
このPRは--masterフラグを追加する。
これはまさにedgeに期待される動作を行うもので、Railsの最新stableブランチではなくmasterブランチを指す。

しかし何でまた?

ほら、開発者が水平シャーディングのようなRailsに最近コミットされた新機能を見たら、とりあえず新しいRailsアプリで試してみたくなるじゃないですか❤️。
このコマンドがあればコンフィグなしでやれるし、普段OSSをサポートする余裕のない自分らみたいな人でもテストコードをコミットしたりもできるので🙏。
同PRより大意

リファクタリング3つ


つっつきボイス:「上の2つはほぼ同じ感じのリファクタリングだそうです」「不必要なwhenを減らしてシンプルにした感じ😋」

# activerecord/lib/active_record/relation/where_clause.rb#L136
        def invert_predicate(node)
          case node
          when NilClass
            raise ArgumentError, "Invalid argument for .where.not(), got nil."
-         when Arel::Nodes::In
-           Arel::Nodes::NotIn.new(node.left, node.right)
-         when Arel::Nodes::IsNotDistinctFrom
-           Arel::Nodes::IsDistinctFrom.new(node.left, node.right)
-         when Arel::Nodes::IsDistinctFrom
-           Arel::Nodes::IsNotDistinctFrom.new(node.left, node.right)
-         when Arel::Nodes::Equality
-           Arel::Nodes::NotEqual.new(node.left, node.right)
          when String
            Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(node))
          else
-           Arel::Nodes::Not.new(node)
+           node.invert
          end
        end

「明示的に呼び出すように変えてる↓」

# actionview/lib/action_view/renderer/partial_renderer.rb#L279
      def render_partial_template(view, locals, template, layout, block)
-       instrument(:partial, identifier: template.identifier) do |payload|
+       ActiveSupport::Notifications.instrument(
+         "render_partial.action_view",
+         identifier: template.identifier
+       ) do |payload|
          content = template.render(view, locals) do |*name|
            view._layout_for(*name, &block)
          end
          content = layout.render(view, locals) { content } if layout
          payload[:cache_hit] = view.view_renderer.cache_hits[template.virtual_path]
          build_rendered_template(content, template)
        end
      end

「こういうinstrumentationの呼び出しって元々シングルトンというか、Railsのどこからでも呼び出せるものなんですけど、以下のinstrument(name, **options)みたいなメソッドがレンダラーのクラスに中途半端に存在していると呼び出しパスが複数できちゃうから、上みたいにグローバルな呼び出しに統一しようよということだと思います」「ふ〜む」

# actionview/lib/action_view/renderer/abstract_renderer.rb#L173
-     def instrument(name, **options) # :doc:
-       ActiveSupport::Notifications.instrument("render_#{name}.action_view", options) do |payload|
-         yield payload
-       end
-     end
-

「自分もたまにこういうメソッドって書いちゃうんですよね: ActiveSupport::Notifications.instrumentみたいな長ったらしい名前空間を何度も書くのが面倒なときとか😆」「わかります〜」「でも実際このメソッドって無意味ですし、こういうのを残しとくと#instrumentの引数が変わったときに挙動が変わったりして害を生じたりすることもあるのであんまりよくないよってことだと思います🧐」「なるほど!」「今なら長い名前空間の入力はIDEに補完させれば済みますし☺️」

「公式情報には『あえてDRYでない方向にリファクタリングした』という感じで書かれてました」「ここではメソッドに別名を付けているだけなので、たぶんですけどDRYでないようにしたというよりは、以前のショートハンドメソッドがよくなかったよねということかなと思います🧐」「なるほど😅」「メソッド内で別のことをしているならともかく、他に何もしてないので☺️」

PostgreSQLアダプタのresult_as_arraymap_types!に置き換えた

# activerecord/lib/active_record/connection_adapters/postgresql/database_statements.rb#L13
        def query(sql, name = nil) #:nodoc:
          materialize_transactions

          log(sql, name) do
            ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
-             result_as_array @connection.async_exec(sql)
+             @connection.async_exec(sql).map_types!(@type_map_for_results).values
            end
          end
        end

つっつきボイス:「map_types!って何だろうと思ったらPGライブラリのメソッドだそうです↓」「なるほど、便利メソッドが元からあるならそれを使いましょうということね☺️」「自分らがPGライブラリを直接触ることはまずなさそう☺️」

find_by_sqlの不必要なループを回避


つっつきボイス:「これも@kamipoさんによる修正ですね」「やらなくていい処理をunlessで囲ったのね☺️」「こういう更新はちょくちょく入ってる」

# activerecord/lib/active_record/querying.rb#L45
    def find_by_sql(sql, binds = [], preparable: nil, &block)
      result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
-     column_types = result_set.column_types.dup
-     attribute_types.each_key { |k| column_types.delete k }
+     column_types = result_set.column_types
+
+     unless column_types.empty?
+       column_types = column_types.reject { |k, _| attribute_types.key?(k) }
+     end
+
      message_bus = ActiveSupport::Notifications.instrumenter

      payload = {
        record_count: result_set.length,
        class_name: name
      }
      message_bus.instrument("instantiation.active_record", payload) do
        if result_set.includes_column?(inheritance_column)
          result_set.map { |record| instantiate(record, column_types, &block) }
        else
          # Instantiate a homogeneous set
          result_set.map { |record| instantiate_instance_of(self, record, column_types, &block) }
        end
      end
    end

アソシエーションを複数回autosaveできるよう修正

# activerecord/lib/active_record/autosave_association.rb#L367
      def before_save_collection_association
-       unless defined?(@new_record_before_save)
-         @new_record_before_save = new_record?
-       end
+       @new_record_before_save ||= new_record?
      end

つっつきボイス:「これはまた面倒くさそうな部分の修正😆」「たしかにdefined?だと1回しかチェックできないし」 「undefしないと戻せない😆」

#38166以来アソシエーションは1回しかautosaveされないようになっていた(レコードをsaveした後は@new_record_before_saveが常にfalseになる)。ここではレコードが永続化に移行するのが1回だけであると仮定しているが、複数回起きるケースが2つある。1つはレコードをsaveするトランザクションがロールバックする場合、もう1つは永続化したレコードが後に複製される場合。
私たちのアプリを6.0.2.2から6.0.3.rc1に進めたときにリグレッションが発生したので、バックポートを希望する。
同PRより大意

番外: ドキュメントの改善

# guides/source/getting_started.md#L612
-we don't specify what the response should be. We just added the `create` action
+we don't specify what the response should be. We added the `create` action

つっつきボイス:「最後のトリビアは、justとかsimpleのような大して意味のない語を削除したそうです」「フォーマルに少し寄せたというか」「軽くポリコレ感😆」「高校生の書くエッセイとかを先生が注意したりするヤツ😆」「言い回しに突っかかる人いますし😆」

「でもjustって便利なんですよ英作文のときとか😆」「言葉に詰まったときにとりあえず書いちゃうヤツ😆」「日本人だと学校英語の影響で始めのうちはonlyを使いがちなんですけど、onlyは文のどこに置くかで限定の対象がデリケートに変わってくるので文が込み入ってくると割と面倒くさくて🤣」「へぇ〜😳」「わかる🤣」「特に会話だとjustって便利😂」

参考: 「Only」の位置で、文の意味は変わりますか? - eigopedia


日本語で言うと「ちゃんと」とか「しっかりと」みたいなあってもなくてもいい語が雰囲気で投入されるのと少し似ているかもと思いました。自分が英文にするときには「ちゃんと」や「しっかりと」みたいな語はだいたい削除しちゃいます😉。

『The Elements of Style』↓という一世紀前からある定番の本は薄くてすぐ読めるのでおすすめです。

参考: 百年前の英文指南書『The Elements of Style』に学ぶ、効果的な文章の書き方11の法則 | ライフハッカー[日本版]

Rails

Rails 6.0.3がリリース

セキュリティリリースでないことがバージョン番号だけでわかるようになって助かります。


つっつきボイス:「そうそう、ちょっと前からRailsのバージョニングが変更されたんですよね😋(ウォッチ20200302)」「たしかにわかりやすくてありがたいです🙏」「セキュリティフィックスのみのリリースには4桁目が付くようになった: 仮に6.0.3にセキュリティリリースが出るときは6.0.3.1みたいになる」「ちょうど今朝rails newしたんですけど見たら6.0.3になってる〜😋」「逆に、たとえば6.0.3.1の次に6.0.4が出たら、それはセキュリティ以外の修正や変更ということですね☺️」

「6.0.3の変更内容は知ってるものも知らないものもありますね」「マルチプルデータベース周りはまだごりごり変わってるっぽい😆」「もうちょい様子見な感じですね😅」

Active Supportのto_sentence

to_sentence↓ってナニコレ知らない〜😆」「”A, B, and C”みたいな英語っぽい形式に変換するのか😆」「あ〜いかにも英語圏のためのメソッド😆」「to_sentenceにはORみたいの他の接続詞も渡せるんですって😆」

参考: Railsで配列の要素から”A, B, and C”形式の文字列を作る時はArray#to_sentenceが便利 - WEB SALAD

# web-salad.hateblo.jpより
%w(one).to_sentence
# => "one"
%w(one two).to_sentence
# => "one and two"
%w(one two three).to_sentence
# => "one, two, and three"

「なんで英語だとand入れるんですかね?」「英語的には列挙するときに最後にandとかorを入れないと許してもらえないところあります😆」「英語圏ではA, B, and Cみたいに書くのが普通だと思いますし😆」「ですです」「日本語なら”AとBとCとD”みたいに全部”と”でjoinすれば済むんですけどね😆」

「ところでこのメソッドってどこで使うんでしょう?」「メッセージじゃないですか?」「あ、そうか😳」

「そういえば工業英語だったか特許英語だったかな、andの前のカンマ,を置くか置かないかで意味が変わるらしいというのを知って英語って面倒くさいな〜って思った覚えがあります😆」「マジで?😆」「自分らはandの前にカンマを置かないと習ったような気がしますけど🤔」


後で本棚から探しだしてみると、”英語ではandの前にカンマを置く(列挙)書き方と、置かない(結合が強まることが多い)書き方の両方があるが、ネストした列挙で誤解を招かないためには、原則として列挙を表すandの前にカンマを置くよう統一するのが望ましい”という趣旨でした。自分なら箇条書きで書きたいところです😆。

  • あいまいな例
A, B, C and D and E
「A」「B」「CとD」「E」なのか「A」「B」「C」「DとE」なのか区別できない
  • よい例
A, B, C, D, and E
「A」「B」「C」「D」「E」で一意に定まる
A, B, C and D, and E
「A」「B」「CとD」「E」で一意に定まる
A, B, C, and D and E
「A」「B」「C」「DとE」で一意に定まる

『続・技術翻訳のテクニック』(富井篤) p145-146より大意

なお自分は日本語なら列挙を「A」「B」「CとD」「E」のように「」の連続だけで表す方法が好きです❤️。ついでながら、bread and butterは全体でひとつの英熟語です。

system specとfeature specの微妙な違い(Ruby Weeklyより)


つっつきボイス:「お気持ち系の記事かな😆」「『オレはこう思う』みたいな😆」

「feature specって一時期流行ったんですよ」「そういえば😳」「turnipとかcucumberとか最近あんまり聞かなくなったと思いません?」「見かけたの結構前だったような😆」「あれですよ、BDD(ビヘイビア駆動開発)が流行ったとき😆」「それですね😆」「feature specもてはやされてましたけど、今思えば夢の世界だったんだろうか🌠」

参考: ビヘイビア駆動開発 - Wikipedia

「一応cucumber-railsとかはメンテはされてるかな👀」「あれ、テスト落ちてる?😆」「ホンマや😆」「cucumber本体の方はちゃんとメンテされてるしテストも通ってる」

「cucumberみたいなツールは、たとえば政府調達系みたいな案件ならむしろマッチするかなという気もしますね🧐」「つまり要件が固いもの?」「そう、めちゃくちゃ要件の固い案件」「ふむふむ」「一次請けの会社がcucumberで要件定義を書いて下請けに発注するみたいな😆」「なるほど〜」


記事見出しより:

  • Railsにある2つのレベルのテスト
    • 高レベルかつ粒度が大きい: feature spec
    • 低レベルかつ粒度が小さい: model spec
  • feature specからsystem specへ
    • 背景
    • system specはsystem testを包含する
  • 構文上の違い
    • feature specの例
    • system specの例
  • まとめ

Docker内でRailsのシステムテストを動かす(Ruby Weeklyより)

# 同記事より
services:
  app:
    build: .
    command: bundle exec rails server -p 3000 -b '0.0.0.0'
    # ... more config ...
    ports:
      - "3000:3000"
      - "43447:43447"
    # ... more config ...
    environment:
      - SELENIUM_REMOTE_HOST=selenium

つっつきボイス:「ハウツー記事ということで」「Dockerの中のテストでSeleniumをぶん回すときの話みたい」


記事冒頭より:

  • Dockerの中でシステムテストを気持ちよく回すために
    • RSpecをシステムテストに使う方法
    • モダンなブラウザ内でヘッドレスモードのテストを回す方法
    • ビルドやデバッグを効率よく行うために、ヘッドレスでないブラウザでテストを回せるか

Railsでライブラリを使わずにReact componentをレンダリングする

// 同記事より
export const mountComponent = (component, componentName) => {
  const nodes = Array.from(
    doc.getElementsByClassName(`react-${componentName}`)
  );
  nodes.forEach((node) => {
    const data = node.getAttribute("data");
    const props = data && data.length > 2 ? JSON.parse(data) : {};
    const el = React.createElement(component, { ...props }, []);
    node.innerHTML = ''
    return ReactDOM.render(el, node);
  });
};
// 同記事より
document.addEventListener("turbolinks:load", () => {
  mountComponent(MessageDisplay, "MessageDisplay");
  mountComponent(AnotherComponent, "AnotherComponent");
  mountComponent(AThirdOne, "AThirdOne");
}

つっつきボイス:「ライブラリってどのライブラリ?😆」「何ともファジーな😆」「サードパーティのライブラリを使わずにReact componentをコンポーネント単位でレンダリングしたりテストしたりしたいということかな」「コンポーネントのテストをRailsで書きたいかというと、データが絡むときとかなら書きたいな〜😋」


見出しより:

  • しくみについて
  • Railsビューの中で特殊なelementをレンダリングする
  • JSを書く
  • mountComponentを呼ぶタイミング
  • まとめ

Rails+StimulusReflex+CableReadyでチャット機能を作る


つっつきボイス:「お、Stimulsか」「こうなるとRailsは単なるWebSocketサーバー同然だったりして😆」

参考: WebSocket - Wikipedia

「CableReadyって最近ちらほらと見かけますけど、Action Cableを使いやすくするとか?」「単にWebSocketを使いやすくするヤツかなと思ったら、Action Cableと接続するライブラリなのか〜😳」「なるほど!」「Action Cableに生でつながれるよりはいいのかな😋」「またフロントエンドの人に嫌がられそう😆」「😆」

<!-- 同記事より -->
<!DOCTYPE html>
<html>
  <head>
    <title>StimulusReflexCableReadyDemo</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css">
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <div class="ui centered grid">
      <%= yield %>
    </div>
  </body>
</html>

Ruby Weeklyで上の記事と同じ趣旨の以下の動画が紹介されていました。10分で作れると言ってます。

その他Rails


つっつきボイス:「3本目はAaron Pattersonのキーノート↓がよかったという感想文😆」「まだ見てませんがめっちゃ楽しいって書いてますね」「RailsConf 2020か、後で見てみよっと😋」

動画冒頭ににオーディエンスの笑い声が入ってますが、本物かな?と思ったらイントロは事前に録画してたようです。

「そういえばAaronさんはつい最近GitHubから離れたんでしたっけ」「今度はShopifyだそうです」


前編は以上です。

バックナンバー(2020年度第2四半期)

週刊Railsウォッチ(20200428後編)Rubyのバックトレース順序が戻る、KubernetesでRailsをスケール、セキュリティソフト入れますか?ほか

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

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

Rails公式ニュース

Ruby Weekly

Hacklines

Hacklines

週刊Railsウォッチ(20200512後編)RubyのPStoreライブラリ、Lambda StoreのサーバーレスRedisは有能、Amazon Linux 2のライブパッチほか

$
0
0

こんにちは、hachi8833です。何だか秒読みが始まってますね⏱ここでプルリク数見えます。

ちなみにコミット数は既に3,424件なんですね😳

参考: Rails Contributors - #5 Ryuta Kamizono - All time

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください

今回のつっつき会は、試験的にZoomで外部ゲストをお迎えして小規模に開催しました。ご参加ありがとうございました!🙇

⚓Ruby

⚓git_curate: gitのブランチ削除支援ツール(Ruby Weeklyより)


同リポジトリより


つっつきボイス:「Rubyで書かれてたのでここに置いてみました」「見たまんまのとおり、ブランチを確認しながら削除できるツール」「upstreamのブランチも消してくれるならよさそう😋

⚓RubyのPStoreを実用的に使う(Ruby Weeklyより)


つっつきボイス:「PStoreって何のライブラリだろうと思って」「へ〜!PStoreってMarshalのラッパーなんだ😳」「しかもトランザクショナルにやれる: まあどうせファイルに格納するんだからファイルロックを使ってるんでしょうけど😆」「こんなのがあるとは😳

参考: class PStore (Ruby 2.7.0 リファレンスマニュアル)

# docs.ruby-lang.orgより
require 'pstore'
db = PStore.new("/tmp/foo")
db.transaction do
  p db.roots       # => []
  ary = db["root"] = [1,2,3,4]
  ary[0] = [1,1.5]
end

db.transaction do
  p db["root"]     # => [[1, 1.5], 2, 3, 4]
end

「PStoreはRubyに標準であるのがいいですね❤」「これがあればSQLite3要らなかったりして😆」「PStoreっていつからあるんでしょう?」「2006年のるびまに載ってる↓ということは、少なくともそのときからあったのかな」「今のRubyなら間違いなく使える😋」「これはいい👍

参考: 標準添付ライブラリ紹介 【第 9 回】 PStore

「Marshalを生で使うより便利という感じでしょうか?」「Marshalと違ってfetchとかdeleteとかpathみたいなメソッドがあるから、一種のハッシュ型データベースとして使えるんでしょうね😋: 保存先がMarshalというだけで」「あ〜なるほど!」

「こういうライブラリの存在を知っておくと便利なことがあるんですよ😂」「というと?」「ライブラリの追加が禁止されている環境で縛りプレイ的にコードを書かないといけない、なんてことがたまにあったりしますし😇」「😆」「ライブラリの追加禁止とまでいかなくても、gemを追加するとbundlerを動かしたりしないといけなくなってすごく面倒になるなんてこともあります😭」「わかります😭」「そういう環境だとRuby本体だけでやらないといけなくなりますし☺

「PStoreいいな〜、よし覚えとこう😍」「もっと評価されるべき」「まあ業務ではそんなに使わないだろうけど作り捨てのスクリプトにはいいかな😋」「ところでPって何なんでしょう?😆」「わがんね😆」「記事のタイトルにあるPracticalだったりして?🤔


Marshalのlが1個なのか2個なのか毎回忘れそうになります😅。Rubyのは1個ですね(整列する、整理する)。2個のMarshallだと人名地名になります。

⚓悪質なRuby gemを探知する(Ruby Weeklyより)


つっつきボイス:「今度はマリシャスなgem👺」「gem名のアンスコをハイフンに変えてて、かつ悪いコードを飲み込んでるヤツをスキャンしたら結構出てきたそうです😱」「あ〜スクワッティングあるある😆ウォッチ20200226)」「まあどんな言語にもありますし、オープンソースで自由にアップロードできる以上どうしようもないでしょうね😭

⚓その他Ruby

つっつきボイス:「Doorkeeperというgemで脆弱性が見つかったそうです」「これは認証用だったかな?」「OAuth2か」「Doorkeeperは使ったことはありませんが、こういうときのためにgemになってるんだから使ってる人はバージョン上げるべきですね☺


⚓DB

⚓Rails+PostgreSQLでフルテキスト検索を高速に実行する(Ruby Weeklyより)


つっつきボイス:「貼ってみてから割と普通の記事だったかなと思いつつ😅」「前方一致とか後方一致なら一応インデックス効かせられますけどね☺

「フルテキストだと単語ごとに割ってインデックス化するのかな?」「そこはフルテキストがLIKEみたいに文字列の部分一致も含めるバイナリ的な検索なのか、構文解析を伴う自然言語検索なのかによりますけど、この記事ではnatural language searchってあるから後者なんでしょうね」「あそうか😅」「前者と後者はアプローチが別なので☺」「こんなふうに↓言語を指定してtsvectorも使っているので、自然言語検索でしょう😆」「てっきりLIKEの話なのかなと😆

-- 同記事より
SELECT
  id,
  title,
  ts_rank(
    to_tsvector('english', title) || to_tsvector('english', description),
    to_tsquery('english', 'ruby & rails')
  ) AS rank
FROM jobs
WHERE
  to_tsvector('english', title) || to_tsvector('english', description) @@
  to_tsquery('english', 'ruby & rails')
ORDER BY rank DESC
LIMIT 3

参考: 8.11. テキスト検索に関する型

「まあ英語だったらこれでいい😆」「楽でいいですね😆、って比較の問題ですけど」「まあ日本語にもそれ用のエンジンありますし」「お〜こんなぽすぐれ拡張があるんですね↓😳」「mecab使ってるのか」「使ったことないからどのぐらい強いかは知りません😆

参考: tsja: 日本語テキスト全文検索 (PostgreSQL)
参考: MeCab: Yet Another Part-of-Speech and Morphological Analyzer

「これってSennaみたいなヤツなのかしら😆」「せな?」「これですね↓」「あ〜こんなのもあるのか😳」「こっちはmecabプラスn-gramでやってますね」「アイルトン・セナから命名ですって😆」「Senna流行りましたよね😋」「そうですね😋」「知らなかった〜😅」「MySQLでこれをよくビルドしてました☺

参考: Senna - Wikipedia

「元記事タイトルのfull text searchは、natural language searchって書いて欲しい😆」「ですよね😆、自分の知ってるfull text searchと違う気がしますし」「この辺は検索専門じゃないのでわかりませんけど、もしかすると大きなくくりがfull text searchで、その中に自然言語検索があったりLIKEのワイルドカード検索があったり正規表現検索があったりするのかも?🤔

⚓Redis 6.0がリリース(StatusCode Weeklyより)

早くも6.0.1が出ています。

見出しより:

  • クライアント側キャッシュの設計が見直された
  • レプリケーション用RDBファイルが不要になったら削除するモードをサポート
  • ACL GENPASSがHMACベースのSHA256で再実装された
  • レプリケーションプロトコルpsync2が改善された
  • Redisコマンドのタイムアウトが改善された
  • 新コマンドの追加

つっつきボイス:「Redis 6、前から出すとか言ってましたね☺

「しょうもないんですけどGAって何の略でしたっけ?」「何だったかな〜?🤔」「これ見るとGeneral Availabilityですって」「あ〜そうだった!」「マイクロソフトがGAって呼んでた気がします」「Zimbraもそうだったかも」「図を見るとRTM->GA->Productionリリース(Gold)ってなってるし」「RTMになったら使っていいんでしょうね?」「RTMならリリースされてますから☺」「たぶんこの呼称を全部使うことってない気がする😆」「きっとそう😆

参考: Software release life cycle - Wikipedia

「まあAWSのRedis(ElastiCache)はライセンス的にどうよって思いますけど😆」「そういえばライセンスで揉めてましたね」「自分でRedisサーバー立てて使う分にはいいんですけど😆

参考: Amazon ElastiCache(インメモリキャッシングシステム)| AWS
参考: Redis、MongoDB、Kafkaらが相次いで商用サービスを制限するライセンス変更。AWSなどクラウドベンダによる「オープンソースのいいとこ取り」に反発 - Publickey

⚓Lambda Storeはスゴい

「Redisといえば、Redisをサーバーレスで使えるサービスがつい最近出てましたよね: そうそうLambda Store↓」「ありゃこんなのが😳」「俺たちが欲しかったものはこれでは?という気持ちになりますね😋」「こっちの方がスゴかったのか😅

「Lambda Storeのどこがいいかというと、マネージドなRedisで、かつ課金がリクエストベースというところ❤」「おぉ〜」「ほら、ElastiCacheってインスタンス課金じゃないですか」「あれ結構お金かかりますよね💰」「Redisが欲しいだけなのに、EC2インスタンスと同じぐらいかかるのはなぁ〜って思いますし」「ですよね😆」「その点Lambda Storeは従量課金😋」「これはたしかに俺たちの欲しかったもの!」

「軽いWebサービスを作るだけなのにElastiCache使うのってどうよって思ってましたし😆」「そんなお金があったら他のことに使いたいし😆」「たかがsmallのインスタンス2台の構成で、わざわざElastiCache立てるのかと😆」「とってもそう思います😆」「AWSのDynamoDBがすっごく使いにくいので、AWSでまともなKVSを使いたいときにRedisが使えたらいいのにって思ってました😆

「とにかくLambda Storeはいいですね👍」「なるほど〜」「あとはこのサービスがいつまで続いてくれるかかな😆」「😆」「仮にこのサービスが終了したら、Redisの引っ越しというやりたくない作業が発生しますし😅」「Redisの引っ越しはやりたくないですね〜😅: VPCの中に移行するときにやりましたけど」「もうダウンタイムを許容してもらうしかない」「自分のときは6時間止めましたよ😭」「それはしんどそう😆

「Redisの移行だと、いわゆるbinlogを流していくみたいなやり方はできないんでしたっけ?」「あのときはElastiCacheからElastiCacheへの移行だったんですけど、それ用のツールとかなかったんじゃないかな…」「とにかくRedisは人間が運用するものじゃない🤣」「Redisの運用はやりたくないっすね🤣

「てなことを考えると、Lambda Storeが仮にシャットダウンしたときにはどうしたらいいのかなって😆」「ちなみにお金払えば1000接続同時とかも従量課金でやれるみたいですね」「あ、もしかするとLambda StoreってAWSのサービスじゃなくてサードパーティがやってるってことですか?」「そうそう、Lambda StoreはAWSの公式じゃないので、仮に将来この会社がなくなったときのことを一応考えちゃいますし🧐」「なるほど、会社名がLambda Storeか↓」


lambda.storeより

ドキュメント見るとLambda Storeは今はAWSでしか使えないって書いてますね」「アカウントはGoogleやGitHubも使えるみたいなのに、なぜAWS限定なんだろう?権限周りが面倒くさいから?🤔

「今の自分はGCPおじさんなのでGCPにもLambda Store来て欲しいです😆」「たしかに😆: AWSもGCPも『ここにこの機能があればいいのに😭』っていうのがお互いにありますよね」「はい、今なくて困ってます😅」「GCPにもRDS欲しい、とかね😆」「それマジで欲しい😭」「😆」「GCPのCloud SQLはVPCの中で使えないという謎の制約があるんですよ😢」「どちらも一長一短感ある😆

参考: Amazon RDS(マネージドリレーショナルデータベース)| AWS
参考: Cloud SQL: リレーショナル データベース サービス  |  Google Cloud

⚓その他DB


つっつきボイス:「はてブでバズってました」「笑うしかない😆」「ORMのデフォルトがWHERE文が空でも通っちゃうという😆」「数億件のデータが消えそうになるってそれって😅」「クライテリアにNILとか空のものを渡したときにWHERE文が空になってDELETE from テーブル名になっちゃってて、このライブラリにそれに対する安全機構がなかったのね😇」「ほわっ😅」「ピュアなライブラリならありそうだけど業務で使うライブラリとしてはありえない感じ😆」「し、しびれる〜😅

「過去にも同じワナ踏んだ人がいるって書いてますね」「こういうのはあったら絶対踏みます🤣」「🤣」「記事の冒頭に、MySQLだと--safe-updatesオプションがあるそうですね」「こういうセーフオプションはそこそこありますね☺」「DELETEやUPDATEにWHEREが付いてないのは基本的に何かのミスでしょうし」「DELETEはトランザクショナルに戻せるけどTRUNCATEは戻せないとか、いろいろあるんですよね😅

Gormが本番テーブルの数億件のデータを消そうとした話 – keroxpのScrapbox

gormを本番で使ってる人は全員これを有効にすべき https://godoc.org/github.com/jinzhu/gorm#DB.BlockGlobalUpdate

2020/05/07 12:40

⚓ORM

「Go言語でORMを使うようなリッチなアプリケーションを作るのは時期尚早だったのかななんて思ったり😆」「なぜGoでやろうとしたのか😆」「Goなら静的検査もできるし、やりたいという気持ちはワカル☺」「単にproductionで使ってた人があんまりいなかったんじゃないかなと想像しますね: Go言語はどちらかというとシンプルでマイクロなサービスのレイヤで使われてて、がっつりデータベース処理みたいなことってそんなに行われてなかったんじゃないかしら☺

「批判のパラグラフが『開発環境で気づけなかったのか?はい』『テストで気づけなかったのか?はい』…ってスゴい😆」「相当念のこもった記事😆」「『Gormを使ってるコードベースを凍結してGormの削除を決定した』というのも😇」「いや〜実際コードベースがでかければでかいほど怖いですよ😇: 誰かがコードレビューで見逃した瞬間に死ぬというのは💀

「Go言語で推奨されてないリフレクションをGormで使っているというのもヤバそう」「記事にも書いてますけどORMを実現するには普通はリフレクションが必要になってくるんでどうしようもないですね🧐」「う〜む😅

参考: リフレクション (情報工学) - Wikipedia

「ちなみにコードジェネレータを使うタイプのORMならリフレクションなしでもいいんですけど、その代わりスキーマ変更のたびにデプロイが必要になる😆」「たしかに」「JavaだとそういうタイプのORMが多くて、スキーマを変更したらORMのクラスを再生成するバッチを実行するとスキーマ情報を拾ってきてJavaのクラスファイルを生成するようになってる」「ふむふむ」「そのタイプだとコード実行時にはスキーマ情報とかが既にバイナリになっているので、動的なスキーマ変更はできない代わりに言語レベルで型検査ができますね😋

「まあコードジェネレータベースのORMは最近流行らなくなってて、ORMといえば実行時にスキーマ情報を動的に拾ってくるものが一般的になりましたけど: ちなみにPHPだと自分が使ってたPropelとかDoctorineとかはジェネレータでやるタイプでしたね↓☺」「なるほど〜」「ジェネレーターベースだとデプロイが必要になってORMのメリットが目減りしてしまいますし、最近は動的にスキーマ情報を拾うのが当たり前になってきましたし☺

参考: Propel, The Blazing Fast Open-Source PHP 5.5 ORM
参考: Doctrine: PHP Open Source Project

「たしかにデプロイは必要でしょうね」「まあ断定はしきれませんけど、実行されるSQLがセーフなものになっていればスキーマが変更されても一応動くはずだと思うんですけどね☺: 実際RailsのActive Recordは、スキーマを変更してもスキーママイグレーションの番号さえ合っていれば一応動きますし😆」「うんうん😆」「とにかくORMには実績のあるこなれたライブラリを使いましょうということで☺

⚓リモートワーク

⚓全員オンラインで気づいた情報格差


つっつきボイス:「こちらもはてブでバズってました」「やっぱりリモートワークは全員フルリモートでやるのが楽だと思うんですよ: リモートの人と出社してる人が混じって働くと、やっぱりめちゃくちゃやりづらい😭」「あ〜」「オンラインで話す人と現地で話す人がそれぞれいるとどうしても情報格差ができてしまって、マイクの具合とかで実はオンラインの人にだけうまく聞こえてなかったりすると齟齬が生じやすいんですけど、全員オンラインなら聞こえてないときは誰にも聞こえないのですぐわかる😆」「😆

「サイボウズの社長が言っていることもパンデミックよりずっと前から言われている話で、部分リモートはよくないという説も自分は当時から同意でしたね☺」「うんうん」「全員フルリモートになる方がコミュニケーション上の齟齬が明らかに起きにくいのはたしか🧐

「こういう意見をサイボウズの社長という知名度の高い人が発信してくれることで全員フルリモートが促進されそうなのがいいですね👍」「サイボウズは昔から社員が働きやすい環境づくりに取り組んでいますね😋」「これでリモート化を推進するときにサイボウズの社長を引き合いに出せる😆

「今の職場でも、今後パンデミックが収束して通常の仕事モードに戻ったときに『自分はフルリモートにしたいです』という人が出てきたら、フルリモートメンバーだけのチームを作る方がお互いストレスもたまらなくていいかなって思いますし☺」「ですね😋」「自分なんかはリモートでも出社してもどっちでも構わないタイプですけど、それはそれで同じタイプの人をまとめてチームを作るとかね」「なるほど」

「ちなみに自分は仕事上のコミュニケーションは、たとえ出社しててもすべてオンライン上でやるべきだと思っているので、出社してオフラインコミュニケーションする意義はそこにいる人と気持ちの上で仲良くなることぐらいしかないと思ってます🤣」「🤣」「込み入った話こそログに残したい派なので😋


ちょうどつっつきの後でサイボウズの社長がNHKに出演していましたね❤

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

⚓Amazon Linux 2にライブパッチ適用機能(Publickeyより)


つっつきボイス:「クラウドはさっきLambda Storeのイイ話が出たのでこの辺は流していただいてもOKです😆」「そうそう、Linux自体はけっこう前にカーネルにライブパッチを当てられるようになっていたんですよ」「へぇ〜😳」「それをAmazon Linux 2でもできるようにしたということでしょうか?」「ライブパッチをyumで配信できるようにしたということでしょうね☺」「あ〜そういうことでしたか😳

参考: 【 yum 】コマンド(基礎編)――ソフトウェア(パッケージ)をインストールする/アンインストールする:Linux基本コマンドTips(42) - @IT

「オンラインのカーネルパッチ機能自体はここ数年のLinuxには既に入っているはず」「やった覚えがなかった😅」「その辺はディストリビューションによって違っていて、ディストリビューションのコマンドでアップグレードするときにライブパッチを使うかどうかはディストリビューションに委ねられていたと思います☺」「なるほど〜」

参考: Linux-4.0のライブパッチ機能を試してみる - Qiita

「今回のニュースはAmazon Linuxがライブパッチをメインストリームに流し始めるぞというプレビュー機能を出したということですね」「あ、プレビューですか😆」「AWSがライブパッチを実装したのでもなければ、Linuxに新たにライブパッチが実装されたのでもないと😆

「でもライブパッチ当てるの、怖いと思いません?🤣」「怖いです〜🤣」「です〜🤣」「まあどこにパッチを当てるかにもよると思うんですけど」「カーネルのバージョンとinitrd(RAMディスク)のバージョンが合わなくなって起動しなくなるとか、一番めんどくさいあるある🤣」「ひえ〜😅

参考: initrd - Wikipedia

「なおライブパッチという概念自体は随分前からあって、リソースをちゃんと管理できていれば本来ライブパッチ自体はそんなに怖いものではないです🧐」「ふむふむ」「やり方も確立してますし、メインフレームだと普通にやってますし☺

「ライブパッチで怖いのは次に再起動したときでしょうね: 何かのミスでゴミが残ったりして二度と立ち上がらなくなるとか🤣」「🤣」「今回AWSがライブパッチを始めるということは、少なくともAWS側で検証したライブパッチを当ててくれると思います☺」「そうであって欲しいです🙏」「そりゃそうしますよ😆

「まあライブパッチだけではカバーできない修正も今後出てくると思いますけど☺」「ありそう😆」「CPUのレジスタをいじるような修正とかドライバのレイヤに近い部分の修正は難しいものもあるかも: まあ今のLinuxはモジュール化が進んでいるのでたいていのものはライブパッチが効くと思いますけど🧐

⚓WSL 2リリース間近


つっつきボイス:「WSL 2、リリースされたのかと思ったらまだだったという😆」「上の見出しに釣られました😆

参考: Windows 10 May 2020 Updateは5月28日に一般公開か? | ソフトアンテナブログ

「ところで今回のパンデミックの件で個人的に最もありがたいのは、開発環境をノートPCから完全にデスクトップPCに移せたこと🎉」「そういえばやってましたね」「それはもうめちゃくちゃ速くなりましたよ🚀」「Windowsはそれができるからいいですね😭」「MacもProタワーあるじゃないですか😆」「いっぱいチーズが削れますヨ😆」「お餅も焼ける😆

⚓JavaScript

⚓スナック「jQuery」


つっつきボイス:「文章としては名文ですね😆」「ようやる😆」「まあjQueryは古いみたいなのを書く気持ちはワカルけど、ビジネス上の判断としてはjQueryやれるエンジニアの方がReactより断然見つけやすいよって思いますし🤣」「🤣」「もちろんjQueryやれるといってもいろんなレベルの人がいますけど😆」「システムづくりで、守らないといけないものと守らなくてもいいものの違いは大事にした方がいいんじゃないかと思います☺

「たとえばフォーム含めて2ページぐらいしかないようなサービスサイトの構築なのに、そこでjQuery禁止してReactでやると決めちゃったりしたら、今後もそのランディングページの修正が永遠に追いかけてくるじゃないですか😆」「😆」「でもそれって意外に大事で、jQueryみたいに十分普及してエンジニアも見つけやすいフレームワークにしておけばキレイに手離れしてくれるじゃないですか😋」「平成のエンジニアでもやれるようにしておくのが大事😆

「逆にこれから技術を勉強する人にjQueryを勧めようとは思いませんし☺」「そうですね〜」「そういう人はどうしてもjQueryを触らないといけなくなったときに勉強すればいいと思います🧐

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

⚓well-known URI


つっつきボイス:「well-known URIという言葉を初めて見ました」「あ、200を絶対返さないwell-known URIを定義しようという話か😳」「仕様はまだ全然ドラフト段階だそうです」

.well-known/ってたしかLet’s Encryptで認証かけたときに必ず作られるディレクトリですね」「へぇ〜」「HTTP通信が必ず通ることを確認できたから証明書あげます、みたいな感じの」「それってACMEのHTTPでやるときだけですか?DNSでやるときも必要ですか?」「えっとDNSではたぶん要らなかったと思います、acme-challenge送ったときだけだったかな」「over HTTPとover DNSとあるんですけど、over HTTPの場合は所定のURIに所定のファイルが存在することを要求されたりしますね🧐」「それです」

参考: チャレンジのタイプ - Let’s Encrypt - フリーな SSL/TLS 証明書
参考: Let’s Encrypt を支える ACME プロトコル - Block Rockin’ Codes

「なるほど、Facebookの.well-known/をChrome DevToolsで見てみるとステータスコード301でリダイレクトしてる↓: リダイレクト先はFacebookのセキュリティページ」「これにステータスコード200を返しちゃうサイトがあるから、それ以外のステータスコードを決めようぜという話なのかな🤔

「200がいけない理由が今ひとつよくわからない😆」「仕様の意図が見えない😆」「.well-known/change-passwordって、アカウントの種類が複数あるようなサイトなんていくらでもあるんだし、この仕様でキレイにchange-passwordやれるんだろうか?🤔」「う〜ん🤔

「こっちの記事↓で言ってるacme-challengeの方ならとてもよくワカル😆」「わかりますね😆

参考: RFC 8307 WebSocketにおけるWell-Known URIの標準化 - ASnoKaze blog


「ところでこの記事に『日和見暗号』って言葉があるけど、これ技術用語?😆」「opportunisticを日和見と訳したんでしょうね」「へ〜、http://でも暗号化する仕組みですって😳」「『暗号化できなければ平文通信で我慢する』って😆」「我慢とは😆」「要するにフォールバックすると」「こうやって無理やり日本語を当てると元の意味がさらにわかりにくくなったりしがち😆」「何にでも訳語を当てるのは日本の伝統芸です😆

参考: 日和見暗号化とは - Weblio辞書

⚓言語・ツール

⚓GitHubとVSCodeのブラウザIDE


つっつきボイス:「社内Slackでも話題になったGitHub Codespaces、これってVS OnlineがWeb IDEとしてGitHubで動くってことですよね」「あ、そういうことか😅」「だからVS Onlineと同時にリリースされたんだと思います☺

「ほら、GitHubは今やマイクロソフトですから😆」「そうだった!😆」「思い出した😆」「そう思えば当然の流れでしょうね☺」「JetBrains IDEがGitHubに乗るんだったらGitHubに移行してもいいかな〜😆」「😆

参考: ASCII.jp:マイクロソフトによる買収から1年、GitHubのユーザー数は800万人増

⚓git-secrets: リポジトリへの鍵コミット防止


つっつきボイス:「AWSが出しているgit-secretsは割と前からあった気がしますね」「だったと思います」「自分のコードをスキャンして鍵が含まれてないかをチェックしたり、フック仕掛けておけば間違って鍵をコミットするのを防いだりできるヤツ🧐」「入れといた方がいいツール😋

「この種のツールってWindows環境だとGit for Windowsでちゃんとフックが動くのかなって気になりますね😆」「😆」「しかもJetBrains IDEからGitにコミットするのがうまくいかなかったりするとWSL 2のシェルでgitコマンドを使ったりとか試行錯誤することが多くて、つい面倒になっちゃう😆」「😆

「やはり純粋にLinux環境で開発するのがいいのかなって思ったり」「Macに戻ったらいいのでは?😆」「いや〜今からだと面倒ですし、Macで4Kモニター2台を60Hzで接続するのってきつくないですか?😆」「まあそれは😅」「Macbook Proでも無理だからチーズ削れるMacにするぐらいしかなさそう😆

⚓その他

⚓病歴を自動通知


つっつきボイス:「あぁ、こういう病歴の自動通知って人によってはかなり大事なんですよね」「ですね」「たとえば何万人にひとりみたいなレアな病気を持っている人だと、普通の人なら大丈夫な薬でもアレルギー反応とかを引き起こして危険なことになるんですけど、そういう人が突然倒れたりするとその情報を知りようがなくなる可能性があるんですよ」「たしかに!」「そういう情報はこういうところに入れるべきだと思います🚑

「もちろん超デリケートな個人情報の塊なので、誰でもアクセスできるようにする必要はまったくありませんし」「この情報をAppleが握るということ?」「それを含めた問題提起ということでしょうね☺


「そういえば、空港でスーツケースのロックに使う、税関の職員しか開けられないロックがあるじゃないですか」「そんなのがあるんですか?😳」「これこれ、TSAロック↓: 今どき海外旅行用に売ってるスーツケースはこれですよ」「へぇ〜😳」「税関しか開けられないという前提になってるヤツ😆」「最近海外旅行してなくて知らなかった😭

参考: TSAロック - Wikipedia

「TSAロックなら職員が開けることも、その後またロックすることもできますし、TSAロックが使われていない場合は職員が鍵をぶっ壊して開ける権限も持ってるんですよ」「よくある話ですよね😆」「だからぶっ壊されないためにTSAロック付きのスーツケースを買うわけです💵

「で、さっきの病歴通知は発想としてはこのTSAロックに似ていて、救急スタッフだけが読める鍵を用意するとかそういう感じになるんでしょうね」「誰でも読めるのはちょっと😅」「本来は国がやることなのかなぁ🤔」「国を信用できるかどうかですけど😆

参考: 【注意】スーツケースなどに使われる「TSAロック」のマスターキー情報が流出 誰でも“合鍵”作成可能な状態に - ねとらぼ — 2017年の記事


「もしかするとAppleは次に保険業を始めたりして🤣」「ああっ😆」「メディカル情報を持ってたらそういう発想になるかも😆

「最近の自動車保険は、指定のドライブレコーダーを取り付けさせて、安全運転していると保険料が下がるなんてこともやってますし」「え〜そんなのも!😳」「リスクが高いものには保険料を上げて、リスクの低いものは保険料を下げるのが保険なんですけど、もしかすると本来の保険の意味から外れてるんじゃないかなと思うことはありますね☺」「まあたしかに」「でも一般の人は『自分は安全運転してるんだから安くしてくれ』って思いますし」「ほんとだ、ドライブレコーダー特約の保険って結構あるんですね↓」「試験運用としては割と前からありますし、タクシーなんかは昔からやってますね🧐」「ふ〜む」

参考: 自動車保険の「ドライブレコーダー特約」はどんな特約? - 自動車保険一括見積もり

「今後それと似たようなトラッキングが医療保険でも起きたらちょっとアレかなと思いました☺」「紙一重😅」「約款でそれを明示してその分安くするというのはありそうですけど: イヤなら他に乗り換えると」「なるほどね〜」

⚓最近の電子工作


つっつきボイス:「最近のはんだ付け事情がちょっと新鮮だったので」「まあ今はキットがいろいろありますし😋」「ロジックボードのパターンを自分で起こすとかまずなさそう😆」「エッチング液に漬けたりとか」「最近なら中国で全部やってくれますヨ😆

「高校生の頃に自分で基板作ったときは、エッチングの廃液(有害)の処理がものすごく面倒でした😅」「たしかに面倒😆」「自宅で処理できなくて、基板作ってる工場を電話帳で見つけて処理してもらったりとか😭

「『基板を収めるケースが高い』、これホントそう」「ケースとスイッチとつまみが高いです💰」「今なら3Dプリンタでやると安いですよ〜😋」「ある程度の量を作るなら3Dプリンタを買う方が安いですし」(以下家庭用3Dプリンタ談義が延々)

⚓番外

⚓目からうろこ


後編は以上です。

バックナンバー(2020年度第2四半期)

週刊Railsウォッチ(20200511前編)Rails 6.0.3リリース、rails newに–masterオプションが追加、system specとfeature specの違いほか

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

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

Ruby Weekly

Hacklines

Hacklines

StatusCode Weekly

statuscode_weekly_banner

Publickey

publickey_banner_captured

Viewing all 1383 articles
Browse latest View live