MJHD

エモさ駆動開発

2020年 振り返りと抱負

どんな年だったか

今年は引き籠りが合法となったことにより、プライベートが充実した年だった。

相対的に仕事の記憶があまりない。めちゃ頑張った気がするけど。

プライベートは年始から急にハマった現代思想に始まり放送大学に入学したり、UberEatsが高いので自炊をしたり、引っ越したり猫を飼ったりした。

 

現代思想

もともと大学の時に教養科目として現代思想の概論のような授業を受講し、毎回板書を三回読み直し、図書館へ通い原著を読む(当然何も理解できない)生活をしていたが、大学卒業後はしばらく触れていなかった。 

社内の技術交流会でひょんなことから現代思想の話が始まり、同時期にOOUIの勉強会などにも参加し、グレアムハーマンの四方対象を読み始めたこともあり、急にマイブームが訪れた。

おかげで今年は自分史上稀にみる読書の年になった。

読んだ本

自分の知識レベルとしては、一般教養として哲学者・思想家の名前を知っている程度だったので、ひたすら入門書を読んだ。

はじめての構造主義 (講談社現代新書)

はじめての構造主義 (講談社現代新書)

 

構造主義のお話。初心者でもとても読みやすく、現代思想でも大事な部分なので取り掛かりとしてとても良かった。

 

資本主義に出口はあるか (講談社現代新書)

資本主義に出口はあるか (講談社現代新書)

 

そういえば今の経済の歴史を何も知らないな?資本主義という言葉に苦手意識があったため、この本を読んだ。これも非常に読みやすく、分かりやすく思想をカテゴリ分けしてくれている。

歴史的な出来事や当時主流だった思想を、右と左、ロックとルソー、保守とリベラル、ルーズベルトとウィルソン…など対立関係で説明している。

現代思想の歴史としても、当時の世界情勢が理解できると思想の背景が理解できるため、学びがあった。

 

資本主義リアリズム

資本主義リアリズム

 

資本主義つながりでもう一つ、気になっていた本。資本主義が唯一の思想となっている現代において、資本主義の終わりを想像するよりも世界の終わりを想像する方がたやすい。資本主義の思想を内面化してしまっている現代人に、本当にこれでいいのか?と呼びかける内容だった。

上の「資本主義に出口はあるか」と一緒に読んだため、歴史的に現代がどのような状態に置かれているのか、理解がはかどった。

 

四方対象: オブジェクト指向存在論入門

四方対象: オブジェクト指向存在論入門

 

OOUI つながりで興味のあった、オブジェクト指向存在論の原著。ド素人が読んでも分かるものではないので、逆に「何を学ばなければいけないのか」をリストアップする用途になった。四方対象はライプニッツフッサールハイデガーホワイトヘッドなどなどの思想を引用して説明されているため、こいつらを学ばなければいけない。

ひとまずハイデガーホワイトヘッドを次に学ぶことに決めた。

 

ホワイトヘッドの哲学 (講談社選書メチエ)

ホワイトヘッドの哲学 (講談社選書メチエ)

 

オブジェクト指向存在論で度々言及される、ホワイトヘッドという思想家の入門書。

世界は連続する有機体である、物と物の間に厳密な区別はなく、我々は世界を抱握によって認識している…。

という有機体の哲学を分かりやすく説明してくれている。

合わせて、

1267夜『ホワイトヘッドの哲学』中村昇|松岡正剛の千夜千冊

を読むと理解がはかどる。

 

 神は実在するのか。

アンセルムスという「神」の定義をした司祭・思想家の解説から始まり、ルイスのそれに対する論理学的な批判を通して、分析哲学という一つの流派を学べる本。最終的に可能世界、様相論理などを解説している。

大学の卒論で様相論理、可能世界意味論を学んだのだが、後半、論理式がとても多くなるため、かなり読むのに苦労した…。

こういう哲学があるんだな、という学びが得られた。

 

 ここまで色々本を読み、これは外せないなと感じた思想家三人、ベルクソンサルトルフーコーを解説した入門書。

読みやすかった。ベルクソンは特に理解しやすく説明されていた。

 

現代フランス哲学に学ぶ (放送大学教材)

現代フランス哲学に学ぶ (放送大学教材)

 

放送大学でテキストとして使っている本。正直、放送大学の授業内容は、この本を音読した音声なので、実はこの本を買うだけで事足りる。

ベルクソンメルロ=ポンティ構造主義フーコー、ポールリクールを軸に、ハイデガー、マルセル、アラン、サルトルフッサール…と一通り概要を説明してくれている。

内容もとても分かりやすいし、都度他の思想家と対比をしながら説明をしているため、脳内マップの作製にとても役立つ。

ここでベルクソンの理解がかなり進み、「あーなるほどー!」と声に出しながら受講できた。

これから期末試験。

抱負

来年も、まだまだ穴埋めできていない思想家が沢山いるため、入門書を漁っていきたい。

特にカント、マルクスハイデガーについてまだ概要しかわかっていないがかなり重要人物なので、きちんと学びたい所存。

そして、準備万端の状態で四方対象を読み切りたい。また、フーコーの系譜学ももう一度読み直したい(今ならもう少し内容が入ってくる気がする)。

エンジニア

今年は、新しい技術や言語の習得ができていない年だった。(マズイ)

Rust を少し齧ったが、まだまだ「Rust らしいコード」を書けていない。

抱負としては「低レイヤーに関する知識を深める」。CPU/GPU、ドライバ、カーネル、OS、コンテナ…などなど。

ひとまず、下記の記事に取り組みたい。

kaminashi-developer.hatenablog.jp

また、Rust についても作成中の作品を作り切るところまでは最低限やっていきたい。

人生

そろそろ彼女作らないとまずくない…?まずくない?

20代後半戦に入って、ライフステージが周囲に比べて低いのが気になるところ。

総じて

来年は自発的に動いていく年になると良いなと思います。

2020年 買ってよかったモノ

一昨年のエントリ: mjhd.hatenablog.com

気がついたら「もうそんな未来?」感のあった2020年も終わりを向かえそうな日頃になってきましたがみなさんいかがお過ごしでしょうか?
僕はと言えば家から出ず会話をするのはコンビニのレジぐらい。「レジ袋要りません」「レシート要りません」「iDでお願いします」「あ、温め要りません、割り箸で」をランダムな順序で店員に伝え、どういう挙動をするのかデバッグするときしか声を使いません。そう言えば最近、上司からも声が小さいとよく言われますが、きっとこの生活で声帯が退化したのだと説明しています。新種の脊椎動物です。毎回ツッコミが入りますが。

そんな今年は家で1人で楽しめる調理器具やオーディオビジュアルをよく買った印象があります。
今年買ったモノを選りすぐり、上から5つご紹介したいと思います。

1位. 月の土地

そろそろ良い歳にもなってきたので、不動産を持ちたいという気持ちが湧いてきました。
でも日本、狭くない?そもそも地球、狭くない?せっかく買うなら最先端の不動産を買いたい。未来に生きたい。

まだ地球で消耗してるの?

ということで月に土地を買いました。場所は「ロット 189/1070 エリア J-05 QUADRANT B」。

f:id:wait0000:20201219133658j:plain:w500
月の土地権利カード

地球に向いた面でいうと、左下の方の盆地(クレーター)の内側です。日当たりも良好らしく、平坦で基地を建てるにもちょうどいいです。一等地に違いありませんね。

f:id:wait0000:20201219133511j:plain:w500
月の住所

広さは約1200坪(1エーカー)、老後は広大な土地を活用して巨大な自動プランターと代替肉工場を建て、余った土地は駐船場として運用しながら相棒の宇宙ネコとともに悠々自適な生活を送ろうと思います。
重力ないので老後の腰に優しい点もオススメです。

f:id:wait0000:20201219133456j:plain
月の土地権利書


真面目な話、飲み会などでこのカードをサッと出すだけで話のタネになるので、値段(3000円)以上の価値がありました。
贈り物などに是非。

www.lunarembassy.jp

2位. なんちゃってホームシアター

地上波は見ないしFPSなどのゲームしかしないため、テレビと悩んだ末にプロジェクターを買いました。
使ってないときはテレビより幅を取らないし、部屋の圧迫感もなく、それでいて大画面(80~100インチ)で好きな動画やゲームができる体験はとても素晴らしいです。

住んでいる部屋がそんなに広くないため、壁から離せる距離は2mぐらい、短焦点なら1~2メートルで100インチぐらいの大きさになります。
解像度は最低 Full HD、ゲームができる低遅延なものを選びました。

f:id:wait0000:20201219174309j:plain:w500
音楽イベントの中継など流すと楽しい


プロジェクタを買って気づいたのは、画面が大きい分ゲームをするにも動画を見るにも体力を使う点。
なので、軽めに動画を楽しみたいときはPCで見たりPS4 Remote Playでゲームをしてます…短焦点じゃないければこの辺り調整効いたのかも?

合わせて↓の周辺機器を買って光デジタルで音声を取り出して、Bluetoothで接続できるようにしてます:

言わずもがな、ブラウザを通じてデスクトップ共有もできます

Google Chromecast 正規品 第三世代 2K対応 チャコール GA00439-JP

Google Chromecast 正規品 第三世代 2K対応 チャコール GA00439-JP

  • 発売日: 2020/03/01
  • メディア: エレクトロニクス

HDMI切り替え機。リモコン付きがおすすめポイント、Nature Remoで切り替えも自動化できる

HDMI → 光デジタルを取り出す機械

手ごろなサウンドバー。音質はそこそこ、音に立体感あるのでFPSゲームで敵の位置が分かる

光デジタルをパススルーしてサウンドバーにつなぎつつ、AAC対応(本当か少し怪しい)なのでFPSゲームできるぐらいの低遅延でBluetooth接続。夜中など音を出せないときや大音量でプレイしたいとき用

3位. MTG Body Make Seat Style

リモートワークが始まって一番初めに躓いたのが、「腰が爆発しそう」
家系的にも腰が大爆発して金具を入れる手術をしてきた系譜を踏んでるので、いつダメになるのかとても怖い。
姿勢も悪い自信があるのでこれはとてもマズイ。

そこで良さげなワーキングチェアを購入したのですが、全く腰に合わない
逆に腰が痛くなる始末で、仕事に集中できない。上司との1on1をしても「腰が悩みです」しか言えない。

一時期はコルセットを巻いて生活をしていたのですが、オススメされて MTG Body Make Seat Style を半信半疑で買ってみたところ、腰がとても楽に。
今では部屋中持ち歩いて、ソファやイス、布団の上に座るときにも愛用してます。

座ってない時の姿勢も矯正されてるような気もする?良い買い物でした。

会社にも持っていきたい…

4位. 電気圧力鍋

リモートが増えて自炊をする機会も増えました。そして以前から抱えていた欲望を抑えきれなくなりました。

「低温調理したい…」

男という生き物は、20代前半はパスタ料理に、20代後半〜30代前半は低温調理に、30代後半はきっと蕎麦打ちにハマる生き物なのでしょう。生物の根源的欲求です、逆らうと体に毒なのです。

ですが低温調理機、用途が限定されるわりにそこそこのお値段する&もしかしたら一回使って満足してしまうかもしれない…という不安もあり、代替案を探しました。

そこで見つけたのが電気圧力鍋

普段は材料とカレールーをぶち込んで自動メニューを選ぶだけで圧力調理で柔らかい「カレー」を作ってくれるカレー製造機ですが、「低温・発酵調理」を選ぶと鶏ハムやローストビーフなどの低温調理ができます。
容量は少なくなりますが低温調理機ほど手間もかからず、美味しい鶏ハムを作ることができます。…鶏肉ってこんなにうまいんだ…

f:id:wait0000:20201122225611j:plain:w500
塩胡椒でシンプルな鶏ハム

「なべモード」を選ぶと、通常のIH調理器具のように電熱調理することができ、炒め物やスープも作れちゃうのでガスコンロ要らないのでは?といった感じです。もちろん圧力調理で煮物なども美味しいです。

上記リンクは一人暮らし向けの小容量版ですが、ご家族がいらっしゃる方は 4.0L のものをオススメします。

5位. Aftershockz AEROPEX

社内の某 times チャンネルで気になってた骨伝導イヤホンですが、ついに買ってみました。

僕はランニングが好きなのですが、普段使ってる AirPods Pro は走っていると耳が蒸れ気味になったり、外音取り込みモードの音がそんなに好きじゃない(うまく言葉にできないですが、現実の音じゃない感)、何かある度に取り外さなきゃいけない&紐もないので失くしがちと難点がありました。

骨伝導初心者なのですが、想像していた骨伝導の音とは全く違い、下手なイヤホンより音質良いのでは?というクオリティながら、外には漏れるのは軽いシャカシャカ程度。
耳が完全に開放されているのが何よりも新体験です。

音としては、低音は全く出ない(代わりにバイブレーションは感じる)のですが、特に中音〜高音の質が良いです。
耳を開放しているからといって、スピーカーから聞こえる音とも違い、ちゃんと近くで鳴ってる感はある。なんでしょう、耳が4つある感覚です(?)。

以上

今年買った5つのオススメ商品を書きました。
来年はコロナが解消しつつ、新しい生活様式が定着してることを願います。

2020年最高のWSL環境を求めて

前回: mjhd.hatenablog.com

熱狂的なWSL信者の皆さん、お元気でしょうか。
前回WSL環境について記事を書いてから1年が経ち、WSLを取り巻く状況も様変わりしました。Windowsのアップデートもあり、手元の環境もスクラップ&ビルドを繰り返したため、開発環境としてかなり完成度が高くなりました。安寧です。もう我々は花びらを散らす必要はないのです。

WSL2

まもなくの正式リリースが予定されている Windows10 version 2004 に含まれるWSL2は、今年一番の変化です。
WindowsのプロセスとしてELFをロードしLinuxシステムコール互換レイヤを通じて実行されていたWSLの仕組みが大きく変わり、軽量仮想マシン上で動くLinuxカーネルのプロセスとして実行されるようになりました。
これにより、システムコールの互換性が100%になったり、付随してext4ファイルシステムを直接使うようになったためIOのパフォーマンスがかなり向上するなど様々なメリットが得られました。
大幅な方針転換ですが、軽量VMの起動速度が1秒ほどという特徴もあり、デメリットをほぼ感じません。
以前のWSLからWSL2へ変換ができるため、開発環境として使いたい人はぜひ乗り換えましょう。
(WSL2の初期にあったlocalhost問題も解決しています)

WSL, WSL2の仕組みについては師匠のスライドが分かりやすいです:

www.slideshare.net

Docker for Desktop

Docker for DesktopがWSL2をバックエンドとして利用できる機能を公開しました。(まだ実験的ですが)
WSL1では様々な問題でdockerdを起動することができませんでしたが、WSL2はそもそも仮想マシンなのでなんでもできます。 そこで、WSL2のディストリビューションの一つとしてdockerd入りのLinuxを起動することで、オーバーヘッドも小さく高速に起動するコンテナ環境が実現できました。
起動したホストには他のディストリビューションWindowsからアクセスすることができます。

f:id:wait0000:20200509143313p:plain
WSL2 backendの設定項目

f:id:wait0000:20200509143944p:plain
docker-desktopがWSLディストリとして作成されます

Windows Terminal

今まで、WSLで使用するターミナルは

  • Xserverを通じてgnome-terminal, terminatorなどのLinux系ターミナルを動かす(少し不安定&起動に時間がかかる&依存がデカい)
  • Hyper, alacrittyなど、マルチプラットフォーム対応のターミナルを使う(微妙に不安定, 日本語入力がバギー)
  • FluentTerminal, TerminusなどモダンなWindows用ターミナルを使う(発展途上)
  • wsltty(レガシー)

など選択肢がありましたが、どれも日常的に使用するには不満が大きかったです。

今は Microsoft 謹製の Windows Terminal があります。

www.microsoft.com

初期のころは機能が十分でなかったり重たかったりという不満がありましたが、最新版は軽く安定していて、設定項目も十分です。
useAcrylicを有効にすれば、FluentDesignのアクリル素材効果が適用されてWindows10っぽさが増します。
iTerm2のカラースキームを取り込むこともできます。 もはやターミナルエミュレータはこれ一択かな、といった状況です。

f:id:wait0000:20200509141719p:plain
WIndowsTerminalの様子

f:id:wait0000:20200509142857p:plain
vimもかなりサクサク動くよ

ディストリビューション

何を選ぶかは信仰の自由もとい個人の自由ですが、僕はArchLinuxを選びます。
GUI方面はWindowsに任せ、主にターミナルを用いた開発環境としてのLinuxをメインに使う場合は、ArchLinuxがミニマルで良いのではと思います。
(そういえばxserverも消しちゃった)

もともとArchLinuxはWindows Store上で配布されていたのですが、偽物騒動などもあり現在は配布されていません。

以下のリンクからArchLinuxのappxを入手できます。これを使うのが現状一番手っ取り早いです。 github.com

Windows<->Linuxのファイル共有

もともとの課題だった、WSLのファイルをWindowsから読めない問題は、(多分)Hyper-Vソケットを通じた9pプロトコルWindows実装がされたことで解決しました。
逆に、9pプロトコルとDrvFSを通じて従来通りLinuxからWindowsファイルを読み書きすることもできます。
以前よりパフォーマンスが悪いご様子ですが、LinuxのFS内でWeb開発をする分には問題ないです。

f:id:wait0000:20200509145305p:plain
WSLのファイルを閲覧する様子

ascii.jp

おわりに

もう今までのようなハッキーなことをしなくても簡単にWindowsPOSIX標準環境が手に入ります。
今のところ開発環境として不満はなく、完成したかに思えます。
スリープ可能なLinux(Unix)としてのMacではなく、スリープ可能なLinuxとしてのWindowsが実現できそうです。

チーム異動後のターミナル周り

半年前にチームの移動をした。プロダクトは同じだが、サーバからWebフロントへポジションチェンジした。

以前からvimを使っていたが、Go言語はlspへの過渡期があったためIntelliJvimバインドを使用するなどCLI離れをしていた。 チームの異動後はTypeScriptを書くことが多く、vimをメインに使用するようになったため、CLI周りの見直しをよく行う様になった。

dotfiles

dotbotというdotfilesを管理するOSSを入れた。 デフォルトでは、dotfilesへのシンボリックリンクを作成してくれる機能ぐらいしかないが、gitのサブモジュールとしてdotbot-brewなどを追加することで、brewを使ったパッケージの自動インストールなどもできるようになる。 macOSとWSLを触ることが多いため、brewaptyayの三つに対応し、普段の開発に必要なツールのインストールを行うようにした。 今まではシェルスクリプトでこのあたりの処理を書いていたが、メンテナンスするのが面倒になってきていた。dotbotyamlだけメンテナンスすれば良いので楽。

vim

設定ファイルをシンプルに

今までは.vimrcファイルをかろうじてneovim以外でも動くよう、ifなどで分岐をしていたが、これを一切やめた。 また、deinautoloadを使って、プラグインが読み込まれた時に設定も読み込まれるようにした。設定ファイルも自然と分割する様になるため、かなり見た目もスッキリした。 副作用として、vimscriptちょっとかけるようになってきた。

ちゃんと操作できるように

正直今までのvimの使い方はvimmerとして酷いものだった。十字キー万歳、テキストオブジェクトをほぼ知らない、プラグインキーバインドはデフォルト。 これをかなり意識して直すようになった。 実践vimを読み進めながら矯正中。

yabai

ターミナルからは少し離れるが、yabaiというOSSを使っている。 タイル型ウィンドウマネージャなのだが、割とマウス操作もサポートしているのが特徴。 今で、Macのタイル型ウィンドウマネージャAmethstなどを使用していたが、バグが多く挙動が不安定なため、使用を諦めていた。 yabaiはその点、割と安定して動作している。(もちろんバグもあるが、設定でカバーできる)

yabaiを使っている様子

動画をPiPっぽく表示したり、Fn+マウスでリサイズ、移動、入れ替えなど様々な挙動ができる。

skhd

ホットキー管理のOSSであるskhdは上記yabaiとセットで使うと便利で、yabaiのウィンドウレイアウトの変更やPiPの切り替え、ターミナルの起動など、様々な連携をホットキーにより設定できる様になる。 Ctrl+Shift+Enterでターミナルが立ち上がり、ウィンドウの配置も自動で行ってくれるため、すぐにコマンドを打ち始めることができる。 動画などはAlt+PでPiP表示にしたり、Alt+Eで分割の方向を変更したり、ウィンドウを半透明にしたりできる。

yabaiとskhdの組み合わせを使い始めたことは今年一番実りのある行為だったかもしれない。

ターミナルエミュレータ

最近はkittyhyperalacrittyなど、クロスプラットフォームGPUレンダリング可能なターミナルをいくつか試していた。(WSLでも同じものを使用したいため、Windowsバイナリが配布されてる必要がある) が、どれも顕著なバグがあり(kittyはコピペ周りでバグるし、日本語ダメ。hyperは描画が崩れる&コピペバグる)またiTerm2に戻ってきてしまった。 WSLで使えないため、まだまだ彷徨う必要がありそう。

Golangメモリ周りのメモ (goroutine割り込み)

前回

mjhd.hatenablog.com

最近、面白いツイートを見つけた。

内容は、ゴルーチンのデッドロックなのだが、原因が「協調割り込み」というゴルーチンが動作するための仕組みと、前回の記事で紹介したmid-stack inliningの複合技により引き起こされていると言う。 今回は、ゴルーチンの内部動作から、なぜこのバグが引き起こされたかをまとめたいと思う。

そもそもゴルーチンってどうやって動いてるんだっけ?

GolangではOSの管理するスレッドとは別に、論理プロセッサと独自のスケジューラを持ち、ランタイムが管理をしている。
コンポーネントは以下のように説明される。

M(Machine): OSの管理するスレッド

G(Goroutine): ゴルーチン

P(Processor): 論理プロセッサ

よく見かけるGOMAXPROCS変数はこのうちPに該当し、論理プロセッサの数を表す。

golangのスケジューリングは二つの階層に分けて説明でき、一つ目は、M(スレッド)とP(論理プロセッサ)の割り当てと、もう一つがP(論理プロセッサ)とG(ゴルーチン)の割り当てである。

work-stealing

グローバルとして、キューを持ちPに割り当てされていないゴルーチンを保持する。

また、各P(論理プロセッサ)もそれぞれキューを持ち、割り当てられたゴルーチンを保持している。

Pはもし自分のキューにゴルーチンが存在しなければ、他のPからゴルーチンを奪い、実行する。 これをwork stealingという。 もし奪えるゴルーチンが存在しなければ、グローバルなキューからゴルーチンを割り当て、実行する。

ゴルーチンの実行が終わると、Pは別のゴルーチンへコンテキストスイッチをし、実行を続ける。

これを繰り返しゴルーチンは処理されている。

協調割り込み

ここで一つ問題になるのが、もし一つのゴルーチンがとても重たく、容易に終了しないものだった場合、このままでは論理プロセッサ P が占有されてしまう。 現在の定義だと、Pがゴルーチンが終わるまで次のゴルーチンへコンテキストスイッチできないのである。

ここで必要になる機能が、ゴルーチンの割り込みである。ゴルーチンの割り込みとは、ゴルーチンの実行中でも他のゴルーチンに処理を譲る(または奪う)ことで、平等に平行に処理をするための機能のことである。

現在のGoの実装では、「協調割り込み(co-operative preemption)」という方式が実装されている。 これは、コンパイル時に任意の箇所に割り込みコード(他のゴルーチンに処理を譲る処理)を埋め込むことにより、ゴルーチンが他のゴルーチンに処理を譲りながら実行できるようにしたものである。 基本的に、この割り込みコードはインライン化されていない関数呼び出しなど周りにコンパイル時に挿入される。つまり、関数呼び出しが合図になる。

逆に言うと、関数呼び出したり、その他割り込みコードが挿入される余地のない強めのループなどを書いてしまった場合、その P を占有してしまう。

非協調割り込み

これは proposal として掲げられている機能なのだが、上記の協調割り込みには強めのループなどのようにエッジケースが存在するため、非協調割り込みという、強制的にゴルーチンの処理を奪う方式を採用しようという動きがある。

proposal/24543-non-cooperative-preemption.md at master · golang/proposal · GitHub

バグの原因は

前回紹介したmid-stack inliningに関連して、より積極的に関数のインライン化が可能になったため、先日 RWMutex のインライン化対応が行われた。

https://go-review.googlesource.com/c/go/+/148958

これにより、RWMutex.RLock, Unlockなどがインライン化されてしまい、割り込みチェックが入らなくなってしまった。 よって、無限にブロックし続けるプログラムが誕生した。

参考文献 

Golangのスケジューラあたりの話 - Qiita Scheduling In Go : Part II - Go Scheduler

次回

多分SSA最適化あたり?

Railsにsorbetインストールしてみた with LSP

Rubyの静的型チェッカー、「Sorbet」がオープンソース化された。
LSPも実装されており、これだけRubyもシェアがあるので、覇権を握れるのでは。
手元にちょうど良いRailsプロジェクトが合ったため、導入してみた。

Sorbetのインストール

ここではあまり詳しく説明しないが、基本的には公式ドキュメントのGetting Started通りに進めていく。
Gemfileに追記し、bundle install、srb initをするぐらいで一瞬で終わった。

デフォルトではファイルの先頭に

# typed: false

と書いてあるため、型チェックはされない。
試しにここを

# typed: true

に変更してみると、例えばRailsのControllerなどでは大量にエラーが出るはず。

これは、Railsが実行時にroutingなど動的に様々なシンボルを生成しているためで、このままだと使い物にならない…。

Rails対応

sorbet-railsというRails向けsorbetの型定義生成ツールがある。
これを入れれば一通り開発ができるようになる。

インストールはこちらもREADME通りに進め、最後に

$ srb tc --suggest-typed --typed=strict --error-white-list=7022 --autocorrect

を実行すれば型チェックが実行可能になったファイルのtypecheck level(ファイルの先頭にあるtyped)を上げてくれる。

これにより先ほどはエラーが出ていたcontrollerなども

# typed: true

となり、型チェックが通るようになる。

LSP導入

せっかく静的型付けができるようになったので、LSPによる定義へジャンプや補完、型チェックを使いたい。
LSP導入の方法は色々調べたがドキュメントが全くなく、自己流で導入した。 (おそらく今後この辺のドキュメントも揃ってくると思う)

まずは、公式レポジトリをクローンする。

$ git clone https://github.com/sorbet/sorbet

次に、README通りにbazelや必要なライブラリのインストールを行う。macユーザで今までC++で開発をしたことがないユーザは、以下のコマンドも必要かもしれない。

$ open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg

準備ができたら、bazelでビルドを行う。この時、プロダクションビルドのオプションを指定する。

$ bazel build //main:sorbet --config=release-mac (またはlinux)

これにより、bazel-bin/main/sorbet というバイナリができ上がる。

このバイナリを以下のようなオプションをつけて、プロジェクトのルートで実行するとLSPとして待ち受けるようになる。

$ sorbet --disable-watchman --no-config --enable-all-experimental-lsp-features--lsp --dir .

(--no-configを設定しているが、これは簡単のためであり、本来はプロジェクトごとの設定ファイル(sorbet/config)を読み込むべき)

これをvimVSCodeに設定すれば、補完や定義へジャンプが有効になり、快適なsorbetライフが送れるようになる。

Golangメモリ周りのメモ (mid-stack inlining編)

前回

mjhd.hatenablog.com

mid-stack inliningとは

mid-stack inliningとは、前回の記事でも紹介したインライン化をより積極的に行うようになる機能のことである。

前回の記事からの引用だが、

Goのコンパイラは、関数が以下の条件に当てはまるとき、関数を直接、呼び出し元に展開する最適化を行っている。(これも上のコマンドで解析結果を確認できる)

コードが80ノード以下(Go1.4以前は40ノード)
関数呼び出し、ループ、ラベル、クロージャ、panic、recover、select、switchなどの複雑な構文を含まない

以上がインライン化の大まかな条件であった。ここには、関数の呼び出しという項目があり、今まで関数のインライン化は一番末端にある関数(木構造でいう葉っぱ)でしかインライン化を行なっていなかった。
mid-stack inliningは、これを改良し末端以外の関数でもインライン化を行うための最適化である。

インライン化による弊害

これはmid-stack inliningの有効無効に関わらない話だが、インライン化により、スタックトレースを出力した際などに実際のソースコードとの差異が出てしまう。

例えば以下のような関数があったとする。

type s struct {
  c int
}

func a(v *s) {
    v.c++
}

func b(v *s) {
    a(v)
}


func main() {
    b((nil)(*s))
}

このコードがもしインライン化されたとすれば、以下のようなコードになる。

type s struct {
  c int
}

func main() {
    ((*s)(nil)).c++
}

ここでnil pointer dereferenceが発生した場合、以下のようなスタックトレースが表示されてしまう。

panic: nil pointer dereference

main.main()
        /main.go:16 +0x2

関数a, bの情報が消えており、デバッグが困難になってしまう。

どうやって解決するの?

mid-stack inliningでは、インライン化した関数のPCとソースコード上の位置を保持する木構造をテーブルとして表した構造体(InlTree)を生成し、シンボルテーブルに格納する。
実行時は格納されたテーブルから実際のスタックトレースを生成し表示を行うことで、インライン化をしたとしても正しく出力が行えるようになる。 ただし制限として、以下のように引数は省略されてしまう。

panic: runtime error: invalid memory address or nil pointer dereference

main.a(...)
         /main.go:8
main.b(...)
         /main.go:12
main.main()
        /main.go:16 +0x2

どのぐらい早くなるの?

ベンチマークによると9%ほどパフォーマンスが改善するらしい。
また、標準ライブラリにもコードを少し調整することでmid-stack inliningの恩恵を受けることのできる部分があるため、以下のような改善を繰り返していくことでGo全体のパフォーマンスが向上するのではと思う。

sync.Once.Do https://go-review.googlesource.com/c/go/+/156362/

sync.Mutex.Unlock https://go-review.googlesource.com/c/go/+/148958

参考文献

talk: Mid-stack inlining in the Go compiler (external) - Google スライド cmd/compile: enable mid-stack inlining · Issue #19348 · golang/go · GitHub proposal/19348-midstack-inlining.md at master · golang/proposal · GitHub

次回

mjhd.hatenablog.com