ちなみに

火曜日の空は僕を押しつぶした。

ボーイスカウト・ルール、先に直すか、後から直すか。

まれによく目的の変更にリファクタリングを混ぜたプルリクのレビュー依頼を受けるので、そのたびに変更とリファクタリングは分けてねって話をしている。

レビューするときにもdiffが混ざっていて見にくいし、将来的に変更の経緯を追いかけるときにもノイズになってしまう。 コミットが分かれていたらまだマシなんだけれど、そういう場合はたいてい同じコミットに複数の目的が混ざってしまっている。

www.clear-code.com

僕は1コミットには1つのことというルールを出来るだけ守ろうと思って暮らしているのでどちらかというと過激派なのですが、プルリク単位くらいではやることを絞って欲しいとは思っています。

みんな単一責任原則は大好きな気がするけど、コミットやプルリクにも同じ姿勢で取り組んで欲しい。

話はそれたのですが、ボーイスカウト・ルール。 来たときよりも美しくっていうやつです。 言うは易く行うは難しというやつで、簡単に見えてこれをチーム全員で当たり前のようにやっていくのはなかなか難しい。

最初の話から機能変更と一緒にリファクタリングするのはよくないと思っているのですが、じゃあいつするのかと言うと、変更の前か後になります。

なんとなく期日に対するプレッシャーがあると、先に機能を実装してしまって、あとから余裕があったらリファクタするということになりがちなんじゃないかと考えています。 しかしながら、なんで綺麗にするのかというと、今後のメンテナンス、つまり機能追加や不具合修正なんかをやりやすくするためです。

つまり何が言いたいかというと、先にリファクタリングした方が、機能追加も楽になって、結果的に早く価値を届けられるのではと言うことです。 しかもメンテナンスしやすいコードになったということは、より品質の高い価値となってユーザーに届くのではないでしょうか。

あとからリファクタリングするということは、綺麗に出来るコード、つまり綺麗じゃないコードに対して頑張って機能を追加したのだから、複雑度が増してしまっていて変更にも時間がかかるし、不具合が発生する確率が高まっていると思うのです。 そして多くのは場合は「あとでやる」と決めたことは実行されません。 つまりユーザーに対して価値を提供したつもりが、システムとしては価値の毀損を招いているとも言えるのではないでしょうか。

よって僕は機能を追加する前にボーイスカウト・ルールを発動するべきだと思うのです。

Gitのおすすめエイリアス5選

motemen.hatenablog.com

触発されて自分も地味だけどよく使っているのを紹介します。

変更を無視してpullする (git st-pull)

st-pull = "!git stash && git pull && git stash pop"

手元に変更があってまだコミット出来ないけど、最新の変更をpullして持ってきたいときに使う。 軽減される労力はめっちゃ小さいけど、積み重なるとそれなりに時間を使っているのでこういう手抜きは重要。

タグやリモートの一覧を表示する (git tags / git remotes)

tags = tag -l
remotes = remote -v

ちょっと一覧したいだけなのに微妙にやり方が違っていつも混乱するので複数形で一覧出来るようにしています。

今見ているブランチをGitHubで表示する (git open)

open = !gh browse -b $(git symbolic-ref --short HEAD)

僕は gh を使っています。

コンフリクトしたファイルの一覧を出す (git ls-conflict)

ls-conflict = !git ls-files -u | cut -f2 | uniq

複数のファイルがコンフリクトしたときにどれがコンフリクトしたかをサクッと一覧に出来る。 最近はVSCodeなんかが優秀なのでそこまで使わないですがたまに便利。

すべての変更を無にする (git bang)

bang = "!git clean -df && git reset --hard"

untracked なファイルも消すし、コミットしていない変更も消す。 適当に試してみてうまくいかなかったら消すということを良くやるので1日に何度も叩くやつ。 ときおり必要な変更を消し去ってしまって泣く。

iPad Proを買いました

f:id:Sixeight:20220322234809j:plain

初代 iPad Pro を買ってからそれに満足して長いこと新しいのを買っていなかったのだけれど、流石に遅いなあと思うようになってきたので久しぶりに買い替えました。Apple製品を出るたびに買っていた時期のことを考えると実質無料ですね。

M1なのでというか7年分の進歩なのでめちゃ快適になりました。

ついでなので Apple Pencil 2 も買ったのですが普通に使えて笑っています。これも1を持っていたのですが、今から考えると実用は厳しい感じだったので進化を感じました。技術はすごい!!!

そしてキーボード好きとしてはやらざるを得なかったBluetooth接続。と言っても技適通っているのがHHKBとMagic KeyboardくらいしかなかったのでHHKBを使ってみる。これはかなり感動して普通に使える。iPadが急にコンピュータになった。最初からコンピュータなのだけれど。

基本的には本を読んだり映画や動画を観たりする用だと思っていたのですが、普通に何か書いたりするのに使えそう。

このブログも iPad と HHKB で書きました。

ひさしぶりにzshに戻りました

仕事用のマシンをM1 MacBook Proに交換してもらったので、開発環境を整え直しました。

2年ほど fish を使ってきたのだけれど、普段は良いのだけれど、ちょっと自動化したくなったときに、やはりPOSIX準拠じゃないシェルはなかなか難しかった。macOSの標準も zsh になったことだし、久しぶりに戻ってみることにした。

導入

現代なので XDG Base Directory Specification に乗っかっておくことにする。 Arch LinuxWiki がよくまとまっていて助かるのでこれを参考にして進めた。

zshの場合は ZDOTDIR を指定するといいのだけれど、これをどこで指定するのかという問題がある。zshの起動時に最初に読み込まれるユーザー設定は ~/.zshenv なのだけれど、ここに ZDOTDIR を書くということは .zshenv だけホームディレクトリに残ってしまう。これはちょっと気持ち悪い。

あんまり嬉しくはないのだけれど、諦めて /etc/zshenv に書くことにします。

ZDOTDIR=$HOME/.config/zsh

これで zsh のユーザー毎の設定ファイルは ~/.config/zsh から読まれることになります。(仕事用の macOS だし自分しかユーザーはいないしまあいいでしょ)

次に仕様に沿った環境変数~/.config/zsh/.zshenv 設定していきます。 特にひねることはないので推奨のディレクトリにしておきます。 (GOPATH~/localghq のルートディレクトリを ~/local/src にしているので ~/.local はちょっと気持ち悪くはあります。)

export XDG_CONFIG_HOME="$HOME"/.config
export XDG_CACHE_HOME="$HOME"/.cache
export XDG_DATA_HOME="$HOME"/.local/share
export XDG_STATE_HOME="$HOME"/.local/state

はい、これで基本的な準備は整いました。

zsh は最新のものを使いたいので Homebrew でインストールしておきます。

$ brew install zsh

Zim

zsh をそのまま使うなんてことは出来ないので、設定をごりごり書いていきたい訳ですが、最近はもう自分で設定を書くのは面倒になっています。 もうちょっと若いときは無限に設定ファイルを触っていられたのですが、こうやってどんどん新しいことを学べなくなっていくのです。

設定なしに良い感じになって、かつ Oh My Zsh の遅さに辟易としていたのでとにかく速いのを探しました。

いくつか見て回って Zim が良さそうだったのでこれを導入します。

導入は最近よく見る curl を叩くやつ。

$ curl -fsSL https://raw.githubusercontent.com/zimfw/install/master/install.zsh | zsh

.zshrc にいくつか設定が書き込まれます。よく見ると設定が読み込まれたときにさらに本体のダウンロードを行うようです。

なんとこれだけでまあまあ良い感じに動きます。そして起動が速い!!!

asciiship という SpaceshipStarship を ASCII 文字だけで表現したテーマがデフォルトになっているのですが、もうこれでいいや感があったのでそのままにしています。どんどんこだわりが失われていっている。

他にもテーマがあったり、公式のモジュールもあるので ドキュメント を参照してください。

その他の設定

履歴ファイルの設定だけ .zshenv に書いても効いてくれなかったので以下のように .zshrc に書きました。 zim が上書きしている感じなのですが、設定済なら無視するように書かれているように見えるので多分何かを間違っているだけなはず。しかし調べる元気がない。

export HISTFILE="$XDG_DATA_HOME"/zsh/history

あとは cdr とか AUTO_CD 周りの設定を少し書いた。 AUTO_CD 自体は Zim が有効にしてくれている。

# cdrを有効にして設定する
autoload -Uz chpwd_recent_dirs cdr add-zsh-hook
add-zsh-hook chpwd chpwd_recent_dirs
zstyle ':completion:*:*:cdr:*:*' menu selection
zstyle ':chpwd:*' recent-dirs-max 100
zstyle ':chpwd:*' recent-dirs-default true
zstyle ':chpwd:*' recent-dirs-insert true
zstyle ':chpwd:*' recent-dirs-file "$XDG_DATA_HOME"/zsh/chpwd-recent-dirs

# AUTO_CDの対象に ~ と上位ディレクトリを加える
cdpath=(~ ..)

u というリポジトリのルートディレクトリに移動する関数を書いておく。 これはたしか ujihisa さんの設定から持ってきたのをずっと使っている気がする。 今回は補完関数も書いたけど、そこまで便利じゃないしバグがある。

function u() {
  cd ./"$(git rev-parse --show-cdup)"
  if [ $# = 1 ]; then
    cd "$1"
  fi
}
_u() {
  _values $(fd --type d --base-directory $(git rev-parse --show-cdup))
}
compdef _u u

zsh-abbr

fishで一番良かったのが abbr だったと思うので、これを zsh でも再現させたい。 abbr は alias とは違って、省略形のコマンドを入力すると省略しない形に展開してくれるやつ。 g って入力してスペース打つと git に展開してくれる。 alias を覚えるのがつらくなってきたので展開してくれる方が元のコマンドに紐付けて覚えるので助かる。

zsh で同じ機能を実現するのに zsh-abbr が使えるのでこれを導入した。

zim にはプラグイン機構もあるのでこれを使って導入する。

$DOTDIR/.zimrc に以下の一行を加えて zimfw install というコマンドを打つだけ。

zmodule olets/zsh-abbr

これで導入が完了するので設定していく。abbr コマンドを使っても設定できるが $DOTDIR/abbreviations に書いておくと一括で指定出来る。 僕は以下のようにしている。

abbr b="bundle"
abbr be="bundle exec"
abbr d="docker"
abbr dc="docker compose"
abbr di="git diff"
abbr e="exit"
abbr g="git"
abbr gd="git diff --cached"
abbr ggrep="git grep"
abbr gl="git log"
abbr gr="git restore"
abbr gs="git switch"
abbr l="git log"
abbr p="git pull"
abbr pick="git cherry-pick"
abbr pop="git stash pop"
abbr s="git status -sb"
abbr st="git stash"

fzf

これまではコントリビュートする程度には peco を使ってきたのですが、気分を変えようと fzf に移行しました。 なんか勝手に重いイメージだったけれど、別にそんなことはなかった。 fzf は preview が出せるのが見た目が良くて楽しい。

導入はREADMEに従って Homebrew でインストールした。

$ brew install fzf
$ $(brew --prefix)/opt/fzf/install

補完の設定が生成されるので、それを .zprofile とかで読み込んでおく。

[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh

ここまですると Ctrl-rzsh の履歴検索、 Ctrl-t でカレントディレクトリ以下のファイル検索が fzf 経由で出来るようになる。

モダンなコマンド達と組み合わせるために fzf module を追加しておく。 モダンなコマンドというのは fdbat のことです。

zmodule fzf

$DOTDIR/.zimrc に追加して zimfw install する。

これでファイルの検索が爆速になるし、プレビューがカラフルで見やすくなる。

あとは良い感じのをいくつか定義しておく。

まずはデフォルトの設定を .zshenv に書いておく。peco のデフォルトに慣れているので --layout=reverse だけは外せない。あとはお好みで。

export FZF_DEFAULT_OPTS='--layout=reverse --border --exit-0'

最近はほとんどを VSCode の中で過ごしているので使う機会は限られているのだけれど、必要そうなのを書いておく。

ghqリポジトリを選んで移動するやつ。最低限これさえ出来ればあとはどうでもいい。

fzf-ghq() {
  local repo=$(ghq list | fzf --preview "ghq list --full-path --exact {} | xargs exa -h --long --icons --classify --git --no-permissions --no-user --no-filesize --git-ignore --sort modified --reverse --tree --level 2")
  if [ -n "$repo" ]; then
    repo=$(ghq list --full-path --exact $repo)
    BUFFER="cd ${repo}"
    zle accept-line
  fi
  zle clear-screen
}
zle -N fzf-ghq
bindkey '^[s' fzf-ghq

プルリクを検索しつつそのブランチに switch するやつ。 仕事では JIRA を使っていて、ブランチ名をチケットの番号にしているので目的のブランチを探すのが大変なことがある。 そんな時にはプルリクから検索して切り替えられると便利なので追加した。 gh が必要なのでインストールしておきましょう。 最近 id:shiba_yu36 さんが pecoで似たようなこと をされていた

fzf-pullreq() {
  local pullreq=$(CLICOLOR_FORCE=1 GH_FORCE_TTY=100% gh pr list | tail -n+4 | fzf --ansi --bind "change:reload:CLICOLOR_FORCE=1 GH_FORCE_TTY=100% gh pr list -S {q} | tail -n+4 || true" --disabled --preview "CLICOLOR_FORCE=1 GH_FORCE_TTY=100% gh pr view {1} | bat --color=always --style=grid --file-name a.md")
  if [ -n "$pullreq" ]; then
    pullreq=$(echo $pullreq | awk '{ print $1 }')
    BUFFER="gh pr checkout \"${pullreq}\""
    zle accept-line
  fi
  zle clear-screen
}
zle -N fzf-pullreq
bindkey '^[p' fzf-pullreq

Git のブランチを切り替えるやつ。特におもしろみはない。

# ブランチを選択して switch する
fzf-branch() {
  local format="\
%(color:yellow)%(refname:short)%(color:reset)|\
%(color:bold red)%(objectname:short)%(color:reset) \
%(color:bold green)(%(committerdate:relative))%(color:reset) \
%(color:bold blue)%(authorname)%(color:reset) \
%(color:yellow)%(upstream:track)%(color:reset)|\
%(contents:subject)"

  local branch=$(git for-each-ref --color=always --sort=-committerdate "refs/heads/" --format="$format" | column -ts "|" | fzf --preview "git log --color {1}")
  if [ -n "$branch" ]; then
    branch=$(echo $branch | awk '{ print $1 }')
    BUFFER="git switch ${branch}"
    zle accept-line
  fi
  zle clear-screen
}
zle -N fzf-branch
bindkey '^[b' fzf-branch

前半で設定した cdr のディレクトリを選択して移動できるやつ。

# cdrの履歴からディレクトリを移動する
fzf-cdr(){
    local dir=$(cdr -l | fzf --preview 'f(){ zsh -c "exa -h --long --icons --classify --git --no-permissions --no-user --no-filesize --git-ignore --sort modified --reverse --tree --level 2 $1" }; f {2}')
    if [ -n "$dir" ]; then
        dir=$(echo $dir | awk '{ print $1 }')
        BUFFER="cdr ${dir}"
        zle accept-line
    fi
    zle clear-screen
}
zle -N fzf-cdr
bindkey '^[r' fzf-cdr

しれっと exa を使っているのでこれもインストールしておきましょう。 ls などを exa に読み替えてくれるモジュールがあるのでこれも入れておく。いつも通り .zimrc に追加して zimfw install です。

zmodule exa

ls挙動 をちょっと弄りたかったので以下のようにしています。

alias ls='exa --classify --icons -h --reverse'

これで fzf を最低限は使えるようになりました。


この記事は Cornelius で書きました。

N+1なの? 1+Nなの?

むずかしいですね。

M1 MacでもApple Watchでsudoのパスワード入力をする

tl;dr

github.com

ARMアーキテクチャでビルドするフォークがあるのでこれを使いましょう。 /etc/pam.d/sudo に書き込み権限がないので sudo chmod +w /etc/pam.d/sudo する必要があるかも。 パーミッションを戻すのを忘れないようにしよう。

はじめに

最近、会社のPCをM1 MacBook Proに交換してもらったので、ちまちま環境を作っている。 一括管理になっていて移行エージェントが閉じられているので手で移行する必要があって、環境を見直すいい機会になっている。

ところで、僕はとてもめんどくさがりなのでパスワードを打つのも出来るだけ避けたい。 幸いなことに Apple Watch を持っているので使えるところでは使っていきたい。

失敗

sudo 時のパスワード入力を Apple Watch で代替するには pam_watchid.so を使う方法がある。

github.com

これまでもこれを使ってきたので、何も考えずにインストールしたところ以下のように sudo が動かなくなってしまった。

sudo: unable to initialize PAM: No such file or directory

/etc/pam.d/sudo を編集するのにも管理者権限が必要なので sudo が必須になってくる。 詰んだと思ってシングルユーザーモードを覚悟したのだけれど、調べてみると Finder からファイルのパーミッションを変更出来るらしい。

Finder から /etc/pam.d/sudoGet Info から一般ユーザーにも編集権限を追加する。 右下の鍵アイコンを外しておく必要があるので注意。

f:id:Sixeight:20220305224843p:plain

これで普通に編集出来るようになったので事なきを得た。

原因と解決

単純な話で x86_64 でビルドしているので当然ARMでは動かない。

TARGET = x86_64-apple-macosx10.15

all:
  swiftc watchid-pam-extension.swift -o $(LIBRARY_NAME) -target $(TARGET) -emit-library

github.com

幸いにも変数になっているのでビルド時に指定してやればよい。

$ sudo make install TARGET=arm64-apple-maxosx12.2

これで無事に動くようになった。

さらに調べてみる

M1が出たからもう一年以上経っているので流石に誰かやっているやろと思って探してみたらやはり対応したフォークがあったのでこちらを使うことにした。

github.com

ビルドターゲットの指定では apple-darwin$(vesion) の方がよさそう。