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

週刊Railsウォッチ(20200630後編)Shopify流テスト削減、仕様化テストでレガシーコードと戦う、PostgreSQLのarray_agg()ほか

こんにちは、hachi8833です。ruby-jp Slack、ひと頃より落ち着いてきた感ありますが、油断すると未読たまりますね😅。

  • 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄

Ruby

実行するテストを減らして「ときめく」には(Ruby Weeklyより)

つっつきボイス: 「お、Shopifyの記事」「動的解析やらいろいろ頑張ってるそうです」「Rubyでやろうとすると大変そう」


「ちょっと思ったんですけど、Shopifyが今後さらに大規模になるようなら、今後ピュアなRubyの代わりにRubyの拡張版を作って使ったりするかなと」「あ〜」「ほら、FacebookがPHPを拡張してHackという上位コンパチ言語を作ったみたいに↓」「そういえばHackってありますね!」「ググりにくそうな名前😆」

参考: Hack (プログラミング言語) - Wikipedia

「自社プロダクト向けに言語を拡張するのってゲーム業界だと割とよく行われますし、見ようによってはJetBrainsのKotlinもその一種でしょうし↓」「たしかにそれはそれでありかも!」「まあ自分たちでメンテしきれるならですけど😆」

参考: Kotlin - Wikipedia


記事見出しより:

  • テストが落ちたり落ちなかったりする原因
    • タイミング
    • データベースが不安定
    • ランダムなジェネレーター
    • テストのステートが他のステートに漏れている
  • Shopifyのモノリスティックなリポジトリ
    • テスト15万件以上
    • 年に20〜30%増加
    • Dockerコンテナを数百個パラレルにしても30〜40分かかる
  • テストの問題を解決する
  • 動的解析とは
  • 動的解析を使う理由
  • Railsで動的解析するデメリット
    • 遅い
    • 生成されたマッピングラグがHEADより遅れる
    • トレースできないファイルがある
    • メタプロで呼び出しパスがあやふやになる
    • 失敗するテストの一部をキャッチできない
  • 新しいパラレル動的解析を試す
    • 失敗するテストの「リコール率」(確実に期待通りに失敗する率)を定義
    • 速度向上
    • 計算時間の短縮
  • その他検討したアプローチ(最終的には使わず)
    • 静的解析
    • 機械学習
    • テストマシンの増強
  • テストを減らすメリット
    • 開発者に短時間でフィードバックできる
    • テストが失敗したりしなかったりする可能性を減らせる
    • CIの方がコストは低い
  • 動的分析やテストの精選への反論は、意外にも出なかった

はみだしつっつき:「ところでタイトルのspark joyって何だろうと思ってググったら、日本語の「ときめき」が由来の流行り言葉だそうです↓」「ときめきがspark joy、わかるようなそうでもないような😆」「コンマリさん、女子の世界ではえらく有名な方みたいですね」「知らない世界すぎる😆」

参考: スパーク・ジョイ! 「コンマリ」が欧米人ウケしている理由分析|THE MAINSTREAM(沢田太陽)|note

後で嫁さんに聞いたら「ときめきを感じないものはどんどん捨てる」というのがコンマリ流型付け術なんだそうです。

仕様化テストでレガシーコードと戦う(Ruby Weeklyより)


つっつきボイス:「characterization testという言葉を初めて見たんですけど説明↓が今ひとつよくわからなくて、他の記事も参考にするとどうやら『レガシーコードがどう振る舞うかを調べるためにテストを書く』ということなのかなと」「なるほどね〜」

A characterization test is a technique coined by Michael Feathers where we write tests for code where we don't have them. It also means that, to some extent, we shouldn't be guessing what the code should do and instead we should be in "exploratory" mode.
同記事より

# 同記事より
def mask(str)
 if str.length <= 4
   return str
 end

 # Email
 if str =~ URI::MailTo::EMAIL_REGEXP
   limit = str.length - 4
   return "#{'*' * limit}#{str[limit..-1]}"
 end

 # Phone Number or ID
 if str.is_a?(Numeric)
   limit = str.length - 4
   return "#{'*' * limit}#{str[limit..-1]}"
 end

 # String, like a name
 limit = str.length - 4
 return "#{'*' * limit}#{str[limit..-1]}"
end

「characteristic testという言葉がどのぐらい一般的なのかはわかりませんけど、記事をざっと見た感じでは、今動いているコードのブラックボックス的な部分に対してテストを書いていくというアプローチのようですね」「おぉ」

「仕様書もドキュメントもないけどメンテしないといけないときなんかに、コマンドラインで手動で動かして目検するような操作を自動化したようなイメージですね: わざとfailするテストを書いてはgot:に出た値をテストデータにコピペしてパスさせて、それを繰り返してテストパターンを増やしながら仕様を少しずつ明らかにしていく、みたいな進め方」「なるほど!」

「他にどうしても手段がないときなんかだと、ときどきこの手のテスト書くことありますヨ」「お疲れさまです...」「ヤマカンで境界値っぽい値をぶちこむのを繰り返して、最終的に以下みたいなテストを増やしていく: もちろんそれが本当に境界値なのかとか、仕様として正しいのかどうかはこれだけだとわかりませんけど、少なくともこの入力に対してこの出力が得られるという情報にはなるので、それを守ってメンテしていくと」「ふむふむ」

# 同記事より
equire_relative './../mask'

describe 'mask' do
  it "masks regular text" do
    expect(mask('simple text')).to eq('*******text')
  end

  it "masks an email address" do
    expect(mask('example@example.com')).to eq('***************.com')
  end

  it "masks numbers as strings" do
    expect(mask('635914526')).to eq('*****4526')
  end

  it "does not mask a string with 4 characters" do
    expect(mask('asdf')).to eq('asdf')
  end

  it "does not mask a string with 3 characters" do
    expect(mask('asd')).to eq('asd')
  end

  it "does not do anything with empty strings" do
    expect(mask('')).to eq('')
  end

  it "masks symbols like regular characters" do
    expect(mask('text .-@$ with symbols-')).to eq('*******************ols-')
  end
end

「そうやってレガシーコードと戦うんですね🤺」「元記事はこれでテストを固めてからリファクタリングしてますね」「こういうテストはバグが出たときにも有効ですね: エッジケースと思われる部分をテストで押さえてから修正すれば、少なくともその部分はデグレを避けられますし」「たしかに!」

「そのままだと怖くて触れないコードにこうやってアプローチするというのは割とあります☺️」「少なくともこういうテストは作業前に作らないといけませんよね」「やらずに済むのが一番ですけど😆」「仕様化テストも増やせば増やすほど当然遅くなりますし🐢」「自分もいずれこういうことしないといけなくなるのかな...😢」「そういえば今もRails 2をメンテしている知り合いいます」「マジで😆」

「なるほど、仕様化テストとも呼ばれてるのね↓」

参考: Grenning > 仕様化テスト (Characterization Test) > 仕様化テストは、チームの長期記憶としての役割も果たしてくれる - Qiita

Inkblot: 電子ペーパーをRubyで制御(Ruby Weeklyより)

# 同サイトより
require 'inkblot'
include Inkblot

Components::SimpleText.new do |st|
  st.div_height = st.div_width = 95
  st.gfonts = %w[Pacifico]
  st.font = st.gfonts.first
  st.text = 'Hello'
  st.size = 60
  st.border_size = 10
end

Components::TableList.new(
  items: %w[Apples Oranges Pears Peaches],
  fullscreen: true
)

Components::IconGrid.new do |ig|
  ig.fullscreen = true
  ig.icons = %i[alarm extension face grade]
end

Components::ScrollMenu.new do |sc|
  sc.fullscreen = true
  sc.items = (1..10).map { |x| "Option #{x}" }
end

Components::BarCode.new(
  fullscreen: true,
  code: "978054538866"
)

Components::QrCode.new do |qr|
  qr.margin_top = qr.margin_left = -5
  qr.div_height = qr.div_width = 95

  qr.message = "https://youtu.be/zt2uIhAvQZ8"
end

Components::FullScreenImage.new(
  fullscreen: true,
  path: Inkblot.vendor_path('chris_kim.bmp')
)

Components::FullScreenImage.new do |fsi|
  fsi.fullscreen = true
  fsi.url = 'https://live.staticflickr.com/'
  fsi.url << '2753/4177140189_f5fd431b26_o_d.jpg'
end

つっつきボイス:「こちらはIoT系のgemで、Waveshareは電子ペーパーデバイスのメーカーだそうです」「お、こういうの好きそうですよね?」「はい触ったことあります、電子ペーパーにArduinoが乗ったような感じのデバイスです❤️」


同サイトより

参考: 2.7inch e-Paper HAT - Waveshare Wiki

「端子にこうやって電圧を印加するといろいろ表示できたりしますよね↓」「このデバイスではそこまでプリミティブに制御したことはないかな〜」「ステッピングモーターぐらいシンプルならいいけど、こんなに複雑なのは自分ではやりたくない😆」「やらざるを得なかったことならありました😅」(以下延々)


waveshare.comより

github-ds: Active Record接続上でSQLを扱うRubyライブラリ集(Ruby Weeklyより)


つっつきボイス:「GitHubが出しているライブラリだそうです」「★500個付いてますね」

# 同リポジトリより
require "pp"

# Create new instance using ActiveRecord's default connection.
kv = GitHub::KV.new { ActiveRecord::Base.connection }

# Get a key.
pp kv.get("foo")
#<GitHub::Result:0x3fd88cd3ea9c value: nil>

# Set a key.
kv.set("foo", "bar")
# nil

# Get the key again.
pp kv.get("foo")
#<GitHub::Result:0x3fe810d06e4c value: "bar">

# Get multiple keys at once.
pp kv.mget(["foo", "bar"])
#<GitHub::Result:0x3fccccd1b57c value: ["bar", nil]>

「GitHub的に欲しいものなのかな?」「RedisインスタンスやElastiCacheなんかをわざわざ立てずにKV(キーバリュー)みたいなものをちょこっと使いたいというのは何となくワカル」「ElastiCache高いですし💵」「それにこういう形で最初に作っておけば、後でmemcachedとかに移行するときにも楽でしょうし😋」「永続化とかも考えると結局RDBでやるのが楽だったりしますよね😋」「ActiveRecordの接続があればとりあえずそういうのを作れると」

参考: Amazon ElastiCache(インメモリキャッシングシステム)| AWS

「この辺のSQL操作↓もActiveRecord::Baseconnection.executeが使いづらいから欲しかったのかも」「ストアドプロシージャっぽい機能もあるみたい」

# Select, insert, update, delete or whatever you need...
GitHub::SQL.results <<-SQL
  SELECT * FROM example_key_values
SQL

GitHub::SQL.run <<-SQL, key: "foo", value: "bar"
  INSERT INTO example_key_values (`key`, `value`)
  VALUES (:key, :value)
SQL

GitHub::SQL.value <<-SQL, key: "foo"
  SELECT value FROM example_key_values WHERE `key` = :key
SQL

# Or slowly build up a query based on conditionals...
sql = GitHub::SQL.new <<-SQL
  SELECT `value` FROM example_key_values
SQL

key = ENV["KEY"]
unless key.nil?
  sql.add <<-SQL, key: key
    WHERE `key` = :key
  SQL
end

limit = ENV["LIMIT"]
unless limit.nil?
  sql.add <<-SQL, limit: limit.to_i
    ORDER BY `key` ASC
    LIMIT :limit
  SQL
end

p sql.results

DB

PostgreSQLのhypothetical aggregates(Postgres Weeklyより)


つっつきボイス:「hypothetical aggregates言いにくい😆」「仮説的集計って言うのかな?」「へぇ〜、array_agg()っていう集約関数があるのね」

「どれどれ、rank(3.5)は、偶数の{10,2,4,6,8}をソートした配列{2,4,6,8,10}なら2と4の間に来るのでrankは2になり、奇数の{9,7,3,1,5}をソートした配列{1,3,5,7,9}なら3と5の間に来るからrankは3になると」「ふむふむ」

# 同記事より
test=# SELECT x % 2 AS grp, array_agg(x), 
              rank(3.5) WITHIN GROUP (ORDER BY x) 
       FROM   generate_series(1, 10) AS x 
       GROUP BY x % 2;
 grp |  array_agg   | rank
-----+--------------+------
   0 | {10,2,4,6,8} | 2
   1 |  {9,7,3,1,5} | 3
(2 rows)

「3.5という値はこの配列の中にはないんだけど、もし配列の中にあったとしたらrankがいくつになるだろうかというのを、配列に入れずに求められるということみたい」「あ〜やっとわかりました」「それがhypothetical aggregatesなんでしょうね」

「データを入れなくても、もし入れたら何位になるかというのがわかると」「データが確定してなくても順位が取れると」「たしかに実際のアプリケーションでそういうのが欲しいときありそう」「記事のユースケースもそういう感じですね」「データを本当に入れてしまうと他のトランザクションに影響するので、こうやってやれるのはいいですね😋」

「hypothetical aggregates、ちょっと名前カッコイイ」「怖そうな名前かな〜」「記事のこの図↓がズバリ内容を表してて秀逸👍」「わかってみるとよくわかる図ですね」「こういう機能があるということを何となくでも知っておくといつか身を助けるかも」「いつになるかはわかりませんが😆」「Rubyの機能だけでやろうとすると件数が多いときにしんどいかも」


同記事より

RDBの「配列」

「ところで、このやり方の場合array型にする必要がありそうな雰囲気ですけど、PostgreSQLなら簡単にarray型にできるのですぐ使えそう👍」「う、MySQL勢だけどぽすぐれの誘惑が〜😆」「PostgreSQLだとサブクエリの結果をarray型にしてINで取ってくるとか普通にできますけど、MySQLのarray型って機能少ないですよね」

「そんなのやれるんですかいいな〜、MySQL一筋なのにぽすぐれの話聞くたびに浮気したくなってきた😂」「まあそれをActive Recordらしく書けたりはしないんですけど、RDB単体の機能としてはそういうことができるということで☺️」

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

銀座Railsスライド「RailsとDocker」


つっつきボイス:「神速さんのスライドだ」

「現状でのRails+Dockerはこういう感じというのがわかって参考になりましたし、開発環境のDockerイメージと本番環境のDockerイメージを同じにすることは諦める、というのも収穫でしたね👍」「やっぱりそうなるのか〜」「開発環境ならちょっとコンテナの中に入って作業できますけど、本番環境は余計なものを何も入れないからほとんど何もできなくなるじゃないですか😢」「本番だとvimすら入ってなかったりしますよね😢」「Alpine Linuxだとpsコマンドすら使えなかったり😭」

「私の翻訳記事↓も取り上げていただいて感激しました😂」

クジラに乗ったRuby: Evil Martians流Docker+Ruby/Rails開発環境構築(翻訳)

RailsとDocker

「ところで、RailsをDocker化する機能もそろそろRails本体に入っていいんじゃないかなってときどき思いますね」「それすごく思います!」「Railsがオールインワンのフレームワークということを考えると、公式のDockerコンテナ化機能があってもよさそうですし」「rails buildで一発ビルドできたらいいな〜😂」「いっそrails sしたらコンテナが立ち上がって欲しい😆」「😆」

「まあRails環境構築の必要条件にDockerが加わったらそれはそれで面倒そうですけど、rails buildみたいなコマンドでDockerイメージ作れるような機能はそのうちできてもいいと思いますよね」

その他クラウド


つっつきボイス:「こういう機能があったらいいなという話をしてたらこの発表があったんですよね」「これ見たんですけど今ひとつわかんなくて、結局何なんでしょう?」「Slackのshared channelって今までは2拠点間でしかできなかったんですけど、その制限が緩められて20拠点までできるようになったと↓」「へぇ〜」「昨日ちょうどshared channelを3拠点でできないかなって社内で話しをしてたときだったんですよ」

本日より、1 つの Slack チャンネルを最大 20 件のオーガナイゼーションが共有できるようになりました。
同記事より

参考: Slack コネクト | Slack


「ところでこのプレスリリース、何だか読みにくいですよね」「要約すれば上の抜粋の一文だけで済むのに、長い文章に埋もれてえらく把握しづらかった😢」「前は2拠点までだったけど20拠点に増えましたと冒頭で要約してくれたらずっと読みやすくなるのに」

JavaScript

ECMAScript 2020仕様がリリース(JSer.infoより)


つっつきボイス:「お、ついに正式版の仕様が出ましたね🎉」「まあ内容は以前から出回っていますけど」「ますますJavaScriptから逃げられなくなるのかな...」

「ところでこの仕様ページ、えらく重くありません?🏋🏻‍♀️」「仕様全部乗せしてるからページがめちゃ長いのか!」「この長さはヤバい」「負荷テストに使えそう」

言語/ツール/OS/CPU

三社三様

Microsoft Defender ATP for Linux

つっつきボイス:「Microsoft Defender ATP for Linuxは便利そうですよね👍」「サーバーにセキュリティソフトを入れないといけない案件もこれで対応できそうですし」「サーバーが確実に重くなりますけど😆」

「Defender ATP for Linuxの挙動が気になるな〜、監査ログ出すぐらいならいいんですけど、もし何かあったときに通信遮断されて障害になっても困るので」「何だかSELinux↓思い出しました😆」「そうそう、SELinuxをまず止めるところから始めたりしましたよね😆」

参考: Security-Enhanced Linux - Wikipedia

「Defender ATP for Linuxがどういう形式で配布されるかは知らないんですけど、もしもバイナリ配布がライセンスで許されるなら、CIでDockerコンテナをチェックしたりAmazon Linux Extrasで入れられたりするといいですよね」「たしかにDockerコンテナのセキュリティチェックって大変ですし」「きりがない😆」「サイズ650MBなので常用は無理かな〜」「for serverとかいうライセンスが必要みたいなので再配布は難しそうですね...」「面倒くさそう😆」「じゃいいや😆」

参考: 2020年6月24日 “我々のLinuxジャーニーはまだ始まったばかり”―Microsoft Defender ATP for Linuxが一般提供開始:Linux Daily Topics|gihyo.jp … 技術評論社


Googleのセキュリティスキャナー「Tsunami」

「GoogleのTsunamiはオープンソースなのね」「nmap使ってますね〜」「うっかりAWSにかけて怒られる人出そう😆」

参考: ポートスキャンツール「Nmap」を使ったセキュリティチェック | さくらのナレッジ


ARM版Mac

「ARM版Mac、x64系はRosetta 2で動くとしても、Hypervisor系のVM拡張命令は動かないってリリースにも出ているので、少なくともx64版のWindowsやVirtualBoxとかはHypervisorでは動かないけど、逆にARM版LinuxやARM版WindowsならHypervisorフレームワーク経由で動くんじゃないかって話は出てますね」「おぉ」「そういえばParallelsがARM版Windowsの仮想環境をサポートするというニュースもありました↓」

参考: ParallelsがARMアーキテクチャ搭載Macに仮想環境を提供へ、ARM on ARMのWin環境が現実的か | TechCrunch Japan

「HypervisorフレームワークがちゃんとARMに移植されて動くようになればそのあたりはやれるかなと」「ARM版Linuxは昔からありますし、そうやってARM版が普及してくると、もしかして今は誰も使っていないAWSのARMインスタンス↓が使われるようになるのでは、なんてね😆」「誰も使ってないんですか😆」「まあARMインスタンスは値段もお安くありませんし」

参考: Amazon EC2 A1 インスタンス | AWS

「今後もしかするとARMが普及することでいろいろ広がるという夢が実現するかもしれませんし、逆にARMがコケて終わるかもしれませんけど😆」「どこかで聞いたような話😆」「少なくともIntel一強よりは夢があるかなと思いますね」


以下はつっつき後の記事です。

参考: 【笠原一輝のユビキタス情報局】IntelからArmへのシームレスな移行を実現する「macOS Big Sur」 - PC Watch


ジム・ケラー

「そういえばIntelとかAMDあたりのCPUを設計したCPUアーキテクトは全部同じ人だというツイートをどこかで見かけました」「ジム・ケラーですね↓」

参考: ジム・ケラー - Wikipedia

「ちょっと前にインテル辞めたんでしたっけ?」「インテルの最近のアーキテクチャを作り終わったところで辞めたとか何とか」「DECのAlphaもやってたのか!」「いろいろ優秀すぎて想像つかない😅」「ひとりで世の中を変えるパワーのあるエンジニア、いますよね」「まさしく偉人」

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


番外: 音

「ある意味こっちの方がうれしいかも↓」「ジャーン」「ジャーン」「2016年まで音あったんですね」「MacbookをSMCリセットか何かで完全にリセットしたときに音が出たような覚えあります」

「ところで大昔のSad Macの音って聞いたことある人います?」「あれ音するんでしたっけ?」「すっごく情けない『チャラララ〜』みたいなメロディなんですけど、運がいいとこの音が出ることがありました」「Sad Macアイコンなら嫌になるほど見ましたけど😆」

↓これでした。

参考: 画像で見る初期Macのアイコンデザイン - 6/10 - CNET Japan

その他

BasecampのHEY.comとは

参考: シリコンバレーで話題のプライバシー重視の有料電子メールサービス、「Hey」が目指していること|市川裕康 (メディアコンサルタント)


つっつきボイス:「これは?」「Basecampの作ったHay.comという招待制のメールサービスだそうです」「そういえばFacebookも昔は招待制でしたね」「Mixiも」「プライバシー重視のメールサービスか〜」「Heyというと秋葉原のゲーセンを連想しますけど😆」

参考: 秋葉原ゲーセンの老舗にしてコアなプレイヤーが集うレトロゲームの王国 「Hey」 | ゲーム文化保存研究所

「自分はもうメールってまず開かない😆」「自分も銀行のメールしか来ません😆」「過去にサブスクしたメルマガを今一生懸命解除してます😆」


「お、Basecampは本社オフィスもなくしてフルリモートにするって参考記事に書いてますね」「へぇ〜」「もともと世界各地でリモートで仕事している会社ならやれるでしょうね」「DHHの場合自宅の仕事部屋↓がめっちゃ豪華ですし✨」

番外

今どきの高校の情報科目教科書


つっつきボイス:「はてブで話題になってましたね」「よくできてる教科書との評判」「普通に大学の授業ですね」「こんなにちゃんと学べるのはいいけど、やりたくない人にはつらそうですね」「こういうのは書いてあるとおりに打ち込めば何とかなりますヨ」「ところでPythonって書きやすいのかな?」「Rでもあんまり変わらないと思いますけど😆」

参考: R言語 - Wikipedia

「今ならもっといいのがあるんでしょうけど、自分は論文とかでどういうグラフを作ろうかと思ったとき、RのWiki(Rjpwiki)↓に掲載されているグラフ実例集を随分参考にしましたね」「お〜、こんなのがあるんですね」「グラフの種類って実際のグラフも見ないと選びようがないので、ここは随分重宝しました😋」「いいこと聞いた!」

参考: グラフィックス参考実例集 - RjpWiki
参考: グラフィックス参考実例集:イメージ図 - RjpWiki


okadajp.orgより


後編は以上です。

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

週刊Railsウォッチ(20200623後編)Bootstrap 5 alphaリリース、Lambda FunctionsとEFS、DB設計で気をつけていることほか

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

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

Ruby Weekly

Publickey

publickey_banner_captured

Postgres Weekly

postgres_weekly_banner

JSer.info

jser.info_logo_captured


CONTACT

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