コード日進月歩

しんくうの技術的な小話、メモ、つれづれ、など

RFC と Internet Draftの関連性にかんしてざっくりまとめる

どういう流れなのか整理する

そもそも RFC(Request For Comment)とInternetDraftとは

直訳すると「コメントを求める」という意味だったが、様々な経緯を経て現在ではIETFの文書シリーズとしての名前として定着している。RFCはインターネットにまつわる様々な仕様やルール群が定義されているが、そのRFCに至る前までの文章がInternetDraftとなる。

Internet DraftからRFCとなるまでの工程

大きく以下のような流れになる

  1. InternetDraftは個人からの場合は Individual DraftIETF内のワーキンググループからあげられる場合は Working Group Draft として出される
  2. 6ヶ月以内に更新か、削除かの判断がされる(個人からの提案でワーキンググループがない場合はワーキンググループが作られるところから
  3. ワーキンググループで合意が取れると、WorkingGroupのLastCallが実施され、IETFの標準化プロセスを担うグループであるIESGの評価を受ける
  4. IESGのOKが出れば、最後にIESGのLastCallが実施され、何も問題がなければRFCとなる。

また、RFCには大きく2つにわけられる

  • 標準化を行うもの
  • そうではないもの(歴史的な情報やベストプラクティスの情報)

前者の場合、RFCになったら終了、というわけではなく「Proposed Standard(標準化への提唱)」という広く意見を募集するフェーズを経てから標準化される。

参考/関連リンク

Rubyのpumaのスレッド設定値に関して、妥当な値をドキュメントから整理する

いくつに設定すればいいのかの根拠がわからない方へ

環境

今回参照したGitHubのVersionは 5.2.2 時点のもの。

出典

出典はREADME.md

puma/README.md at a99331d32e762c1b9823ab44bed92d622a65b6d3 · puma/puma

pumaのスレッド数に関してREADMEには以下のように書かれている。(なお 0:16 などは pumaのコマンドライン起動時のスレッド数指定の方法である puma -t 0:16 に沿った表現で 最小スレッド:最大スレッド という意味)

Puma will automatically scale the number of threads, from the minimum until it caps out at the maximum, based on how much traffic is present. The current default is 0:16 and on MRI is 0:5. Feel free to experiment, but be careful not to set the number of maximum threads to a large number, as you may exhaust resources on the system (or cause contention for the Global VM Lock, when using MRI).

機械和訳をすると

Puma は、トラフィック量に応じて、スレッド数を最小値から最大値まで自動的に調整します。現在のデフォルトは0:16で、MRI(Matz Ruby Interpreter = CRuby)では0:5です。自由に試してみてください。ただし、最大スレッド数を大きく設定すると、システムのリソースを使い切ってしまう可能性があるので注意が必要です(MRIを使用する場合は、Global VM Lockの競合が発生します)。

ということでデフォルトは(多くの場合はCRubyだと思うので)5がデフォルト値となる。

そして推奨の数値に関しては deployment のドキュメントに言及がある

puma/deployment.md at a99331d32e762c1b9823ab44bed92d622a65b6d3 · puma/puma

Here are some rules of thumb for cluster mode:

MRI * Use cluster mode and set the number of workers to 1.5x the number of cpu cores in the machine, minimum 2. * Set the number of threads to desired concurrent requests / number of workers. Puma defaults to 5 and that's a decent number.

クラスターモードという複数のワーカーを動かす際の推奨値の説明となるが、 Puma defaults to 5 and that's a decent number. とあり、5スレッドが妥当な数値な旨の記述がある。(なお、デフォルトはworkerの設定値が0となっており、クラスターモードにはならない)

そのためCRubyにおいては1プロセスあたり5スレッドが妥当な数値としてpumaのドキュメント内からは読み取れる

関連リンク

GoogleTagManager(GTM)を介してGoogleAnalytics(GA)のイベントを直接記述するときは気をつける

GTMを使いながら、GTMを利用せずイベント発火をさせずに手動でGAのイベントを発火させようとするとおかしなことになるので気をつける。

TL;DR

  • GoogleAnalyticsのタグをGTMでセットし、純粋に ga('send') でイベントを送ろうとしてもうまく行かない場合がある。
  • トラッカー名が指定されていないため送れない現象が考えられるので、トラッカー名をつけたトラッカーを作るなどの方法を検討すること。

どういうことか

GoogleAnalytics(以下GA)でイベントを送るときなどの記述では以下のような文法が紹介されている

ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');

引用元: サイトに analytics.js を追加する  |  ウェブ向けアナリティクス(analytics.js)

アナリティクスを識別する固有のID(上記の UA-XXXXX-Y 部分)を指定してcreateを行う、あとはsendを行うとイベントが発火してデータが送られる。

ただしこれは純粋に単体でGAを使うときのみで、GoogleTagManager(以下GTM)を利用する場合は様相が変わる。

GoogleTagManagerを使うときの注意点

GTMを利用する場合は、GAのタグを読み込ませるようにGTM上で設定することができる。そこで行われているのも ga('create') 相当の処理ではあるが、先程とは違い、トラッカー名が設定されている。

トラッカーとは

トラッカー名が設定されていると何が問題かと言う前に、トラッカーがどういうものかをざっくり説明します。

まずはヘルプの説明から引用です。

トラッカー オブジェクト(「トラッカー」とも呼ばれます)は、データを収集および保存して、Google アナリティクスに送信できるオブジェクトのことです。新しいトラッカーを作成する場合は、トラッキング ID(Google アナリティクス プロパティの 1 つに対応するプロパティ ID と同じ)と、Cookie の保存方法を指定する Cookie ドメインを指定してください(推奨値の 'auto' を使用すると、Cookie ドメインの自動設定が指定されます)。 - トラッカーを作成する  |  ウェブ向けアナリティクス(analytics.js)  |  Google Developers

このようにGoogleAnalyticsの一意のIDであるトラッキングIDを指定して作成を行います。

トラッカーを作成する方法として create が紹介されている。この際に先程には紹介のなかった「トラッカー名をつける」という方法が紹介されている。

下記はトラッカー名に myTracker という名前をつける記述の例

ga('create', 'UA-XXXXX-Y', 'auto', 'myTracker');

そしてこのトラッカーでイベントを送信したい場合は以下のように記述する

ga('myTracker.send', 'pageview');

トラッカー名を意識しない使い方

このトラッカー名、設定しないような以下の書き方はデフォルトのトラッカー名が付きます。

ga('create', 'UA-XXXXX-Y', 'auto');

name フィールドを設定せずにトラッカーを作成すると、「デフォルト」のトラッカーが作成されます。デフォルトのトラッカーは内部的に「t0」という名前が付いています。 - トラッカーを作成する  |  ウェブ向けアナリティクス(analytics.js)  |  Google Developers

また、トラッカー名を指定しない以下のような send はデフォルトのトラッカーを利用するとヘルプにもある。

ga('send', 'pageview');

特定のトラッカーに対して analytics.js コマンドを実行するには、コマンド名の先頭にトラッカー名とドットを加えます。トラッカー名を指定しない場合は、デフォルトのトラッカーに対してコマンドが実行されます。 - トラッカーを作成する  |  ウェブ向けアナリティクス(analytics.js)  |  Google Developers

GTMがトラッカー名を指定する弊害と回避法

前述の通りトラッカー名が指定されたトラッカーを利用したい場合はトラッカー名を指定しないと利用できない。しかしながらGTMでGAを設定した場合は目に見える形でトラッカー名はわからない。また、GTMで作られたトラッカー名は衝突の観点から利用者側で設定することは推奨されておらず、ランダムな文字列が振り出される。そのため以下のような状況になる。

  • GTMでのGA設定はトラッカー名を指定して作成しているため、デフォルト名のトラッカーは作成されない。
  • デフォルトのトラッカーが存在しないので、トラッカーを指定しないjs上でのイベント送信( ga('send', 'pageview'); に類する実行)はできない。

そのため、GTMの設定を利用するのではなく、独自で名前をつけたトラッカーを発行し、そのトラッカーでイベントを送信してあげるとGTMに干渉せず送信ができる。

参考リンク

ActiveRecord::Type::Boolean.new.cast はかなり揺らいだ変換になるので気をつける

昔のPHPを彷彿とさせる変換だったので書き留める

環境

$ bin/rails --version
Rails 6.0.3.6

どういうことか

ActiveRecord::Type::Boolean.new.cast は引数をtrueあるいはfalseに変換してくれるのだが、変換の基準は以下のものに引っかかるものがfalseになる。

クラスとしてはこちらに定義がある。

FALSE_VALUES = [
  false, 0,
  "0", :"0",
  "f", :f,
  "F", :F,
  "false", :false,
  "FALSE", :FALSE,
  "off", :off,
  "OFF", :OFF,
].to_set.freeze

また、""nilnil になる

def cast_value(value)
  if value == ""
    nil
  else
    !FALSE_VALUES.include?(value)
  end
end

つまり以下のものはすべて false に変換される

  • false
  • 0
  • "0"
  • :0
  • "false"
  • :false
  • "FALSE"
  • :FALSE
  • "off"
  • :off
  • "OFF"
  • :OFF

また、 以下のものは nil になる

  • nil
  • ""

そしてそれ以外のものは true になる。

false になるシリーズは以下

target = "f"
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = 0
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = "false"
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = false
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = "FALSE"
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = "off"
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = :off
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = :false
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = :FALSE
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = 0
ActiveRecord::Type::Boolean.new.cast(target)
# => false

target = 1
ActiveRecord::Type::Boolean.new.cast(target)
# => true

ただし False (いわゆるパスカルケース)は設定値にないので true になる

target = :False
ActiveRecord::Type::Boolean.new.cast(target)
# => true

target = "False"
ActiveRecord::Type::Boolean.new.cast(target)
# => true

そして空文字とnilnilになる

target = nil
ActiveRecord::Type::Boolean.new.cast(target)
# => nil

target = ""
ActiveRecord::Type::Boolean.new.cast(target)
# => nil

関連リンク

Rubyの生成されたインスタンスのクラスを調べるときはinstance_of?とkind_of?(is_a?)を使い分ける

エイリアスかと思ったら違うのでちゃんと記述する

環境

$ ruby -v
ruby 3.0.1p64 (2021-04-05 revision 0fb782ee38) [x86_64-darwin19]

概要

生成されたインスタンスのクラスを調べたいときは instance_of? を使う。継承元のクラスも含めて調べたいときは kind_of? あるいは is_a? を使う。

実例

Exceptionクラスを継承しているStandardErrorクラスをベースに説明する。

error = StandardError.new
# => #<StandardError: StandardError>

継承関係まで見る kind_of?is_a? は継承元のExceptionでもtrueになるが、 instance_of? は生成したクラスのみにtrue反応をする

error.kind_of?(StandardError)
# => true
error.kind_of?(Exception)
# => true
error.is_a?(Exception)
# => true
error.instance_of?(Exception)
# => false
error.instance_of?(StandardError)
# => true

参考リンク

ActiveSupportにはモジュール名の一部やクラス名の部分だけを取り出すためのメソッドがある

モジュールの部分はいらないんだけどな…というときに文字列処理をしなくても用意してくれている。

環境

$ bin/rails -v
Rails 6.0.3.1

利用例

今回サンプルとして扱うのは以下のようなクラス

module Hoge
  module Piyo
    class Test
      def initialize(test: nil)
        @test = test
      end
    end
  end
end 

newするときは以下のようにする

::Hoge::Piyo::Test.new

クラス名だけを取り出したい場合

demodulize を使う。ただし Class オブジェクトでは使えないので、 to_s などをしてあげる必要がある。

object = ::Hoge::Piyo::Test.new
object.class.to_s.demodulize
# => "Test"

モジュール部分だけを取り出したい場合

deconstantize を使う。こちらも Class オブジェクトでは使えないので注意。

object = ::Hoge::Piyo::Test.new
object.class.to_s.deconstantize
# => "Hoge::Piyo"

参考リンク

[Rails5] Active Support::Inflectorの便利な活用形メソッド群|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社

テストダブルの種類をざっくりまとめる

自身の記憶整理の文脈でまとめる

出典

テストダブルについては書籍 xUnit Test Patterns にて取り上げられたテストに依存するコンポーネントを置き換えるためのパターンのこと。

Test Double at XUnitPatterns.com

なおダブルは2倍のほうの意味ではなく、「代役」や「替え玉」などの意味。

テストダブルのパターン

  • TestStub
  • TestSpy
  • MockObject
  • FakeObject

TestStub(テストスタブ)

テストスタブは「テスト対象の中で行われる外部要因の戻り値を偽装する」というような用途の内容になる。

クラス外のメソッドを実行してデータを行うような処理をもつクラスがある場合、その中のメソッドの戻り値をテストコード内を定義して、期待した動きを見るなどになる。

実際あるケースとしては「色々なAPIを叩いてデータを取得した結果を総合計する」等の場合にAPIからの戻り地をテストコードで定義して期待する結果を確認するなどのコードになると思われる。

TestSpy(テストスパイ)

テストスパイは「テスト対象の中で外部への実行の実行先をすり替えて、その実行メソッドの値が期待したものが返ってくるか」というような用途の内容になる。

実際にあるケースとしては「内容を集計して、ファイル書き出しなどをする」というような場合にファイル書き出しの部分をスパイとして置き換えて、実際に書き出される期待値がマッチするかを確かめる、というようなものになると思われる。

MockObject

モックオブジェクトは「予め期待値を設定し、テスト対象の中の外部への実行を見て、期待値担っているかを判断する」というような用途の内容になる。

テストスパイと似たような動きですが、違いとしてはテストスパイはテストの実行後に値を評価するのですが、モックは予め期待値をセットするので、その期待値どおりに動くかを見るという点に違いがあります。

FakeObject

フェイクオブジェクトはまま文字通り、「偽物」として本物と同様の動きをするためのものです。他のものとは異なり、あくまでも検証のための代用品であり、このオブジェクトそのものはテストをすることに使われるものではない。

関連リンク