週刊Railsウォッチ(20191001後編)RedisとRubyをつなぐredis-object gem、Fullstaq Rubyの新バージョン、COUNT(*)とCOUNT(1)の速度ほか

こんにちは、hachi8833です。Macbookのディスク容量がいつの間にかあふれていて焦りました。

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

週刊Railsウォッチ「公開つっつき会」第15回のお知らせ(無料)

第15回目公開つっつき会は、今週10月5日(木)19:30〜にBPS会議スペースにて開催されます。週刊Railsウォッチの記事にいち早く触れられるチャンスです!皆さまのお気軽なご参加をお待ちしております🙇。

Ruby

Ruby 2.7のIRBはこう変わる(RubyFlowより)

見出し:

  • シンタックスハイライト
  • relineによるマルチラインモード
  • タブキーを2度押しするとドキュメントが表示
  • オートインデント
  • 履歴保存と読み込みがデフォルトで有効

つっつきボイス:「2.7のIRBはこんな感じで↓色が付くようになったんですよね」「わぉ〜すんばらしい〜!❤️」「矢印キーで履歴を辿る機能とかも強化されますし☺️」「マルチラインで履歴をずごっと戻せますね😋」


同記事より

「Ruby 2.7をDockerで取り込んでIRBしてみたことあるんですが、微妙に不安定なところがあるような気がしました😅」「それはもしかするとDockerのターミナルの問題かもしれませんね😎」「あ〜」「docker execでbashにしたときのDockerのターミナルって微妙に挙動怪しいんですよ😆: 何ならDockerにsshd立てて、そこにsshしてからIRBしてみると結果違うかもしれない😋」「後で試してみます😀」

「ちなみに自分はもう最近pry入れてませんし😆」「自分も😎」「マジですか!😳」「最近は割とIRBで生きてます☺️」「まだpry使ってる…」

Rubyのリファクタリングから学んだ10のこと

「テニス」をお題にした設計になっています。

見出し:

  1. 容赦ないリファクタリングは絶好の学びの機会
  2. RedがGreenになったときがリファクタリングどき
  3. テストを信用するな
  4. 対象分野(ドメイン)の基礎知識ぐらいは学んでおこう
  5. いいIDEならメソッド切り出しを何も考えずにやれる
  6. クライアントのpublic API呼び出しを制御できないならAPIを変えずにモジュールに委譲する
  7. 新しいクラスに切り出すと概念(テニスのドローや勝ちなど)のカプセル化に役立つ
  8. ガード文でif条件をシンプルにしよう
  9. データとしてのコード」は、実践というより理論寄りな印象
  10. ミューテーションをテストする

つっつきボイス:「イケてなさそうなコードから始まって、1つずつリファクタリングしていくぜみたいな記事みたい☺️」「『テストを信用するな』と😆」「こういう記事を丁寧に書くモチベーションの高さがいいですね〜😋」

「最終的なTennisモジュールのコード↓が何だかスゴい😆」「こうやって並べるとちょいギャグっぽいというか😆」

# 同記事より
module Tennis

  class LoveAll
    def score;          "Love-All"      end
    def player_1_score; FifteenLove.new end
    def player_2_score; LoveFifteen.new end
  end

  class FifteenLove
    def score; "Fifteen-Love" end
    def player_1_score; ThirtyLove.new end
    def player_2_score; FifteenAll.new end
  end

  class ThirtyLove
    def score; "Thirty-Love" end
    def player_1_score; FortyLove.new end
    def player_2_score; ThirtyFifteen.new end
  end

  class FortyLove
    def score; "Forty-Love" end
    def player_1_score; WinPlayer_1.new end
    def player_2_score; FortyFifteen.new end
  end

  class LoveFifteen
    def score; "Love-Fifteen" end
    def player_1_score; FifteenAll.new end
    def player_2_score; LoveThirty.new end
  end

  class LoveThirty
    def score; "Love-Thirty" end
    def player_1_score; FifteenThirty.new end
    def player_2_score; LoveForty.new end
  end

# (省略)
end

type_struct: Rubyで型付きstruct

# 同リポジトリより
Point = TypeStruct.new(
  x: Integer,
  y: Integer,
)
Color = TypeStruct.new(
  code: /A#[0-9a-f]{6}z/i,
)
Line = TypeStruct.new(
  start: Point,
  end: Point,
  color: Color,
)

hash = JSON.parse(%({"start":{"x":3,"y":10},"end":{"x":5,"y":9},"color":{"code":"#CAFE00"}}))
line = Line.from_hash(hash)

p line
#=> #<Line start=#<Point x=3, y=10>, end=#<Point x=5, y=9>, color=#<Color code="#CAFE00">>
p line.start.y
#=> 10
line.stort
#=> NoMethodError

つっつきボイス:「るびまでたまたま目にして気になったので」「おぉ、これってdry-rbでやれることとはまた違うのかな?」「あ、たしかに路線近いですね」「type_structはちょっぴりGo言語やCrystal言語っぽい要素も入れてるそうです」「まあ型が欲しい人は多いので☺️」

Ruby: Dry-rb gemシリーズのラインナップと概要

# 同リポジトリより
Foo = TypeStruct.new(
  bar: TypeStruct::Union.new(TrueClass, FalseClass)
)
p Foo.new(bar: false) #=> #<Foo bar=false>

「type_structを眺めていて、Rubyの中でbooleanを指定する↑のが大変そうだなと思いました」「まあarrayやhashも大変ですし、あとArrayOf的にarrayの要素の型も含めて定義したいとかも大変ですし☺️」「arrayだけど中にはこういう要素しか入れたくないみたいなヤツですね」「お、type_structにもまさにArrayOfがある↓」

# 同リポジトリより
Bar = TypeStruct.new(
  baz: TypeStruct::ArrayOf.new(Integer),
)
p Bar.new(baz: [1, 2, 3]) #=> #<Bar baz=[1, 2, 3]>

「こういうArrayOf的なことは自分もすっごくやりたいですね〜: 安心を買えるから😋」「そうなんですよ〜😂」「他の型付き言語なら普通にやれますけどね☺️」「型付き言語でどうしても何でも入れたければオブジェクトにしろと」「voidでね😆」「そうそう、void使いまくり😆」

Fullstaq Ruby epic 2がリリース(Ruby Weeklyより)


fullstaqruby.orgより


つっつきボイス:「お、Fullstaq Rubyの新しいバージョンですか!」「Ruby 2.6.4にも対応」「aptやyumのリポジトリもできたのね」「Fullstaq Rubyはどこかで試してみたいな〜😋」

redis-object: Radisの型をRubyオブジェクトに直接マッピング(Ruby Weeklyより)


つっつきボイス:「なるほど、これはRedisの型をRubyでそのまま扱えるようにするgemですね」「ほほぉ~」「Redisにはいくつかデータ型がありますけど、それに1対1対応するものを作れる: たとえば以下に並んでいるのはRedisの型ですね↓」「おぉ〜😍」「counterはたしかアトミックにインクリメントできる型だったかな☺️」

class Team < ActiveRecord::Base
  include Redis::Objects

  lock :trade_players, :expiration => 15  # sec
  value :at_bat
  counter :hits
  counter :runs
  counter :outs
  counter :inning, :start => 1
  list :on_base
  list :coaches, :marshal => true
  set  :outfielders
  hash_key :pitchers_faced  # "hash" is taken by Ruby
  sorted_set :rank, :global => true
end

「以下のincrとかもRedisのコマンドですし」「へぇ〜!」「こんな具合にRedisの型を直接Active Recordで扱えるんですね😋」「それはアツい🔥」「Redisの機能をがっつり使いたいなら、このgemはなかなか良さそう👍」「その代わりRedisにロックインすることになりますけど😆」「まあそれは😆」

# 同リポジトリより
@team.hits.increment  # or incr
@team.hits.decrement  # or decr
@team.hits.incr(3)    # add 3
@team.runs = 4        # exception


redis.ioより

おたより発掘

その他Ruby

@unasukeさんのPodcastと、XP祭り2019のキーノートです。



今年のRubyKaigi 2019でもやってた「Apple IIでRubyを動かす企画」のその後の発表です↓。

DB

クエリ言語GQLが国際標準に(DB Weeklyより)


つっつきボイス:「GraphQLかなと思ったら違うみたいです」「へぇ〜?、あ、GraphQLはソフトウェアの名称だけど、これはクエリ言語の部分だけGQL(Graph Query Language)という名前にして標準化を進めているということか」「SQLとは別物ですね☺️」「GQLというクエリ言語の標準化が始まったということなので、これからという感じ」「GQLのマニフェストもありますね」「RDBMSでSQLの亜種がいろいろ出たみたいにGQLの亜種が今後出たりするんだろうかと思いますけど、ま使ったことないし😆」

COUNT(*)COUNT(1)はどっちが速い?(Postgres Weeklyより)


つっつきボイス:「COUNT(*)COUNT(1)って同じ意味だったっけ?🤔」「データがそこそこ入ってるPostgreSQLで試してみるか」(しばらく調べる)「どちらも件数は同じだな〜😳」「DISTINCTとかすれば別でしょうけど😆」

COUNT 関数にアスタリスク(*)を使用するとグループ内の全レコード数を戻す。
式、または、列名を指定した場合、その式が NULL 値 のものをカウント数に含めない。
www.shift-the-oracle.comより

COUNT(1)の書式
COUNT(1)構文ではすべてのレコードが返されます。これには、NULL値を持つレコードも含まれます。たとえば、Endecaデータ・ドメイン内のデータ・レコードの数を知るには、次のようにします。

RETURN results AS
SELECT COUNT(1) AS recordCount
WHERE WineID IS NOT NULL
GROUP

docs.oracle.comより

「あぁ〜、COUNT(1)はNULL値も数える!?」「上はOracleだけど、他でもそうなんだろうか?🤔」「標準SQLってネットにあんまりない印象だけど、この辺がそうかな↓」

参考: SQL COUNT function – w3resource


w3resource.comより

「手元でnullableなテーブルでやってみたらこうなった↓」

SELECT COUNT(*) FROM nullables;
--> NULLを含む全件
SELECT COUNT(department) FROM nullables;
--> NULLを含まない全件
SELECT COUNT(1) FROM nullables;
--> NULLを含む全件
SELECT COUNT(null) FROM nullables;
--> 0(全ての行をNULLとしてカウントし、その際にNULLを含まないモノをカウントするため)

「ほんとだ〜!COUNT(0)だと件数返ってくるけどCOUNT(null)だとゼロになるし: むずい😭」

  • COUNT(*)はNULLもカウントする。
  • COUNT(1)は全ての行の評価結果を1にした上でカウントするのでNULLもカウントする
  • COUNT(column)はNULLをカウントしない

「いろいろ総合してみると、これが正しそう↑」「つまりCOUNT(*)COUNT(1)は同じということですね」「仕様レベルでは結果が同じになることが保証されると」「あ〜ややこしかった😅」「一度わかっちゃえばいいんですけど」「仕様をたどらないとわからんという話でした😆」「まあCOUNT(1)使いませんけど🤣」「🤣」


「記事によるとRDBMSによってCOUNT(*)COUNT(1)のパフォーマンスに違いがあるみたいですね↓」「ぽすぐれだとCOUNT(*)の方が速くなるように作られてるのかも🤔」「いずれにしろ実装依存か」

  • MySQL: 違いは影響しない。COUNT(1)が速い場合もCOUNT(*)が違う場合もあり、ベンチマークのつくり次第。
  • Oracle: MySQLと同様。
  • PostgreSQL: 違いは影響する。100万行ではCOUNT(*)の方が常に10%ほど速い(筆者の予想を越えていた)
  • SQL Server: MySQLと同様。

「つまりPostgreSQLではCOUNT(*)が速くて他ではどっこいどっこい」「へぇ〜」


「たしかMySQLでは、オートインクリメントとかで使えるように各テーブルの行数をinformation_schemaあたりに持ってた気がするんで、そこから持ってきてたら速いでしょうね」「なるほどっ😊」

参考: information_schemaでMySQLの情報取得 | データベース | DoRuby

おたより発掘

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

サーバーレスは遅くて高いのか?


つっつきボイス:「このツイートと同じ記事がServerless Statusにも出てました」「Serverlessにしてみたら15%遅くなって8倍お高くなったと😆」「まあもともとマネージド・サービスってそういうものですし、そうやったらそりゃ高くなるでしょうし😆」

「ツイートにもワークロードやリクエストの性質によって変わる、とあるように、こういうのって結局システムの使われ方の傾向でしか変わらないんですよ☺️」「ですね〜」「多数のリクエストが恒常的にやってくるようなサービスだったら、データセンターに普通にサーバーを立てる方が安くなるのはもう自明ですし💰」

JavaScript

Safari 13でWeb SQLが削除された


つっつきボイス:「Web SQLもついに滅びぬ」「使ってるの見たことありませんけど🤣」「Safari 13のリリースノートにWeb SQLを削除したとあって、調べてみたら仕様も他のブラウザもとっくにWeb SQLやめてました」「Safariも今は使ってないな〜😆」

その他JS


つっつきボイス:「これ面白かった😋」「INFINITYって数字と言っていいんだろうかというのが微妙に気になっちゃいました😅」「数字じゃなくて数(すう)ならよかったりして?」「少なくとも字は付かないかな〜: 無限って単一の元にならないから、数と呼ぶのは無理があるかも😆」「INFINITYイコールINFINITYにはならないですよね?」「なりませんね〜☺️」「数学科出身の人がそう言ってるのできっと正しいでしょう😆」「諸説ありですし😆」

参考: 無限 – Wikipedia

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

フォームのボタンやチェックボックスはどう配置すべきか(Frontend Weeklyより)

それぞれ別の著者が書いています。


つっつきボイス:「記事1は、ボタンみたいな要素をどこに置くべきかという話というか提案みたいです」「こういうのって、それぞれのユーザーインターフェイスガイドラインに従えばいいのでは?😆」「自分もそう思いますし☺️」

参考: デザイン – Apple Developer
参考: Android Developers
参考: Guidelines – Windows applications | Microsoft Docs

「このプライマリボタン↓って、たしかAppleだと右寄りに配置するんじゃなかったっけ?」「そうだったと思います」「デフォルトというかおすすめのボタンは画面右に配置するみたいなルールがあった気がする」「スマホだと右親指で押しやすいからとか?」「スマホの前からそうなってましたね: だからAppleはOKボタンが画面の右に配置されます☺️」


同記事1より

後で調べると、「否定的な情報は左に配置する↓」となっていました。

参考: 日本語でヒューマンインターフェースガイドライン15の原則を5分で解説 | フリーランスで稼ぐ方法まとめ

「Backボタンはフォームの上に置けと?↓」「記事1書いた人の意見なのかな?」「すぐには賛同しかねるな〜😅」「まあこういうのは1つのサイトの中で統一されていればいいんですけどね☺️」「サイトの中でバラつくのは困る😤」

「記事1の人はもろもろ左側に寄せたい感じがしますね」「レスポンシブ対応のことを考えると、これみたいに↓最初から縦を左に揃えとけみたいなのはわかる」


同記事より

プロフィールを見るとinteraction designerとありますね」「Androidのガイドラインとかは知らないのでわかりませんけど、記事1の人はどちらかというと少数派側の気がしますね🤔」

Firebase Summit 2019


つっつきボイス:「FirebaseはBPSのアプリチームでも使ってるという話がありましたね」「それ以上のことは知りませんけど😆、Firebaseってむちゃくちゃサービス数が多いんですよ」「そうなんですか!」「Firebaseはこれまで買収に次ぐ買収を重ねて最後にGoogleが買っているからか、前からAPIの数がすごく多い😳」

「前に聞いたときは、Firebaseは計測とかアナリティクスが強いみたいな話もありましたけど」「Firebaseは1個の機能じゃないので、それも機能のひとつですね」「そうでしたか!」「まあGCPみたいなものだと思えばいいかと😆」

参考: Firebaseを使い始めたら人生が変わった(ような気がした) – Qiita

「上のQiita記事でいうと、Firebase AuthenticationがAWSでいうCognitoで、Cloud StorageはAWSのS3に近そうですし、Firebase Hostingは静的ホスティングだからS3のStatic Website Hostingに近くて、Cloud FunctionsはAWSのLambdaに近い、AnalyticsとCrashlyticsはFirebaseのアナリティクス、という感じに見立てられそうですね☺️」「なるほど〜!」

参考: Amazon Cognito とは – Amazon Cognito
参考: Amazon S3 での静的ウェブサイトのホスティング – Amazon Simple Storage Service

言語・ツール

TextMate 2.0がリリース(Ruby Weeklyより)


つっつきボイス:「おおなつかしのTextMate!😂」「昔使ってたっておっしゃってましたね」「TextMate、PHP書いてた頃にむっちゃ使ってた〜なつかしいな〜😘」「Changelogを見ると、そんなに大きく変わってないしwishlistも残ってるけど、いつまでもバージョンアップしないのもどうかと思うので2.0を出したいう感じでした」「長い道のりだったな〜🛣」

DHHは今でもTextMate使ってるそうですね」「でもTextMateは日本語がアカンのです😇」「そういえばそんな話が」「半角幅になる全角文字をコンパイルして適用するとかいろいろやると一応見られるようになりますけど😆」

参考: TextMateを日本語化してみた – morizotter blog

「TextMateによく似たSublime Textも、未だに検索窓の日本語入力がダメですよね😢」「やっぱりIMEとの連携ってどうしても難しくて、IMEのある世界線にいる人でないと正しく実装できなかったりします🧐」「そういえば今年のbuildersconのこのセッション↓でも同じ話がありました: 英語圏の人にIME連携のところを話してもなかなかわかってもらえなかったそうです」「相手側にIMEという概念がそもそもなかったりしますし☺️」

「中国語の入力メソッドとかもそうですよね: 部首入力みたいなのがあったり」「キーボードに謎の部首がびっしり並んでたり😆」「そして日本語みたいに変換という処理のある入力メソッドはさらに特殊ですよね😆」「たしかに! 」

参考: 中国語入力方法 – Wikipedia

おたより発掘

その他言語


つっつきボイス:「そうそう、この動画めっちゃ面白いですよ〜😋」「貼ったばかりでまだ見てませんでした😅」

(動画を見ながら)「これはマジ面白くて、Hide and Seekというシンプルなかくれんぼゲームです」「鬼の視線ビームがプレイヤーに当たったら負けなんですね」

「鬼とプレイヤーは最初は学習なしでランダムに動いているんですけど、ひたすらぶん回しているうちに、動かせるブロックを使って鬼が入って来られないようにプレイヤーがブロックすることを学習し始めるんですよ」「へぇぇ〜!😳」「開始後に鬼が探し始めるまでに一定時間待つルールがあるので、その間にプレイヤーがいそいそとブロックで塞いで回る📦」

「もっと進むと、斜めのジャンプ台を鬼が見つけて、それを使ってブロックを乗り越えることを覚え始める」「おほぉ〜!😆」

「すると今度はプレイヤーが、その前にジャンプ台をブロックの内側に隠して鬼に使わせないようにすることを覚え始める」「すんげぇ〜!」「こんな調子でだんだん高度なことをするようになってきます☺️」

「その先がまた面白くて、舞台が変わると今度は動かせる壁をシェルターにしてプレイヤーが隠れ場所を作ったり、壁やジャンプ台をロックして絶対動かせないようにしたり」「はぁ〜!」

「すると鬼は、ロックされたジャンプ台を無理やり使って箱に飛び乗って、それをずりずり移動してプレイヤーのところにたどり着くことを覚える(box surfing)」「ひぇ〜😆」「言ってみればエンジンのバグを自らハックして突破してるという😆」「裏技や!」

「最後はプレイヤーがすべての物体をロックしてから壁に引きこもる: これはほんと面白い👍」「面白すぎます!😋」「ボックスサーフ最高😆」「生命ってこういうふうに進化してるのかなと思ったりしました☺️」

その他

わからなくなったとき


つっつきボイス:「たまたま趣旨の近い記事が立て続けに出てたので」「強い人だって『何がわからないかわからない』ときがあったんだよと」「やっぱり『わからない』って自分で気づいて言えるのが大事」「そうそうっ😊: 3日考えた末に出た結論が『オレはわかってない』だったことありましたし😆」

番外

折り紙の次は切り紙?


折り紙に続いて数学の分野がまた1つ増えたようです。英語でもKirigamiだそうです。

参考: Kirigami – Wikipedia
参考: 折紙の数学 – Wikipedia

今は亡き某ビジュアルSF雑誌で、この前川淳さん↓が折り紙で5角形を折る方法を考案したという記事を見たのが30年ほど前でしたが😅、折り紙が数学界で広まってひとつの分野となるきっかけとなったようです。代表作「悪魔」の両手の5本指を折るのにその5角形が応用されています。

参考: 前川淳 (折り紙) – Wikipedia
参考: 悪魔を飼いならした!-前川淳「本格折り紙」上級篇 : 大田原の明日は、僕たちの手で。


後編は以上です。

バックナンバー(2019年度第3四半期)

週刊Railsウォッチ(20190925-2/2後編)AWS Lambdaの秘密鍵保存法、Rubyコミット歴史の動画、Rubyコードの最適化と式展開ほか

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

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

Rails公式ニュース

Ruby Weekly

RubyFlow

160928_1638_XvIP4h

Postgres Weekly

postgres_weekly_banner

DB Weekly

db_weekly_banner

Serverless Status

serverless_status_banner

Frontend Weekly

frontendweekly_banner_captured

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の監修および半分程度を翻訳、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れて更新翻訳中。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好きで、Goで書かれたRubyライクなGoby言語のメンテナーでもある。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

BPSアドベントカレンダー

週刊Railsウォッチ