吉祥寺.pm 31 で LT した

kichijojipm.connpass.com

www.slideshare.net

SlideShare 広告がエグくなったんだけど、embed では入らないので一旦アップロード先はコレで)

IPA組織における内部不正防止ガイドライン では

  • 犯行を難しくする(やりにくくする)
  • 捕まるリスクを高める(やると見つかる)
  • 犯行の見返りを減らす(割に合わない)
  • 犯行の誘因を減らす(その気にさせない)
  • 犯罪の弁明をさせない(言い訳させない)

としても語られていたんだけど、機会・動機・正当化の三要素を削減していくことで発生しないようにしていく。これは CI でコードベースを守ってることと近いなぁと思ったので、その気づきを LT として話してきた。

  • 動機
    • 過度の開発速度への期待をしない
  • 機会
    • CI することで検査頻度を高める
  • 正当化
    • CI を定常的に無視する状態を作らない

内部不正防止の研究の歴史に乗っかって、我々は CI で何を守りたかったのかを、体系立てて見つめ直してみるのはいかがでしょうか。

吉祥寺.pm はここ数年よく顔を出しているコミュニティだけど、今回もまたバラエティに富んだ発表があって良かったです。この幅広さがとても魅力だと思う。

最近買ったイヤホンたち

密閉型イヤホン以外でWeb会議アドベントカレンダーに遅れて参戦!

こういう状態。

ここ3年で増えたヘッドンホホたち

SONY WH-1000XM4

www.sony.jp

ヘッドフォンですね。2020-09 に買った。

外音取り込みは、外の音が聞こえるイヤホンを↓でいっぱい買ったので、むしろ外音を取り込まないために使うヘッドフォンになった。

ノイズキャンセリングは最高に便利。僕も妻も机を並べて WFH しているので、同時に会議すると声が混ざって困り、この子に付け替えている。

AfterShokz OpenComm

OPENCOMMjp.shokz.com

骨伝導。2020-11 に買った。

耳を塞がず (外耳炎にならなくて最高) に外の音が自然に入ってくる (在宅作業しやすくて最高) のはものすごく快適で、しばらく「最高〜〜〜〜!!!」と思って暮らしていた。

完全ワイヤレスではなく、ヘッドレストに頭を預けられないとか、寝っ転がれないとかが難点。

ambie sound earcuffs AM-TW01

ambie.co.jp

イヤーカフ型。2021-09 に届いた。

Shokz のものよりも無限にずっと付けてられる。Shokz は室内ではずっと付けていてコンビニに行くときに割と取り外すけど、ambie は外さずに外出しています。 付けたまま寝っ転がれるのも最高。そのまま寝ていることも多い。

OpenComm からメインを奪ったぐらいに最高。ストレスがマジで少ない。

上手く耳に装着したときはよく聞こえるが、ちょっとズレてると聞きづらくなるのが難しい。耳の形のせいかもしれない。電池の持ちが少し足りなくて、午後ずっと会議のときとかは定時直前に電池切れになる。

SONY SRS-NB10

www.sony.jp

ネックスピーカー。2021-09 に買った。

スピーカーの 1/5 ぐらいの音量で普通に音漏れしまくるので、同室に人が居ると使いづらい。また、僕は普段ヘッドフォンsとは別のコンデンサマイクを使っているので、音がハウりそうだなぁと思って会議には使えていない。音もそんな良くないと思う。

他の全てのヘッドフォン、イヤホンよりも身体的には楽で、夜中に動画を垂れ流しているときによく使っている。今年は魔動王グランゾート新機動戦記ガンダムWをこれで全話見た。

Anker Soundcore 3

Soundcore 3www.ankerjapan.com

Bluetoothスピーカー。

誰も居なくて音楽を垂れ流しながら作業しているときとか、風呂でポッドキャストを聞くときとかに使っている。

Shokz OpenRun Pro

OPENRUN PROjp.shokz.com

骨伝導

Shokz の新作が出ると聞いたのでとりあえず買い増してみた。2 本あれば充電が切れても安心。充電ケーブルが増えたのでどこでも充電できて便利。

OpenComm との差は僕にはあんまり分かってない。どっちも普通に使える。

SONY LinkBuds

www.sony.jp

穴が空いているイヤホン?

耳の穴に装着する。僕の耳の形には合わなかった (どうやっても引っかからない) ので、買ったはいいけど 1 週間ぐらいで試行錯誤は諦めてまったく使っていない。合う人には合うと思っているけど、物理的に耳に入れるので、耳が疲れることもあるんじゃないかと思う。

耳の中に収まるので、バイクのメット被りながら使えるんじゃないかと妻は言っていた。

Oladance ウェアラブルステレオ

www.oladance.jp

オープンイヤー型イヤホン。今一番満足度&使用頻度が高いです。 Shokz と割と似た付け心地、使い道で、同じバッテリーの持ち、段違いの音って感じで、買う前に思ってた以上に良かった。

他の全てを押し退けてメイン機になるぐらい良いので強くオススメしたい。

マスクを外したら一緒に耳から外れて飛んでいくのが難点。

CioDat Q10

オープンイヤー型イヤホン。

Oladance が凄いのか、オープンイヤー型だとどれでも似たような感じなのか知りたくて買った。悪くはないかな。コスパは良いのでは。Oladance は充電ケースが付属してないが、こっちは 5000 円で充電ケース付きなのでクソ安い。

Oladance の方が断然音が良い&僕の耳には付け心地が良いので、あんまり使わないかもしれない。丸 1 日付けていたらちょっと耳が痛い。

他に気になっていた子たち

まとめ

Shokz か ambie か LinkBuds かが世の中では人気だと思うけど、Oladance ウェアラブルステレオも検討してみてください。耳元にスピーカーがあるのはかなり快適です。

これだけ買って耳いくつあるのって感じだけど、順繰りに電池が切れているので、耳にハマらない LinkBuds 以外は割と全部使ってます('A`)

git revert -m1 の -m は --mainline

TIL

merge commit は親が 2 つ (以上) あるので、revert するときはどちらの親に戻したいかを -m (--mainline) で指定する。

起きたこと

「意図せず feature branch を main に混ぜて push しまった」と呼ばれて飛び出したんだが、コミットツリーがこうなっていた。

525adcbf69 ●─╮ [main] {origin/main} Merge branch 'main' of ...
de745c8669 │ ∙ commit for main
2060e2be19 │ ∙ commit for main
813528befb ∙ │ commit for feature
9ed9cb80a9 ∙ │ commit for feature
9f8e1bb2e1 ∙ │ commit for feature

元々の main 最新は de745c8669 で、そこに feature branch を merge してしまったっぽい。

merge commit を revert して push すれば良いかなと思って

$ git revert -m1 525adcbf69

をしたんだが、何かおかしい。僕の意図としては de745c8669 と同じ状態になって欲しかったんだけど、813528befb と同じ状態になった。

revert で親のどっちにするのか選べたっけ、と man git-revert していたら -m parent-number, --mainline parent-number の記述が見えて、納得した。何も考えずに -m1 としたのが間違いで、-m2 とすべきだった。

git revert の -m

merge commit には親が 2 つある。

$ git show 525adcbf69
commit 525adcbf69824c1888504f5c07f69697baad5aa8
Merge: 813528befb de745c8669
...

このどちらの状態に戻すのかを指定するのが -m (--mainline) オプション。

なお、octopus merge の場合は 3 以上を使うこともある。

5580d0beb1 ●─┬─╮ [main] Merge branches 'foo', 'bar' and 'baz'
a5334bc232 │ │ ∙ [baz] Add baz
0b9531a81e │ ∙ │ [bar] Add bar
b54c490b75 ∙ │ │ [foo] Add foo
2dfb6b27be ◎─┴─╯ Initial commit

親が 3 つあるので

$ git show
commit 5580d0beb173c8e8695f4c0782e3620e93f13cb1
Merge: b54c490 0b9531a a5334bc
...

revert で 3 番目に戻す、とすると

$ git revert -m3 5580d0beb1
[main 2825475] Revert "Merge branches 'foo', 'bar' and 'baz'"
2 files changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 bar
delete mode 100644 foo

baz branch の状態になる。

感想

-m1 は merge commit を revert するときのおまじないとして覚えていたので、-m は merge の m ぐらいのつもりだったが、全然違った。

feature branch に main をマージした上で、branch 名を main にした (もしくは feature branch の push 先として main を指定してしまった)、というトラブルは git 生活 10 年超で初めて見て、面白かったです。

irb に show_source があることをもっと知らしめたい

要は以下の記事の繰り返しなのだが。

k0kubun.hatenablog.com

Kaigi on Rails _2022_ new というイベントの LT で、メソッド定義を探ろうという話があった。

speakerdeck.com

Rails のソースをシュッと眺めに行くという、非常に尊い良い発表でした。

Object のことは Object に聞け、は Ruby の非常に面白いところなので、Method を取り出して source_location を尋ねるのは一度体験して感動して欲しいんだけど、実務だとタイプ数の少ないやり方も知っておくと更に便利に使えるのでご紹介。

Pry の $

https://github.com/pry/pry

irb よりも色々できて便利な REPL、というのでよく使われている gem だと思う。その後 irb が追いついて追い越していったので多分使いどころは減ってきているが、既存のコードベースには入っていることも多いだろう。

pry には show-source (alias の $ をよく使う) という機能があって、メソッドの定義に非常に簡単にアクセスできる。

https://github.com/pry/pry/blob/v0.14.1/lib/pry/commands/show_source.rb

使い方:

$ bundle exec pry
[1] pry(main)> require "set"
=> true
[2] pry(main)> $ Set#merge

From: /opt/rubies/3.1.2/lib/ruby/3.1.0/set.rb:603:
Owner: Set
Visibility: public
Signature: merge(enum)
Number of lines: 9

def merge(enum)
  if enum.instance_of?(self.class)
    @hash.update(enum.instance_variable_get(:@hash))
  else
    do_with_enum(enum) { |o| add(o) }
  end

  self
end

メソッド表示時に Syntax Highlight も入っていて、非常に見やすい。

pry には pry-doc という plugin もあって、これを使うと C 言語で実装されているメソッドも読みに行けるのが好きです。

[1] pry(main)> $ puts

From: io.c (C Method):
Owner: Kernel
Visibility: private
Signature: puts(*arg1)
Number of lines: 9

static VALUE
rb_f_puts(int argc, VALUE *argv, VALUE recv)
{
    VALUE r_stdout = rb_ractor_stdout();
    if (recv == r_stdout) {
        return rb_io_puts(argc, argv, recv);
    }
    return forward(r_stdout, rb_intern("puts"), argc, argv);
}

最近 こちらのエントリ でも紹介されていた。(あれオレ)

IRBshow_source

irb にも show_source コマンドがある。というか pry の同機能が欲しくて id:k0kubun さんが入れた。

https://github.com/ruby/irb/blob/v1.4.2/lib/irb/cmd/show_source.rb

irbshow_sourceIRB::Color という Syntax Highlight の仕組みが使われていて、読みやすくなっている。

なお、irb の制限として「Rubyとしてvalidな入力しかできない」というのがあり、pry と同じ書き心地ではない ($ の alias は無いし、引数も文字列として渡さなければいけない) が、それでも irbshow_source があるのは最高です。というか、pry の show-source を多用しまくっていたので、これが無いと僕は pry を卒業できなかった。

そして、エントリにもある通り .irbrc に細工をすると $ を再現できる。

# .irbrc
IRB::Context.prepend(Module.new{
  def evaluate(line, *, **)
    case line
    when /\A\$ /
      line.replace("show_source #{line.sub(/\A\$ /, '').strip.dump}\n")
    end
    super
  end
})

軽く説明すると

  • IRB::Context.prepend
    • 入力を eval する部分に介入したいので IRB::Context#evaluateprepend で上書きする
  • Module.new{}
    • prepend && super するために無名モジュールを作っている
  • when /\A\$ /
    • 入力が $ で始まっていたら
  • line.replace("show_source #{line.sub(/\A\$ /, '').strip.dump}\n")
    • show_source "..." に書き換えて
  • super
    • evaluate を実行する

はい。

これでタイプ数少なく実装を読みに行けるようになった。show_source が期待と違った、という人もこれなら満足するんじゃないでしょうか。

$ irb
irb(main):001:0> $ Set#merge

From: /opt/rubies/3.1.2/lib/ruby/3.1.0/set.rb:605

  def merge(enum)
    if enum.instance_of?(self.class)
      @hash.update(enum.instance_variable_get(:@hash))
    else
      do_with_enum(enum) { |o| add(o) }
    end

    self
  end

=> nil

irb 上の入力を加工して eval する手段もこれで分かったので、自前の面白機能を育てていくと良いと思う。

ここがもう一声

pry の show-source--super がメチャクチャ便利なので、欲しい。

どんな機能かというと、show-source でメソッドを読んでいるときに super が出てきたら --super を付けると親クラスのメソッドを表示できるヤツです。

こういう C < B < A というクラスがあるとして、

class A
  def foo
    puts "A"
  end
end

class B < A
  def foo
    puts "B"
    super
  end
end

class C < B
  def foo
    puts "C"
    super
  end
end

--super を付けて呼ぶとこうなる。

[1] pry(main)> $ C.new.foo

From: (pry):13:
Owner: C
Visibility: public
Signature: foo()
Number of lines: 4

def foo
  puts "C"
  super
end
[2] pry(main)> $ C.new.foo --super

From: (pry):7:
Owner: B
Visibility: public
Signature: foo()
Number of lines: 4

def foo
  puts "B"
  super
end

複数回 --super を渡すと super_level が上がる。

[3] pry(main)> $ C.new.foo --super --super

From: (pry):2:
Owner: A
Visibility: public
Signature: foo()
Number of lines: 3

def foo
  puts "A"
end

というのが欲しいんだけど、引数に渡したオブジェクトの ancestors を --super の数だけ遡ればできそうではあるな。 .irbrc でやってみるかー。

Ultimate Hacking Keyboard のキーマップメモ

どこかに書いておかないと確実に忘れて困る。

UHK とは

コレです。

ultimatehackingkeyboard.com

割れてる、60%、row-staggered、半田付け不要で、これ以上沼に踏み込みたくない人間には最高です。 v1、v2 と 2 台買ってきた。

キーマップ

専用アプリでキーマップを変更し、キーボードに書き込める。接続されているキーボードをそれぞれ認識してくれるので、複数台持っていても安心です。

以下に設定していますが、とりあえずで使っているので全然拘れてない。丸 3 年ぐらい使ってて全然カスタマイズできていないのでだいぶ老化したと自分でも思う。

左右の Space(?)手前の謎キーを Mod にしているのが一番特徴的なんじゃないか。交換不能なところをよく使うキーにしているのは心苦しいが、親指で押しやすい他のキーが無かったので仕方ない。

Mod 二度押しで Mod レイヤーに固定できるのは、右手だけで pdf やスライドめくってるときとかに特に便利。

他はほぼほぼデフォじゃないかな。記憶がもう無い(からこのメモを書いている)。

一番のこだわりはキーマップ名 を ONK にしているところです。

ONK と光ると、自分のキーボード感が出て気持ちいい

使い心地

2 台買う程度に文句が無い。「人生最後のキーボード」は本当だと思う。

aotamasaki.hatenablog.com

割れてる 60% row-staggered キーボードは他に Mistel BAROCCO MD600v3 RGB Classic Black も持っているんだけど、親指周りにキーが少なすぎて、UHK に慣れた身ではまったく常用できる感じではなかった。

モジュールは Key Cluster Module と Trackball Module を買ってみて、Trackball Module は接触不良か何かで使えてない。

Key Cluster Module は普段使いには指が自然には届かなくてイマイチ。親指が他人より短くてな……。左手でもスクロールできるのは便利かなと思う。今思ったけど、左手だけでカーソルキー (特に )が使えるとめっちゃ便利なので、Mod 押したときにはカーソルキーになるようにしよう。

意識的に職位を下げる

僕はチーム join 時に、Docker は初手で剥がすし、GitHub Actions でやっているワークフローの全体像を把握するのを次に行う、というのを基本的にはやっている。これはシステム構成やデプロイ周りの全貌を把握するのが好きなのと、何かが起きたときにコレをやっているのといないのとで問題切り分けの精度に圧倒的な差があるからなんだけど、join 直後にやるのが最適解とは限らない場面もある。

チームの人員構成として、テックリード業を既に担っている人が居る場合、追加人員にはテックリード未満の「プラスの工数として数えられる戦力」となって欲しい。この戦力というのは、「目の前に積み上がった問題を一緒に解いて欲しい」という期待。問題と言うよりも、既にタスクになっているものを消化したい、という期待の方が大きいと思う。

そういう期待があるときには、ちんたら Docker を剥がしている場合ではなく、何も考えずに docker compose up の 1 コマンドで環境構築を終わらせ、テストもローカルでは実行せず CI に任せても良いので、タスクを消化した量を稼がなければいけない。今実行しているコマンドが何なのかは一旦「おまじない」で構わない。

つまり、言われたことしか作業しない兵卒プログラマとしてのロールに下げる、というのが期待されている。

この期待と行動とが一致していないと、周りからはガッカリ評価を貰うことになる。

「今この瞬間にクリティカルではない問題に時間を費やしている」 「チームが相対している目前の問題に対して、一緒に戦ってくれない」

チームの本当の問題を見つけにかかるのは、もう少し信頼を稼いでから。将校の役割を期待されるようになってからで良い。兵卒は、ブラックボックスブラックボックスのままとして扱うことも必要。

兵卒ロールとテスト

こういった兵卒ロールを保証するのが CI/CD である。

他のコードに影響を与えてしまうリスクは CI で担保されているので、変更したファイルの外の世界を全て把握している必要がない。デプロイに関する人類の叡智は YAML に落とされており、誰も具体的な 1 コマンドずつの手順を知らなかったとしても粛々と動き続けてくれる。

テストコードがある世界はすごくて、すべてのコードに「間違いなく動く自信」が無くても構わない世界に連れて行ってくれる。「自信は無いけどコンパイラは怒っていないし CI も通ってるので多分動くだろう」という曖昧な認識で作業を完了しても大丈夫なのだ。この状況を作り出すためには一定以上のテストカバレッジが必要になるが、いちど閾値を突破するとテストに信頼が置けるようになり、兵卒が兵卒として生きていられる環境が成立するようになる。

プログラマの教育では「書いた全ての行について、影響を説明できるようになれ」というのを口を酸っぱくして言ってきたが、これは実は兵卒ロールに対しては過剰な努力であって、CI さえ通ってれば気にしなくても良いのかもしれない。(というのは言い過ぎで、その気になれば追える能力を持った上で、意識的に自分で上下できるとより良いよね、ということを言いたい)

考えたきっかけ

テストコードが無い世界で、テストの導入を渋る人にどう説得するのか、テストのメリットとは何なのか、という話題を見て。

テストのメリットは手動テストの時間短縮と、考慮漏れに気づける場合があることだと思っている。時間短縮は素朴に短縮できるのでやればいいが、考慮漏れの方は、僕自身が全貌を把握しているプロジェクトでは、自分ではテストを必要としていないよなぁという感想を抱いた。逆に言うと全貌を把握していなくてもコードを書けるようになるのがメリットで、全貌を把握しないという選択肢があるし、それを要求されることもある。

実際、全貌を把握しきっていないプロジェクトだと型が欲しいしテストも助かる。型さえあれば勘でコードが書ける。*1

全貌を把握することは必要ないのかと言うと、テックリードやアーキテクトの役割なら必要だろう。意思決定をするためには、どこに問題があるのか、何に効くのかを知っていると良い。そして何をするとどこがどうなるのかをだいたい知っているなら、テストの嬉しさは少ない。つまりテストの期待は「テックリードではない誰か (数ヶ月後の TL 自身も含む) が最低限の成果を出せることを保証する」ことと言えるんじゃないか。

*1:型がなくても勘でコードを書けるのが Rails というレールの凄いところだとも思う

使用頻度とコマンド (エイリアス) の文字数を合わせたい

1 文字エイリアスのすゝめ

1 文字エイリアスが好きで、例えば

alias s="git status -sb"

している。

入社してからの 4 年半で溜めた 53 万行の .zsh_history から集計すると、

$ history 1 | awk '{ print $2 }' | sort | uniq -c | sort -nr | head
121714 g
114128 s
57124 v
34210 cd
26095 tig
23281 rg
11382 plenv
10837 t
9647 :q
6867 ll

となった。ちなみに以下の略です。

alias g="git"
alias s="git status -sb"
function v() {vi -p ${${=*/:/ +}/:*}}
alias t="tig"
alias :q="exit"
alias ll='ls -lFG'

cdplenv は主に fzf 経由で入力しているので、おそらくこんな頻度では入力していないはず。 fzf は bindkey '^s' とかに割り振られています。

1 年前ぐらいにも似たような集計をして、よく使ってる tig に 3 文字も費やしているのは最適化できていないな、と思って alias t="tig" を追加したのでした。

github.com

t の追加後は

$ history -152000 | awk '{ print $2 }' | sort | uniq -c | sort -nr | head
40638 s
37374 g
14205 v
10817 t
8550 cd
6760 rg
3948 plenv
2491 npm
1499 ll
1023 docker

と、しっかり 1 文字が上位に食い込んでいることが分かる。なお今は ll は更に短く l 1 文字にしたし、 alias d="docker" も追加済みです。

1 文字にするだけでいいのか

alias g="git" なので、g の後にサブコマンドを打っているはずなんだ。サブコマンドも含めて集計しよう

$ history 1 | awk '{ print $2,$3 }' | sort | uniq -c | sort -nr | head -n 20
114047 s
22225 tig
20599 g a
13867 g ci
11149 plenv exec
11072 g ds
10728 g co
10686 v
9726 t
9647 :q
7681 g f
6019 ll
5969 g ap
5042 g fix
4839 com
4716 g switch
4650 g b
4279 bundle exec
4169 g r
3881 g ri

g の色んなサブコマンドが出てきている。

それぞれ

a = add
ci = commit -v
ds = diff --staged -b
co = checkout
f = fetch -p
ap = add -p
fix = commit -v --amend
b = branch
r = rebase
ri = rebase -i

なんだけど、こんなに入力しているならサブコマンドではなく、alias a="git add" にするとか、空いている 1 文字エイリアスに格上げするのが望ましいはず。

サブコマンドをどんどん登録していくと 26 文字を超えちゃうんじゃないかって心配をするかもしれないけど、大文字や記号もエイリアスに使えるという発想を忘れてはいけない。50 文字ぐらいはしれっと行けるので、柔軟にやっていきましょう。少なくとも g a より ga の方が 1 文字少ないので、2 文字には縮めたい。

alias or abbr

主に fish 派閥から、「これからは alias じゃなく abbr だ」のような言説をよく目にするが、こうして使用頻度に合わせてログから最適化しようと思うと、やっぱり alias を使っている方が望ましいのではないか。 いやこれは僕はマジでよく知らなくて、もし入力文字列も history に残ってるなら何の問題無いので、abbr を使うなと言っているわけではない。

とにかく使用頻度に合わせて最適化したい。