blog.8-p.info

小関さんが TikTokの発明:起動すると始まること (2018) で書いていたことだけど、フォローしている人々の投稿を時間順に表示する、昔の Twitter のようなシステムには、

  1. 人々が自分にあう人々をフォローして
  2. フォローされた人がフォローしている人の興味にあうことを投稿して
  3. 投稿は他の人々のものが流されてしまわないように、適度に流量が制御されていて
  4. 1 について人々の変化に応じて定期的に見直し、整理する

という前提がある。1 と 4 は自分で頑張れるけど、2 と 3 は他人の働きへの期待だし、この全ての条件が満たされた状態は、滅多に発生しない。

なので、いまの Twitter も含めた運営側が、順番を並び替えたり、フォローしていないものを突然表示したりするのは、私は理解できてしまう。彼らも別に嫌がらせでやっているわけではなくて、全体を見て最適化したときに、人々の明示的に選んだ意思を無視したほうがうまくいくと気づいてしまっただけなのだ。

ただ、彼らにとっての「うまくいく」は滞在時間だったりエンゲージメントだったりしていて、ほとんどの人々とは利害が一致しない。Twitter を1日に4時間見て、2割をお気に入りに入れて、1割をリツイートするのが、今月の目標の人はいないだろう。

一方で、これをソフトウェア業界側の私がいうのは whataboutism だけれども、企業と個人の利害なんて滅多に一致しないでしょうとも思う。外食のラーメンは美味しいけれど、体に良くはないし、マンガばかりを読んでいたら、給料は上がらない。企業は私の持続可能性を気にしない。

オリオンビールがストロング系チューハイから撤退するのは英断だけれど、全ての企業がそういう倫理観をもっていて、なので企業から提供されるものを無批判に消費していても自分は大丈夫と思うのは、楽観的すぎると思う。

コロナウィルス定点観測です。

追加接種

CDC Expands Eligibility for COVID-19 Booster Shots

For the nearly 15 million people who got the Johnson & Johnson COVID-19 vaccine, booster shots are also recommended for those who are 18 and older and who were vaccinated two or more months ago.

というわけで追加接種で Moderna を打ってきた。予約に出遅れて、妻の予約時間と私の予約時間に一時間程度あいだが空いてしまったのだけど、薬局の受付で「とっていた予約は一時間後なんだけど、いま一緒に打てますか?」と聞いたら、特に問題なく一緒にやってくれた。こういう融通が効くところはアメリカの良いところだなと思う。

打った当日は腕がだるいなあというくらいだったのだけど、翌日は一日中ぐったりしていた。

仕事

何度かチームの人々であわせて会社に行く機会があった。会社に行くと、人が引っかかっているのに気づきやすいし、雑談するにしてもビデオカンファレンスより場が持つ感じがある。非同期にやりとりして、普段は集中して仕事をすすめるのが理想なのだけど、なかなか難しい。

結局のところ、仕事の効率のためにどのくらい家庭を犠牲にするのか、という話のようにも思う。パンデミック前の私は「昼食を家族ととれないのは当たり前だけど、夕食を家族ととれないのは働きすぎ」という認識で、これは私の会社では平均的な感覚だったと思う。でもいまは、昼食も夕食も家族と一緒にとるのが当たり前になっている。子供が泣いていたら見にいくのも当たり前。この新しい当たり前をすてて、仕事をがんばって、さて私は何を得られるんだろう。

買い物

相変わらず米が Amazon で買えずに不便。近所の中国系アジアンスーパーで買っている。

学校

上の子も下の子も学校に行っている。下の子はまだ送り出しの時に泣いてしまうし、病気をもらってきがち。また近所で一度 PCR 検査を受けた。

週刊ブログ続報

Oct 23, 2021

読者を意識した、キャリアのためのブログ

そういったわけで、今年の残りは「ちゃんとした」技術的な話を一定のペースで書く、ブログというものに挑戦してみることにした。

9月と10月は、毎週一回プログラミング関係の話を書いて、それに文字数ギリギリまでリードをつけて Twitter に流す、というのをやってみた。毎週つづけられたこと、下の三つがよく読まれたことは良かった。

ただ、これがキャリアにつながるか、転職の足しになるかというと、まあそういうものではないよね、とも思った。ブログを転職の足しになるようにするには、もうちょっとしぼった分野で、継続的な努力が必要そう。そして、自分の出来ていることとの差分を考えると、仕事がオープンソースなことでインターネット活動ポイントみたいなものは足りているので、地道にコーディングインタビュー対策でもしたほうが良さそうである。

インターネット活動と採用

そもそも、世の中の会社はインターネット活動を採用でどのくらい考慮しているのか、というのにも疑問がある。見ているにしても配分はだいぶ低いのではないか。

昔はインターネット活動を単純に熱意と才能の表れだと思っていたんだけど、実際にはもうひとつ、時間という要素があって、これは予算が人によって大きくちがっている。20代の頃より私の可処分時間は減っていて、それでも例えば、シングルマザーの人よりは多いと思う。

そういう不平等を前にすると、採用の文脈で「ブログと GitHub には必ず目を通します!」みたいなのも、あんまり良くないのかなと思ってしまう。

Twitter

長らくフォロワーが増えるような使いかたをしていなかったので、Twitter に自分が書いたものを投稿して、それがリツイートなどで遠くに流れていって、結果としてフォロワーが増えるのは楽しかった。せっかく書いたのだから読まれるほうがいい。

ただ、よく読まれたものには「シェルスクリプトやめろ」「モックするな」とか、言い切りの要素があって、それは炎上マーケティング的なところがちょっとあったよね、とも思う。

英語圏

残りの二ヶ月は英語ブログのほうのテコ入れ、と言いたいところだけど、もう年末なのでほどほどにやります。ここ二ヶ月で日本語ブログに書いた話は、過去に英語のほうに書いたものの翻訳もいくつかあって、それらはここまで話題にはならなかった。この差には

  • 英語圏のブログは競争が激しいので、私が書いたくらいのものでは話題にならない
  • 私のフォロワーは英語圏より日本語圏に偏っているので、リツイートで流れていくのにも限界がある
  • 日本語インターネットにおけるプログラミング界隈は、小さくて密なコミュニティで、話題が波及しやすい
  • Twitter に自動投稿するより、ちゃんと手動でリードをつけたほうがいい

色々要因はあるのだと思う。日本語ブログのほうは、またもうちょっと個人的な話も増える予定。

ここ2年くらい、仕事では大体 Go を書いている。jmuk さんが

Go言語は、なんというか「ちょうどいい」言語だな、と思っている。異論は認める。

と書いていたけれど、私はやっぱり Scala や Kotlin あたりが好きで、これは変わらなそう。

例えばコレクションを map しているのをみると、私は「なるほど、ここではコレクションの要素数は変わらないんですね」と思う。filter だったら「コレクションの要素数は変わるけど、個々の要素は変わらないのか」ということを、あるいは Result を map していたら「ここではエラーのほうは触らないのね」ということを読みとっている。

こういう意図が、素朴な for ループと、if err != nil だと読みきれなくて、いや真面目に字面を追っていけばわかるんだけど、私が「map するか」と思いながら for ループを書いて、その for ループを誰かが読んで「これは map だね」と理解していることを考えると、それソースコードに map って書けたほうがいいんじゃない、と思ってしまう。

同様に、このコレクションに要素は追加されませんよとか、この変数はここから先では再代入されませんよとか、あの参照は nil になるけど、この参照は nil にはなりませんよ、みたいな「意図」がプログラミングには色々とあって、私はこれをプログラミング言語の語彙で、immutable なコレクションや、val と var の違い、Option[T] なんかにエンコードしている。意図に反することが起きたら、コンパイラにはエラーにしてほしい。

こういう関係をプログラミング言語に求める私にとって、Go はちょっと違う。「この参照は int* なので int しか指しませんよ」をコンパイラに教えるのと「この参照は nil になりませんよ」のを教えることの間にそこまで差はないので、どこで立ち止まるのか、立ち止まることで何が得られるのか、というところについて Go が好きな人々とは見解の相違があるんだろうと思う。

自分の語彙にない表現

一方で、私の知っているプログラミング言語の語彙は、過去の経験からくるバラバラな機能のセットでしかなくて、それが Scala や Kotlin のところで止まっていることには一抹の不安もある。

Idris にある依存型とか、CatsScalaz が提供する色々とか、Rust のオーナーシップとか、存在を知っているけど使い道がわかっていないものは色々あって、どうしたものかなあと思う。Idris なら Seven More Languages in Seven Weeks に出てくるので、そこだけでも読むといいのかもしれない。

語彙を増やすことの反対にある、Go の人々の素朴さへの渇望はあまり理解できていない。多機能な言語の、その機能を使いまくって大変なことになっているコードをさわる機会があるといいのかもしれないけれど、正直いって体験したくはないなあ。

Mockitogomock が使いやすいせいか、単体テストというのはモックするものである、という思い込みがあるのか、人々がモックしすぎているのを時折みかける。

モックは必要悪で、しないにこしたことはない。外部の API サーバーとかはガンガン叩くわけにもいかないけれど、ファイル読み書きくらいは、実際にファイルを作ったり消したりしてしまっていい。/etc/passwd を消すとか、1GB のファイルを作るとかだと難しいかもしれないけれど、その場合でも、パスのプレフィックスを指定できるようにして、一時ディレクトリの中の etc/passwd を使うとか、ファイルサイズを指定できるようにするとか、逃げ道はいくつもある。そこを飛ばして「ファイル操作は一律モックしましょう」とか頑張りだすと辛いことになりがちだ。

モックの一番の問題は、本番とテストで違うコードが走ることで、これは自動テストの価値をだいぶ下げてしまう。テストが通っているのは、コードが正しいのか、コードがモックと揃っているからなのかわからなくなる。

もう一つの問題は、モックと実装が密結合してしまうことで、後々コードを変更するのが大変になる。実装が変えやすいようにテストを書くのに、実装を変えづらくなっては本末転倒だ。

Test Double の用語を使うと、ダミーオブジェクトは無害で、フェイクオブジェクトは、色々不変条件を足したりできるので、最初は面倒だけど役に立つことが多い。スタブ、スパイ、モックオブジェクトあたりは逆に簡単にはじめられるけれど最終的には後悔しがちだと思う。

単体/結合テストという二分法もよくない

Google Testing Blog に Test Sizes (2010) という話があって、

What do you call a test that tests your application through its UI? An end-to-end test? A functional test? A system test? A selenium test? I’ve heard all them, and more. I reckon you have too. Tests running against less of the stack? The same equally frustrating inconsistency. Just what, exactly, is an integration test? A unit test? How do we name these things?

それから10年以上たった今になっても、単体テストとか結合テストとかの用語にみんなが合意できる定義はない、と思う。この記事は、ここから Small, Medium, Large というデータドリブンな定義に進むのだけど、個人的には、この離散的な定義もあんまり好きではない。

ソフトウェアの部分を抜き出して、ここからここまでが単体です、というのは難しい。オブジェクト指向的には一つのクラスが単体なのかもしれないけれど、そこにこだわると、まさしく「ファイル操作は全てインターフェース経由で操作して、テストではモックをコンストラクタから渡しましょう」という方向に進んでしまうので、あまりよくない。

単体テストと結合テストというのは、きれいに二分できるものではない。二つの間は連続していて、個々の自動テストは、単体テストと結合テストの間のスペクトラムのどこかに位置している。そこに線を引いて「ここからこっちは単体テストです」といってみせることに、あまり意味はないと思う。

「なるだけモックしたくない」派閥は古典派と呼ばれています

(2021-10-14: ここ以降は追記です)

和田さんが Twitter

テスト駆動開発にはざっくりいうとモックを積極的に使う派(ロンドン学派)とあまり使わない派(デトロイト学派、古典派)がありまして、私は後者なのでほとんど使わず、このエントリに深く同意するところです

と、補足されていて、私の「なるだけモックしたくない」派閥にはちゃんと名前がついていたことがわかった。

Mocks Aren’t Stubs (2007)

The classical TDD style is to use real objects if possible and a double if it’s awkward to use the real thing. So a classical TDDer would use a real warehouse and a double for the mail service. The kind of double doesn’t really matter that much.

A mockist TDD practitioner, however, will always use a mock for any object with interesting behavior. In this case for both the warehouse and the mail service.

Martin Fowler のこの記事は、モックするかどうかを、やりとり (インタラクション) をテストしているのか状態をテストしているのかの違いだと説明し、モックのほうがうまくいくパターンに触れつつも、最後に自分は古典派だと断っていて、両論併記で終わらないところも含めて良かった。Martin Fowler は偉大…。