Don't Repeat Yourself

Don't Repeat Yourself (DRY) is a principle of software development aimed at reducing repetition of all kinds. -- wikipedia

年初でアップデートした開発環境の話

いくつか記事を読んで、もう少しGitならびにGitHubの操作周りを便利にしたいと思ったので、いくつかアップデートをしてみました。追加したのは次のとおりです。

  • ghqの導入と、リポジトリfzfで探せるようにした。
  • ghコマンドをちょっと覚えた。
  • Orbstackをbrew installで追加できるようにした。
  • tmuxで新しいウィンドウを開いた際に直前で使用していたディレクトリパスで開くようにした。
  • miseを入れた。

ghqの導入と、リポジトリfzfで探せるようにした

これまで私の開発環境ではリポジトリ間の移動が結構大変だなと思っていました。ghqそれ自体にはいろいろ用途があるようなのですが、今のところはghq listを便利に使っています。

公式にはpecoと組み合わせてリポジトリ一覧を取得しつつ、カーソルを動かした先でEnterすると該当するリポジトリに移動できるというものが載っています。私はfzfの方を使っているので、fzf用にカスタマイズしました。このgistを参考にしました

github.com

exaを使っているので、ついでにexaが呼び出されてカーソルを動かした先のプレビューがツリーで表示されるようにしています。Ctrl+gを押すと出てきます。

実のところ仕事の方のPCではtmuxのウィンドウを仕事用のリポジトリに割り当てて行き来してるだけなので、仕事の方は困りません。時々ウィンドウに用意しているリポジトリ以外に移動する必要が出てきた時に活用しています。

ghコマンドをちょっと覚えた

全然使っていませんでしたがghqをBrewfileに登録する際に近くにghというのがいたので、せっかくだから使ってみようかと思った次第です。普段はlazygitでほとんど管理しているのでlazygitと組み合わせて使おうかなと思っています。lazygitのショートカットキーを割り当てて使うといいよというアドバイスを見かけたので、どこかで整理したいと思っています。

とりあえずPull Requestをターミナルを出ずに作成できるのが便利です。gh create prですね。ただPull Requestを作成する際、descriptionを書く時にNanoが開いてしまって困ったので、そこだけ微調整しました。Vimが開いて欲しかったので、

gh config set editor vim

で調整できました。

Orbstackをbrew installで追加できるようにした。

少し前まではたしか手元にダウンロードしかダメだったと思うんですが、Docker Desktopが重すぎて無理と思いOrbstackをインストールしようとしたところ、brew installできるようになっているのを見つけました。やったね!

tmuxで新しいウィンドウを開いた際に直前で使用していたディレクトリパスで開くようにした。

地味に不便だったため。この記事を参考にしながら修正しました

github.com

あと、水平分割は-で、垂直分割は|でできるようにしておきました。直感的だったので。

miseを入れた。

miseを導入してみました。少し前にrtxからリネームされたツールです。さまざまなenvをこれひとつで管理できるようになります。細かい機能はまだまだ開発途上な気はしますが、すでにある程度使える状態にはあると思います。

github.com

miseのおかげで結構な数のbrew installを飛ばせていることがわかるdiffです↓

github.com

そのほか

あとはこの記事を見ながら、xhを追加したりしました。exaのフォーク版ezaが出てるんですね。どこかで乗り換えなければと思いつつ、さまざまに設定したエイリアスを切り替えるのが面倒で重い腰が上がっていません…

zenn.dev

dieselでbatch upsertをするには

Rustのdieselでbatch upsertをやる方法について、検索してもなかなか苦労したのですごく簡単にメモしておきます。バックエンドはPostgresを想定しています。MySQLでもこれができるかはわかりません。

結論

diesel::insert_into(...).values(...).on_conflict(...).do_update().set(...)でいける。

excluded句を入れたい場合

たとえばcolumn_aというカラムをexcludedしたいとします。最後のsetの呼び出しのところで、.set(column_a.eq(excluded(column_a)))とすれば実装できます。複数カラムの場合、setにタプルを投げ込むと指定できます。たとえばcolumn_acolumn_bcolumn_cに対してexcludedしたい場合、

diesel::insert_into(...)
                .values(...)
                .on_conflict(...)
                .do_update()
                .set((column_a.eq(excluded(column_a)), column_b.eq(excluded(column_b), column_c.eq(excluded(column_c))))

のようにです。

複数カラム指定を楽にする

ただカラムの数が増えてくるとだんだん間違えます。そこで、このタプルの生成はマクロに任せてしまうといいと思います。次のようなマクロを書きます。

macro_rules! excluded {
    ( $( $column:expr ),* ) => {{
        use diesel::{upsert::excluded, ExpressionMethods};
        ($( ($column.eq(excluded($column))) ),*)
    }}
}

これを先ほどのsetに投げ込みます。

diesel::insert_into(...)
               .values(...)
                 .on_conflict(...)
                .do_update()
                .set(excluded! {
                    column_a,
                    column_b,
                    column_c
                })

これで、あとはコードが展開されて勝手にexcludedを含むタプルが生成されます。結構便利だと思うので、困ったなと思ったらぜひ使ってみてください。

『詳解Rustアトミック操作とロック』(Rust Atomics and Locks)

昨年買っていたんですが、年末年始の時間を使って少し読めました。

著者はRustコンパイラにコントリビューションをしたことがあれば誰でも知っているかもしれない、Mara Bos氏です。

ちなみにですが、原著は下記サイトで無料でも読むことができます。

marabos.nl

書籍は下記です。

なおこの記事内で「本書」と明記する場合、それは『詳解Rustアトミック操作とロック』を指します。また、「筆者」は私自身のことであり、「著者」はMara Bos氏のことです。

内容のメモ

読んだ内容のうち、印象に残ったり初見だったものをメモしておきます。

1章

1章は主にはRustの並行性を理解するために必要なツールと概念が説明されます。具体的には、スレッド、Mutex、スレッドの安全性、内部可変性などです。TRPLよりさらに深く説明されるため、なるほどそういう意味があったのかと思う箇所がいくつかありました。

Mutexのpoisoning周りの説明と、ならびにMutexGuardの説明はとくに勉強になりました。MutexGuardの説明の中で、次のコードは一見すると結果が同じに見えるものの、実はボローチェッカーの挙動が異なるせいで挙動が変わるらしいというのを知りました。

if let Some(item) = list.lock().unwrap().pop() {
    process_item(item);
}

if list.lock().unwrap().pop() == Some(1) {
    do_something();
}

後ろのコードから説明しますが、後者のコードは後続の処理内で何かリストから取り出した要素を使用したりしません。返す値は常にboolであり、何もそこから借用しません(コピーセマンティクスです)。したがって所有権を気にする必要がなく、また一時変数の生存期間を気にする必要がありません。これにより、一時変数のガードはif文が実行される前にドロップされます。つまり、ロックは条件式を抜けると解除されます。

一方前者のコードでは、一時変数itemは(後続のブロック内で)借用の可能性があるため、生存期間をif文の最後まで延長する必要があります。仮に借用が一度も起こらなかったとしても、ボローチェッカーはドロップするタイミングや順番には影響を与えず、生存期間のチェックだけは行なってしまいます。これにより借用した場合と同じように見かけ上は動作してしまうらしいです。ロックは解除されません。

上記のコードは、次のように一時変数をifの外で作っておいて、それを利用するようにすると良いです。生存期間を意図通り細かく区切れるため、意図したスコープを抜けるとドロップが発生します。結果Mutexのロックを解除することができます。

let item = list.lock().unwrap().pop();
if let Some(item) = item {
    process_item(item);
}

以前X上の議論で、似たようなものがありました。そのときの説明では、これはパターンマッチに脱糖されるのでそこからスコープを考えてみると、生存期間がパターンマッチの腕の中までと断定できるのではという話がありました。が、これは微妙に説明不足だったと思っていて、理由としてはとくに私が手元でHIRで脱糖の状況を確認したところ、if letは必ずしもmatchに変換されているわけではなさそうだったためでした。そういうわけで、脱糖の観点からの説明は難しいのではないかと当時は考えていました。アナロジーとしては正しいんですけどね。そしてこの節を読んで、実はこのように借用とそれにまつわる生存期間からの説明が妥当だったということがわかりました。

2章

RustのAtomicではじまる機能についての解説です。Javaでは結構使ったことがあって馴染みがあるんですが、Rustの方はあまり使ったことがなかったなと読みながら思いました。いい勉強になりました。アトミック操作を使うとこういう機能を実装できるよ、という例がいくつか示されており、実アプリケーションでの利用を考えながら学べてよい構成になっていると感じました。

3章

ところで、この章を読んでいる最中にtokioのIssueを眺めていたところ、自作ツールを使ってtokioの特定の箇所に対して検査をかけてみた結果、SeqCstではなくAcquire/Releaseで十分な箇所を見つけている人を見つけました。ちょうど学んでいる内容がリアルタイムでやってくるとテンションが上がりますね。

github.com

Mara先生の教訓、

SeqCstは警告だと思った方がいい。SeqCstをどこかで見かけることがあったら、何か複雑なことを行なっているか、それを書いたプログラマがメモリオーダリングに関する想定を十分な時間をかけて解析していない、ということだ。いずれも、特に注意しなければならないサインだ。

を見た気がしました。もちろん、tokioではSeqCstが必要な箇所にはこのようにコメントがされていて、よく検討されているかどうかはすぐにわかるようになっていそうに思いました。

4章、5章

スピンロックやチャネルをフルスクラッチします。手を動かしつつ先ほど3章で出てきたメモリオーダリングを復習する章になっていると思います。

4章ではガードと呼ばれる実装パターンが紹介されています。これはRustを触っているとたびたび出てくる実装パターンなように思います。ガードは何か内部的に状態をもっておき、ドロップされるまでそれを維持する役割を果たします。ロックの実装と相性がよく、主にはロックで用いられているように見受けられますが、それ以外の用途でもたびたび見かけます

6章

この章ではArcを実装しつつ、メモリオーダリングについての理解をさらに深めていきます。ArcはRustの標準ライブラリに存在しており比較的使う回数は多いものの、内部で何をしているかはなんとなくしか把握していないことが多いと思います。この章をWeak対応版まで進めると、実質Rustの標準ライブラリのそれとほとんど同等になります。

Miri

ところでこの章を読んでいて作ったArcに対するテストが実装されるのですが、そのあとに「miriを実行してみるといいだろう」という話があります。これをやってみたので補足しておきます。

MiriはRustの中間表現であるMIRを実行するインタープリタです。unsafeコードをチェックする際に利用できるツールで、未定義動作の発生をチェックできます。MiriはコンパイラのMIRを用いて、ネイティブなプロセッサ命令にコンパイルせず、型やライフタイムなどの情報がまだ残っている状態でコードを実行・解釈させるツールです。インタプリタ方式なのでコンパイル後の実行と比較するとかなり実行時間はかかりますが、その文未定義動作になりうるようなさまざまなミスを検出できます。データ競合の検出も実験的ながらもサポートされており、これを使うとメモリオーダリングの問題も検出することができるそうです。

Miriは意外に簡単に実行できます。次のようにしてMiriを手元にインストールして、既存のテストに対してMiriを実行するだけです。

$ rustup +nightly component add miri
$ cargo +nightly miri test

ちなみにですが、今回実装したArcのテストではとくにMiriによる不具合の検出はありませんでした。unsafeなコードを書く際にはMiriもきっちり実行しておきたいものです。はじめて使いましたが便利でした。余談ですが、RustでLinked Listを実装してみる有名なチュートリアルにもMiriで検証する節があり、こちらは実際に不具合を検出させて修正させる形をとっているようです。一度このチュートリアルもこなしておきたいなと思いました。

Loom

こうした並行処理にまつわるテストにもうひとつ使えるツールとして、tokioが提供するLoomというプロジェクトがあります。[*1]Loomは、C11のメモリモデルで有効な実行の構成に応じて実現可能な組み合わせを変えながら、テストを何度も実行してくれるツールです。同時に状態数を削減しつつ組合せ爆発を回避しているようです。並行処理のテストは往々にしてこうした組み合わせを網羅するのが難しいわけですが、Loomを使うとこの点をある程度緩和できるというわけです。

私も今回はじめて使ってみたので使い方が合っているか謎ですが、tokioのテストケースなどを見る限り、次のように使いこなすことができそうでした。下記は本書で一度目に書くWeak実装前のテストコードをLoom化してみたものです。

#[cfg(test)]
mod tests {
 // 他のテスト用の余計なimportsも含まれるかも
    use loom::lazy_static::Lazy;
    use loom::sync::atomic::AtomicUsize;
    use loom::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
    use loom::thread;
    use std::marker::PhantomData;

    use crate::Arc;

    #[test]
    fn test() {
        // static NUM_DROPS: AtomicUsize = AtomicUsize::new(0);
        static NUM_DROPS: Lazy<AtomicUsize> = Lazy {
            init: || AtomicUsize::new(0),
            _p: PhantomData,
        };

        struct DetectDrop;

        impl Drop for DetectDrop {
            fn drop(&mut self) {
                NUM_DROPS.get().fetch_add(1, Relaxed);
            }
        }

        loom::model(|| {
            // Create two Arcs sharing an object containing a string
            // and a DetectDrop, to detect when it's dropped.
            let x = Arc::new(("hello", DetectDrop));
            let y = x.clone();

            // Send x to another thread, and use it there.
            let t = thread::spawn(move || {
                assert_eq!(x.0, "hello");
            });

            // In parallel, y should still be usable here.
            assert_eq!(y.0, "hello");

            // Wait for the thread to finish.
            t.join().unwrap();

            // One Arc, x, should be dropped by now.
            // We still have y, so the object shouldn't have been dropped yet.
            assert_eq!(NUM_DROPS.get().load(Relaxed), 0);

            // Drop the remaining `Arc`.
            drop(y);

            // Now that `y` is dropped too,
            // the object should've been dropped.
            assert_eq!(NUM_DROPS.get().load(Relaxed), 1);
        });
    }

// 他のテストが続く

Arcは今回自分たちで作ったテスト対象なので、これはそのまま利用します。それ以外のたとえばメモリオーダリングを指定するOrderingや、スレッドを生成するthread::spawnの類はすべて、loomが提供するものに置き換えられています。あんまり中身がよくわかっていませんが、このloomで始まるものは内部的にトラッキングされていて、loomの並行処理実行時(loom::model)にエラー等が検出された場合、このトラッキング情報を追ってデバッグできるように作られているようです。

7章

キャッシュ周りを一旦読みましたが、この章はあとで戻ってきてじっくり読みたいと思っています。

8章

futexに関する解説が載っていました。著者はMutexの性能向上に貢献した張本人ですが、この件について調べていた際にfutexについていつか深く学んでおかないとと思っていました。ちょうどよかったです。

9章

8章までで出てきた概念やライブラリを用いて、Mutex、条件変数、リーダ・ライタ・ロックを実装します。どれもステップバイステップで少しずつ想定される問題を解決しながら実装していくので、非常にためになります。

たとえばMutexの場合、まず最小の実装で一旦実装し切ります。その後、wait/wakeに関連するシステムコールの呼び出し回数が問題になりうることが説明され、呼び出し回数を削減するためには他の待機スレッドがあるかどうかの判定を入れれば良いことが説明されます。最後にベンチマーカーを実装して実際に動かしてみつつ、Mutexのベンチマーカーを作る難しさと簡単に実装したベンチマーキングの結果の解説が挟まれるといった方式です。私はこれが非常によかったと思っています。

作られるMutexはRust標準ライブラリのそれとよく似た構成になっています。Rust標準のMutexのロック部分を作るのにはLinuxならfutex、それ以外のOSであれば相当するシステムコールが必要になりますが、それはatomic-waitというクレートを使うことで結構簡単に実装できました。

リーダ・ライタ・ロックを実装する際にはwriter starvation問題まできちんとステップバイステップで解消していきます。

10章

これまでの章で拾いきれなかった話題について解説されます。セマフォやロックフリー連結リストなどです。解説を読みながら実装してみるとおもしろそうですが、まだ試せてはいません。

感想

私は普段RustでWebバックエンドのアプリケーションを実装しています。RustでWebバックエンドを実装していると、本書で紹介があったようなMutexArcなどを利用しはするものの、中で利用されているツールや概念について使用することはほとんどありません。

また、こうした機能を深く理解しているかというとそうでもありません(Arcは後述する通り一度ある記事を読み込んでいてちょっと知ってたものの)。表面的には何をやっているかはもちろん把握していますが、メモリオーダリングの話などは詳しく把握しているかというとそうでもないのが実情です。こういう場合、最適化を本気でやろうとすると困るわけなのですが、もっともたとえばAWS上でインスタンスサイズをスッとあげれば問題が解決してしまうことが多く、突っ込んで最適化するよりも札束で殴る会社の方が多いのではないでしょうか。それがあるべき姿なのかというと、もちろんケースバイケースだと思いますが。

そして、細かい生存期間や所有権、借用について気にすることはほとんどありません。せいぜい長い生存期間を持つもので、アプリケーションのローカルに用意するインメモリキャッシュくらいでしょうか。基本的にはほとんどの生存期間はHTTPリクエストが送られてから、HTTPレスポンスが返されるまでとなります。したがってその程度の生存期間では、ドロップの順番等はほとんど気にすることはありません。また内部可変性についても、データベースをはじめとしたミドルウェアにほとんど丸投げしてるため意識することもないでしょう(ただたとえば、書き込み頻度の高いインメモリキャッシュを持っている場合は別ですが)。

そうした意味では、ほとんど見ることのなかった世界を覗けたという意味でよい読書体験だったと思います。技術を使うことに精一杯で、裏側に控える議論をあまり深ぼっていなかったなと改めて気付かされました。読後、Rustと並行処理への理解度がまた一段あがったと感じました。

私が行なったようにtokioを探索しながら読み進めるとおもしろいかもしれません。本書で登場した内容はtokioでもそのままよく議論されている内容であることが多いようです。tokioやRust本体にコントリビューションする際によい糸口になってくれるはずです。そうしたOSSへのコントリビューションを考えている方は手元に置いておいてもよいのではないでしょうか。

著者も書籍の最後の方で説明しているように、Rustの並行処理に関する文献や資料は思ったよりありません。私の知る限りでは、後ほど紹介する『並行処理プログラミング入門』と未邦訳の『Rust for Rustaceans』10章くらいでしょうか。文法入門レベルのものはいくらでも存在するのですが、それを使ってどう実装を組み上げていけばよいかに関する教材や資料が不足しているのは著者の指摘の通りだと思います。

ところで、今回紹介されたような話題について、並行処理そのものにもう少し絞ってキャッチアップしたいと思いました。何か定番の教科書や資料などあったら教えてください🙌🏻

日本語での別の資料

この話題は実は日本語圏でも結構いい資料がいくつかあり、あわせて読むと理解が深まるかもしれません。

ひとつはqnighyさんの連載で、Arcを切り口に本書で扱う話題に入っていく流れになっています。私は実は本書の前半の内容はだいたい既知だったわけですが、それはこの記事を読み込んでいたからかなと思いました。

qiita.com

もうひとつは『並行処理プログラミング入門』という書籍です。この書籍でもやはり同じくらいのレイヤーの低いところから一気に解説がなされます。それだけでなく、Rustの難しいポイントのひとつであるasync/awaitや、Futureに関連する章もあり非常に網羅的だと思います。あわせて読むと理解が深まるかもしれません。

*1:余談ですが「loom」は織機のことです。無数の糸(thread)を束ねるもの、というイメージでしょうか。

2023年、読んで印象に残った本

あけましておめでとうございます。年がもう明けてしまいましたが、2023年に読んでよかった本について簡単に書いていこうと思います。noteで書いていましたが、こちらのブログをしっかり使わないといろいろもったいなと思ったので、技術に関係ない話題ではありますがこちらに書いていきます。

技術書

昨年は子育てに加え、そもそも技術書の執筆と翻訳を行なっていたこともありほとんど時間を取れませんでした。が、何冊か読んだので紹介しておきます。

単体テストの考え方/使い方

2023年に読んで一番よかった一冊かもしれません。テスト周りはわりとチームのエンジニアによって考え方が違うことが多いように思います。たとえば、モックをするべきかすべきでないか、あるいは単体テストでモックするか、インテグレーションテストでモックするかなどは、大きく考え方が分かれます。考え方が分かれる場合、さまざまな意見を整理して採り入れつつも、最終的には何かしらのチーム全体のマニフェスト(方針)を策定する必要があると思います。その際、この本を参考にしながら取捨選択すると、議論を空中戦にさせずに済むなと感じたのが一番大きな感想です。

また書籍内では「どういったテストが不要か」を議論していたのもよかったです。テストコードも結局のところ成果物でありメンテナンス対象となります。コードを書かされるものの得られる成果が少ないテストはできるだけなくしておいた方が、メンテナンスする対象を減らせてよいといえます。たとえば読み込みのみでほとんど複雑なビジネスロジックを持たないようなテストは、リグレッションの防止等の得られるリターンが少ない割にメンテナンステストが大きくなるだけで嬉しくない、などです。

フロントエンド開発のためのセキュリティ入門 知らなかったでは済まされない脆弱性対策の必須知識

たぶん産休育休中だったと思うけれど、フロントエンドのセキュリティを全然知らないのはまずいかなと昔から思っていたのを思い出して読みました。フロントエンドはそれなりに仕事上関わる機会があるものの、社内向けの管理画面の実装などが多く、なかなか本格的にやる機会のない分野でした。そういう人でも十分理解できるように書かれているいい本だと思います。

とくにこれまでの現場で迷いがちだったのは、ログイン周りの情報をどこに保存しておくべきかという問題でした。個人的にはCookieにHttpOnly属性をつけて入れておくのがよいと漠然と思っていましたが、これがなぜよいのかについて詳しく理由を知ることができました。このような日頃から疑問に思っていたことは一通り学べたという意味でよかった一冊だと思います。

私のように普段はバックエンドに軸足があるものの、ときどきフロントエンドも触る必要があるようなソフトウェアエンジニアにおすすめです。

プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで

基礎的な文法はある程度知っていて、実際になんとなく書いているものの、体系的に言語仕様を理解していないなと思っていたランキング1位(個人)TypeScriptを学ぶ際に使った一冊です。これも育休中に読みました。著者が言語処理系に詳しそうな印象をもっており、そこを期待して購入した一冊です。もちろん期待通りでした。

この本のすばらしいところは、TypeScriptの仕様に関連する言葉をふわっと利用せずきちんと定義し、説明し切るところです。入門書を書いたことのある方ならもしかすると共感していただけるかもしれませんが、そうした本を書いていると、どうしても初学者のうちは理解の妨げになるかもしれないと思い、説明を少し緩めにして誤魔化すといったことを時折することがあると思います。本書ではそういったことはせず、読者の理解力を信じてきちんと説明し切っているように見受けられました。

技術書でないもの

月に1、2冊は読んでいたと思いますが、とくに印象に残ったものを紹介します。

サピエンス減少 縮減する未来の課題を探る

投資をしていると未来の人口動態というのはとても気になるものです。労働者人口が伸び続ける限りは、基本的には経済は成長を続けるだろうという予測がこれまでの歴史から立つためです。というわけで人口動態については、私は結構キャッチアップするようにしています。

これはさまざまな本や予測で論じられていることですが、世界人口は2060年ごろにピークを迎えてその後減少に転じるという予測が今のところ有力なようです。日本ではすでに人口増加率が落ちてきて人口減少に転じていますが、これが世界の多くの地域で起こる未来が来る、ということです。つまり、全世界株式インデックスの長期保有は私たちが生きているうちは大丈夫そうなのですが、私たちの子どもの世代まで有効な投資戦略かどうかはちょっとわからないかもしれない、ということです。人口減少は資本主義の歴史上初めて到達する局面であり、単純に何が起こるかよくわかりません。

そしてそれより衝撃的なのが、一度人口が減り始めると結構がんばらないと人口は戻らず、300年もしないうちにそのまま一気に100分の1程度にまで減少してしまうというモデルです。人口は一度減少しだすとどうやら戻すのが難しいようで、場合によってはそのまま大幅に自然減少してしまうもののようです。車に乗っていてスピードを結構出しているとブレーキをしたとしても少し効くまでにラグがあると思うのですが、あれと似たようなことが人口減少でも起きると言うわけです。

人口減少は地域に関係なく起こりうる未来であることも示されます。平均寿命の伸びが関係します。平均寿命が伸びると、女性の再生産期間の残存数が伸びます。たとえば平均寿命が25歳の地域と50歳の地域とでは、35歳を適齢期の上限とすると単純に考えても10年ほど子を産める期間が延びることになります。これにより、結婚出生のタイミングが自由化します。自由化すると、たとえば私たちの世代が今まさに悩んでいるように、キャリアと出産の天秤をかけはじめるようになります。あるいは、恋愛も自由化しているので相手を吟味して数年費やします(私たちの世代が今マッチングアプリでやっていることだと思います)。私たちの世代では30歳前後で産むのが最適解っぽく感じられるので、そのくらいで子どもを産むわけですが、そうすると適齢期の上限問題に行き当たります。25歳で第一子を産むのと、30歳で第一子を産むのとでは、第二子、第三子を産むためのハードルが全く異なります。これにより、生涯に産む子どもの数が減ります。

この本もやはり似たような話が書かれていた記憶があり、おすすめです。

ネガティヴ・ケイパビリティで生きる

タイトルのネガティブ・ケイパビリティというのは最近はやりつつある概念だと思います。一言で説明するのは難しいですが、「答えを出すことを急がずに一旦そのまま事実を受け止めしばらく抱えて考えておく」みたいなイメージでしょうか。ここ最近は、どうもスパンと物事を言い切る人に人気が集まりがちですが、物事というのはそもそもどういう側面から見るかや、解釈する側がどういう立場かによって味方が変わるものであり、そう簡単にスパンと峻別できるものでもないです。この辺りを意識しつつさまざまな事象に向き合う姿勢がネガティブ・ケイパビリティというものだと思います。

タイトルはあくまで標語みたいなもので、本書の中身は哲学者や公共政策学者が、ここ数年の現代社会についてさまざまにああでもないこうでもないと対話する本になっています。哲学の役割のひとつに、その時代に生きる人々がなんとなく思ってはいるものの言語化できていない考えや思想をスパンと言語化していくというものがあるのですが(だから哲学を形容して、ミネルヴァの梟は迫り来る黄昏に向かって飛び立つ、などと言われる)、これをまさに果たせている本だと思います。

この本を知ったのは著者のうちのひとりの本を読んだからでした。やはり同様に現代社会に対して感じていることを言葉にしてくれる一冊になっていて、ある種のカタルシスを読後得られると思います。

2050年の世界 見えない未来の考え方

未来予測はあまりあてにはならないので参考程度に読みました。個人的には未来予測よりも最初の章の方の現状の各国や各地域の分析のところをおもしろく読みました。人口が伸びる地域伸びない地域があり、金融危機はヨーロッパで起こる可能性が少しありそうで、暗号資産は価格変動が大きすぎる関係で基軸通貨にはなれず、民主主義はあまり人気のない政体であり、テクノロジーは引き続き人類のさまざまな問題を解決し続けるといったところでしょうか。ただ、いかんせん扱われる国や地域、話題が広いため、おもしろかったです。

訂正可能性の哲学

東浩紀氏の新作です。まだ前半しか読んでませんが印象に残っているので記しておきます。「家族」という概念を手がかりに訂正可能性を軸とした共同体という新たな発見をし、これを政治社会に適用してみるみたいな構成なように今のところは見えています。

最初の方はプラトンの国家を参考に家族がどう扱われていたかを見つつ、そこから閉ざされた社会と開かれた社会の対立軸を見出します。プラトンの思想には若干全体主義的要素があるのは有名な話ですが、そこを批判したことでさらに有名なポパーを引きます。が、ポパーは実は微妙な勘違いを元にプラトンを読んでいるという読みをします。ここからプラトンから脈々と続く家族の否定という思想史は、実は家族を完全に否定し切ることができていないということになってしまいました。家族を出た人間関係は作れず、家族の枠の中で議論する必要があるのでは、というところから、今度はウィドゲンシュタインとクワインの議論を引いていきます。この辺りから訂正可能性という概念を導き、これを政治社会に適用できないかを検討するために、アーレントやローティの力を借りていくみたいな構図でしょうか。

後半はルソーの一般意思や、人工知能民主主義あたりが議論されるようです。楽しみです。

GitLabに学ぶ 世界最先端のリモート組織のつくりかた ドキュメントの活用でオフィスなしでも最大の成果を出すグローバル企業のしくみ

GitLab社の働き方や文化について解説されている一冊です。GitLab社はフルリモートワークかつ分散オフィスを上手に回していることで有名です。どうやったらそうした組織を上手に回せるか、そのための文化や制度について網羅的に解説されています。私も同様にフルリモートかつ分散拠点をもつアメリカの会社に勤務していますが、ここまできっちり制度化されてはおらず、非常に興味深く読みました。また、日系企業に勤める方にとっては外資の会社の回し方を知るいい機会になると思います。

全体的な感想としては組織運営をかなり「科学している」と感じました。たとえばおもしろかったのは、人間関係に専門性を持つチームがいて、人間関係に関連するトラブルを一定に引き受けることがあるらしい、などです。また、再現性が高まるようなオンボーディングの設計や、さまざまに用意されたガイドラインの存在などがそうした印象をより強めました(ところで本書のサブタイトルは結構微妙で、ドキュメントが中心というわけではなく、私はこうした科学的手法のとり入れに伴う再現性の担保による属人化の防止が大きなポイントなのかなと思っています)。

本書の魅力はGitLabの紹介にとどまらないと思っています。おそらく著者の方による解説だと思いますが、GitLabの施策がなぜ有効なのかを、最近の経営論や組織論の学説を踏まえて解説してくれるところがすばらしいです。仮にGitLabの紹介だけにとどまっていたとしたら一社だけの事例でしょ、で済んでしまった話が、こうしたアカデミックな議論も踏まえて解説されることにより、実は他の組織でも重要な話であり応用可能なのだ、ということに気づけると思います。

2024年の展望

技術書でない本は引き続き、自分のおもしろそうと思った本を読んでいると思います。技術書の方は、今年買ったもののキャッチアップできなかったChatGPTやLLM関連の書籍をいくつか読みたいと思っています。具体的には下記です。

ゼロから作るシリーズの生成AI編も楽しみですね。

GitHubスポンサーの募集

GitHubスポンサーの募集を作ってみたので、したいなと考えています。スポンサーの詳細は下記にまとめました。

github.com

今年はもう書籍を2冊執筆しているのでお腹いっぱいなのですが、来年からたとえば

  • Rust関連では
    • ずっとやりたいと思ってるもののここ数年全く時間がなかったためにできなかった、Rust本体への貢献やその他周辺のエコシステムへの貢献。
    • Async Bookの翻訳の続き。
    • もう少し応用的な内容を含む記事の執筆(個人ブログないしはZennなどで)。
    • Rust.Tokyoへの貢献。
  • 加えて、その他の技術へのOSSでの貢献。

あたりを行っていきたいと思っています。主にOSSに割く時間を捻出したいです。

金額に応じた特別な見返りなどはないです。が、よく他の方がやっている事例を真似て、GitHubのトップページにプロフィールロゴを掲載させていただきたいと思います。One-time shotも嬉しいです(むしろこっちの方がMonthlyよりプレッシャーがなくて嬉しいです)

よろしくお願いします✨

JISキーボードからUSキーボードに切り替えた

小学生の頃にパソコンというものを触り始めてから社会人になってソフトウェアエンジニアとして働いて10年近く、ずっとJISキーボードを使ってきました。「日本語を打つのになぜUSキーボードをわざわざ使うのだ」という考えからずっと使ってきましたが、最近ついにUSキーボードに変えてしまいました。

買ったキーボード

Nuphy Halo75

Nuphyの「Halo75 Wireless Mechanical Keyboard」というものに変えました。Night Breeze軸の音と軽さがちょうどよかったのでこれにしました。あんまり指の力が強くないので軽めのものがタイプです。ただ軽すぎると押したつもりもないのに押した判定されてそれはそれでストレスなので、35g〜45gくらいがちょうどいいなと思っています。この辺りの条件にフィットしたのがNight Breeze軸でした。

テンキーは不要というかデスクのスペースを取りすぎるので96は選択肢にはありませんでした。

以前はHHKBを使っていたので、これに近い65のものも迷いました。しかし、写真をみた限りで「`~」がESCと同じ位置にあって、多分何かのキーと複合で押す形になるんでしょうが、プログラマ的には「```」を結構使用する関係で絶対面倒に感じるだろうなと思ってやめました。これさえなんとかなっていれば65を選んでたくらいには好みでしたが。

HHKBから切り替えて困ってしまったことといえば、JISのHHKBに戻すと思い出すのに時間がかかるのと持ち運びができないことです。近年はオフィスはフリーアドレスで自席がないことが多いですし、カフェなどで作業したい際にはやっぱり外付けのいいキーボードで作業したいなというのがあり、持ち運び用のものはどうしようか悩んでいます。USのHHKBを買うか、もしくはAirを買うかで頭を悩ませています。Airの方はロープロファイルなのであんまり好きじゃないかも、みたいな点で悩んでいます。JISをメルカリで売ってから考えてもいいかもしれません🤔

切り替え時にやったこと

さて本題ですが、切り替え時にやったことです。前提として、私は仕事プライベート含め、macOSしか使いません。なので、前提としてMacの話になります。

JISからUSへの切り替えですが、Karabinarを使うと比較的楽にできます。しかし変えたら変えたで苦労した点もあり、この辺りをまとめておきます。ポイントは下記でした。

  • 「かな」と「英数」の切り替えをCmd単体でできるように
  • Cmd単体操作の微調整&「Cmd+Q」を数秒押さないと稼働しないように
  • CapsLockと左下のCtrlの入れ替え

MacのUS配列標準では、「Fn」キーを単体で押すとトグル方式でかな入力と英数入力(というかIMEの入力言語でしょうか?)を切り替えられるほか、「Control + Space」でもトグル方式で切り替え可能です。しかしWindowsの「半角/かな」キーをはじめとしたステートフルなこの切り替え方式は好きではなく、MacのJIS配列にあった「英数」「かな」の切り替えが非常に良いデザインだと思っています。なのでこれをUS配列でも再現したいわけですが、一方でUS配列には「かな」「英数」の切り替え専用のキーはありません。

これを実現するためには、いくつか手段がありますが、私が最も有力かなと感じたのは「左のCmdキーを単体で押したら英数入力に切り替え、右のCmdキーを単体で押したらかな入力に切り替える」というものです。これならJIS配列のときと切り替え方法をほぼ変えずに済みます。これを実現するには、Karabinarというソフトウェアを使いつつ、このソフトウェアに追加の設定を行う必要があります。

やり方は下記のサイトに書いてあり、こちらを参照するか

misc-log.com

私のdotfilesのリポジトリを参照することでも確認できます。Karabinarは設定をJSON形式でエクスポートでき、普段はエクスポートしたものをdotfilesに置いて管理しています。

github.com

ただ、この「Cmd単体で押したとき」の判定が若干シビアです。たとえば、「Cmd」を押した後にすぐ「W」を押すと、普通にショートカットキーを押した判定をされてしまい、結果文字入力中にウィンドウが閉じてイライラしてしまうことが最初多発しました。Cmdキーを単体で押した判定をさせる時間を伸ばすなど若干のカスタマイズが必要でした。完全に対策できたわけではないので時々今でも起こりますが、頻度はかなり減りました。

上記のショートカットキーを押してしまう問題で致命的だと感じるのが「Cmd+Q」(アプリケーションの終了)でした。これが起こるとたとえばターミナルが突然落ちることになるので、コーディング中などは非常に困りました。そこで、Cmd+Qだけは特別に、1秒以上両方のキーを押し続けないと終了動作が作動しないように調整を加えました。KarabinarのJSONを直接いじって対応させました。

github.com

あとUS配列に変更したこととはあまり関係ない話かもしれませんが、Nuphyは、HHKBだとControlキーの位置にCapsLockがあって、HHKBだとCapsLockの位置にCtrlがあるレイアウトになっています。普段はNeovimで作業する関係でHHKBのレイアウトになっていてくれないと非常に厳しいので、Karabinarを使って、CapsLockとCtrlを入れ替えしました。これによりこれまでの操作感を損なうことなくVimを操作できるので快適になりました。これはやっている方が多いかなとは思いますが、重要な作業だと思います。

切り替えてよかったこと・ストレスを感じること

プログラミングで出てくる記号類が、実はUS配列だと手数少なく押せると判明した点でしょうか。たとえばバックスラッシュ\なんかは、JISだと遠い位置にあって面倒だしどこにあったかもあんまり覚えてない、みたいな感じだったんですが、USだとShiftも不要で入力できてしまいます。シングルクオート'やダブルクオート"も入力するのめんどくさいランキング上位でしたが、これもUS配列だと押しやすい位置にあります。

何よりも、キーボードを選ぶ選択肢が格段に広がるというのも大きいです。YouTubeチャンネルなどでキーボードをアンボクシングする動画を見るのが結構好きなんですが、「US配列なんだよな〜〜〜」と思うものが結構多かったです。しかし、US配列に切り替えてしまった今となっては、こうした憧れのキーボードにも手が届くようになりました。散財が捗ってしまうなあと今から悩みが尽きません。

www.youtube.com (「:3ildcat」というチャンネルをよく見ていました)

ストレスを感じることとしては、まずはホームポジションの中心がJISから微妙に右にズレる?ので、まだそれに慣れません。無意識にJISの頃の位置に指を置いてしまう関係で、よく打ち間違いをします。

また、記号はまだ完全には覚えられていません。*をよく打ち間違えるのと、()のふたつもまあまあ正確に押せずにイライラします。この辺りはストレスを感じますね。

加えて、「Cmd」を使った英数とかなのモードの切り替えをしている関係で、だんだん筆が乗ってきてタイピングのスピードが上がってくると、ショートカットキーを誤って押してしまってイライラすることがあります。「Cmd+Q」による終了は制御したのでこれは起こらなくなりましたが、たとえば「Cmd+W」のウィンドウを閉じるものはしょっちゅう起きてしまいます。ただこのショートカットはQのときのように長押しにすると使い勝手が下がってしまうのでそうするわけにもいかず、ちょっと悩み中です。

あとMac本体はJIS配列のままなので、ラップトップを開いてキーボードを使う際には頭を切り替える必要があります。これは外付けキーボードを持ち歩けば解消できる話なので、今のところはあまり気にしていませんが…。

総じてJIS配列だったころと比べると打ち間違いは格段に増え誤操作も格段に増えましたが、JIS配列だった頃には得られなかった自由も手にできたので、しばらくはUS配列を利用し続けてみようかなと思っています。

追記:このリンクのコードを使うとNuphyを10% offで買えます。もしよければぜひ使ってください→nuphy.refr.cc

はてなブログのドメインをお名前.comからCloudflare Registrarに移行した

タイトルの通りでドメインを移管したので、そのメモを残しておきます。ほとんどスムーズに行ったけど一つだけハマったポイントがありました。同様のドメイン移管を検討している方の参考になれば幸いです。

背景

このブログで利用している「blog-dry.com」ドメインの更新期日が迫っていたのですが、ちょうどお名前.comからのメール配信がうざかったことを思い出して、周囲の知人からの評判がよかったCloudflareに移管することにしました。

お名前.comは以前から「管理画面へのログインが確認できませんが保護対策はお済ですか?」という旨のタイトルのメールを送ってきていたのですが、このメールはモニタリング設定という有料オプションへの誘導になっています。ただこのオプションは利用したくないため放置していたのですが、そうすると永遠にメールが配信されます。これが嫌で移管することにしました。たぶん、メールの配信設定を管理画面でちゃんとやれば届かなくなります。

今回はサブドメインは使用しない前提です。

手順

手順は下記が参考になりました。実際この通りにやるとうまくいきます。

zenn.dev

余談ですが私も VISA の楽天カードで支払い登録をして移管作業を行い、最後の最後まで来て支払いを押したところ、なぜか決済がエラーでうまくいきませんでした。PayPal に変えたらうまくいったので、最初から PayPal で登録しておくとスムーズだと思います。

はてなブログ特有のはまりポイント

ドメインを移管すると自動でお名前.comから設定が読み込まれますが、「DNS Records」の画面の「Proxy Status」が「Proxied」になっているとうまくいきません。「DNS only」のモードに直す必要があるようです。

developers.cloudflare.com

Proxied にすると Cloudflare のグローバルネットワークを利用し、これによりキャッシュの最適化やより強固なセキュリティ保護を受けることができるようになります。ただ、Proxied にすると全然違うところ(Cloudflare 管理の IP)を向いてしまいます。

❯ dig blog-dry.com

; <<>> DiG 9.10.6 <<>> blog-dry.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6515
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;blog-dry.com.                  IN      A

;; ANSWER SECTION:
blog-dry.com.           93      IN      A       172.67.188.61
blog-dry.com.           93      IN      A       104.21.48.225

;; Query time: 10 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Jul 12 06:29:50 JST 2023
;; MSG SIZE  rcvd: 73

DNS only にしておくと、Cloudflare をバイパスして DNS サーバーだけを利用するようになります。この設定に直すと正しくはてなブログの求める 13.230.115.16113.115.18.61 が返ってくるようになります。

❯ dig blog-dry.com

; <<>> DiG 9.10.6 <<>> blog-dry.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 11987
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;blog-dry.com.                  IN      A

;; ANSWER SECTION:
blog-dry.com.           300     IN      A       13.115.18.61
blog-dry.com.           300     IN      A       13.230.115.161

;; Query time: 200 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Wed Jul 12 07:03:03 JST 2023
;; MSG SIZE  rcvd: 73

qiita.com

DNS only モードでも DDoS からは守ってくれます。が、代わりに Cloudflare に置き換えることによるページ表示スピードの高速化といった恩恵は一切受けられなくなります。はてなブログで Cloudflare を用いてサイト表示スピードの高速化を検討している方は、最初からこの選択肢がないように思います。注意が必要なポイントです。