The King's Museum

ソフトウェアエンジニアのブログ。

『超予測力』を読んで

『超予測力』を読みました。9 月の読書。

超予測者

『超予測力』は未来の予測についての本。

  • 「ロシアは今後三ヶ月以内に新たなウクライナ領土を正式に併合するか」
  • 「来年ユーロ圏を離脱する国はあるか」
  • 「北朝鮮は今年度中に核兵器を使用するか」

このような未来の問いに対する「予測の正しさ」についての研究成果がまとめられている。 著者はこのような問いに対して予測をしてくれるボランティアを広く集め大規模な実験を行った。 その結果、一部の予測者は統計的にも有意に優れた予測をし、CIA などの諜報機関で働くプロの情報分析官すら上回る成績を残した。

筆者は彼等を「超予測者」と呼ぶ。

彼らは以下のような特徴を持っていた。

  • 確率的にものごとを考える
  • 予測をサブ問題に分割して考える
  • 外側の視点と内側の視点を持っている
  • 常に予測を検証し必要に応じてアップデートする
  • 知的な誠実性を持っている

彼等の職業はばらばらで、専門分野も異なった。 筆者は超予測力は生まれつきの才能ではなく、その「やり方」や「考え方」に秘密があると述べる。 その方法を模倣することで、誰でも優れた予測力を身につけることができるのだ。

“専門家”と我々

一方、世間で予測を商売にしているアナリストや評論家などのいわゆる“専門家”は、超予測者とはならなかった。 予測の成績が振るわなかったのだ。 筆者がいうところによると「平均的な専門家の正確さは、チンパンジーが投げるダーツとだいたい同じぐらいである」ということだ。

新聞やテレビのニュース番組を見れば、専門家が今後どうなるか予測している。 ただほぼ例外なく、彼等がカメラの前にあっているのは予測力に優れているという何らかのお墨付きを得ているためではない。 予測の正確さが問題になることなどほとんどない。

そもそも評論家やコメンテーターに求められていることは、その正確性ではなく「予測に説得力があるかどうか」だと述べる。 人は説得力やつじつまが合うことを求める気質があり、正確性などは二の次になる場合が多い。

過去の予測は過去のニュースと同じで、すぐに忘れ去られ、評論家が過去の予測と現実に起きたこととを照合するよう求められることはまずない。 コメンテーターが明らかに持っておいる才能は、説得力ある節を確信持って語る能力であり、それだけで十分なのだ。

予測の消費者となる我々が予測の結果に対して無頓着であることに著者は警笛をならす。 経営者や政治家から我々に至るまで、有効性の確認されない薬は飲まないが、予測に関しては行商人が出してくる不老不死の薬と同じくらい怪しい者でもお金を払ってしまう。

予測が企業や政府など、社会にとって重要な位置付けであることは間違いない。 だからこそ、エビデンスを重視する科学的プロセスを取り入れて検証を行うことが社会にとって必要である。

余談

「人は説得力やつじつまが合うことを求める気質がある」という話は、カーネマンの『ファスト&スロー』のシステム1とシステム2の話に繋がっていて、この本でもよく引用されている。

www.thekingsmuseum.info

以前、読んだことがある本がいくつか引用されていてこの分野への興味がまた沸いてきた。

『ワークシフト』を読んで

ワークシフトを読みました。8月の読書。

ワークシフトは2011年に書かれた本。 未来の働き方、具体的には 2025 年の働き方について予測し、そこで起こっているであろう<シフト>について書かれている。 筆者は働き方において、これから 3 つのシフトが起こるだろうと述べている。

  1. ゼネラリストが評価される時代が終わり、高い専門性を持つスペシャリストが求められるようになる
  2. 人的関係に基づいたコラボレーションによるイノベーションが重要になる
  3. 経済的な成功と消費を求める画一的なキャリアゴールから、やりがいを求めるキャリアを築く必要がある

これら 3 つのシフトの具体例として筆者が想像した悲観的なストーリーと楽観的なストーリーが語られる。 悲観的なストーリーはこれらのシフトにうまく適応できなかった人々のストーリー、楽観的なストーリーはこれらのシフトにうまく適応できた人々のストーリだ。 そして、これらの想像上のストーリーを踏まえて 3 つのシフトをうまく乗りこなす術が書かれている。

ゼネラリストエンジニア

3 つのシフトはそれぞれ「確かにその通りだ」と感じたが、中でも特に気になったのが 1 つ目のシフト。

第一に、ゼネラリスト的な技能を尊ぶ常識を問い直すべきだ。 世界の50億人がインターネットにアクセスし、つながり合う世界が出現すれば、ゼネラリストの時代が幕を下ろすことは明らかだと、私には思える。

どうやらゼネラリストの価値は下がっていく一方のようだ。 反面、高い専門性を持つスペシャリストが求められるようになる。

省みて自分のキャリアはどうだろうか。 自分はプログラマー/エンジニアだと思っているが、世間的には技術職にあたるわけだしある程度の専門性がある職業だと思う。

でも、ソフトウェアエンジニアとして専門性の高いスペシャリストではないと最近感じる。 職業人生はそろそろ 10 年を迎えるが、何か一つの領域を長くやってきたわけではない。 Java の GUI を書き、C++ で HPC のミドルウェアを書き、Android もやったし Web のフロントエンドもそこそこやった。 サーバーサイドもそれなりにいじれるし、インフラ構築もそれなりにできる。 フルスタックエンジニアとポジティブに呼ぶこともできるが、端的にいえばソフトウェアエンジニアの世界でのゼネラリストなのかもしれない。

ゼネラリストの価値は下がっていく。 さて、自分のキャリアは大丈夫だろうか? でも、この本にはこんなことも書かれている。

新しい時代には、本書で提唱する「専門技能の連続的習得」を通じて、自分の価値を高めていかなくてはならない。 未来にどういう技能と能力が評価されるかを知り、その分野で高度な技術を磨くと同時に状況に応じて柔軟に専門分野を変えることが求められるのだ。

専門性は高めていかなければならないが、専門領域も時代に合わせて変化させていく必要がある。 なるほど。専門性を維持しつつ求められている専門領域にキャリアを常にシフトさせていく、というのは説得力がある。

自分のキャリアをポジティブに捉えるのならば、ずっと「ソフトウェア開発」には携わってきたわけで、それを軸にして時代に合わせた技術を習得すればよいのではないか。 勉強を続けなければいけないことは大変といえば大変だけど、この仕事は今でも楽しいと思えるのでそれほど苦にはならなさそうだ(能力的な限界が先にくるかもしれないが)。 ただ、どの能力・技術が評価されるかを見極めるのはとても難しく、常にアンテナを高く立てておく必要はあるだろうし、経験を思い切って捨てるようなキャリアを選ぶ柔軟性も必要になってくるだろう。

そうやって、自分のキャリアを見つめ直した一冊だった。

『リーダブルコード』を読んで

『リーダブルコード』を読みました。7月の読書。

内容はかなり初歩的で特に目新しいことはなかったかな。 ただ、これを実践できてるかは別で、書かれていることを意識してコード書いていきたいと思った。

日々、コードはシンプルで分かりやすくなるように気をつけているけど、他者からの視点を意識するというのは少し抜け落ちてた気がする。

最近、まとまったコード書いてなくてあまり良くないな〜と思う今日この頃…

『エンジニアのためのマネジメントキャリアパス』を読んで

『エンジニアのためのマネジメントキャリアパス』を読みました。

「今年は毎月本を読む」と決めていたので五月中に読み終えたかったけど、五月中は忙しくて読み切ったのは六月。 けっこうボリュームがあったっていうのも一因だけど。

インターンのメンターから CTO まで

この本はその名の通りエンジニアのマネジメントキャリアパスについて書かれた本。 インターンの監督(メンター)から始まり、CTO に至るまでのエンジニアのマネジメント職について幅広く書いてある。 エンジニアの管理職のキャリアラダーを登り始めた人にはとても役に立つ本だろう。

印象的だったのは、エンジニア求められるスキルとはまったく違うスキルが必要だという点。 言われてみれば当然なのだが、テックリード、技術部長や CTO に至るまで、エンジニアの延長線上にあるように見えていて実はまったく違った役割が求められる。 その上、エンジニアとしての技術力は必要とされており(コードを直接書くことは求められていないが)、そのことがより一掃これらの職位のハードルを高くする。

それぞれの職位の役割がかなり詳細に書かれているので、その職位に就いたときには参考書としてとても役に立つ本だと思う。 仕事についてかなり細かく具体的に書いてあるし、ありがちな失敗や筆者自身の経験などが書かれていてとても親切だ。 たとえば、技術部長になって複数のチームを管理するようになったら「手一杯で何も成果があげられていないように感じるのが普通」というようなことも書かれている。 きっと新米の技術部長はこれを読んで少し安心するのではないだろうか。(逆に手一杯だと感じない場合は、仕事がちゃんとできてない可能性があるとも書かれているが)

いつか CTO になったら

最初に「読み切ったのは六月」と書いたけど、実はこの本全部読んでない。 後半の四割くらいは斜め読みして飛ばしてしまった。

とても細かく仕事について書いてあるけど、通して読むには記述が細かすぎて読み物として飽きてしまった。 翻訳の問題なのか、一部の文がすごく長ったらしいのもあって少し読みにくかった。 もう少しエッセンスを抜き出して書かれているとうれしかった。

より経営に近い職位については今の自分の立場とはレイヤが違うし、あまり頭に入ってこなかった。 それでも、そのレイヤの職位のあるべき姿みたいなのがぼんやりとは見えて勉強にはなった。 加えて、自分の上司やさらにその上の上司がどのような役割で働いて、どういう部下だったら嬉しいか?みたいなところを考えるきっかけになった。

自分がもし CTO になるようなことがあったらまたこの本に手を伸ばそうと思う。 今はそんな予定ぜんぜんないけど。

Cousera: Architecting with Google Kubernetes Engine Specialization の Course 1 & 2 を修了した

Architecting with Google Kubernetes Engine Specialization の前半を修了した。

f:id:hjm333:20200712134852p:plain

f:id:hjm333:20200712134840p:plain

Course 1 は Kubernetes というよりも GCP の概要を演習つきで学習。 Course 2 は Container と Kubernetes の基礎、というか表面だけさらっと流した感じ。

正直、身になってる感じがあまりしないな。 演習もほとんど自分で考える要素がないし。 やっぱり自分でいろいろ試行錯誤して構築する経験を積まないと身につかない気がするな~。

残りは 2 コース。どうなることやら。

Kubernetes を勉強するよ

今更ながら Kubernetes を勉強しようと思う。

とりあえず公式のチュートリアルをやったけど、まだまだ理解できないことばかり。 理解できなくてもどかしい感じは居心地が悪いけど、何か新しいことを学ぶときには必ず通る道だからと自分に言い聞かせる。

チュートリアル終わって何をやろうかなと思っていたところで、Coursera の Specialization を見つけた。

www.coursera.org

Google 公式のコースだしまぁきっと間違いないでしょう。 他にも似たようなコースがあったけど、今まで AWS しか触ったことなくて GCP も少し触ってみたかったし Coursera の方をやろうかな。 有料だけど多少はお金がかかったほうがいいプレッシャーにもなるし。

Coursera のコースはたくさん受講してきたけど、基本的に外れがないので安心感がある。

継続とは何か(2)

継続について考える第二弾。

前回の記事では、足し算と掛け算という単純な例を用いて継続について考えた。

www.thekingsmuseum.info

今回は再帰での継続渡しスタイルについて考えて、継続についてさらに理解を深めたい。

累乗を計算する

再帰を用いて 1 から n までの累乗を計算する関数は次のようになる。

(define (fact n)
  (cond [(= n 1) 1]
        [else (* n (fact (- n 1)))])) 

n=1 の時は 1 を返し、それ以外の時は、n に n - 1 までの累乗を掛け算する。

実行すると次のとおり。

(fact 6) ; => 720

ここまではいつも通りの計算だ。

継続渡しスタイル

累乗の計算を継続渡しスタイルにするとどうなるだろう。

まずは n=1 の時を考える。 1 の累乗は 1 なので、これを関数 col に与えてやればよい。

(define (fact&co n col)
  (cond [(= n 1) (col 1)]
        [else ...TODO...]))

次は n が 1 より大きい時だ。

簡単なところから一歩ずつ考えていこう。

継続スタイルでは col に計算の結果を与えてやる必要があった。 だから、col に対しては n の累乗の結果を与えてやればよい。 x を n-1 までの累乗とすれば、n の累乗は (* n x) だから、col にはそれを与えることにする。

(col (* n x)) ; => ただし、x は n-1 までの累乗

こうすれば継続スタイルの約束を守れる。 問題は x すなわち n-1 までの累乗はどうやって得られるかという点だ。

n-1 の累乗を再帰的に fact&co を使って定義する。 fact&co はそれ自体が累乗を計算して col に計算結果が渡ってくるのだから、次のように計算すればよい。

(fact&co (- n 1) (lambda (x) x)) ; => x は n-1 までの累乗の値が入る

上の lambda の中の x を使えば n-1 までの累乗の値が取得できる。 これを、さきほどのパーツを合わせれば n が 1 より大きいときの計算が得られる。

(fact&co (- n 1) (lambda (x)
                   (col (* n x)))) ; => n の 累乗を計算して、col に与えている

これで else のケースもそろったので fact&co は次のように定義できる。

(define (fact&co n col)
  (cond [(= n 1) (col 1)]
        [else (fact&co (- n 1) (lambda (x)
                                 (col (* n x)))) ]))

実行は次のとおり。

(fact&co 6 (lambda (x) x)) ; => 720

展開してみる

理解を深めるため n=3 として、fact と fact&co の関数適用を展開してみる。

fact は展開すると次のようになる。

(fact 3)
=>
(* 3 (fact 2))
=>
(* 3 (* 2 (fact 1)))
=>
(* 3 (* 2 1))

これは簡単。 ちなみにどの時点でも評価可能で、どの時点の評価も 6 になる。

fact&co は展開すると次のようになる。

(fact&co 3 (lambda (x) x))
=>
(fact&co 2 (lambda (a)
             ((lambda (x) x)
              (* 3 a))))
=>
(fact&co 1 (lambda (b)
             ((lambda (a)
                ((lambda (x) x)
                 (* 3 a)))
              (* 2 b))))
=>
((lambda (b)
   ((lambda (a)
      ((lambda (x) x)
       (* 3 a)))
    (* 2 b)))
 1)

少し複雑だが、順を追って見てみる。

  • (fact&co 3 ... ) は、(fact&co 2 ... ) の結果の a に対して 3 をかけたものを col に渡す。
  • (fact&co 2 ... ) は、(fact&co 1 ... ) の結果の b に対して 2 をかけたものを col に渡す。
  • (fact&co 1 ... ) は、1 を col に渡す。

末尾再帰

こうやって眺めると、その関数の計算が終わったあとにやるべき計算をクロージャにして col に渡していることが分かる。 例えば (fact&co 2 col) には「計算結果に 3 をかけて (lambda (x) x) に渡す」というクロージャを渡している。 これはやはり「これから行われるであろう計算をパッケージ化したもの」だ。

もう一つ気づいたのは、継続スタイルでは関数が末尾再帰になってる。 本来(?)の末尾再帰だと即値で計算した結果を引数に渡してるイメージだけど、継続スタイルではやるべき計算がクロージャとして col に渡されていく。

通常の再帰では「2 までの累乗の結果に 3 をかける」という計算は、関数呼び出しのスタックにつまれて保存されている。

(* 3 (fact 2)) ; → 3 をかけるという計算 (* 3 []) はスタックに積まれて保存

一方、継続渡しスタイルではスタックには積まれずクロージャとして計算を保存している。

(fact&co 2 (lambda (a)
             ((lambda (x) x)
              (* 3 a))))
; => 3 をかける計算はクロージャに保存されている              

また、通常の呼び出しでは見えづらい「3 をかける計算」が継続渡しスタイルでは明示的な計算((* 3 a))になっている。

少し継続がつかめてきた。 次回はさらに複雑な再帰の継続渡しスタイルについて見ていく予定。

(c) The King's Museum