おうちで食べる二郎系ラーメン

コロナでラーメン屋が減った

コロナが始まったころ、近所では飲食店がテイクアウトしかできなくなり、好きだったみそラーメン屋近所で唯一二郎系ラーメンを出していた店はその間に閉店してしまった。

ふと二郎系ラーメンを食べたい気持ちになったが、自宅からその次にくらい近い二郎系ラーメンを出す店は飛行機で行くような場所にあるし、デリバリーで自分の家まで二郎系ラーメンが届くサービスもどうやらなさそうなので、自分で作ることにした。

よくある本格二郎系ラーメンレシピ

ちゃんとした味を再現しようとすると、以下のように、ゲンコツや背脂みたいなやや調達が面倒そうな材料を用意して、スープだけで最低2時間半かけて作る感じのレシピが出てくる。 *1

Cpicon ラーメン二郎 (乳化) 完全再現 by ★メタボのレシピ★

これはちょっとやってられないので、とりあえず手抜きで作ることにした。

手抜き二郎

角煮を作ったときに、煮汁の醤油と脂っぽさがなんか二郎っぽいな、と思ったことがあったので、角煮を作ったときにその汁と市販の濃厚豚骨スープを融合させ、醤油を足してカラメにし、二郎っぽいトッピングを使ったところ割りとそれっぽい感じになった。

角煮を普通に作ってこのパックを用意するだけで面倒なパートが大体終わるので、これのコスパは結構よかった。自作二郎のいいところは、もやしとキャベツとにんにくと醤油が味の大部分を占めていて、それらの準備で失敗することはまずない上に、この辺りをマシマシにしておけば結構味がキマるため、料理がヘタクソでも高い確率で二郎っぽくなるところかなと思う。

でも、この市販スープも麺もあんまり二郎っぽくない (かといってそれより二郎ぽいのもない) ので、麺とスープは調達方法変えてもいいなと思ったのだった。

ろたすさんの家二郎レシピ

ラーメンろたすという店をやっている ge-c さんがYouTubeで家で作れる二郎系ラーメンの作り方を紹介している。ge-c さんの 極上のおうちラーメン という本にも、家二郎という章にレシピがまとまっている。

本の家二郎の章の写真は割りと本格的に見えるのに、YouTubeのレシピより材料の調達が簡単かつスープが1時間ちょっとで完成するところに惹かれ、今回それを作ってみた。

前回の手抜きの奴より大分それっぽい味になった。レシピについては本やYouTubeの方を見て欲しいが、特徴的な材料の調達に関する知見だけまとめておく。

麺については、パスタ麺なのだが、リングイネフィットチーネが推奨されている。僕はリングイネを試してみたが、ある程度太麺で、ほどほどに平たいので、たしかに市販パックのラーメンよりぽいなという感じがした。調達は簡単で、Amazonとかで結構ある。僕は乾麺を買ったけど生パスタの方がおいしいらしい。

豚バラ

豚バラ (Pork Belly) は普通の部位なのに何故か置いてなかったりとか (売り切れ?)、なんか皮つきで売られてたりとか、切られたサイズが結構小さめだったりとかして面倒くさい。僕の近所ではマルカイというスーパーで売ってる奴がちょうどいい。

豚足

豚足を買ったことがなかったが、中国系スーパーの99 Ranch Marketに行ったらおいてあった。でも足が3cmおきに切り込みが入った状態で売ってるので、ここで買うとどちらかというと豚骨を使うような感じになる気がする。

背脂

最難関。背脂は普通は破棄する部位なので売っておらず、基本的にはスーパーの肉カウンターか肉屋に行って、店の人に話しかけて出してもらうしかないらしい。僕の近所では、肉屋が全部ハラール屋さんで、どこも豚肉だけはないのでスーパーを使うしかない状態だった。Safewayというスーパーで聞いてみたら、その時は置いてなかったけど、正午までに店に電話して聞いてくれれば用意しておくよと言われた。99 Ranch MarketでPork Fatどれ?って聞いて言われた奴を今回は使ったけど、それは何か背脂とは違うものだった感じがした。

次作るときは

次は手抜き二郎と家二郎レシピの中間くらいの感じにしてみようかなと思っている。特にチャーシューは圧力鍋でやった方がおいしくなるかなと思った。

*1:あとで https://cookpad.com/recipe/6254137 というレシピも見つけた。これはスープの材料的には楽そう。

まだパソコンのOS選びで消耗してるの?

昨日、大学生協推奨のPCが20万のWindowsマシンなのを見てなぜMacじゃないのかという声がTLに流れていたり、それで思い出したのか、逆にMacじゃなくてLinuxを使っている人はなぜそうしてるのかみたいな話がvim-jpで盛り上がったりしていた。

Windowsを使い始めてから17年、Macを使い始めてから8年、Linuxデスクトップを使い始めてから6年経ち、今は用途に応じてその3つをどれも使っているという感じなのだが、個人的にはどれも善し悪しだと思っているので、状況に応じて何を使うべきか自分の考えを書いておく。

大学生は何を買うべきか

特にプログラミングとかやるつもりがない大学生でお金がある人は、素直に推奨されたWindowsマシンを買っておくと、大学側が使わせてくるソフトが動かない可能性も流石に低いだろうし、周りと環境が揃っていて質問とかしやすいので無難だと思う。金がなければ中古で似たような奴を探したり、バイトなどすると良い。

これからプログラミングを始めますという学生は、Mac (中古のIntel MacBook Proか、M1のMacBook Proあたり) を買うのが良いと思う。理由は単純で、開発に使うものはWindowsじゃなくても大体動くし、逆にiOS開発は突然やりたくなってもmacOSでしかできないため。あと、その辺のWeb系企業が社員に貸与するマシンはMacなことが多いので、そういう会社が視野の人は早いうちにそれでの開発に慣れておくと便利。

開発が趣味の人は何を使うべきか

仕事以外でもプログラミングするけど、別に開発環境にそんなに拘りがないという人は、普通に趣味でも会社と同じOSを使っておく方が業務中にハマる時間が短く済むのでそれが良いと思う。

じゃあ、開発環境いじったり開発効率を向上したりする活動そのものが趣味ですみたいな人はどうか。そういう人は、きっとどれを選んでも大体楽しんでなんとかできるので、面白そうと思ったOSを全部試してみるのがおすすめ。そのうち自分のお気に入りが見つかると思う。

まあこれだと何らかの理由で選択肢が複数ある人や、そもそもどれから試すべきか悩んでるステージの人には何の足しにもならないので、現時点での個人の感想を以下に書く。書いてない奴も、単に今思いついてないだけの可能性もあるけど、普通に知らない可能性もあるので何かあったら教えてほしい。特にWindowsは僕が勉強不足な可能性が高い。

Windows

良い所

  • ゲームを始めとして、Windowsにだけ対応してるアプリが結構ある
  • 優秀なキーリマッパー (例えばのどか *1 ) があり、Macっぽいキーバインド *2 もある程度再現できる
  • WSL2ができたのでmacOSよりもLinux寄りの環境が使いやすくなった
  • OSSのWin32やMinGW対応をするときに便利

悪い所

  • ファイルパスの扱いの違いや、ANSIエスケープシーケンスや、ネイティブなシステムコールの違いにより、Windows以外では大体スッと動くがWindows対応には一手間かかる開発用ツールはそこそこあり、Windowsに対応してないか、mattnさんがWindows対応したかみたいな状態になりがち。
  • HiDPI (MacでいうRetina) にOSレベルでは対応しているが、アプリ側が対応してないとそういうアプリだけ文字の解像度が低く汚ない感じになる。

macOS

良い所

  • Retina表示の対応率がすごい。ありとあらゆるアプリがほぼ常に綺麗に表示される。
  • 極めて便利なキーリマッパー (Karabiner-Elements) がある
  • Emacs キーバインドが標準で使え *3、かつCommandキーのショートカットとデフォルトで分離されている
  • Windowsほど対応アプリは多くないが、Linuxは対応してなくてmacOSは対応してるアプリは割りとある *4
  • iPhoneやそのアクセサリとの連携が最も自然に動く
  • OSSmacOS対応をするときに便利

悪い所

  • ターミナルの動作がLinuxのそれに比べて遅かったり、(Intelの) フルスペックのMacBook Proなのに普通にIDE使ってるだけで度々カーソルがグルグルして待たされるので、あまり快適にプログラミングできない。まだ試せてないけど、M1やM2だとこれが劇的に改善されていると期待している。
  • Linuxではない。Linuxサーバーをいじるのが仕事な人は、LinuxにあるけどmacOSにはないか普通使わないツール *5 にも慣れておくと、便利なことがある。
  • homebrewの依存管理がゆるふわなので、brewを使っているとある日突然so名がズレたりしていろいろ壊れることになる
  • ウィンドウの半透明化 *6 が難しい。Deskoveryというアプリでできていたのが、Catalina以降はSIPを切らないといけなくなった。

Linux

過去にはArch LinuxGentooなどのディストリビューションや、Awesomexmonadなどのウィンドウマネージャを試したので自分の環境以外の話もある程度わかるつもりだが、今はUbuntuGNOMEなのでそれ特有の話が混ざってるかも。

良い所

  • ターミナルの動作が速い。エディタなども含め、マシン購入にかかる値段あたりの比較では一番軽快に動作する印象。
  • Dockerを動かすときのオーバーヘッドが小さく、軽快に動作する
  • Linuxサーバーサイドエンジニアの場合、本番環境と手元の環境を揃えられる
  • ある程度機能が揃ったキーリマッパー *7 があり、Macっぽいキーバインド *8 もある程度再現できる
  • WindowsmacOSだけでなくLinuxもサポートしているデスクトップアプリは結構あり、開発以外の用途にも使う場合も、意外とある程度は普通に生活できる *9
  • ウィンドウマネージャの自由度が高い。タイル型WMとかが使える。 *10
  • OSSLinux対応をするときに便利

悪い所

  • ドライバーのサポートが不安。何かケーブルを繋ぐ度に「動くのか…?」とビクビクすることになる。例えばうっかり最新のGPUを買うと、Nvidiaのドライバをいれれば動くがnouveauだと動かず、何らかの拍子にNvidiaのドライバが抜けると、画面が映らない状態でNvidiaのドライバをインストールする必要が発生するみたいな状況に陥ることもある。
  • 動かないアプリが多い。最近、SteamがLinuxに対応してるっぽくて驚いたけど、たとえばAmong UsとかはSteam Play (中身はProtonという、Wineベースの互換レイヤ) を使って起動できたりするのだが、ネットワーク接続が動かなくて、なんかそれをデバッグするRedditスレが盛り上がってたりする。
  • 音を出すみたいな割りと基本的なところがデフォルトで動かなくてハマることがある。まあそういうのを直すのをエンジョイするのがLinuxみたいなところがある。
  • HiDPIに対応してないアプリがある。Windowsと違って、文字が低解像度表示されるのではなく、文字が小さく表示されるか、何か画面を切り替えた時にウィンドウ幅が画面サイズ以上になっていたりする。

まとめ

*1:窓使いの憂鬱の派生プロジェクト

*2:CtrlでEmacsキーバインド、Ctrlじゃない修飾キーでコピーやペーストなど

*3:これ、ほとんどはWindowsLinuxでも再現できるんだけど、じゃあ何が嬉しいかっていうと、例えばHomeやEndでC-aとC-eをエミュレートする時、論理行頭/末じゃなくて物理行頭/末になってしまうという違いがあるため。C-kも同様。ただし、Emacsバインドは様々なWebサイトで奪われるので、キーリマッパーのサポートはEmacsキーバインド自体に対しても結局必要がなことが多い

*4:ライセンス時代の1Passwordとか、Appleなのでやや例外的ながらiTunesとか

*5:具体的にはstrace、perf、gdbなど。gdbは使えないことはないが入れるのが若干面倒な上、普通Clangを使う場合lldbを使うのが無難なのでgdbはなかなか使わない。

*6:これ何に使ってるかというと、シングルディスプレイでエディタを全画面表示しながら、それに透かしてブラウザとSlackやTwitterを同時に眺めるということをやっている。Vimだとターミナルの半透明機能でいけるけど、IntelliJ IDEAとかを使ってるときにそれができなくて不便。

*7:Rubyが好きな人は拙作 xremap や、Pythonが好きな人は xkeysnail など

*8:CtrlでEmacsキーバインド、Ctrlじゃない修飾キーでコピーやペーストなど

*9:参考: https://k0kubun.hatenablog.com/entry/linux-desktop-2017

*10:macOSにもないこともないが、もともとそれを念頭にデザインされてないデスクトップ環境なので、僕が過去に試したものは微妙な挙動だった

リモートワークを支える技術

コロナのせいでフルリモートになってから1年くらい、それ起因でPCのセットアップを度々いじっていて、今日で大体いい感じになった気がするので買ってよかったと思っているものをシェアする。

USB-C to Ethernet アダプタ

Zoom をするときに "Your internet connection is unstable" と出ると不便なので、リモートワーク時代はインターネットにWi-Fiを使うのは避け、有線で繋ぐのが良い。ケーブル本数を抑えるため、USBも刺さる奴を使っている。部屋の配置と配線の都合で廊下のど真ん中をケーブルが横断する感じになりそれは不便なのだが、この問題は解決してない。

HDMI スプリッタ

自宅に4Kディスプレイが1つだけあるのだが、パソコンは私用と社用で2つある。勤務開始と終了で毎日2回ディスプレイをつけかえるとき、HDMIを2本ディスプレイに刺しておいてディスプレイのボタンをポチポチしてもいいんだけど、毎日やるにはポチポチの回数が多くて面倒くさいので、ボタンを一回押すだけで切り替えられるととても便利。

これを買う前は 別のHDMIスプリッタ を使っていたのだが、どうもこれは電力供給がコネクタ1側に依存していて、そっちのマシンがスリープ状態になるともう一方の画面がたまに点滅するという問題があったので買い替えた。ほぼ同じ値段での買い替えでこの問題が解消できたのはよかった。

キーボード・マウス スイッチ

キーボードとマウスのUSBも毎日2回抜き刺しするのは明らかに面倒なので、これもボタン一つで切り替えられるようにしておくと便利。これだけはたまたま前から持ってるやつで、9年使っているが全く壊れてないし安いのでお勧め度が高い。

ボタン1つでHDMIとUSBを両方同時に切り替えられる奴使った方が便利なんじゃないのと思うかもしれない。実際 これこれ を買って試したのだが、なんか画面の切り替えがうまく動かない不具合が頻発したので返品した。結果として、HDMIだけは別のボタンで切り替える方が安定性の観点から体験が良かった。

ヘッドホン to USB アダプタ

Apple EarPodsiPhoneに付属してくる上に個別で買っても安く、形や耳障りがPixelのそれに比べて良く、音質も無難で、そのままマイクにもなるお気に入りのイヤホンなのだが、3.5mm 端子をそのへんのデスクトップマシンのライン出力に刺しても、マイク用端子は別なのでマイクが動かない。*1

ヘッドホンスプリッタを使えば普通はいいのだが、この辺のApple製品は非Apple製品と互換性がないという噂があり、実際 これ を買ってみたが、Linuxでは低音質でマイク入力ができるがWindowsでは何故か全く使えないという感じだった。

なので、Apple純正のUSB-C to ヘッドホンアダプタを買い、さらに USB-C to USB (Type-A) アダプタ に接続してやる *2 ことで、社用MacBook Proと私用デスクトップマシンのWindowsLinux両方でマイクが綺麗な音で入るようになった。上述のUSBスイッチは2つしか口がないのだが、小さなUSBハブ をつなげてやることで、1つのボタンでキーボードとマウスとイヤホンが全部切り替えられるようになった。

f:id:k0kubun:20210428162840j:plain

最終的はこういう感じに落ちついた。便利。

*1:そもそも、元はデスクトップマシンでマイクを使う用事がなかったのでマシンごとに別のApple EarPodsをさして使っていたのだが、イヤホンが2つデスク上にあると、間違って今使ってない方のマシンに繋っている方をつけがちという問題もあった。大学院の授業のグループプロジェクトで毎週他の生徒とGoogle Meetで通話をする用事ができたので、私用マシンでもEarPodsでマイク使いたいなと思い、今回これら2つの問題を解決した。

*2:僕のデスクトップマシンにUSB-Cの口がないため。あとこれにより上述のスイッチが使える。

Pryはもう古い、時代はIRB

僕はRubyで開発をする時は毎回Pryを使うくらいの熱狂的Pryユーザーだったのだが、PryはGemfileに書いてないと binding.pry できなくて不便。任意のgemをdefault gem化するgem default コマンドも作ったのだが、これをやるのすら面倒だと思っていた。

ある日、nobuさんがRubybinding.irb という機能をいれた。Pryがdefault gemになるのを待つよりPryで僕が使う機能をIRBに全部移植してしまった方が早いのではないかと思い、4年前からPryの機能の移植活動を始め、今日僕がよく使う機能を全て移植し終えた。

その記念に、この記事ではIRBのPry互換の機能を紹介する。昔 今更聞けないpryの使い方と便利プラグイン集 という記事を書いたんだけど、この中で僕が毎日のように使うコマンドは全てIRBに移植したので、それを紹介する本稿を読むだけで今日からあなたもIRBが便利に使えるようになる。

IRBのPry互換機能の変遷

新しめの機能が多いので、使えるようになったバージョンごとに機能を紹介する。

Ruby 2.4

binding.irb

nobuさんが binding.irb入れた歴史的バージョン。この時点ではどこで起動されたかが表示されず、binding.pry の代わりとしては正直ちょっと不便かなという状態だった。ただ、標準ライブラリなのでGemfileに書いてなくても使えるのが強み。

$ cat a.rb
foo = "hello world"
binding.irb

$ ruby -rirb a.rb
irb(main):001:0> foo
=> "hello world"

Ruby 2.5

irbの自動require

nobuさんが次に、binding.irb をするとirbが自動でrequireされるという機能を入れた。pryはrequireしないと使えないので僕はViminoremap <C-v> require "pry";binding.pry という設定があるのだが、binding.irb はこんな面倒なことをしなくても使えるので、また一つPryにない強みができた。

binding.irb の周辺行表示

ここから僕が参戦。Ruby 2.5から、binding.irb の周辺行が表示されるようにした。やっぱりこれがないと使いにくい。この時点ではまだ白黒。

$ ruby a.rb

From: a.rb @ line 2 :

    1: foo = "hello world"
 => 2: binding.irb

irb(main):001:0> foo
=> "hello world"

Ruby 2.6

default gem化

hsbtさんがIRBdefault gem化Ruby 2.6になるまではIRBはgem化されてない標準ライブラリだった。gem化によって、Pryと同じように gem install irb でインストールやアップデートが可能になった。gem install irb さえしてしまえば、例えばRuby 2.5でも最新のIRBの機能が大体使える。Gemfileに書いてない限りは bundle exec してしまうとそれは使われないので、新しいRubyを使うことはgem化された今でも重要である。

Ruby 2.7

シンタックスハイライト

僕の好きな標準ライブラリはRipperなんだけど、その趣味を炸裂させて実装したのがシンタックスハイライト。binding.pry での周辺行に色がつくようになり、本格的にPryっぽくなってきた。IRB::Color が標準添付のRubyシンタックスハイライトライブラリとなり、個人gemで使ったりしている。なお、inspectの結果はシンタックスハイライトとは少し勝手が違うため、このバージョンではRubyリテラルとしてvalidになるようなinspectのみ色がつく感じになっている。

f:id:k0kubun:20210402210027p:plain

インクリメンタルハイライト

このバージョンでaycabtaさんがreadline実装を彼が実装したRelineに差し替えたことで、入力行の描画のフックが容易になったため、1文字入力するごとにシンタックスハイライトする機能も実装できた。Pryではこの機能は標準でなく、かつpry-coollineはパフォーマンスに問題があるのかチラチラしてちょっと不快で、その点IRBではチラつきがないのでPryよりとても快適。

Ruby 3.1

これ以降の機能はRuby 3.0がリリースされてから開発したため、リリース済みのRubyには標準では入っていない。aycabtaさんがそろそろIRBのリリースをするらしいので、そのうち gem install irb では使えるようになる予定 (追記: 1.3.5でリリースされた)。バージョンが古くても以下のコマンドは使いたいなと思ったので、僕はirbrcに当面の間ベタ書きすることにした。

複雑なオブジェクトのinspect色付け

inspect結果はRubyとしてvalidではないことがあるためシンタックスハイライトのコードが流用できないのだが、Pryの真似をしてmasterではこれを実装してあるActiveRecord::Baseインスタンスも綺麗に色がつくようになったので rails c で便利。IRB::ColorPrinter が標準添付のinspect色付けライブラリとして使えるようになったので、power_assertもこれを使い始めたらしい。

f:id:k0kubun:20210402210201p:plain

ls コマンド

ここでやっとPry風のIRB使いこなし記事っぽくなるのだが、Pryには ls というコマンドがあって、短い記述でメソッドや変数の一覧を調べられて便利。あまりにも欲しいのでこれを個人の ~/.irbrc に実装して過ごしていたのだが、他の人も使いたいという声を見たので、最近IRB本体に実装を移した。とてもよく使う。Pryのcdっぽい機能はIRBに既にあるが、個人的には binding.pry の貼り直しで済んじゃうことが多いので、Pryでもcdは最近あまり使わない。

f:id:k0kubun:20210402210407p:plain

なお、IRBではRubyとしてvalidな入力しかできないため、-G / --grep オプションで出力をgrepするためには ~/.irbrcちょっと細工をする必要がある。

show_source コマンド

ソースコードリーディングに便利なのがPryの show-source なんだけど、IRBではRubyとしてvalidな入力しかできないため、まずコマンド名が show_source になっていて、かつ引数も文字列リテラルで書かないといけないことになっている。それでも便利かなと思っていれたのだが、~/.irbrc細工をすると以下の感じで $ という短いエイリアスで使える。

f:id:k0kubun:20210402210556p:plain

whereami コマンド

細かいが、binding.irb していろいろやると画面外に元の行が追い出されてわからなくなることがある。そういう時に便利なのが whereami で、再度 binding.irb が実行された行を表示することができる。 ~/.irbrc細工をすると短い @ というエイリアスで使える。

f:id:k0kubun:20210402210739p:plain

IRBRubyとしてvalidでない入力もできるべきか

IRBはコマンドの実装が全てメソッド呼び出しなので、ls -Gshow-source@ に関しては上記の通り ~/.irbrc をいじらないとPryっぽく使えなくなっている。これを受け付けるのは周りの人があんまり乗り気じゃなさそうだったので一旦保留にしたけど、これが欲しいという世論が形成され、誰かがIRBにマージできるような実装を書けば、皆が手元に ~/.irbrc を持たなくても便利に使える日が来るかもしれない。

pry-byebugは?

僕はpry-byebugを10倍速くしたことがあるので10倍速くしたことがない人よりは多分pry-byebugに思い入れがあるが、個人的には cd の話と同じく binding.irb の貼り直しで大体の用事が足りてしまうことが多く、いわゆるデバッガっぽい機能は使わなくても済んでしまうことが多い。

しかし、ささださんが標準添付の debug.rb をいい感じにするプロジェクトを最近やっておられ、その過程でIRB連携が導入される可能性があるため、そこでIRBにデバッガ機能が標準でつくこともあるかも。

余談

昔は初心者がPryじゃなくてIRBを使っていると馬鹿にされるということがあったという話を思い出した。今では初心者も安心して使えるREPLになってめでたい。

Special Thanks

僕がIRBにいれた機能は主にaycabtaさんにレビュー、リリースしていただきました。ありがとうございます!

Java, MySQLをKotlin, PostgreSQLに移行した

7年前にGitHub Rankingというサービスを作り、APIを叩きすぎてGitHubからの風当たりが強くなって*1からはデータの更新を止めていたが、KubernetesGraphQLの時みたいに技術を試す砂場用に惰性で動かし続けていた。

Issueの機能要望対応が段々面倒になってきて、サーバー代節約のために潰すかと考えていたのだけど、毎日1000PVくらいあるので試しにGoogle Adsenseを設置してみたところ1日平均 $1 くらいは入ってて黒字になりそうだったので、ちょっとメンテしやすくしてデータの更新再開するかー、ということで今回いろいろ綺麗にした。

DB: MySQLPostgreSQL

なぜPostgreSQLにしたのか

個人的には多くの用途ではMySQLPostgreSQLどっちでもいいと思っているんだけど、今所属してるチームがメンテしてるサービスのDBの多くがPostgreSQLな割に自分はまだPostgreSQLの経験が浅いので、練習的な意味でPostgreSQLに移行して慣らすことにした。

ConoHaのDBサーバー

ConoHaのDBサーバーは月500円でマネージドMySQLが使える素晴らしいサービスなのだけど、PostgreSQLには対応していないのでこれをやめる必要があった。500円だとSSD 10GBなんだけど、GitHubのDBをまるごとぶち抜いてくる都合上ストレージが足りなくなってきていたので、どの道何かする必要はあった。最初610円のVPS (SSD 30GB) を別途立ててそこに移行したけど、割りとメインのVPSのキャパシティ余裕あるし、SSDも100GBあるので、結局そっちに同居させた。

Embulkでデータ変換

MySQLからPostgreSQLへのデータ転送は皆Embulkでやってるイメージがあったので、EmbulkでMySQLからPostgreSQLへデータ転送という記事を参考に自分もそれでやってみた。DBはusersが1000万レコード、repositoriesが1800万レコードあったが、usersは数分で転送できて速いなと思った。

repositoriesはこの記事に近いエラーになって、記事のようにタイムアウト伸ばすのを試したがそれでは直らなかった。transactionを使うところで落ちていたので、transactionを使わなくて済むようembulk-output-postgresqlのmodeをinsertからinsert_directに変えた。結局同じところで落ちて700万行だけinsertされた状態になったけど、usersさえ全部あればrepositoriesの復旧は大変ではないので、そのまま行くことにした…。

ridgepole → sqldef移行

PostgreSQLスキーマをEmbulkのguessだけに頼って作ったため雑なスキーマになっていたので、UNIQUEやNOT NULLをつけるなど整理する必要があった。もともとRidgepoleというActiveRecordベースの羃等スキーマ管理ツールを使っていて、これを使ってもいいのだが、以前の記事に書いた通りそのActiveRecord非依存版であるsqldefをメンテしているので、この機会にそれに移行した。移行はsqldef --exportを叩くだけでできる。

リリースしてから3年経ち、様々な方、特にZOZO社の方面からいっぱいバグレポートをいただき全て直してきたのでほとんど問題なく動いたが、最近いただいたパッチPostgreSQL 12に対応してなかったので直したり、次に伸べるcitext拡張に対応したりした。ついでにsqldef-railsというのも作った*2。そのうちGradleプラグインも作りたい。

citext拡張

MySQLPostgreSQLの違いは、ORDERなしでSELECTしてidでソートされないとか、AUTO_INCREMENTのかわりにserialとsequenceを使うとか、GET_LOCKのかわりに pg_advisory_xact_lock とか使うなどいろいろあったが、一番苦労したのはMySQLの文字列は普通case insensitiveだけどPostgreSQLに移行した瞬間case sensitiveになってしまうというものだった。GitHubのユーザーやリポジトリの名前はcase insensitiveで引きたいのである。

これは LOWER(foo) にインデックスをかけて常に LOWER(foo) でfooを引いてやっても解決するが、常に LOWER(foo) するというのがいかにも忘れそうである。これを単にMySQLっぽい挙動にしてくれるのが citext (case-insensitive text) という型。psqlRailsからアクセスするとcase-insensitiveにアクセスできたのが、JDBCからアクセスするとなぜかcase-sensitiveになる というとこころにハマった。URLに ?stringtype=unspecified をつける と直るが、まさかクライアントが挙動をコントロールできると思ってなかったので、気付くのに時間がかかった。

Worker: Java → Kotlin

このサイトはRailsで作られていてワーカーも元々Sidekiqで実装していたのだが、高速化のために100スレッドでAPIを叩きActiveRecordを使うということをやったらメモリリークっぽい挙動になって詰んだので、それ以外を使う必要があった。僕が使える言語でこの要件だと多分Goが一番妥当なんだけど、現行のワーカー実装を書いた当時に社のチームが使っていたスタックであるJavaJDBIUndertow *3を練習用に使ったのであった*4

で、大体同じ人がいるチームに今もいるんだけど、JVMでは主にKotlin、jOOQDropwizardを使うように変わったので、普段使っているそれに差し替えることでメンテコストを下げることにした。JDKも8から11に上げた。

Javaと比べたKotlinのいいところ

Kotlinのdata classを使うとJavaより行数が減らせて便利みたいな話をすると、Lombokで十分という反応をしてくる人がいて、僕はLombokは実際使ったことがあるわけではないけどこのスライドとかに出てくる機能だけど見ると、以下の点でKotlinの方が便利かなあと感じる。

  • Named argumentsをキーワード引数的に使える *5
  • 複数行文字列が綺麗に書ける *6
  • String interpolationが便利
  • 標準でもList, Mapの操作が楽
  • LambdaがJavaより書きやすい
  • ?:, let, also みたいな便利な奴が何かと多い
  • 型でNull安全にできる
  • throws書かなくていい
  • extensionが便利、Rubyのrefinementsが気軽に使える感じ
  • Smart castで型操作が楽になることがある
  • coroutineで気軽に軽量なIO多重化ができる

jOOQ

JDBIは生のSQLを毎回書く奴だけど、jOOQSQL風のDSLでクエリをビルドする。JDBIは複雑なクエリを動的に組み立てるみたいなのにはあんまり向いてなくて、実際社で僕がcancancanKotlinに移植した奴はクエリが動的に変わりまくるのでjOOQが活躍している。また、KotlinのNamed argumentsとjOOQを組合せるとオプショナルなキーワード引数でクエリを動的に変える感じにできるので、ActiveRecord風のインターフェースが作りやすい。

普通はテーブルごとにコード生成をして使う奴なんだけど、使い始めた当初Kotlinのコード生成がうまく動いてなかった都合、コード生成なしで使っている。ただ、onDuplicateKeyUpdate とかがコード生成用のAPIを使わないと使えないのは困った*7

Dropwizard

ワーカーなのにUndertowでAPIを生やしていたのはワーカーの操作用APIを生やしていたからだが、メンテコストに対して利益が薄いのでAPIは落とした。なのでDropwizardはここでは使っていないのだが、Dropwizardにはパッケージ構成指針があって、これに従っているとRailsみたいにどこに何があるか予測しやすいのが気にいっていて、このワーカーでもなるべくDropwizardっぽい感じで物を配置することで普段と同じ感じで色々探せるようにした。

Jersey Client

DropwizardはJAX-RSベースなので、opentracing-contrib/java-jaxrsでOpenTracingに対応できるのだが、APIクライアントにもJAX-RSベースのものを使えば同じものでOpenTracingに対応できるので、JAX-RSのクライアントの参照実装であるJersey Clientが弊チームでは使われている。このワーカーでは適当に見つけたgoogle-http-clientを使っていたのだが、今回Jersey Clientに差し替えた。

Jersey Clientでリクエストを投げるとstatus codeに応じた例外を投げることができるんだけど、レスポンスヘッダに入っているRate Limitの残りを見るために一旦 Response を取るとその機能は使えないので自分で投げる必要がある、という仕様にJAX-RSがなってるのがちょっと困った。

Server: Rails

https://gitstar-ranking.com を返してるのはRailsで、RubyのJITや自作の最速テンプレートエンジンであるhamlitが試せるので特に他の何かに移行することなく続投。バージョンアップや使ってないGemの整理だけを行なった。

Ubuntu 20.04

Ubuntu 18.04 で動いていたのでアップグレードした。プロビジョニングはmitamaeで自動化しているものの、ConoHaをポチポチするのが面倒だったのでおもむろに sudo do-release-upgrade をしたが、Rubylibffi.so.6 で No such file or directory になったのでRubyをビルドし直して、それで終わり。

Ruby 3.0

Ruby 2.6だったのをRuby 3.0に上げた。個人的にはendless method definition *8 がお気に入り。逆に、2.7で入ったNumbered parametersは、使いたい状況には度々遭遇するけど、KotlinのitScala_に比べると_1という字面が微妙なので妥協で { |x| x と書くことが多い *9

Rails 6.1

Rails 5.1から6.1に上げた。最近はRailsのアップグレードは bundle updatebin/rails app:update するだけで終了で、あまり困らない感じになってきた。むしろRuby 3に上げる時はHashでキーワード引数渡してたところがおもむろに壊れたので、今回はRubyの方がアップグレード難易度が高かった。Rails 6といえば公式に複数DBやbulk insertに対応したなどがあって、どっちもこのアプリでは使わなかったが、地味にActiveRecordpick は使った。

GraphQL退役

GraphQLでAPIを生やしているところがあったが、ここ以外でgraphql-rubyを一切使ってなくて何も覚えてないのでRails Wayからあまりにも外れたこれをメンテするのがしんどいのと、ほとんどのスキーマは単に実装してみたくて生やしただけだったのでGraphQLは撤去した。JavaScriptから使われていたAPIが一つだけあったが、それのためにjbuilderを依存に足したくなかったので、render json: だけで済ませた。

React, Webpacker退役

毎日使っているTwitterクライアントをReactで自作してそこそこメンテを続けているのでReactの使い方は普通に覚えているのだが、このアプリではユーザー更新ページで部分的に使っているだけだった割りにnpmのライブラリの脆弱性アラートが無限に来るのがコスパ悪いなと思ったので、素のJavaScriptに書き直して、yarnとWebpackerもやめてSprocketsから配布することにした。モダンWebフロントエンドの素振りはどの道Twitterクライアントの方でやり続けるのでこちらではいいかなと。

Sprockets 4移行

長い間betaだったが去年やっと出たSprockets 4にアップグレードした。manifest.js というのを書かないといけなくなるのが面倒でサボっていたが、sprockets/UPGRADING.mdを見たら割りとすぐいけた。

Omniauth 2移行

Omniauth 1の脆弱性アラートが出ていたので上げようとしたのだが、DeviseとかいうGemがOmniauthのバージョン番号をチェックして例外を投げていて、しかもそのチェックを修正したバージョンが未だにリリースされていないのでDeviseはmasterを使う必要があった。それから、Omniauth 2に上げたらコールバックがGETじゃなくてPOST必須になり、そしてPOSTに変えるとCSRF protectionに引っかかるという問題があった。Stackoverflowcookpad/omniauth-rails_csrf_protectionが紹介されていて、メンテナが信頼できそうなのでありがたく導入させていだたいた。

感想

データの更新を再開しつつ壊れた時にメンテしやすいようにしただけで機能追加とかは一切してないので、このサイトのGoogle Adsenseの収益がこれで増える気はしないが、jOOQやJersey周りで仕事中に気になってたけど時間の都合触れてなかった部分をいろいろ試せたりとか、sqldefのPostgreSQL対応の改善に繋ったのでよかった。

*1:この時についでに、サービス名にGitHubいれるのやめろと言われて、Gitstar Rankingという名前になった

*2:元々ActiveRecordが入っているRailsだとRidgepoleを使わない理由はほとんどない気がするけど、同じDBをActiveRecord以外からも読むので素のSQLで管理されてる方が扱いやすい (今回のアプリがそれ) とか、DDLは覚えてるけどActiveRecordDSLは調べないとわからないというようなニッチな用途には便利かもしれない。

*3:正確にはそれを自社でラップした Underwrap https://github.com/treasure-data/underwrap

*4:ちなみに、MySQLのテーブル上に実装したキューにRailsからジョブをエンキューしてJavaのワーカーでデキューして処理するという普通はしない構成を取っていたのだけど、これはTreasure Dataでは頻出のパターンで、TDではRubyJVMが一緒にワイワイしてないサービスを探す方が難しい

*5:メソッドに引数が複数あると、その順序は自明じゃないと思うことが多い。なので順序を覚えてないとろくに呼び出せないメソッドは不親切だなと思っていて、例えばRubyでも引数が2〜3個に達したあたりで2つ目以降か全部の引数をキーワード引数にして呼んだりしていて、これができない言語は結構イライラする。静的型付言語なら引数の型合わなければコンパイルエラーになるし覚えなくていいんじゃない?と思うかもしれないが、同じ型が複数並ぶとその主張は崩壊する。なるべくNamed argumentsで呼び出してやることで、引数のリファクタリングとかも安全感が出る。

*6:JavaにJEP 326 https://openjdk.java.net/jeps/326 入らなかったの残念

*7:コード生成用に用意されてるAPIを自分で呼び出した。まあ、今はコード生成使ったらいいんだけど

*8:この機能見る度にKotlin https://kotlinlang.org/docs/functions.html#single-expression-functions を思い出す

*9:これに関してはCommiter vs the worldか何かの時の投票でそういう立場であると表明しているので、ここでおもむろに意見を出してるわけではない

USのITIN申請と確定申告

5月末までにGoogleにtax infoを送らないとアメリカがYouTubeの広告収益の最大24%を課税するぞ、というメールが最近YouTuberに届いているらしく*1、そこに入力するTIN*2どうする? マイナンバーでいいの*3? ITIN 申請が必要なの? という話が盛り上がっている

僕はアメリカで確定申告をする身だしYouTuberでもないのでこの話とは直接関係ないんだけど、妻のITINの申請をちょうど最近したところだったので、忘れないうちに何をしたか書いておく。

ITINとは

Individual Tax Identification Number。日本におけるマイナンバーはアメリカではSocial Security Numberと呼ばれ、アメリカ人や就労ビザの人はSSNを持ってるんだけど、SSNは非就労ビザの人には付与されないので、SSNがない人が取得できるのがITIN。

US移住とブートストラップ問題に書いたが、確定申告の他、銀行や医療保険に加入する時にSSNかITINの提出が必要で、当然ながらクレカや医療保険なしではアメリカでは生きていけないので、ITINがないのは実質人権がない状態に等しい。とはいえそういう状況であることを説明すると実際には入れるんだが、ネットの申請が空欄だと弾かれて電話が必要だったりとか、ITINを申請したくてもアメリカ人はITINを申請したことがないので周りの人が誰もやり方を知らない、といったところで困りが発生するという感じ。

ITINの申請に必要なもの

在日米国大使館・領事館のサイトにおおまかな流れは書いてあるが、これは結局英語のInstructions for Form W-7を読まないとよくわからん感じになっている。これのHow To Applyのところをまとめると:

  • W-7
  • ITINが必要な確定申告
    • Exceptions Tables に該当する場合は不要
  • 身分証明書の原本か認証コピー
    • 米国入国日付のあるパスポートか、その認証コピー(Certified Copy)があればそれ一本でOK。他の書類だと多分2つ送る感じになる。

うちも最初はExceptions Tablesで申請しようとして会社からサインをもらおうとしたのだけど、HRがITINなしでも医療保険はいけるの一点張りで結局もらえず、そして医療保険の方からは必要だと返され3か月くらいたらい回しが続き、死ぬほど消耗したのでこれは諦めた。なので、正攻法の確定申告時の申請をした。

郵送で申請する場合、日常的に郵便がロストするアメリカでパスポートを郵送するというのはちょっとありえないので、パスポートの認証コピーを取得することになる。日本領事館のサイトにやり方が書いてある。予約制だが、人気なので予約の確保が難しい

注意しなければならないのは、ITINが届くまでに申請から最悪7週間かかりうるので、もしマイナンバーがTINに使えないとしたら、5月までにITINが必要なYouTuberは今すぐ申請しないと手遅れである。うちも2/24に先方に郵便が届いた通知をもらってからまだITINは来てないし、確定申告で追納したチェックもまだ引き落とされておらず、日々震えている。

Tax Return

ここからはITINに一切関係なくなるが、その申請書類の一部であった確定申告でやったことを書いておく。なお、申告期限が4/15から7/15に伸びそうなので、W-7で早めに提出しろと書かれているITIN申請者でもない限りは、まだ焦る必要はない。

日本の確定申告

日本の収入もアメリカで課税対象になるので、日本の収入がある人は先に日本の確定申告書類を作り、納税額だけでも確認しておく必要がある。

税理士 vs TurboTax

移住した直後のTax Returnは、大企業Armのご厚意により日本とアメリカの確定申告両方の面倒を見てくれる税理士が手配されたため、2019年分の確定申告はほとんど何もしなかったのだが、それは移住直後だけの提供だったので今回の2020年分から自分持ちになった。

税理士を頼むと、確定申告をする時にその人の名前で提出することになるので、うっかり申告ミスがあった場合にも自分が捕まるリスクがやや低くできる気がする。ただ、単に自分がケチなのと、今後節税ができるように自分で仕組みを理解したかったというのがあり、今回はTurboTax *4を使って自分でやることにした。別にTurboTaxしかツールがないわけじゃないけど、タイムラインの日本人はTurboTaxを使っている人が多く感じる。

TurboTax

実際に自分で確定申告する時に何が必要が書いておく。必要な書類は大体1月に来るんだけど、申告を終えてから3月に来たやつとか、そもそも額が低すぎてフォームが来ない (ただし報告義務はある) やつとかがあり、やっていく必要がある。

My Info

Married Filing JointlyだとTax Bracketが安くなるので、配偶者の情報をいれる。SSNかITINの入力が必要だが、ITIN申請の瞬間はないので、何度もエラーを出されながらも空欄で進める。後でもう一度聞かれるけど、扶養者の情報もここで聞かれる。

Federal: Income & Expenses

W-2: Job

会社から郵送されてくる、源泉徴収票に相当するやつ。会社が使っているADPという給与明細サイトがTurboTaxと連携していて自動で入力されたが、Otherに書いてあるAT401というのが自動でカテゴライズされなくて、そこだけ自分で適当な奴を選ぶまでエラーになっていた。

1099-NEC: Self-employment income and expenses

Uberドライバーの収入とかが該当する奴。去年GitHub Sponsorsを始めたので、これがGitHubから郵送されてきた。全く源泉徴収されてないのでここで納税するんだけど、経費を入れると控除することができて、年末に注文したRyzen代などをここに充てた。インターネット代は普通いけるらしいけど、電気代*5はどうなんだろう。

1099-INT: Interest

銀行口座の利息がここで課税される。$10以下だとFormが郵送されてこないが報告義務はあるというを見たので、今回は安全側に倒し、思いつく全てを申告した。

  • Bank of America: 額が小さいからか、TurboTax連携に失敗。Formも来ないし、サイトにもTax statementなし。自分で利息合計を計算して入力。
  • Chase: サインアップボーナスが$200で、これが利息に分類されるらしい*6。Formが郵送され、TurboTax連携も動いた。
  • Amex HYSA: $10を超える程度には利息がついていたので、Formが郵送され、TurboTax連携も動いた。
  • Charles Schwab: Vanguardに乗り換えるまで使ってた証券口座だけど、サインアップボーナスの$200がこれに分類された。アカウント削除済みだった*7ので、郵送されてきた奴をスキャンしてアップロードした。
  • Vanguard: サイトに1099-INTがあったけど $0 だったので何もなし。

1099-DIV: Dividends

株とかの配当。アメリカのTax-Exempt Bondのインデックスを保有していた結果、dividendsのアメリカ全51州とグアム、プエルトリコへの分散を計算して入力するという修行を行なうことになったのだが、yuskさんとdraftcodeさんの議論の結果、カリフォルニアの割合が50%超えてない以上は州税は一切免除にならなそうなので、単にMultiple Statesを入力して終わりとすればいいらしい。

1099-OID: Foreign Accounts

アメリカ国外に資産が $10,000 あると、Tax Returnとは別にFBARという奴を申告しておかないといけない。Tax Returnには影響しないんだけど、国内外の合計資産が $2M 超えているとグリーンカード破棄する時に総資産の2〜3割をアメリカに取られるというExpatriate Taxがあるので、まあそういう奴とかマネーロンダリングとかのための監視なんじゃないだろうか。まだやってないんだけどそのうち申請する。やり方はIRSのサイトに書いてあるが、電子申告できる。

1099-B: Stocks, Mutual Funds, Bonds, Other

株とかの保有量を書いておく。VanguardをTurboTaxに連携して終わり。

1099-K: Payment Card and Third Party Network Transactions

2020年分にはなかったけど、最近アメリカのメルカリを使ったので、来年はこれが該当する。$20,000 売り上げないとFormが送られてこないけど、報告義務はあるので手動申告になる見込み*8

2555-T: Foreign Earned Income and Exclusion

日本とかの収入を入力する。ドル円はIRSのサイトのAverage Currency Exchange Ratesで変換しておくと安心そう。これを入力するまではめっちゃ還付されるやんという感じだったのが、これをいれた瞬間Tax Bracketが一段上になって税率が爆増してしまい、Foreign Tax Creditで日本側の大部分*9は控除されるにも関わらず、税率増加が主にアメリカi分に効いて死ぬほど追徴されることになった。

Federal: Deductions & Credits

以下に紹介する奴の他に、Estimated Tax PaymentsとかHSAとかもここに入る。来年はEstimated Tax Paymentsも入力することになりそう…

Child and Other Dependent Tax Credit

扶養者の情報をいれる。小さい子供がいるとTax Creditが$2,000もらえる。ところでBiden's Covid relief billでこの額が増えるらしいけど、まあ当然ながらincomeが高いとphase outする。

Car Registration Fees

車の登録料が控除に使える。レシート破棄したけど、レジストレーションの紙に $275 と書いてあった。*10

1098-T: Expenses and Scholarships

大学の授業料が控除に使えるらしい。僕も学生なので1098-Tもらったし、教科書だったドラゴンブックを経費にしちゃうぞーとか考えてたけど、"Your income exceeds the maximum limit" だった。さようなら。

Medical Expenses

医療費が $18,171 を超えてると控除に使えるらしい。そんな使うことある…? 出産があったけど麻酔とかも保険でカバーされたし、保険でカバーされない金歯を3本いれたけど、金の値段は日本と同じなので、$18,171 もしない。明日歯医者に行ってFMXというレントゲンをやるんだけど、これが3年に1度しか保険でカバーされなくて $154 する*11んだが、$18,171 もしない…

Foreign Tax Credit

日本との二重課税を避けるためのやつ。10年とかキャリーオーバーできるらしいけど、その上限にも一発で達したっぽい。申告方法は二択で、Form 1116の方が税額が小さくできるらしいんだけど、auditされるリスクもこちらの方が高いらしい。でも、ここの税額があまりにも大きかったので僕はForm 1116一択で、日本の給与をGeneral category incomeとして申告した。

State: Your State Returns

Federalを入力すると、Stateの方にほとんど自動でコピーされてくるので、こっちでやることはほとんどない。 最初に "Made an estimated tax or extension payment over $20,000" か "Filed an original return with a tax liability over $80,000" であるか聞かれるが、2020年は該当してない気がするのでスルー。2021年は前者が該当しそう?

1095-B: Health Coverage

医療保険。Kaiserから郵送されてきた。娘は産まれてからの加入だったので加入月を入力したが、通常は年中加入している、で終わりな気がする。

Underpayment Penalty

アメリカが日本の収入から源泉徴収をしてくれない*12せいで、特に州税が死ぬほど追徴された結果*13、元々払ってた額が少なすぎということでペナルティが課せられた。来年のそれを避けるためか、TurboTaxが予定納税っぽい紙を印刷してきた。

郵送

普通はインターネットで提出と支払いをして終わりなんだけど、ITINの申請の際は郵送か対面で出す必要があり、郵送することにした。Tax Returnのための本来の住所ではなく、ITINの申請用の住所に送らないといけないことに注意。

パスポートのCertified Copyがロストするとあまりにも面倒くさすぎる状況になったので、確実に届くようPriority Mail Expressで送った。自分で封筒持っていったけど現地に置いてある専用の封筒じゃないと出せないというミス。ラベルは自宅で購入、印刷してUSPSに持っていくことができる。専用の封筒への貼り付けも自分でやる必要がある。まあ多分来年は郵送しないけど…

感想

給料2か月分くらい追徴されてワロタ。初のTax Returnで不安なので早く受理されてITINが届いてほしい。

*1:YouTuberの https://twitter.com/mametter さん情報

*2:Tax Identification Number

*3:良さそうという情報も見た https://www.j-cast.com/2021/03/10406776.html

*4:Deluxeプラン。税理士よりは大分安そう

*5:Silicon Valley Powerに比べて、PG&Eめっちゃ高くて困っている

*6:実際6か月加入してないとexpireするので見掛け上利息感はある

*7:郵送されてこなかったら確認が面倒な感じになるので、不要になったアカウントもTax Returnまでは取っておくのが良い…

*8:https://www.mercari.com/us/help_center/article/163 https://turbotax.intuit.com/tax-tips/irs-tax-forms/form-1099-k-decoded-for-the-self-employed/L6xHSTXwR

*9:そもそもこれにリミットがあっが全額引かれてないので、普通に二重課税を食らっているというのも不満

*10:Form 1014, line 12でstandard deductionを選択した場合は車の登録費は控除できないらしい https://twitter.com/yusk_/status/1369569396792823819

*11:引っ越して初回なのでこれをやるだけで、以降は毎年2回保険でカバーされるレントゲンしかやらないらしい

*12:当たり前なんだが

*13:流石カリフォルニア

8年ぶりに vimrc を書き直した

2013年にEmacsの使いすぎで小指が痛くなってからVimユーザーをやり始めて、かれこれ8年が経つ。 当時書いたvimrcを秘伝のタレ的に使い続けてきたが、正直あんまりまともにプラグインの更新とかをやっていなかったせいで、ある日突然、普通に使ってるだけなのにエラーが出まくって困る状態になった。

f:id:k0kubun:20210303201233p:plain

Vim の寿命

後ろめたさを感じつつも NeoBundle.vim、neocomplete.vim、Unite.vim といった一世代古いShougoさんウェアを使い続けていて、特に Unite.vim は後述の都合により2014年のバージョンに固定して更新をサボっていたのだが、Unite関係の何かがVim 8.2で動かなくなった*1macOSではsystem Vimを使うようにしてみたところ、system Rubyが何か壊れているせいでif_rubyで書いている自作のUniteプラグインが常にバックトレースを吐く状態になった。

Linuxでも、neocompleteが特定のバージョン以上だと動かないという警告を見てからその直前のバージョンのVimを手動コンパイルすることで耐えていた。仮にその問題がなくとも、if_rubyを使っているせいでそれと+clipboardがついてるVimがapt installで入れられず、よくVimを温かみのある手動コンパイルをするハメになり、不便だなあと思っていた。

何かと不便な点を直したかったのと、仕事で使っているmacOSのマシンでVimが全く使えない状態が致命的だったので、思い腰を上げて vimrc を書き直すことにした。

NeoVim 移行

f:id:k0kubun:20210303203118p:plain

@giginet が昔 neovimが実用段階になったようなのでvimを置き換えてみた話 を書いてたのを見てからずっと気になっていたので、今回試してみることにした。 vimrcを読みにいく場所が違うので、(Linuxでは) ちゃんと動く普通のVimでスクラッチの設定ファイルを書きNeoVimでそれをテストするというのにちょっと便利だった。

Shougoさんの新しいプラグインサフィックスが.nvimなことや、roxma/vim-hug-neovim-rpcというNeoVimのRPC (MessagePackを使っているらしい) をVim用に変換するというワークアラウンドっぽい方法でVimがサポートされているのを知っていたので、それらのプラグインを使う以上はNeoVimにしておいた方が筋が良さそうと思っていたというのもある。挙動は大体同じで、あともしかしたら速いんじゃないかと期待したけどそこはあまり変わらなかった。

プラグインの廃止と更新

まず、Shougoさんのプラグイン3つを新しくした。それから、そもそもmacOSでヒットした2つのエラーはどちらも出所は自作のプラグインっぽい感じだったが、いろいろ調べたところ自作すべき理由がもうなさそうだったので、それらは使わなくて済むようにした。

Shougo/neobundle.vim

最初にneobundle.vimを後継のdein.vimに移行した。設定はNeoBundleみたいにVim Scriptで書くこともできるが、TOMLで定義することもでき、僕はTOMLを使うことにした。neobundle.vimは2018年でメンテが止まっていて、かつdein.vimの方が速いらしい。

Shougo/unite.vim

後継のdenite.nvimにしようとしたのだが、2014年のUnite.vimとはあまりにも挙動が違いすぎる上、結構時間を使っていろいろ調べたがなかなか自分の期待通り動くように設定できなかったので、一旦これに移行するのは先送りにすることにした。

fzf.vim というのも一瞬試してみたけど、denite.nvimよりも更に期待から離れる挙動だったのでこれも保留にした。思ってたよりファンシーなUI。

諦めてunite.vimのバージョンを2014年のものから最新のものに更新して一旦凌ぐ方針に変えた。そもそもneobundle.vimと違ってunite.vimはバグフィクスの範囲で現在もメンテが継続しているため、古いバージョンに固定などしていなければ、ある日突然壊れるリスクはneobundle.vimより低い感じがする。

適当にmasterに更新してみたところ、見た目が自分が元々使っていたものと大分異なるため違和感がある状態だった。カーソル行ハイライトの挙動が変わったのが原因だなとわかったが、パフォーマンスの都合により、これは戻されることはないらしい。元のハイライト方法がシェルで愛用しているpecoのそれと一緒だったのが気にいっていたので、どうにかして戻したかったので、forkしてリバースバックポートした。まあ2014年のものに固定し続けるよりforkの運用の方がマシとはいえ、本質的には何の解決にもなってないので、そのうちdenite.nvimに移行する予定。

Shougo/neocomplete.vim

後継のdeoplete.nvimに移行。設定のインターフェースがneocompleteそのままっぽい感じだったので移行は一瞬でできた。

k0kubun/vim-open-github

Vimで開いているファイルのGitHub URLをブラウザで開く奴。元々tonchis/vim-to-githubにPRを送りつつ使っていたのが、GitHub Enterpriseに対応させたりなどのために自分で書き直したのだった。で、これがif_rubyを使っていて、Vimをインストールするとif_python3が有効なことは多いがif_rubyは大体ついてなくて面倒なので、このプラグインは捨てたいなと思っていた。

tyru/open-browser-github.vim がよく使われていてメンテもされてそうだったので、これに移行することにした。OpenGithubFile 以外にもOpenなんとかコマンドがいっぱい定義されるせいで :Op<Tab> で一発で補完できないのが不便だなと思ったけど、使わないやつをdelfunctionとdelcommandしていくことで解決できた。

k0kubun/unite-git_files

Gitリポジトリ内では git ls-files を使い、それ以外の場所では file_rec を使うUniteソース。元々yuku/unite-gitに高速化のためにLua対応のPRなども送りつつ使っていたが、多分 file_rec へのフォールバック部分が欲しくてforkした。LuaがなければVim Scriptで動くようにしたとはいえ、このプラグインのためにif_luaに気を使わないといけないのもちょっとなあ、と思っていた。

で、これはdenite.nvimのドキュメントで推奨されている finddir('.git', ';') != '' ? 'file/rec/git' : 'file/rec' がUniteでも同じ感じで設定できるので、このプラグインも不要になった。finddir('.git', ';') だとGitリポジトリトップじゃないと期待通り動かないんじゃないかと心配だったが、それは杞憂だった。

追記: ファイルが多いと file_rec/git が結構遅いことに気付いた。Luaなしなら最新のUnite.vimとNeoVimで問題なくこのプラグインが動くし、別にLuaなしでも file_rec/git よりは大分速いという感じだったので、ひとまずこのプラグインの利用は継続することにした。

Language Server Protocol

あとは使ってそうな設定を持ってきて整理するだけで大体準備できたけど、NeoVimも特にVimと変わった感じしないし、Uniteも無理やり元の挙動に合わせたことで何も変わり映えしなくてつまらんなという感じがしたので、気になっていたLSP連携*2を試すことにした。

deoplete.nvim に移行したことで、どうやら deoplete-vim-lspvim-lsp をいれるだけでLSP連携が動くらしいと @giginet 先輩に教えてもらった。

deoplete-vim-lsp のREADMEにあったGoの例を試そうとしたが、そこにあったbingoはgolspがあるのでメンテが停止していたとのことだったので、mattnさんの記事を参考にgopls*3を試した。なんか型に応じて補完されたり、使われてない変数がハイライトされたりとか、IDEっぽい感じに使えて面白かった。

まあ、IDEみたいに起動してから長い時間インデックスに待たされることもなく、インデックス用のバックグラウンドプロセスが壊れるのを直したりするのに時間を使わされることなくスイスイ書き始めたい時にVimを使っているみたいなところもあるので、実際VimでLSP使いたいかどうかはまた別の話なんだけど。

最近のタイムラインに関する余談

冒頭に昔EmacsやめてVimに移った話を書きはしたが、Emacsが滅んだと思ったことはなかったので、いつのまにかそういう風潮になっていることに驚いた。同僚や同世代にEmacsを使っている人は今でもいっぱいいる*4し、Emacsを使ってることで知られている僕が尊敬する人たちも今でもEmacsを使っていそう、というくらいの認識だった。LispハッカーPaul Grahamが (Lispで設定できるEmacsではなく) vi使いらしいという話が出てたのはちょっと面白かった。

僕はこれまでvim-jpに入ってなくて雰囲気を知らなかったのでこの内容に関してはニュートラルなんだけど、ちょうどvimrc書き直してるところにこれが流れてきて質問とかするのに便利そうだなと思ってvim-jp Slackに入り、「mizchiさんのツイートを見てvim-jp Slackにジョインしました」というボケをかましたらこのツイートでちょっと盛り上がっていた

*1:Vim 8.2がLuaに互換性がなくなったことによるもので、unite.vim最新版では修正済みとのことです https://twitter.com/ShougoMatsu/status/1367281209638674432

*2:どんなエディタでもLanguage Server Protocolに対応することで、それを実装しているサーバーと連携すればIDE的な機能が使える、というもの

*3:ていうか、golspからgoplsに名前変わった…?

*4:単に自分がもう若者ではなくなってしまったからだとは思うが