ちなみに

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

「Tidy First?」を読んだ

www.oreilly.com

Kent Beck 御大による、ソフトウェア設計に関する書籍シリーズの第一弾である「Tidy First?」を読みました。

この本では開発中に散らかってしまうコードをいかに片付けて、読みやすい状態を保つかについて説明されます。 ソフトウェアの設計は人間関係のエクササイズだとし、シリーズ第一弾である本書ではまずは一人で行える範囲の話題を扱います。

リファクタリングのサブセットとして、誰もが気に入って反対する人もいないくらいの小規模の改善と "Tidying" として定義して、代表的な Tidying のカタログと、その適用方法、そこから踏み込んで理論的な解説が続きます。

Tidying

どうして Tidying が必要になったかと言うと、御大は以下のように最近の「リファクタリング」という言葉の使われ方を嘆いている。

“Refactoring” took fatal damage when folks started using it to refer to long pauses in feature development. They even eliminated the “that don’t change behavior” clause, so “refactoring” could easily break the system.

リファクタリング」は、機能開発を長期間止めることを指す言葉として使われるようになって致命的なダメージを受けてしまった。彼らは「振る舞いを変更しない」という条項さえ削除してしまってので、「リファクタリング」によって容易にシステムが破壊されるようになたのだ。

どうしてコードが散らかっていると駄目なのだろうか。

本書ではソフトウェアを変更するコストを、コードを理解するコストとニアリーイコールであるとしている。 コードが散らかっているとコードを理解するコストが上がり、結果的に開発速度も落ちてしまう。

つまり Tidying をしてコードが理解しやすくなると、将来的な変更のコストも下がって、選択肢が増えるということである。

Managing

コードの変更を「振る舞いの変更」と「構造の変更」に分けて解説している。「振る舞いの変更」は直接的な価値を生むが、「構造の変更」は間接的な価値しか生まない。

「構造の変更」= たとえば Tidying が価値を生むケースは cost(change) > cost(change + tidying) ということになる。 この式から分かる通り、Tidying によって理解しやすくなったコードを変更することによって、何もせずに変更する場合よりコストが下がる場合だけ適用すべきということになる。

つまり、Tidying は「振る舞いの変更」より長い時間をかけて行うべきではないことが分かる。

ではいつ Tidying をするべきかについても書かれている。コードを変更する前に行うのか、すぐ後に行うのか、ずっと後に行うのか、やらないのか。 これまで説明したとおり、変更のコストが下がるのであれば先にやるべきではある。ただし、どうやるべきかがはっきり見えてなかったりすると後でやった方がいいケースもある。 忙しくて時間がない場合もあるだろう。そういうときは Fun List (= Tidying は楽しいのでTODOリストではない) に書いておいてあとでやるということも可能である。 また、そのコードを二度と触らないのであれば、コードが散らかっていても問題はないと言えるので、やらない方がよい場合もある。

blog.nishimu.land

いつやるかというのは以前から僕も気になっていたテーマだったので、答え合わせのような内容でとても良かった。

他にも面白かったのが、レビューのコストについての話で、レビューのコストもチリツモで影響が出てくるので、Tidying による「構造の変更」についてはレビューするべきではないという書かれている。 逆にいうとレビューが必要なくらい複雑な変更は Tidying ではないということでもある。 ただし、これを実際にやるのはかなり勇気がいるので実践はできていない。

Theory

このパートはおもしろくて経済とソフトウェア開発について書かれている。 「ディスカウントキャッシュフロー」と「オプション取引」についてをソフトウェア設計に当てはめて解説されている。

「ディスカウントキャッシュフロー」は未来の価値より今の価値の方が高い。 つまり早く手に入れて、支払を出来るだけ遅らせる方が得という話で、これをソフトウェア開発に置き換えると、出来るだけ早く機能開発をすることで、顧客に届ける価値が高まるということになる。(=開発者は収益を得られる) 開発の初期段階はまだ何の価値も得られていないので、特にこの傾向が強まることで、直接的に価値を生む「振る舞いの変更」を優先してしまいがちである。

オプション取引」は将来購入する権利を買う取引で、例えば「一週間以内に10,000円で株券を買う権利」を買ったとすると、株の値段が10,000円を超えたらお得だし、下回ると損になる。 ちなみにこれは「買う権利」でしかないので放棄することも出来るのがみそである。 これをソフトウェア開発に適用すると「構造の変更」を行うモチベーションになるという話である。 つまりコストを払って「構造の変更」を行うことで、将来の変更しやすさが高まり、システムとしての選択肢が増やせるので、その時に手に入る価値が妥当だと思うならコストを払うべきと言える。

ところで本書ではソフトウェア開発全体のコストを以下のように定義している。

cost(software) ≒ cost(change) ≒ cost(big change) ≒ coupling

つまり変更のうち大きな変更のコストが支配的で、そのコストは「結合」からきていると言うのだ。

「結合」しているとは「同時に変更する必要がある」ということであり、「結合度」が高いと同時に変更する箇所が増えてしまうので、変更のコストも上がるということである。 それではとにかく「疎結合」にすればいいかというとそうでもなくて、結合度が0のソフトウェアは存在しないし、結合度を下げるにもコストがかかるのである。 ここら辺は「要はバランスおじさん」が登場している。

Conclusion

最後に一番好きな一文を紹介して終わります。

The world is challenging enough that we can’t afford to ignore opportunities to make things easier for ourselves and others.

この世界は過酷なので、物事を簡単にする機会を逃すわけにはいかない

もうすぐ日本語版も出るみたいなのでとっ散らかったコードをなんとかしたいと思っている人はぜひ。

また、第二弾の「Tidy Together?」も執筆中なので楽しみです。

tidyfirst.substack.com

TSVファイルをCLIでテーブル表示する

なんかあるやろと思ったら macOS にも標準で入っている column コマンドで十分だった。 miller とかを眺めていたが高機能すぎて持て余したのでこれで良かった。

これが、

$ cat service.tsv
Twitter X
G Suite Google Workspace
Office 365 Microsoft 365
HipChat Stride

こうなる。

$ cat service.tsv | column -t -s $'\t'
Twitter     X
G Suite     Google Workspace
Office 365  Microsoft 365
HipChat     Stride

ポイントは $'\t でまったく知らなかったのだけれど対応しているシェルだと $'<エスケープシーケンス>' と書くとエスケープシーケンスを解釈した結果に置き換えてくれるらしい。(see also)


最終的にやりたかったのは gh の結果をシュッとテーブル形式で表示するので以下のような感じで扱えて見栄えがよくなった。(スクショ参照)

$ gh pr list --json 'number,author,title,headRefName' -q '.[] | [ "#" + (.number | tostring), "@" + .author.login, .title, .headRefName] | @tsv' | column -t -s $'\t'

ちなみにこれだとデフォルトの表示の方が綺麗なのであくまでサンプルです。

tigでfixupを簡単にする

2つ以上前のコミットを修正したいときに --fixup を使うのは近年ではよく知られている。

$ git commit --fixup <commit>
$ git -i --autosquash <commit>~ # rebase.autosquash = true にしておけばオプションは不要

しかし、この方法だと毎回 $EDITOR が開いてしまいちょっと面倒である。

これを回避する方法は GIT_SEQUENCE_EDITOR 環境変数を使う方法で GIT_SEQUENCE_EDITOR=true などとしておくと、エディタを開かずに rebase が完了する。

また git 2.44 以降は --interactive じゃなくても --autosquash が可能になったためさらに簡単になった (GitHubのブログが詳しい)

これを使うと以下のような alias を定義することができる。

fixup = "!f() { git commit --fixup \"$1\"; git rebase --autosquash --autostash \"$1\"~; }; f"

--autostash は自動で stash してくれるオプションで、他の変更があるときに先に fixup したいときにべんり。 残念ながら rebase.autosquash は interactive mode にしか有効でないので、オプションの指定は必須。

ここまでくると目的のファイルを stage に index しておいて、git fixup <commit> とするだけでコミットの修正が完了するようになる。

しかし、この commit hash をコピペするのも面倒になってきたので、今回 tig の設定に以下のような bind を追加した。

bind main F @git fixup %(commit)
bind log F @git fixup %(commit)
bind diff F @git fixup %(commit)

これで tig の main view などで目的のコミットにカーソルを合わせて F って押すだけになってめちゃくちゃ楽になった。

zshの補完関数が適用されなくて困った

めっちゃしょうもない話だけれど、新しく追加した補完関数がどうしても適用されなくて困っていた。

fpathが通ってないのかと思ったけどそんなこともない。

$ echo $fpath | tr ' ' '\n' | grep '目的のファイル'

うーんと唸ってChatGPT先生に聞いてみたらキャシュじゃないかってことだった。

$ rm ~/.config/zsh/.zcompdump

これでzshを起動しなおすと無事に適用された。

フラワードリッパーDEEP27を導入した

最近ちょっとコーヒー関連がマンネリになってきてしまって、あんまり楽しくなかった。 美味しいから飲んでいるけど、行為そのものを楽しまないと愉快な人生とは言えない。

ある日、フィルターが切れかかっていたので、新しいのを購入しようとしたところ、関連商品に同じ会社のなんか長細いフィルターが表示された。 なんだこれはと思って気になって調べたら、DEEP27という一杯取りの長細いドリッパーがあるらしい。

フラワードリッパーは試したことがなかったし、この長細いフォルムが面白かったのでマンネリ打開にはちょうど良さそうということで買ってみた。

抽出は基本真ん中に注ぎつづけるだけで、注ぐ速度と落ちる速度が同じくらいになるのがいいらしい。簡単!

いまのところ2回くらい使ってみたけど、まだうまく淹れられなくて、いっしゅんめっちゃ美味しい予感がするのだけれど、奥からエグ味がやってきてしまう。ちゃんとレシピを見ずにやっていたので、次はちゃんとレシピを見てみようと思う。2杯作りたいので、なかなか出番がないんだよな。

朝おきて、ドリッパーを選ぶところから一日が始まるのはやっぱり楽しい。

cafec.shop

VSCode Neovim に移行した

きっかけ

産まれてからずっと Vim キーバインドで生きてきました。

エディタは VimAtomEmacsVSCode と渡ってきたけど、いつだって Vim キーバインドです。

もちろん VSCode でも VSCodeVim を使ってきました。 こいつはVimの動きを頑張ってエミュレートしていて努力の結晶という感じなのですが、概ね良い感じで動いていて、VSCode に移行した日から今までずっとこれを使ってきました。

VSCode Neovim という存在は以前から知っていました。初めてみたときに Neovim と通信して VSCode 上で Vim そのものの動作を実現するというのを読んでそこまでしてやりたいことか?と思ったのを覚えています。なぜか Neovim に対していい感情を持っていなかったというのもあったと思います。「ナードは黙って Vim 」とか思ってました。(なお当方 VSCode 使い)

しかし、同僚が使っている Neovim を見てからは、ネガティブな印象が払拭されていて、さらに VSCode Neovim紹介記事 をたまたま読んだことで、いっちょ試してみるかと移行してみました。

移行作業

馴染まない可能性をかんがえて VSCodeVim はアンインストールせずに無効化して進めました。

導入は Getting Started を見るとよくてシュッと完了します。NeovimHomebrew でシュッと。起動すると Vim の操作が即座に有効になります。Insert モードは VSCode に完全に委ねられるので、ネイティブの Extension とカニバることもなし。

次は Neovim の設定です。過去の .vimrc はもう参考にならないだろうし、ゼロから設定することにしました。Lua で書けるらしいので、じゃあそれで。XDG Base Directory Specification に対応しているので、~/.config/nvim/ 以下に設定を書いていきます。

ディレクトリ構成はこういう感じになった。VSCode 用の設定を分けたけど、それ用の設定しか要らないので分ける必要はなかった気がする。設定はほとんどキーマッピングで凝ったことはしていません。そもそも多くの設定は VSCode 向けには意味がないし。

- nvim
    - lua
        - config
            - lazy.lua
            - vscode.lua
        - plugins
            - init.lua
    - init.lua

プラグインマネージャには Lazy.nvim を選択しました。なんにも分かってないのでひとまず有名っぽいものを。 いろいろプラグインの紹介記事を眺めながら、VSCode でも動きそうなものを選んでいきます。ふつうに動いていてすごい。

いったんこういう布陣になりました。VSCodeVim では出来ていなかったことを実現できてめっちゃ助かり。 (clever-f が欲しくて欲しくて...) おすすめのやつがあったら教えてください。

あとは VSCode 側に書いていたキー設定で vim.mode == insert とか書いていたのを neovim.mode に置き換えて完成。

まだこれで仕事のコードを書いた訳じゃないけど、今のところ快適に使えています。

よしあし

VSCode Neovim

  • pros
    • 速い (ひっかかりを感じなくて快適)
    • 各種プラグインが動く
  • cons
    • 別途 Neovim のインストールが必要 (依存が増えてリスクも増える)
    • 設定ファイルの資産がないとゼロから書かないといけない
    • マルチカーソル関係が弱い (特に VSCode 側の選択位置との連携ができないところ)
      • editor.action.addSelectionToNextFindMatch で目的の単語を全部選択してから c で置換とか出来なくなった

VSCodeVim

  • pros
    • 入れたら即使える
    • 困ることがほぼない (いっかい undo が爆発したけど)
  • cons
    • 動作がじゃっかんもっさりする
    • 設定ファイルを settings.json に書くので肥大しがち
    • エミュレートしているので若干本家と動きが違う
    • プラグインを足せない

それでもVSCodeにこだわる

そこまでするなら NeoVim に移行すればいいじゃんという話はある。話はあるけど僕は VSCode を使いつづけます。

あんまりいい言語化はできないのだけれど、コミュニティやエコシステムの規模が段違いなので安心感があるのと、手触りがめっちゃ気に入っているというところなのかもしれない。 キーボードでやることとマウスでやることのバランスがちょうどいいのかもしれない。キーボードは好きですが別に全部キーボードで操作できなくてもよい。GUIの方が見た目も触りやすいしね。

感情的なことをいうと VSCode が好きなので使いつづけます。

楽しみながら続ける

今年に入ってからあんまり元気がなかったので、元気を出そうと思ってエアロバイクをこいでいる。元気がなくて運動できないのじゃなくて、運動していないから元気がないのである。

朝に無理しないように15分だけこぐようにしていて、最初はオーディオブックを聞いたり、真面目なYouTubeを見たりしていたが、なかなかにしんどい。15分早く終わってくれーと思いながらこいでいた。(脂肪燃焼は20分から発生するのでダイエットの人は30分くらいやろう)

それもそのはずで、運動という習慣になっていない活動をしながら、さらに勉強をして追い込むというのはなかなかに攻めている。つらさ2倍である。(便宜上つらいって書いたけどどっちも目的をもってやっているのでつらくないよ!)

ここで発想の転換。どっちかを楽しいことにすればいいのだ。

映画を観ながらエアロバイクをこいでみた。一瞬で15分たっていて、もうちょっと観たいので20分くらいこいでしまう。先にも書いたが有酸素運動は本当は最低でも30分くらいやった方がいいのでちょうどいい。

全てのことに言えると思うけ楽しくないことは続かない。言いかえるとそれを楽しめたらたいてはうまくいくという話。

楽しくないことをしている時間はないのである。


これを使ってます