本番導入へ向けての社内キックオフ

出張で道具がないのでバドミントン練習はおやすみ。

プロジェクトの進捗報告

出張したときの月例報告の21回目。前々回の進捗報告はこちら 。前回の9月は特別な話題がなかったのもあって書いてなかった。今回も淡々と進捗を報告してあまり話題はないものの、プログラミングを教えることの、抽象化能力と論理的思考、モジュール設計について話題にしてみた。経験のあるプログラマーやできる人は勝手にできてしまうものの、普通の人へどうやって指導していけばいいのか。どこでもよく聞く話しではあるし、プロダクト開発で課題管理をする上での延長上にある話題かもしれない。プロジェクトで解かないといけない問題の本質を認識できるかどうか、気付くかどうかという個人の素養に基づくところが大きい。経験を積んでスキルアップする過程で身につけていく特性を言語化したり明文化したりすることには意味がある。いまの私は答えをもっていないのだけど、とりとめのないの話題だけ共有した。

その後、ある案件の社内向けキックオフがあった。うちらが約2年開発してきたプロダクトがお客さん先で導入することが決まった。1月にテストして2月下旬から本番導入となる。最初のお客さんなので本番導入後のトラブルがあることも想定しておく。それが終わったらフルタイムもお仕事もようやく終えられるかもしれない。うちの会社のプロダクト開発に工数を取るようにしていきたい。

とりとめのない出張初日

目次

出張で道具がないのでバドミントン練習はおやすみ。

始発の新幹線で東京へ。定例会議に出て、昨日の カバレッジ計測 の成果をメンバーに共有して、その後もバグ修正や結合テストのリファクタリングをしていた。夕方には疲労で眠くなってきて17時でお仕事を終えて、お気に入りの 中華料理屋さんの晩酌セット を食べて、ホテルに帰って3時間ほど寝てた。起きてから軽く散歩に外に出たぐらいでまたホテルに戻って寝てた。毎月の出張で生活のリズムが乱れる。食べものと生活の拠点がいつもと違うのがしんどくなってきた。

出張前日の資料づくり

今日は1日中オフィスにこもって作業と出張準備をしていたのでバドミントン練習はお休み。夕方にお土産として モロゾフのプリンクッキー を購入するために本店へ行ってきた。これも神戸限定らしい。

パッケージ外のディレクトリにあるテストのカバレッジ計測

先日 深夜にバイナリのビルド・起動調査 をしたのに、最終的にはそんなことしなくてもよかった。デフォルトではパッケージ外のディレクトリにあるテストのカバレッジを計測しないことから普通にはできないと考えていた。しかし、調べたら次の SO で解決法をみつけた。結論としては -coverpkg ./... のように go test で実行している結合テストに対してオプションを指定するだけでよかった。

この調査を終えて最終的な makefile の coverage ターゲットは次のようになった。

coverage: lint
	rm -f coverage.*
	go test -tags=integration -race -cover ./... -coverpkg ./... -covermode atomic -coverprofile=coverage.out
	go tool cover -html coverage.out -o coverage.html

この make ターゲットを gitlab ci/cd から実行して coverage.out/coverage.html を自動生成する。coverage.out があるので必要に応じて好みのツールで統計情報を解析すればよい。たとえば nikolaydubina/go-cover-treemap でツリーマップを作るなら次のように実行する。

$ go-cover-treemap -coverprofile coverage.out > treemap.svg

近況報告の資料作り

普段は週末に報告資料を作っているのにもうやる気が無さ過ぎてお仕事を終えてから作っている。今回はネガティブな内容も報告に入れる。過去の経緯などを調査しながら3時間もあれば一通りのアウトラインはできた。明日がマイルストーンの最終日になるため、明日を終えてからでないと細かい数字は決定しない。マイルストーンの issue を調べたら qa テストでみつけた不具合の issue がそれなりに溜まっているようにみえる。本当は次のマイルストーンで5次開発は完了予定だが、もう1つ増やしてもよいかもしれない。いずれにしても12月/1月に本番導入のための準備もある。今の開発フェーズを完了しても次の開発フェーズには入らないのではないかという見通しもある。

バドミントンの基本練習

今日のバドミントン練習は磯上体育館で9時から12時半頃まで3時間ほど練習できた。ひとりでリフティング練習をするよりも相手がいて打ち合いする方がずっと楽しい。午前中にしっかり動いたので2万歩を超えて昨日の消費エネルギーは4500カロリーを超えた。

体育館でバドミントン

前回の所感 。磯上体育館では月に2回ぐらい個人利用という先着順で予約できる仕組みがある。8時過ぎに磯上体育館へ行ったらすでに2組並んでいた。先頭の方は9時から2面予約するという。私は3番目で並んでいた。8時半頃には10人以上後ろに並んでいたので8時頃に行くと確実に予約できると思う。事務側も本当は9時から受付だけど、並んでいるせいか8時45分頃から予約受け付けしてれくた。こうやって予約を取るためにどんどん並ぶ時間が早くなっていくのかもしれない。

先頭に並んでいたシニアの方が気さくに周りに声をかけていて、話しているうちに仲良くなってその人たちの9時からの練習に混ぜてもらうことになった。ベテランのシニアな方で経験もあって教え方もとても上手だった。丁寧に教えてくれてすごく勉強になった。来週も個人利用で9時から借りると話されていたのを聞いて来週も練習に混ぜてもらうことにした。今日は3つの打ち方の基本を教えてもらいながら練習した。

  • クリア
    • コートの奥から相手のコート奥へ大きく前方へ打ち返す
  • ドロップ
    • クリアを同じ打ち方でコートの奥からネットを超えた前方位置へゆるく落とす
  • プッシュ
    • ネット前で浮いた球を下方に叩きつけるような打ち方になる

打ちながら、私のラケットの振り方や持ち方のよくないところを指摘してもらった。我流でやっていたからちゃんとした知識やフォームを教えてもらえるのは本当にありがたい。教えてもらったことで覚えていることを書いておく。

  • 足は肩幅に開いて準備をする
    • まだ言語化できないが、右足/左足の使い方について説明されてた
    • 足の親指部分にチカラを入れてコントロールするように話されていた
  • フットワークと足の位置を意識してみる
    • 私は無意識に一歩目は左足から動いてしまう
      • フォアハンドで打つときは右足から動いた方が速いのかもしれない
  • シャトルが来てから動くのではなく、来る前から位置を予測して動いて備える
  • ラケットを振るときに左手をあげてカラダのバランスをとる
    • 基本として左手をどう使うのかがすごく大事とのこと
    • 左手を下げない、肘を90度にまげてあげるのに備えておく
    • 手首をまげずに固定してラケットを振る
  • ラケットは親指と人差し指でつまむ気持ちで軽くもち、シャトルを打ち返す瞬間だけ握る
    • この感覚で打ち返すと真っ直ぐ強い打球を返せるようになった
    • バックハンドで返すときも同様でシャトルを打つ瞬間だけ握り込んで止めるような感覚で返す
  • 向かってくるシャトルに対してカラダの正面でとらえて打つ
    • この位置を固定にすることで安定して打ち返せる気がする

1時間ちょっと練習の指導をしてもらって30分ほどダブルスの試合をした。私は下手だからすぐ失敗してラリーが止まってしまう。試合形式になると簡単そうにみえるシャトルの打ち返しも緊張や前後左右の動きの中で失敗してしまう。練習でできないことは試合では絶対にできない。ラリーを止めてしまって他の人たちに悪いなと罪悪感を感じるし、練習する方がたくさんシャトルを打つことができて楽しい。もう少し上達するまでは試合は棄権しようかなとも思う。11時からいとうさんが来られて、前の時間帯に教えてもらった打ち方を意識しながらひたすら打ち合いの練習をしていた。その前の練習で教えてもらったことをゆっくり反復する時間をとれてこの時間もよかった。基本の打ち方を教えてもらった通りにやっていると狙ったところにうまく返せる回数が増えたように感じた。

ストレッチ

先週は実家へ帰ってストレッチをお休みして2週間ぶり。午前中にバドミントンの練習をたくさんして疲れていたのと、試合をしているときにころんで足と腰を少し痛めていた。その部位を伸ばす意図でもストレッチしてもらってちょうどよかった。運動して筋肉痛もある状態でストレッチするとよく伸びて、その日の睡眠もよく取れるし疲労回復も早くなる。今日の開脚幅は開始前146cmで、ストレッチ後155cmだった。ストレッチ前は筋肉痛で伸びないのがストレッチ後によく伸びていることが伺える。トレーナーさんはサッカーをずっとされていた方なのでたまたまはてブでみかけた町田ゼルビアの記事を話題にしたら盛り上がった。この著者の記事が3つもあがっているようにいまホット話題ではあるらしい。

ストレッチを終えて晩ご飯を食べた後にオフィスで作業しようと思っていたものの、家に帰ったら疲れてそのまま休んでしまった。体調が悪いわけでもないのに、最近はやらないといけないことをがんばる気力がなくなっている。なにか内からのやりたいが出てこない。

コンパクトな REALFORCE R1 キーボード

コンパクトな REALFORCE R1 キーボード

今日は午前中寝ていたのと雨降りだったのもありバドミントン練習はお休みした。

REALFORCE R1 レビュー

bluetooth の初回ペアリング設定を過去の R3 のペアリング設定 をみながら行った。手順を忘れていたのでまた書いておく。agent を介してパスキーを入力する必要がある。その手順が少しわかりにくい。30分ほどペアリング設定をうまくできなくてやり直ししたりしていた。滅多にやらないことだし。今回も GUI ツールではなく bluetoothctl を実行してペアリングした。

$ bluetoothctl
[REALFORCE_2 (R3)]# default-agent
Default agent request successful
[REALFORCE_2 (R3)]# scan on
Discovery started
... (デバイスを検索しているうちに RC1 がみつかる)
... MAC アドレスを確認してペアリングする

[REALFORCE_2 (R3)]# pair F7:62:4B:02:D6:EB
Attempting to pair with F7:62:4B:02:D6:EB  (キーボードに接続を試みる)
..
[agent] Passkey: 946185 (エージェントがパスキーを受け取る)
...

エージェントが受け取ったパスキーを、bluetooth 接続するキーボードで入力して Enter を押下する。

[NEW] Primary Service (Handle 0x0000)
	/org/bluez/hci0/dev_F7_62_4B_02_D6_EB/service000a
	00001801-0000-1000-8000-00805f9b34fb
	Generic Attribute Profile
[NEW] Primary Service (Handle 0x0000)
	/org/bluez/hci0/dev_F7_62_4B_02_D6_EB/service000b
	0000180a-0000-1000-8000-00805f9b34fb
	Device Information
[NEW] Characteristic (Handle 0x0000)
	/org/bluez/hci0/dev_F7_62_4B_02_D6_EB/service000b/char000c
	00002a29-0000-1000-8000-00805f9b34fb
	Manufacturer Name String
[NEW] Characteristic (Handle 0x0000)
	/org/bluez/hci0/dev_F7_62_4B_02_D6_EB/service000b/char000e
	00002a50-0000-1000-8000-00805f9b34fb
	PnP ID
[NEW] Primary Service (Handle 0x0000)
	/org/bluez/hci0/dev_F7_62_4B_02_D6_EB/service0010
	0000180f-0000-1000-8000-00805f9b34fb
	Battery Service
[NEW] Characteristic (Handle 0x0000)
	/org/bluez/hci0/dev_F7_62_4B_02_D6_EB/service0010/char0011
	00002a19-0000-1000-8000-00805f9b34fb
	Battery Level
[NEW] Descriptor (Handle 0x0000)
	/org/bluez/hci0/dev_F7_62_4B_02_D6_EB/service0010/char0011/desc0013
	00002902-0000-1000-8000-00805f9b34fb
	Client Characteristic Configuration
[CHG] Device F7:62:4B:02:D6:EB UUIDs: 00001800-0000-1000-8000-00805f9b34fb
[CHG] Device F7:62:4B:02:D6:EB UUIDs: 00001801-0000-1000-8000-00805f9b34fb
[CHG] Device F7:62:4B:02:D6:EB UUIDs: 0000180a-0000-1000-8000-00805f9b34fb
[CHG] Device F7:62:4B:02:D6:EB UUIDs: 0000180f-0000-1000-8000-00805f9b34fb
[CHG] Device F7:62:4B:02:D6:EB UUIDs: 00001812-0000-1000-8000-00805f9b34fb
[CHG] Device F7:62:4B:02:D6:EB ServicesResolved: yes
[CHG] Device F7:62:4B:02:D6:EB Paired: yes
Pairing successful
[CHG] Device F7:62:4B:02:D6:EB Modalias: usb:v0853p031Ad0001
...
[REALFORCE_2 (R3)]# exit

ペアリングが成功したらキーボード入力できるようになる。bluetoothctl を eixt してから再実行すると今度は RC1 で実行された。

$ bluetoothctl
[RC1_1]# info
Device F7:62:4B:01:D6:EB (random)
	Name: RC1_1
	Alias: RC1_1
	Appearance: 0x03c1
	Icon: input-keyboard
	Paired: yes
	Trusted: no
	Blocked: no
	Connected: yes
	WakeAllowed: yes
	LegacyPairing: no
	UUID: Generic Access Profile    (00001800-0000-1000-8000-00805f9b34fb)
	UUID: Generic Attribute Profile (00001801-0000-1000-8000-00805f9b34fb)
	UUID: Device Information        (0000180a-0000-1000-8000-00805f9b34fb)
	UUID: Battery Service           (0000180f-0000-1000-8000-00805f9b34fb)
	UUID: Human Interface Device    (00001812-0000-1000-8000-00805f9b34fb)
	Modalias: usb:v0853p031Ad0001
	Battery Percentage: 0x5b (91)
[RC1_1]# trust 
[CHG] Device F7:62:4B:02:D6:EB Trusted: yes

この日記を R1 のキーボードで書いている。R3 と比べてたしかにコンパクトで軽い。キーボードを持ち運びするならよさそう。R3 と比べて右シフトキーが小さいのでその隣にある PgUp キーをタイプミスしてしまう。私は左右両方のシフトキーを使う。!記号などの左手でタイプするときは右シフトキーを使う。それからコンパクトサイズのせいか、キーとキーの隙間が若干狭くなったように感じる。矢印キーの位置もエンターキーの下の方に移動している。R3 の矢印キーの位置を無意識にタイプしようとして空打ちしてしまう。意外と矢印キーを私は使っていたことに気付く。これらの操作の違和感は慣れの問題だと思う。キーボードの打鍵感も R3 と比べて若干違う。気持ち、深さが増して軽い印象を受ける。キー荷重は 45g を選択した。R3 では変荷重モデルを使っていたので小指キーが 30g から 45g に変わる。その違いはあまり感じない。

キーボードは毎日たくさん使うものだから慣れによる無意識の最適化が自然と行われる。私の用途では R3 と R1 では右シフトキーと矢印キーの位置の違いに違和感を感じる。両方のキーボードを使い分けるというようにはならないのかもしれない。どちらかに慣れるともう一方に違和感を抱くように思える。

能楽の勉強

玄宗皇帝と楊貴妃の愛情物語の後日談《楊貴妃》 第41回能のことばを読んでみる会 に参加してきた。前回の所感はここ 。中国史上もっとも有名な美人といわれる 楊貴妃 の幽霊を主人公とした能になる。方士 と呼ばれる修行者が玄宗皇帝の命令で楊貴妃の魂魄の在り処を探していて蓬莱島でみつけて話しを聞くといった、とくに変わったこともない普通の物語の構成になっている。作者ははっきり分かっていないらしいが、世阿弥の娘婿になる金春禅竹 (こんぱる ぜんちく) ではないかと推定されるとのこと。

貴妃 というのは皇帝の后に与えられる位の1つで皇后に次ぐ高い位だという。楊が姓になる。唐の 玄宗皇帝 は在位期間が45年と長い。前半は善政をしいて唐は絶頂期を迎える。後半は楊貴妃にうつつを抜かすようになる。楊一族が政治の重要なポストを占めるようになり、玄宗皇帝が政治に関心をなくして最終的に反乱が起きて国が乱れてしまう。その後、白居易 (はくきょい) という著名な詩人が玄宗皇帝と楊貴妃の物語を 長恨歌 にした。この漢詩が素晴らしい内容だと評価されて後世にまで楊貴妃の物語が広く伝わる影響を与えたという。

源氏物語に出てくる 桐壺更衣 (光源氏の母) が楊貴妃のイメージや長恨歌から引用されて創作されているという。この能は源氏物語に出てくる長恨歌を引用した文章を引用して作られてもいて、伝言ゲームのように、引用を繰り返すうちに少しその内容が変わってしまうといったことも起きているらしい。おもしろかったのが、漢詩に序文をつけたりするのを詩序と呼ぶ。オリジナルの中国の長恨歌には詩序がないのに、日本に伝わって残っている長恨歌には詩序が残っていて、その詩序の内容を能でも引用していたりする。当時は長恨歌には詩序があったのに現代では失われてしまった可能性もないわけではないが、おそらく日本に伝わってきた後に誰かが詩序を追加したのではないかと考えられているらしい。

会者定離ぞと 聞く時は、逢うこそ別れなりけれ

以前 蝉丸の能 を読んだときにも 会者定離 (えしゃじょうり) が出てきた。一種の悟りのような表現だと朝原さんが解説していて私も記憶によく残っている。直接なにかの役に立つわけではないけれど、こういう言葉や概念に触れて自分の価値観をふりかえる機会があるのはおもしろい。能の言葉を読んでいるとそういう出会いがある。

exec とスクリプト

今日のバドミントン練習はエアシャトルでリフティングを60分した。連続最大回数は191回だった。もう少しで200回だったのに残念。木曜日は睡眠をたくさんとって疲れは少し取れたし、安定的に50回前後は続くようになりつつも、100回までに失敗してしまう。今日は100回を超えたのが2回だけだった。ラケットのスィートスポットでとらえたときにきれいに真上にあがる感覚が楽しい。うまくいくときは数回は続く。それが自然にできるときとそうじゃないときの違いを私は制御できてなくて言語化もできない。

エアシャトルとメイビスにおけるリフティングの違いを比べてみると、メイビスの方が打ち上げて落ちてくるときにあまり回転せずコルクが下を向く傾向が多いようにみえる。エアシャトルの方がコルクが重い分、縦方向に回転し始めるとその回転が止まらず、回転しているからラケット面でとらえるのが難しくなる。だからエアシャトルの方がメイビスよりもリフティングが難しいといえる。シャトルを高く打ち上げると、落下してくる距離が長くなりその回転が落ち着く傾向があるからリフティングしやすくなるのではないかと仮説を考えた。伸び悩みかもしれないし、地道に練習を継続するときかもしれない。

exec とエントリーポイントのスクリプト

コンテナを起動して stop すると SIGTERM が送られる。そのときに api サーバーでシグナルの処理をしているのに、気付いたらシグナル処理が行われずタイムアウトするようになっていた。デフォルトでは10秒でタイムアウトして強制終了となる。なぜシグナルを捕捉しなくなったかを調査したら、あるときサーバーの起動前に前処理が必要になってエントリーポイントをシェルスクリプトにしていた。そのときに exec しないと、シェルスクリプトのプロセスに対してシグナルが送られるため、api サーバーがシグナルを検知できなくなるという副作用があることに気付いた。これまでも exec を使うとプロセス ID は変更されないという知識を知っていたが、それがどういう状況で役に立つかを理解できていなかった。シグナルを用いた同期処理に exec が役に立つ状況があることを学んだ。修正は次の1行のみ。

--- a/docker/entrypoint.sh
+++ b/docker/entrypoint.sh
@@ -2,4 +2,4 @@
 ...
 ... (pre process)
 ...
-./bin/api "$@"
+exec ./bin/api "$@"

go test からバイナリをビルドしてサーバーを起動する

先日 結合テスト向けカバレッジ計測の調査 をした成果を使って実際に go test からカバレッジ計測のカスタマイズを施したバイナリをビルドしてサーバー起動するコードを書いてみた。やや手間取ったが、一通り動いてカバレッジを計測できた。例えば、単体テストのカバレッジを計測するための makefile のターゲットは次のようになる。

GO_COVER_DIR:=$(CURDIR)/tests/coverage

coverage:
	@mkdir -p $(GO_COVER_DIR)
	go test -tags=integration -race -cover ./... -covermode atomic -args -test.gocoverdir=$(GO_COVER_DIR)

go は fork ができない。fork の代わりに exec を使う。How do I fork a go process? に go の goroutine のスケジューリングと fork は相性が悪くてうまく動かないということが背景だと説明されている。それはともかく exec を使ってもサーバープロセスを非同期に起動できたのでそのスニペットを書いておく。

binaryPath, err := buildBinary()
if err != nil {
	return 1
}
args := []string{
	"-verbose",
	"-port",
	strconv.Itoa(ServerPort),
}

r, w := io.Pipe()
go func() {
	s := bufio.NewScanner(r)
	for s.Scan() {
		fmt.Println(s.Text())
	}
}()

cmd := exec.Command(binaryPath, args...)
cmd.Stdout = w
if err := cmd.Start(); err != nil {
	slog.Error("failed to start api server", "err", err)
	return 1
}
defer func() {
	if err := cmd.Process.Signal(syscall.SIGTERM); err != nil {
		slog.Error("failed to terminate the api process", "err", err)
	}
	if s, err := cmd.Process.Wait(); err != nil {
		slog.Error("failed to wait terminating the api process", "err", err)
	} else {
        w.Close()
		slog.Info("completed to terminate the api process", "s", s.String())
	}
}()

// サーバーに対するテストを実行

サーバープロセスの標準出力のログを io.Pipe を使って出力することもできる。exec で生成したプロセスに対してもシグナルを送ったり終了を待つこともできる。デバッグしている分にはこれで意図したように制御できた。この知見は将来的に役に立つ気がする。0時過ぎから調査を再開して4時前ぐらいまでやっていた。少しはまって時間はかかったものの、久しぶりに集中してデバッグしていた。

変な疲れかた

目次

今日のバドミントン練習はエアシャトルでリフティングを40分した。連続最大回数は168回だった。いくつか練習場所を転々としながら最終的にはホームのビルの軒下に行き着いた。環境のよい場所を知ってしまうと、それよりも劣る環境で練習することに抵抗を感じてしまう。昼間なら風がなくて人通りの少ないところであればどこでもそう大差はないが、夜は証明と背景でシャトル視認性 が変わってくる。21時まではホームのビルで、21時以降はその隣のビルでといった定番の練習場所ができつつある。今日はなんとなく調子がよくなくて練習していて手応えや集中力を感じなかった。

午前中に結合テスト改善に関するドキュメントを書いて、お昼から rpm パッケージングのリファクタリングやって、夕方に午前中に書いたドキュメントを使いながらメンバーに結合テスト改善の要項について共有した。そして17時半にはお仕事終えて帰った。晩ご飯も外食してリフティング練習も早めに切り上げて帰った。ここ数日あまり睡眠時間を取れていなかったのもあり、疲れているかも?と21時過ぎから横になって寝ていた。

テストライブラリの導入

今日のバドミントン練習はエアシャトルでリフティングを25分した。連続最大回数は277回できた。初めてエアシャトルで200回を超えた。しかも夜なのに。やや高めに打ち上げれば安定的にリフティングできるようになってきた。連続回数が増えることはラケットとシャトルの距離感、ラケットコントロールが上達していることの証左でもあるので200回を超えたときは嬉しかった。

テストライブラリの追加

結合テストを改善するために2つのライブラリを新たに使うよう導入した。

testify は名前だけ知っていたが、実際に使ってみるのは初めて。testify は大きく3つの機能もっている。

  • アサーション
  • テストスィート
  • モック

うちらのチームで使うのはアサーション機能だけになる。モックも将来的に使う可能性はある。アサーションを使うと自分でエラーメッセージを書く手間を省ける。次のようなコードがあった場合、

if expected != actual {
    t.Errorf("expected %d, but got %d", expected, actual)
    return
}

次のようにエラーレポートを testify に委譲できる。このぐらいの利便性でしかないが、テストの規模が大きくなったり、量が増えていけば読み書きのコストを削減できるかもしれない。

if !assert.Equal(expected, actual) {
    return
}

httpexpect はまったく知らなくて初めて使ってみたが、感触がよい。これもデフォルトのエラーレポート機能は testify のアサーション機能を使っているようにみえる。これまでは http リクエストに対して自前のユーティリティ関数と組み合わせて次のようなコードを書いていた。

res, err := doHTTPRequest(body, UserPath, http.MethodGet, "")
if res.StatusCode != http.StatusOK {
    t.Errorf("expected to get %d, but got %d", http.StatusOK, res.StatusCode)
    return
}
var actual entry.User
if err := convertBody(res, &actual); err != nil {
    t.Errorf("failed to convert: %s", err)
    return
}

httpexpect を使うと次のように簡潔に記述できる上にエラーレポートを httpexpect に委譲できる。これはかなりテストコードを読み書きする工数を削減できると思う。

var actual entry.User
e.GET(UserPath).
    WithJSON(map[string]any{ ... }).
    Expect().
    Status(http.StatusOK).
    JSON().
    Decode(&actual)

mongodb のテストデータ管理

今日のバドミントン練習はエアシャトルでリフティングを45分した。連続最大回数は146回できた。調子は悪くなく安定的に30回前後は続くものの、50回を超えたぐらいで失敗してしまう。打ち上げる高さの違いかな?と気付いて少し高めに打ち上げるようにしたら100回を超えた。エアシャトルはラケット面に対して適切な角度でコルクを打たないとあらぬ方向に飛んでいってしまう。高く打ち上げるほど、重力で落ちてくるときにコルクが下を向きやすくなるため、うまくシャトルを打ち上げやすくなる。ラケットコントロールをうまくできれば、エアシャトルをより低い高さでリフティングできるようになるかもしれない。まだ私はそのレベルには満たない。

json からの mongodb にテストデータを追加する

結合テストの改善をしていてテストデータを json で管理したい。これまで go の構造体でテストデータを定義して mongodb の client で insert するといったことをしていた。それも役に立つのだけど、共有のテストデータがどこにあるのか、ソースコードに書いてしまうと時間とともに散らばっていって把握できなくなっていく。テストデータを管理するためのディレクトリを設け、そこに json で記述してどのテスト関数で使うかといったメタ情報も定義できるようにした。次のコードは mongodb に json からデータをインポートするための原理を説明するための疑似コードのようなもの。

go の構造体で定義したテストデータと json で管理するのとどちらがよいかというのは議論の余地はあるし、一概に言えないとは思う。

type testData struct {
	Documents    []bson.Raw `bson:"documents"`
}

func InsertData(
	t *testing.T, client *mongo.Client, b []byte,
) (func()) {
	var data testData
    err := bson.UnmarshalExtJSON(b, false, &data)
	require.NoError(t, err, "failed to get json files: %v", err)

	ctx := context.Background()
	col := client.Database(dbName).Collection("mycollection")
	r, err := col.InsertMany(ctx, docsToInterfaces(data.Documents...))
	require.NoError(t, err, "failed to insert: %v", err)

	return insertResult, func() {
		t.Helper()
	    col := client.Database(dbName).Collection("mycollection")
		for _, id := range r.InsertedIDs {
			filter := bson.D{{Key: "_id", Value: id}}
			if _, err := col.DeleteOne(ctx, filter); err != nil {
				t.Errorf("failed to delete %s: %v", id, err)
				return
			}
		}
	}
}

呼び出し側のイメージ。defer で teardown を呼ぶことでテスト完了時に追加したテストデータを削除してくれる。

teardown := mongotest.InsertData(t, mongoClient, b)
defer teardown()

...

bson.Raw として読み込める json データは bson パッケージのユーティリティを使って dump できる。

func dumpAsJSON(value any) {
	b, err := bson.MarshalExtJSON(value, false, false)
	if err != nil {
		slog.Error("failed to marshal as extended JSON", "err", err)
		return
	}
	fmt.Println(string(b))
}

バドミントンのセンスは距離感らしい

バドミントンのセンスは距離感らしい

今日のバドミントン練習はエアシャトルでリフティングを110分 (エア110分) した。1回あたりは20-30分で休憩する。最大連続回数は192回だった。もうちょっとで200回を越せそう。

ラケットとシャトルの距離感の考察

エアシャトルでリフティングをしていると、きれいに真上にあげられるときとシャトルにスピンがかかってしまうときがある。スピンしてしまうと、ラケットのスィートスポットでコルクをとらえるのが難しくなる。試しにエアシャトルをラケット面に並べてみた。中心部でシャトル3つ分の横幅しかない。この中心部分でラケットのコルクをとらえるとうまく弾ける。シャトルが回転していると、コルクが垂直方向から傾いた角度でラケット面に当たったりフレームに当たる確率が高くなる。ラケットの上部だとシャトル2つ分の横幅しかない。リフティングを失敗してしまうのは回転中のシャトルをはたいたり、あらぬ方向へ飛ばしてしまうことが多い。うまくラケットコントロールを行い、なるべくシャトルをスピンさせずに上げることができればリフティングが安定する。

今日は昼間と夜間にビルの軒下で練習した。風の影響も軽微だったので安定的に連続して50回前後はできていたと思う。121, 146, 192, 152, 122, 106, 102, 120 と連続して100回を越せたのが8回もあった。うち2回は夜になる。メビウスだと100回に1-2回ラケットコントロールをミスしてシャトルをうまく上げられないときがある。そのときにリカバリをうまくやれば続けられる。安定的に100回程度のリフティングができるからリカバリを連続で2-4回できれば200回を超える。この原理はエアシャトルも同様になる。仮にエアシャトルだと20回に1回うまく上げられないとする。200回を超すには連続で10回リカバリできないといけない。リカバリできるかどうかは運の要素もある。回転しているシャトルがフレームのどこに当たるかでリカバリ可能な場合とそうではない場合がある。10回連続でリカバリするよりも5回連続の方が、5回連続よりも2回連続の方が容易な状況と言える。つまり、ラケットコントロールが上達するとリフティングにおけるシャトル打ち上げのミスが減る。ミスが減るとリカバリ試行の回数が減る。リカバリ試行の回数が減ると連続回数が増えるという理屈になる。

今日エアシャトルで192回連続で続いたことはたまたまリカバリが連続的に成功した結果であり、リカバリを必要とせず安定的にどれだけ長くリフティングを続けられるかの方が重要ではある。よいときのラケットコントロールの感触を覚えておいて再現できるように努めていく。

次の動画によると、バドミントンのセンスとは「距離感」とのこと。練習しているうちに距離感は少しずつよくなる。そして速いプレーになると距離感をつかむのはもっと難しいとのこと。

距離感をつかむための練習としては次になる。私がいまひとり練習しているのはまさにこれになる。

  • シャトルのキャッチ
  • シャトルのリフティング
  • 一人でロビングを打ってみる

2人いればシャトルパスもおすすめとのこと。

中学校体育館の夜間開放

バドミントンができる体育館探し。抽選予約のためのアカウント登録 を終えて初めての抽選。15日ゼロ時に抽選が行われる。初回なので0時頃に待機してみていた。本当に0時まわってから抽選のバッチ処理が動いているようでサイトで更新していると2-3分後に抽選結果が表示されるようになった。最大4つ抽選申し込みできる。残念ながらすべて落選だった。15日以降は先着順で予約できる。抽選結果が出た後も空きがあれば先着で校区以外の中学校も予約できる。校区以外の夜間開放されている中学校のうち、私が住んでいるところから近い区で駅から徒歩10-15分程度で歩いていけそうな中学校をピックアップしてみた。

灘区

  • 原田中学校

中央区

  • 渚中学校

兵庫区

  • 兵庫中学校
  • 湊川中学校
  • 須佐野中学校

長田区

  • 駒ケ林中学校
  • 長田中学校

予想した通り、抽選確定後にみんな先着申し込みを検索しているらしく断続的に 504 エラーが出たりもしていた。私が検索して確認できた中では渚中学校と須佐野中学校に先着の空き枠が1つ2つあった。他の中学校はすべて埋まっていた。空きがある中学校もあるんだなと検索してみているうちに0時10分までにはそれらも誰かに先着予約されたみたいで埋まっていた。14日の深夜 (15日ゼロ時過ぎ) に街中の駅からアクセスのよい中学校の予約はすべて埋まると考えてよさそう。中学校によって貸し出し可能な日が平日/休日ともにあるところもあれば週末だけのところもある。11月はどこの体育館も予約できなかったが、今回は抽選申し込みと先着申し込みの雰囲気を把握できた。

田んぼの畝作り

今日のバドミントン練習は主にエアシャトルでリフティングを80分 (メイビス10分、エア70分) した。今日の連続最大回数は79回だった。メイビスなら10分以内に200回は続けられるようになってきた。ウォームアップにメイビスでリフティングを始める。今日は5回目ぐらいで250回続いた。リフティング練習を1時間もやれば1日の消費エネルギーは3,000カロリーを超える。

田んぼの宿題

8月に実家に帰って田んぼを耕した が、土がよく乾いていて畝を作れるような状態ではなかった。その後、雨を待って土が適度に水分を含む状態になるのを待っていた。帰れるタイミングもあって今日になった。前回から約2ヶ月たつとまた雑草が茂り始めていたところだった。雑草を駆除するだけでも3ヶ月に1回ぐらいの頻度で田んぼを耕さないといけない。昨日の夜から帰っていたため、朝7時半ぐらいからトラクターで耕し始めて11時頃には畝作りも終えた。

いずれコワーキングスペースで農業体験を始めたらトラクターで田んぼを耕すのもメニューに組み込みたい。多くの人はトラクターになんか乗ったことないだろうから1度はやってみたいと思う。3ヶ月に1回は雑草駆除のために耕した方がよい。気軽に縦横無尽に田んぼを耕せる機会を提供しやすい。

その後、粗大ごみを市の処分センターにもって行ってお昼ご飯食べてから帰途につく。

いつもと違う帰り道

先日の 毎日1つ新しいことを試して変化を楽しむ という学びを思い出したのと、時間に余裕があったからいつもと違う道を通ってみようと、明石海峡大橋を渡って垂水ジャンクションから降りて海岸線の下道を走りながら帰ってきた。垂水ジャンクションの出口は山側になるのでそこから海岸線までわりと距離がある。海岸線に下るのに20分ほどかかる。垂水から須磨の海岸線はそんなに混雑しないので下道でもそれほど時間はかからない。10分ぐらいかな。その後、若宮からまた阪神高速に乗る。湊川IC付近は常に渋滞する というのも知った上で軽い渋滞なら高速の方が早いだろうと予測した。やはり渋滞はしていたものの、それでも時速20-30kmで流れている程度の軽微な渋滞だったので20-30分で若宮-京橋間を走って帰宅した。垂水ジャンクションを降りずにそのまま高速道路を走るよりもずっと時間はかかっているのだけど、知らない道を走るというのも気分転換にはなる。

バドミントンの練習

ダイソーでベルトにひっかけるポーチ (300円) とベルト (100円) を購入した。エアシャトル も9個購入した。このポーチにシャトルを10個ほど詰めて、こまめにシャトルを拾わなくても効率よく練習できるようにした。

夕方から磯上公園でリフティングをしていたが、いまひとつ続かない。調子が悪い。田んぼ作業で疲れているせい?暗くなったので場所を変える。旧居留地にある新しい練習場所としてワイズロードの近くや三井住友銀行神戸本部ビルの前とか、転々としながら試してみたがいまいち。その後、バスの営業所の駐車場へ行った。まぁまぁできたが、風がやや吹いているのが気になって、次にみなとのもり公園へ行ってみたが、そこはもっと風が強くてリフティングできる環境ではなかった。最後に サンボーホール のビルへ行ってみた。前から試してみたいと思っていた。このビル前の広場も休日の昼間は子ども連れの家族がよく遊んでいる。日曜日の22時には誰もいない。

磯上公園よりもバスの営業所よりも風の影響が小さくてとてもよかった。この場所で20分ほどエアシャトルでリフティングして安定的に20-30回をこなすことができた。最高は79回と過去最高ではないが、3回以上は連続50回を越した気がするので練習をしてしての感触は悪くなかった。そこでエアシャトルのリフティングは風の影響を受けやすいことに気付いた。エアシャトルを安定的にリフティングをするにはメイビスよりも高く打ち上げないといけない。しかし、高く打ち上げるほど風による影響を受けやすい。そよ風がふくだけでも軌道がずれる。シャトルが落ちてくる位置を目視しつつ予測しつつラケットコントロールをする。しかし、ちょっと風が吹くだけで微妙にズレてしまい、ラケットのフレームなどに当ててしまう。昼よりも夜の方が暗いから風の影響による補正が難しい。サンボーホールがもっとも風が弱くてリフティングが安定することに気付いた。そして、この場所は日曜日の夜でも照明がついている。

ホームのビル はオフィスビルのせいか、休日は消灯している。これまで休日の夜に練習する安定的な場所がなかった。だから休日は公園で明るい時間帯に練習してきた。しかし、サンボーホールが休日でも照明がついていて風の影響を受けにくい構造なら休日の夜の練習場所になるかもしれない。偶然よい場所をみつけた。