@kyanny's blog

My thoughts, my life. Views/opinions are my own.

Go: golang.org/x/time/rate を利用したコードのテストの書き方

速度制限をかけているコードの実行に要した処理時間を計測すれば良い。

package main

import (
    "context"
    "fmt"
    "testing"
    "time"

    "golang.org/x/time/rate"
)

func TestWait(t *testing.T) {
    // rate = 10 req / sec
    // burst = 1
    // 0.1 秒ごとに token が 1 ずつ増える
    r := rate.Every(time.Second / 10)
    b := 1
    limiter := rate.NewLimiter(r, b)

    ctx := context.Background()

    tests := []struct {
        name    string
        n int
    }{
        {
            name: "n = 10",
            n: 10,
        },
        // ループの実行開始直後に token を 1 消費する (burst=1)
        // これを考慮に入れるため、 PASS するテストケースではループを 11 回実行している (n=11)
        {
            name: "n = 11",
            n: 11,
        },
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            t0 := time.Now()
            for i := 0; i < tt.n; i++ {
                // token が増えるとすぐにループが実行され、 token を使い切る
                // token を使い切っていると limiter.Wait でブロックする
                // つまり、ループを 1 回実行するのに 0.1 秒かかる
                if err := limiter.Wait(ctx); err != nil {
                    // noop
                }
                // ここ (Wait() のあと) に速度制限をかけたい処理を書く
                // 例: resp, err := http.DefaultClient.Get("http://example.com/")
            }
            t1 := time.Now()
            elapsed := t1.Sub(t0).Seconds()
            // ループを 10 回実行する間に limiter.Wait でブロックする時間の合計は (10-1) * 0.1 = 0.9 秒
            // ループを 11 回実行する間に limiter.Wait でブロックする時間の合計は (11-1) * 0.1 = 1.0 秒
            // ループを 11 回実行するのに要した時間 (elapsed) が 1.0 秒以上であれば 10 req / sec の速度制限が効いているといえる
            if elapsed < 1.0 {
                t.Errorf("must take > 1.0 sec, but took %f sec", elapsed)
            }
            fmt.Printf("took %f sec\n", elapsed)
        })
    }
}

https://play.golang.org/p/lnrqdM3FI5c

EarPods 壊れてなかった

EarPods のマイクが壊れた - @kyanny's blog

イヤホンジャックの EarPods をセブンイレブンで買ってきて繋いだが、やはりマイク入力をほとんど拾わない。新品でもダメということはもしや本体側の問題か?とここで初めて思い当たり、別の MacBook で試すと新旧どちらの EarPods でも問題なくマイク入力を拾う。 MacBook のイヤホンジャックの接触不良らしい。 EarPods 買う必要なかった。三千円無駄にした。二択で外すってふざけんなという気持ち。通販で一日待つよりセブンイレブンで買ったほうが早いからそうしたのに、裏目に出た。Lightning 変換アダプタを使うにせよ接点回復剤を試すにせよ、いずれも通販で買わないといけない。だったら最初から通販でアダプタ買えば良かった。

最近、気分が落ち込みがちで、ブログに書きたいこともいくつかあるのに筆が進まない。

悲しいニュースが多いが、竹内結子が亡くなったのはけっこうショックを受けた。同い年(学年は一つ違い)で出身地も近いし、「いま、会いにゆきます」は映画館で観て泣いた(なぜわざわざ映画館で観ようと思ったのかは覚えていない)。

自宅勤務が続いていて、動かないせいで体重が増え、人生最高値を更新してしまっている。さすがにもう「クローン病患者が太れるなんて嬉しい話だ」などと言ってもいられない。コロナの感染者数もなかなか減らず、通勤再開に踏み切れない。ジムで運動する頻度を増やして、食事(特に間食)の量を減らさなければ。

おれには懐かず目があっただけでダッシュで逃げていた三毛猫が、大人になって性格が落ち着いてきたのか、最近はずいぶん人慣れしてきて撫でさせてくれるようになったり、粗相もしばらくしていないのが、最近の数少ない良かったことのひとつ。

Zoom の好きになれないところ

待機室。ホストがいちいち入室許可する、という手間の無駄さに、何度となく落胆させられた。

Zoom Bombing 対策で追加された機能なので、セキュリティ担保のためにオフにできない場合もある。セキュリティ対策は重要だが、人間に負担をかける解決方法がいけてないと思う。

先に入室しておき時間になったらホストを待たずに会議を始める、ということができない。ミーティング URL の発行者と実際のミーティングの主催者が異なったりするとミーティングを開始するまでに無駄なやりとりと待ち時間が発生する。

対する Google Meet は、 G Suite を使っていれば同一ドメインのメールアドレスを持つユーザーのみ参加可能にできる。というかデフォルトでそうなっているので、ユーザーは何もしなくて良い。本当のゲストを参加させたいときだけ招待する作業をすれば良い。こういう風になっているのが当然だと思う。

さらに、 Google カレンダーとの連携も見事だ。カレンダーに予定を入れるとワンクリックで Meet の URL が発行され、予定にリンクが付与される。ミーティング参加者は時間になったらカレンダーの予定に紐づいている URL を開いて入室するだけ。カレンダーに従って行動すれば良い。シンプルで理にかなった導線だ。 (昔はワンクリックすら不要で、予定を作ったら自動的に Meet の URL が発行されていた気がする。ゼロクリックのほうが明らかに良いのに、わざわざ不便なほうに変えたのだろうか?)

一方 Zoom では、新規発行した URL を Slack や Teams のような別のツールで共有する手間がしばしば発生する。 URL があらかじめわかっていれば先に入って待機しておけたものを、直前に発行・共有されるまでわからないので、ミーティング開始時刻の少し前からチャットに張り付いていないといけない。ちょっと気を逸らして作業していたりすると URL 共有を知らせるメッセージを見逃してミーティングに遅れてしまったりする。

さらに待機室のせいで、遅れて入室するときホストが入室リクエストに気づかないと、ずっと入室できない。仕方ないのでチャットのほうでメンションして気づいてもらうまで待つ、など、無駄が無駄を呼ぶ。

Zoom もミーティングをスケジュールして先に URL を発行することはできるし、 Chrome 拡張を使えば Google カレンダーの予定作成時に Zoom URL を発行して紐づけておくこともできる。しかし、 Google カレンダーの標準機能でできる Meet と比べると、スマートさに欠け、面倒だ。面倒くさいことは普及しないし、続かない。

ツールの問題ではなく使い方の問題、だけとも言い切れないと思う。ツールを使いこなせば可能、というのと、使いこなさなくても最初から可能になっている、の間には大きな隔たりがある。創意工夫をこらしてツールを使いこなしたいと思っている人ばかりではない。

EarPods のマイクが壊れた

オンラインミーティングでこちらの音声が聞こえないと言われた。断線してしまったのだろうか。

普通にイヤホンをつけた状態で QuickTime Player でオーディオ録音しながら喋ると確かにほとんど音を拾わない。システム環境設定のサウンド→入力でマイクが拾う音量のインジケーターもまったく振れない。マイク部分の間近に口を近づけて喋ると音を拾う。

iPhone を買うたびについてきて、ほとんど全く使わなかったので、家の中に新品がいくつか眠っていそうではある。なので、たかが三千円でも書い直すのは気が進まない。そして一つ発見した新品は Lightning コネクタのものだった。 MacBook には挿せない。

Lightning から USB-C にオーディオ接続を変換するアダプタも三千円で売っている。これを使えば余りがちな Lightning コネクタの EarPods を MacBook でも使えるし、必要であれば iPhone でも同じイヤホンを使いまわせるが、小さな部品の管理に気を使いたくはない。

逆に、イヤホンジャックの EarPods を書い直して、イヤホンジャックを Lightning に変換するアダプタを追加で買えば、一つのイヤホンを MacBook と iPhone で共有できるが、やはり小さい部品が増えるし千円余計にかかる。

AirPods を買えば端子で悩まずに済む、とは思うが値段の桁が違うし、日中つけっぱなしだとバッテリーが気になる。二組買ってローテーションなんて贅沢は無理な話。どれも決め手に欠ける。