プログラマー脳 ⑦ Chapter 10 複雑な問題をより上手に解決するために

Chapter 8 & 9 は、ザッと見た感じ、今の自分にそこまで有益だと思わないため割愛

Chapter 10 複雑な問題をより上手に解決するために

《本章の内容》

要は、長期記憶を鍛えるとその分の余裕を使えるので、より大きな課題を解決できるよ、という感じ

10.2 プログラミングの問題を解決する際に長期記憶はどのような役割を果たすのか

10.2.3 問題解決において重要な役割を担う 2 種類の記憶

いかに顕在記憶を潜在記憶にするか、特に考えなくてもできるほど自然なレベルにもっていくかが重要、とのこと

10.3 自動化:潜在記憶の形成

10.3.2 自動化するとなぜプログラミングが速くなるのか

10.4 コードとその説明から学ぶ

  • 数学の解き方のセオリー(前の項での「クラス」に該当)を示された生徒達は、そうでない生徒達よりも、優秀な成績を収めた
    • 一般的な「自力で考えた方が伸びるのでは」という予想を覆す

10.4.1 新しいタイプの認知負荷:学習関連負荷

  • ワーキングメモリがいっぱいだと、長期記憶への保存が働かなくなることが、前の実験の意外な結果の要因
  • 自力で考えていた生徒達は、一般的なルールよりも、目の前の課題の解決に焦点を合わせていた

感想

  • ある問題を苦労して解決した時は、その際に用いたどのような知識が他の場面で適用可能か考えてみよう。できれば Anki に入れよう

プログラマー脳 ⑥ Chapter 6 プログラミングに関する問題をよりうまく解決するには / Chapter 7 誤認識:思考に潜むバグ

まずは昨日読んだ内容を思い出したい。

《変数の役割 11》

  • 固定値
  • ステッパー
  • ウォーカー
  • フォロワー
  • ギャザラー
  • コンテナ
  • オーガナイザー
  • フラグ
  • temp
  • Most Recent Value
  • Most Wanted Value

良い感じ。

起きる前、寝床で試してみたところ、最初は苦戦した

ギャザラー、フラグ、temp, MOR, MWV が思い出しにくかった

Anki に入れてしまおう。

また、ChatGPT に頼んで、mnemonic を作って貰おう。

→ 作ってくれたものが微妙だったので mnemonic 作戦はギブアップ

ただ、これらは無事に覚えられて嬉しいが、Kindle みたいなワードが頭から抜けがちなのはヤバいし悲しい。

ほら、また、「メタベース」が思い出せなかった。

…えっ、metabase、オープンソースなの!?

「メタベース」を覚えるためにググったら発覚した衝撃の事実。

あと、昨日の内容に「構造の理解と計画の理解」があったことが思い出せなかった。

Chapter 6 プログラミングに関する問題をよりうまく解決するには

《本書の内容》

  • プログラム上の問題を効果的に推論するためのモデルを適用する
  • 問題に対する様々な考え方が、問題解決の方法にも影響を与えることを理解する
  • コードについて考え、より効果的に問題を解決するためのモデルの活用方法を探る
  • 長期記憶の能力を向上させることで問題を解決する新しい方法を学習するテクニックを試す
  • ワーキングメモリの活用方法を工夫することで問題を解決するモデルを利用する方法を学ぶ
  • 無関係な内容を省き、重要な内容のみに注目することで、問題を正しく切り分ける

1 つのテーマは「モデル」なのかな?

昨日、自分は文章の読解時に「スキャン」を行わないという反省を得たばかりだったので、少なくとも今日は(できれば続けたい)、スキャンから始めてみよう。

「本章のまとめ」を覗いたところ、「メンタルモデル」や「想定マシン」といった新ワードが登場している。

「メンタルモデル」はまずまずイメージがつくけど、「想定マシン」はよく分からない。

英語では "Notional machine" らしいけれども、全然イメージの助けにならない。

メンタルモデルを使うとき、人は無駄を惜しむようになる。なぜなら、脳は多くのエネルギーを消費するので、人は頭脳労働の量を減らすために筋肉で解決したがるからである。

草。

自分が先週、クリップが極限まで伸縮してしまう不具合を調査した際のやり方もそんな感じだったと思う。

今となっては、ライブラリのコードの中身を見に行くのが正解だとは知っているけれども、デバッグの方法はなかなか分かっていなかった。

  • メンタルモデル
    • デザインパターン
      • これ、なるべく早く自分のものにしたい。ChatGPT にクイズを出して貰ったら良いと思う。これは Observer パターンでしょうか、みたいな。後々、二択にしたり、もっと複雑にしたり。

結局、スキャンというよりは、スピーディーに読み通してしまった。 結果として有用だと感じられたのは、上にメモした 2 点のみだった。 でも、見落としがあるかもなので、今から読み直してみる。

「本章の内容」一つの

長期記憶の能力を向上させることで問題を解決する新しい方法を学習するテクニックを試す

というもの、興味深いけど、読み通して思い当たるものがなかったような…

デザインパターンがそれに該当するのか?

あと、「想定マシン」については、メンタルモデルのうちの、PC の働きを表すものだと理解。

6.1 コードについて考えるためにモデルを利用する

6.1.1 モデルを利用することの利点

  • 利点
    • その時に必要な情報のみにフォーカスできるよう、余分な部分を見えなくしてくれる
  • コードのアーキテクチャ図や、値の遷移図なども、モデル。
  • 「列車の間を往復する鳥」問題にて、鳥の軌跡をモデル化するかどうかによって複雑さが大きく異なるのと同様に、何でもモデル化すれば良いという訳ではない

6.2 メンタルモデル

状態表やグラフなどもモデルであるが、このようなものは、手を動かして作成する必要がある。

それに対し、そのような作業を必要としないモデルが存在し、それをメンタルモデルという。

例えば、木構造というメンタルモデルのおかげで、「ある要素を参照している要素」と表現せずに「あるノードの子ノード」と表現できる。

フォルダとファイルの関係も、メンタルモデル。

また、「コードのこの行が実行されると…」という場合も、実際に実行されるのは対応して生成されたバイトコードであるため、メンタルモデルである。

6.2.1 メンタルモデルを詳しく検討する

  • メンタルモデルは、不完全で不安定

6.2.2 新しいメンタルモデルを学ぶ

6.2.3 コードについて考えている際にメンタルモデルを効果的に使う方法

読み直しても、やはり、デザインパターンが気になる。

少しでも簡単なものから始めたかったので、Singleton パターンについて調べてみた。

design-patterns-in-ruby/singleton.md at master · davidgf/design-patterns-in-ruby

アプリケーション内で、あるクラスのインスタンスが1つしか生成されないようにするものなのか。

自分が開発しているコードでは、Singleton モジュールは利用されていない様子。

6.3 想定マシン

想定マシンは、特定のプログラミング言語の実行に関係する機能を正しく抽象化したもの。

メンタルモデルとは異なり、それぞれが完全であり、お互いで矛盾しない。

6.3.1 想定マシンとは何か

6.3.2 想定マシンの実例

6.3.3 さまざまなレベルの想定マシン

6.4 想定マシンと言葉

なるほど、return / 返す というのは、「関数がスタックに値を積み、呼び出し元(この考え方もメンタルモデル)がその値を使えるようにすること」か。

6.4.1 想定マシンの拡張

6.4.2 想定マシン同士がメンタルモデルを作り出す場合

6.5 想定マシンとスキーマ

6.5.1 なぜスキーマが重要なのか

6.5.2 想定マシンは意味論的なものか

Chapter 7 誤認識:思考に潜むバグ

本章では、バグに焦点を当てる。

7.1 2つ目のプログライング言語を学ぶのは、最初の言語を学ぶよりも、なぜ簡単なのか

  • 何かの知識が別の領域で役に立つことを 転移 という
  • 新しい情報を既知の情報と関連付けることを 精緻化 という

7.1.1 既知のプログラミングに関する知識を最大限活用する方法

  • 既存の知識と新情報との関連性を自発的に意識することが重要らしい

7.1.2 転移の種類

  • 意識することなく実行できるスキルの伝達 → 一般道の転移 (Low Road Transfer)
  • 意識して獲得するような複雑なタスクの転移 → 高速道路の転移 (High road Transfer)

  • 近転移

  • 遠転移

7.1.3 すでに持っている知識は呪いか幸いか

  • 正の転移
  • 負の転移
    • BASIC を学ぶと他の言語で負の転移が起きやすい様子

7.1.4 転移の難しさ

  • チェスの優秀さが他の知的分野の優秀さに繋がったりはしないことが研究で知られている

7.2 誤認識:思考の中のバグ

7.2.1 概念変化で誤認識をデバッグする

  • 誤認識を解くには、多くの場合は間違いを指摘するだけでは不十分で、誤った考え方を新しい考え方に置き換える必要がある
    • どこかで学んだ「誤って覚えた後に正しい内容を覚えなおした方が定着が強固になる」という説とは逆だ

7.2.2 誤認識の抑制

7.2.3 プログライング言語に関する誤認識

7.2.4 新しいプログラミング言語を学習する際の誤認識を防ぐ

7.2.5 新コードを読む際の誤認識を診断する

学びの少ない章だった

プログラマー脳 ⑤ Chapter 5 コードの深い理解に到達する

今日から、Part 2 「コードについて考える」らしい。

これまでの Part 1 は「コードをよりよく読むために」だったらしい。

Part 3 は「よりよいコードを書くために」、Part 4 は「コーディングにおける共同作業」とのこと。

本日は、PC を使えない時間が多かったため、まず本章を一読した。

今から読み直していく。

Chapter 5 コードの深い理解に到達する

《本章の内容》

  • 変数の様々な役割を理解する

  • コードの構造を理解することと意図を理解することとは異なることを理解する

  • 自然言語の理解とコードの理解とを比較する

5.1 「変数の役割」フレームワーク

  • フィンランド大学のサヤニエミ教授によれば、プログラマが変数を理解しにくいのは、変数と関連付ける良いスキーマを長期記憶の中に持ち合わせていないからだ、とのこと。
    • なるほど、納得。まあ、薄くは意識しているだろうけれども、もっとはっきりと意識すると良さそう
    • つまり、変数用のスキーマをもつことが重要

5.1.1 違う変数は違う目的を持つ

5.1.2 ほぼすべての変数をカバーできる 11 の役割

  • 固定値
  • ステッパー
  • フラグ
  • ウォーカー
    • 配列中の要素を示すためのインデックスなどが該当
      • ChatGPT に聞いてまずまず分かった
  • 直近の値の保持者(Most recent holder)
    • 封筒マークで表される
  • 最も重要な値の保持者(Most wanted holder)
  • 収集者(Gatherer)
    • これも分かりにくい。和とか。
  • コンテナ
    • 要は配列的なもの
  • フォロワー
    • "current" に対して "previous" というような形で保持されがちなヤツ
  • オーガナイザー
    • 単なるコンテナではなく、その中の順序の管理などまで担う
  • テンポラリ

これ、前回読んだ際も有意義な感じがしたんだけど、いざとなるとなかなか意識しないんだよな…

意識的かつ積極的にやらねば

5.2 役割とパラダイム

5.2.1 役割を見つけることの利点

  • 前述の役割の一覧を認識することで、変数について議論する際の分かりやすいカテゴリーが与えられる
    • チーム内でのコミュニケーションの効率を向上させてくれる素晴らしいツールになる
    • 輪読会などで共通認識を築けていると楽なヤツ

5.2.2 ハンガリアン記法

  • strName → この "Name" の型は string だよ、というような記法

5.3 プログラムに関する知識を深める

  • これまで本書で学んできた手法は、有効ではあるが、局所的
    • コードの構造は理解しやすくなるが、そもそものコードの目的や意図を理解するための助けにはならない

5.3.1 文章の理解と計画の理解

5.3.2 プログラムの理解に関するさまざまな段階

  • コードを読む時は、多くのプログラマーが、フォーカルポイント と呼ばれる場所から読み始める
    • c でいう main() とか
    • もしくは、チェックしているコード範囲における中心的な部分

《コードへの深い理解のための段階の適用》

  • あるコードの箇所についての関連箇所を スライス という

5.4 文章を読むこととコードを読むことは似ている

本章の残りの部分では、以下のことを見ていく

  • コードを読むことと文章を読むことがいかに似ているか
  • 文章を読むためのテクニックの中で、コードリーディングにも応用可能なものにはどのようなものがあるか

5.4.1 コードを読む際に脳内では何が起こっているのか

《コードが脳内でどのように処理されるかを fMRI で分析する》

  • ある実験で出た結果
    • 「ワーキングメモリ」と「自然言語処理」とをそれぞれ担う脳の働きが重要
    • たとえ変数名が難読化されていても、参加者はコードの変数以外の要素を自然言語を読むのと同じように読んで、そこから意味を引き出そうとした

5.4.2 もしフランス語を学べるなら、Python も学ぶことができる

  • 数学の能力はあまりプログラミングの能力と連動していないような実験結果が出た

プログラマーがコードを読む時、まず全体をスキャンする》

  • まあ、文章と比べると、コードではそうせざるを得ない感があるような?
    • むしろ、自分は、文章を読むときにスキャンの作業が足りていないような気がする

5.5 コードを読む際にも適用可能な文書理解の戦略

5.5.1 過去の知識の活性化

5.5.2 監視

  • コードのどの行を理解でき、どの行がよく分からなかったのかを、印を付けることで分別する

5.5.3 コード中のどの行が重要なのかを判断する

5.5.4 変数の名前の意味を推論する

  • コード中の変数名について、次の二種類に分類する
    • ビジネス領域に関係するもの
      • startTime, endTime など
    • プログラムの概念に関係するもの
      • tree や list など
        • 純粋にこちらの要素のみというものは、自分が業務で扱っているコードでは少なそう

5.5.5 可視化

5.5.6 自問自答

5.5.7 コードの要約

本章のまとめ

  • 変数の役割を把握することで理解が捗る
  • 「構造の理解」と「計画の理解」という理解の種類がある
  • コードリーティングと文章読解は似ている

個人的には「コードリーディングと文章読解が似ている」と言われても、だから何だ、という感がある。 その後の、「文章読解でのテクニックはコードリーティングにも応用可能」というものも、無理やり感があるような気がして、眉唾というか、実践してみようと感じにくく、この箇所を読む上でも食指が動きにくかった。

プログラマー脳 ④ Chapter 4 複雑なコードの読み方

寝床で、昨日読んだ内容を思い出そうとしていた。

なかなか思い出せないものだ。

自分は、想起が嫌いであり、そのせいで長期記憶がスカスカなのだと思う。

他の人は、読んだ漫画の内容などを自然に思い返したりするのだろうけど、僕は刹那的に消費してしまうので、その作品について語ったりできない。

まあ、プログラマー脳については、このように所感を述べるほどに吸収したい意欲があるので、他の事柄よりは思い出しやすかった。

《昨日読んだ内容の想起》

  • 人が同時に覚えていられる内容(= 短期記憶)はせいぜい 6 つ。そのため、次の 2 つの方策が重要になる。

    • チャンキング
      • その「せいぜい 6 つ」を最大限に活用する方法。対象を意味の塊という単位で把握する
    • 長期記憶化
  • 「都度調べれば良い」の何が問題か

    • 想起を伴わないので、その対象が長期記憶化すべきものだと脳が認識しない
      • → また忘れて調べ直すという悪循環
    • コンテキストスイッチの切り替えコストが発生する
  • コードを覚え、再現してみるのが学習に有効

    • 自分の苦手な部分が浮き彫りになる
  • 長期記憶を増やすには

    • フラッシュカードによる、対象を絞っての意図的な反復練習が有効
      • Anki をインストールし、デッキを作った
      • カードを増やすのに適切なタイミングは、何かを調べようとした時
    • 精緻化
      • この用語自体を覚えるのを面倒臭がっていた自分に気付いた
      • 学んだばかりの内容を他の事象と繋ぎ合わせたりして分析し理解を深めるプロセス
  • 「記憶の強さ」は次の 2 つの概念で表せる

    • 貯蔵強度
      • 学べば学ぶほど強くなる
      • 時間が経っても減退しない
    • 検索強度
      • 減退する
      • 想起を試みることで強化可能

まあ、まずまず思い出せているか

読んだ内容の多さに対して、まとめた内容は少ないけれども、そういうものだろう

ここで、これまでのまとめを読み直して、何が思い出せていなかったのかを確認してみる

大体は思い出せていた感じだ

アイコニックメモリの点で、声に出したりすると自分にとっては良さそうかもね、というのは重要だった

ただ、Chapter 2 が「速読」、3 が「文法を習得する方法」だったけれども、そこら辺の区別は曖昧だった

Chapter 2 は、いかに上手にチャンキングして、短期記憶をフル活用するかが主題だったようだ

そして、コードを読んでから再現する方法は、チャンキングに上達するための方法であるとのこと

また、デザインパターンも、短期記憶を助けるためのもの、とのこと

チェスの盤面を、よくある場面で覚えているのと同じようなものだろう

Chapteer 4 複雑なコードの読み方

《本章の内容》

  • プログラムを書くときに発生する 2 種類のワーキングメモリの過負荷を比較する
    • 2 種類、気になる
  • 複雑なコードを読むときのワーキングメモリをサポートする状態表と依存関係グラフの作成
    • 面倒でやらなさそうなヤツだというのは覚えている

これまで読んできた内容は、短期記憶と長期記憶に関するものだった

本章では続けて、ワーキングメモリ、つまり処理について扱う

4.1 複雑なコードを理解するのが難しい理由

処理を追うのが難しい場合は、メモを取りたくなるようね、という話

ワーキングメモリと短期記憶の違いは何か

短期記憶とワーキングメモリを区別しないケースもあるとのこと

ただ、本書では区別し、ワーキングメモリを「問題の処理に用いられる短期記憶」と定義する

  • ワーキングメモリも、一度に処理できる事柄の個数は 2 〜 6
    • 自分はそんなに処理できていないような気が
    • この容量を 認知的負荷 と呼ぶ
      • これをオーバーすると「過負荷」になる

4.1.2 プログラミングに関連する認知的負荷の種類

認知的負荷は以下の 3 つに分類される

  • 課題内在性負荷
    • 本質的な難しさ
  • 課題外在性負荷
    • 同じ処理でも可読性によって変わるヤツ
    • 問題の図が読みにくかったり
  • 学習関連負荷
    • 考えたことを長期記憶に保持する際に引き起こされる認知的負荷

4.2 認知的負荷を軽減するテクニック

4.2.1 リファクタリング

保守性に優れているコードが認知性でも優れているとは限らない、ということ、盲点だった

確かに、処理を分散させると、追うのが大変になる

でも、保守性の方が重要だよね

読みやすさを目的に、自分用にコードを書き換えることを、認知的リファクタリングと言う

メソッドとして切り分けられているものをインライン化したり

4.2.2 使い慣れない言語構造の置き換え

コードを読むときに起こりうる混乱を、

  • 知識不足
  • 情報不足
  • 処理能力不足

と 3 つに分類している。

なるほど、長期記憶が知識、短期記憶が情報か

4.2.3 同義で書き方の違うコードはフラッシュカードデッキの非常によい追加要素

とても長い見出しで内心笑っていたけれども、考え直してみると、それだけ強調したいことなのだろう

実践するようにしよう

4.3 ワーキングメモリに負荷がかかっているときに使える記憶補助ツール

4.3.1 依存関係グラフを作成する

変数、関数、インスタンスという 3 つで色分けをしている。

また、同じ要素を線で結び付けて、どこで登場しているのかが一目瞭然になるようにしている。

まあ、確かに、こうすると分かりやすいよね

4.3.2 状態遷移表の利用

各変数の値がどのように変化していくかを記したもの。

コードリーディングの際、コメントなどで、もっと積極的にやっても良いのかも。

頭の中でコードを実行するプロセスを、トレース、または 認知的コンパイル と呼ぶ

↑ これは、デバッガーにやらせると良いことだ

でも、環境の要因もあって、デバッガーを上手く使えていないんだよな…

使わないとだよな…

4.3.3 依存関係グラフと状態遷移票を組み合わせる

《本章のまとめ》

まあ、本章で提唱されている内容の中で、自分が実践しうることとしては「デバッガー使おう」ということだろうな

RubyMine のデバッガーが Docker との絡みで上手く動かないのは解決が難しそうだけれども、JS の debugger は多用していきたい

プログラマー脳 ③ コーディング中の混乱 ③ / コードを速読する / 文法を素早く習得する

全然関係ないけど、先日覚えた、storybook の構文の再現から始める

import '../HogeComponent';

export default {
  title: 'fuga/HogeComponent',
  Component: HogeComponent,
  ArgTypes: {
    peko: {
      description: 'あいうえお',
    },
  },
}

const Template = (args, { ArgTypes }) => ({
  components: { HogeComponent },
  setup() {
    return { args };
  },
  template: '<HogeComponent v-bind="args"' />,
});

export const Default = Template.bind({});
Default.peko = 'ペコ';

どんなもんだろう。

確認してみたところ、最終行が違うな。

Default.args = { peko: 'ペコ' };

としてやれば良い。

そりゃあそうじゃ。

Chapter 1 コーディング中の混乱を紐解く

1.2.3 ワーキングメモリとプログラミング

  • ワーキングメモリは、脳のプロセッサ
    • 長期記憶 → HDD、短期記憶 → RAM
  • ワーキングメモリが担うのは、脳内でのコードの実行
    • トレース という
      • 実際の動きをなぞるから、トレースか

1.3 それぞれの認知プロセスが協調的に動作する仕組み

1.3.1 認知プロセスの相互作用の概要

これまで見てきた 3 つの認知プロセスが図解されている。

自分の認識と異なっていたのは、短期記憶の在り方。

今目にしたばかりの情報群から、必要な情報を掬うためにフィルタを掛けた結果が、短期記憶。

変数名などがこれに該当するということなのだから、この図の通りになるだろうに、なぜか自分は、この他にももう少し長い間保持される記憶までこのカテゴリに含まれると勘違いしてしまっていた。

その理由は恐らく、短期記憶がコード中で扱われる例として、toBinaryString といったような関数が例に出されているのが自分の中でしっくり来ていないからだろう。

1.3.2 プログラミング作業に関係する認知プロセス

本章のまとめ

Chapter 2 コードを速読する

本章の内容

  • 脳が新しい情報を認識可能なパーツに分割する仕組みを解明する
    • 知りたい
  • 言葉やコードのような情報を分析する際の、長期記憶と短期記憶の連携の仕方の発見
  • コードを処理する際のアイコニックメモリの役割を検証する
    • new word キタ
  • コードをどのように記憶しているかが、コーディングレベルの(自己)診断のために利用できることの説明

  • コードは書かれるものである以上に理解されるものである

    • その「理解される」、つまりリーディングに焦点をあてているのが本章
      • なお、コードスニペットを速読する練習をすれば、コーディングスキルが改善されるとのこと

本章を読んだ後には、

  • コードを速く読む方法が理解できている
  • コードリーディングのスキルを向上させるためのテクニックを理解できている

2.1 コードの速読法

  • 「プログラムは人間が読むために書かれ、機会が実行するのは、そのついででなければならない」という文が有名
  • 現実には、プログラマは読む練習よりも書く練習ばかりしている、とのこと
    • 自分は以前、読むのが大嫌いだった
    • 今はそうでもないというか、むしろ、学習目的で積極的に読んでいるような気もするけど

Java の 二重配列を覚え、再現した

2.1.1 今、あなたの脳内で何が起きたのでしょうか?

まあ、Java は分からないので、JavaScript に変換してしまったのだけど

2.1.2 再現したコードを見直しましょう

再現したコードは、長期記憶由来の部分と短期記憶由来の部分に分別できるよね、とのこと

確かにそうだ

と言っても、for 文の各条件がセミコロン区切りであることは正しく認識できておらず、カンマ区切りにしてしまっていたのだけど

JS でわざわざ for 文を書く機会が少ない、という言い訳はできるが、こんな基礎的なものをちゃんと覚えていないのも問題ではある

temp 変数を用いた配列の要素のスワップは、42 Tokyo で何度もやったので、長期記憶由来だ

なお、再現にあたってはコメントを書く人もいる、とのこと

自分には、前回読んだ時も今回も、そのような発想はなかったものの、脳内でやっていたこととしては一緒だな

2.1.3 2回目のコード再現の振り返り

これはやらなかった。

「こちらの方が文脈に欠けているから覚えにくい」というオチを覚えていたので。

2.1.4 なぜ馴染みのないコードを読むのは難しいのか?

  • コードを記憶するのが難しいのは、短期記憶の容量が限られているから
    • 7 ± 2, あるいは 2 つから 6 つ
  • 短期記憶が可能な期間は 30 秒ほど

2.2 記憶のサイズ制限を克服する

6 文字以上再現できていたのは、どういうことか、1 つのカタマリとは何なのか、の分析

2.2.1 チャンキングの威力

  • 「チャンク」という言葉を初めて使ったのは、チェスの盤面の記憶の実験を行った研究者
    • オランダの数学者
  • その実験の結果
    • よくある盤面の再現は、達人の方が一般的なプレイヤーよりも優秀
    • めちゃくちゃな盤面の再現は、達人も一般的なプレイヤーも等しくできていなかった
  • よくある盤面の記憶法について
    • 一般的なプレイヤー → 1 コマずつ覚える
    • 達人 → 長期記憶に保持された情報を多用していた
      • 盤面のパターン名と結びつけたり
      • 自分が過去にプレーした盤面と結びつけたり

《演習》

  • 知らない言語の 12 文字よりも、アルファベットの 12 文字の方が覚えやすい
  • 無意味なアルファベット 12 文字よりも、同じ 12 文字の "cat loves cake" の方が覚えやすい

コードでも同様、とのこと。

そして、チャンク化しやすいコードの書き方を教えてくれる、とのこと

2.2.2 熟練プログラマーは初心者よりもコードを上手に記憶できる

熟練のプログラマでも、不慣れなキーワード、構造、ドメインの概念を扱う際には苦労する

2.3 読めるコードよりも見えるコードの方が多い

  • 情報が短期記憶に到達する前に、感覚記憶と呼ばれる場所を通過する
    • 五感がそれぞれ有する記憶領域
      • そんなものが存在するのか。確かに以前読んだけど、認識から抜けていた
      • 僕が弱そうなところだ
    • この感覚記憶が、アイコニックメモリ
    • プログラミングの文脈では、視覚に関して説明するとのこと
      • 安心した
      • と言っても、これも自分は弱いけど
      • 英単語だと、触覚や聴覚での記憶があり、同じ対象をそうした複数の側面から認識するよう心がけていたことで自分は上手くいったのだと思う
      • とは言っても、実際のプログラミングでも、口には出せるじゃんね。僕にとっては、視覚に限定しない方が良さそう。口に出したら触覚でも認識できるし

2.3.1 アイコニックメモリ

  • 本のページを見続けた後で目をつぶると、ページの輪郭が視覚的な記憶として一時的に残る、とのこと
    • 自分は全然残らない。苦手だ
  • アイコニックメモリに格納された情報の全てが短期記憶によって処理されるわけではない
    • ここでまずフィルターが掛かるという話だろうか
  • 「コードをざっと眺める」練習が、コードの最初のイメージをつかむのに役立つ、とのこと
    • まあ、いつかやってみても良いのかもな。例えば、Rails の、同じ種類のファイルをいくつか見る、など
    • 自分が一昨日に storybook の構文を覚えた時に行ったことも、同じではある

2.3.2 何を覚えているのかではなく、どのように覚えたか

初級者は、英単語をそのまま連ねて覚えがち

上級者は、自分で意味ごとにグループして覚える傾向がある

自分は初級者のやり方でやってしまっていた。

試しに上級者のやり方でやってみたところ、そちらの方がずっと覚えられた。

デザインパターンを利用する》

→ 効果が大きいっぽい。 なるほど、確かに、これも一種の長期記憶だからな。

自分で「このコードはあのパターンだな」などとカテゴライズできると強そう

《コメントを書く》

良し悪しはありそうだけど、チャンク化しにくい長々としたコードブロックには、コメントによる区分を与えるのも手かも

《ビーコンを残す》

  • ビーコン
    • コードの内容を理解するのに役立つプログラムの部分
    • 例えば、変数名に root などと使えば、いかにも木構造っぽい
    • 単純なビーコン複合的ビーコン に分けられる

2.3.3 チャンク化の練習

この本では「意図的な練習」という言葉を多用する

意味は、漫然と量をこなすのではなく、特定の分野での上達を目的として集中的に練習する、というもの

自分がやるべきことのように思う

ステップ 1:コードを選ぶ

ステップ 2:2 分間で覚える

     3:再現

     4:どこが再現できてどこが再現できなかったのかを見比べ、分析

本章のまとめ

  • 短期記憶できるチャンク数の限界は小さいので、この容量制限を克服するため、長期記憶と協調する
  • 長期記憶に十分な知識がないと、単純な情報に頼らなければならなくなるので、すぐに短期記憶の容量の限界を迎えてしまう
  • コードを覚えて再現する作業により、自分に定着していない分野を洗い出せる

Chapter 3 プログラミング言語の文法を素早く習得する方法

《本章の内容》

  • プログラミング言語の文法を記憶するための技術を選ぶ
    • おもしろそう
  • 文法を忘れないためにどんなことができるのかを整理する

    • 自分は今のところ、「覚える!」と意識することがまず功を奏している
  • どれだけ長期記憶に保存されているかが、コードをトレースする速度を左右する

  • この章を読めば、以下が得意になる
    • プログラミングの知識を長期記憶に留める
    • うまくチャンク化する
    • コードをうまく読み進める

3.1 文法を覚えるためのテクニック

自分は、英単語の意味を覚える際、「英 → 和」だけでなく「和 → 英」もできるようになることを重視していたな

プログラミングでも、「書けないけど、読めば何となく分かる」という状態を脱却するために、書く練習をするのが重要そう

3.1.1 割り込みがワークフローを混乱させる

  • 「調べれば分かるからそれで良い」という意見の人もいるだろうが、その「調べる」作業により、ワークフローが中断してしまい、コンテキストスイッチの切り替えに苦労する
    • 苅宿さんみたいに、自分宛じゃない情報は後でまとめて見るようにした方が良いかも
      • 自分の性質を考えると、非常に難しそうだけれども…

3.2 フラッシュカードを使って文法を素早く覚える

勧められている方法の例は、次のようなもの。

「基礎的なリスト内包表記」 ↔︎ numbers = [x] * y

なるほど。

と言うか、同じ要素を複数個持つ配列って、こんな風に作れたんだ。

ChatGPT で調べて初めて知った。

他には、Array.new(y, x) という方法も教えてくれた。

第一引数は、配列のサイズで、必須。第二引数はオプショナル。

まあ、でも、[x] * y の方が直感的で良いな。

3.2.1 フラッシュカードを利用するタイミング

次のアプリが勧められている。

  • Cerego
  • Anki
  • Quizlet

ひとまず、Anki を入れてみた。

カードとして、冒頭の storybook のものと、先程の、Ruby での配列の生成方法との 2 つを追加してみた。

3.2.2 フラッシュカードのセットを拡張する

新たなカードを追加する最適なタイミングは、ある概念を検索しようとしたときです。

なるほど。

3.2.3 フラッシュカードのセットについて考える

3.3 物忘れを防ぐには

3.3.1 なぜ我々の記憶は失われてしまうのか?

《階層構造とネットワーク》

  • 人間の記憶は、フォルダ構造ではなく、ネットワーク構造

3.3.2 間隔をあけて繰り返す

フラッシュカードは、覚えたと思ったものでも長い期間で反復し続けるのが大事

3.4 文法を長く記憶に留めるには

  • 記憶を強化するための2つのテクニック

    • 想起練習
    • 推敲
      • 新しい知識を既存の記憶と積極的に結び付ける
  • 思い出そうとすることが重要

    • 完全な答えを知らなくても、頻繁に思い出そうとした記憶は、簡単に見付かるようになる

3.4.1 情報を記憶する 2 つの形態

  • 長期記憶から情報を取り出す際に、2 つのメカニズムが存在
    • 貯蔵強度
      • どれだけ強固に保存されているか
      • 学べば学ぶほど強くなる
    • 検索強度
      • 思い出すのがどれくらい簡単か

貯蔵強度は増加する一方。

しかし、検索強度は低下していく。

思い出そうとすることで、検索強度が上がっていく。

3.4.2 情報をただ見るだけでは不十分

3.4.3 情報を覚えることで記憶が強化される

知らない文法をその都度調べるなら、脳はその文法を覚える必要があるとは認識しない。

結果として、検索強度は低いままになる。

これは悪循環を生み、いつまでも調べ続けることになる。

3.4.3 能動的に考えることで、記憶を強化する

長期間に亘って練習を行う以外にも効果的な方法がある。

それは、学んだばかりの情報について考え、振り返ること。

このプロセスを 精緻化 と呼ぶ。

これは、複雑なプログラミングの概念を学習する際に、特に効果的。

スキーマ

  • 思考とその関係が頭の中で整理されたもののこと
  • なお、脳は、スキーマ化のために事実を歪曲化さえする
  • 自分は、この精緻化が弱いかも。と言うのは、新しい知識を、既知の何かと結び付けて覚えようとはあまりしないから。

ある程度集中的に読み進められて良かった。

でも、もっと時間を確保しないと、来週の木曜までに読み通すのはキツそうだな…。

次回は 4 章 『複雑なコードの読み方』から。

プログラマー脳 ② コーディング中の混乱 (2) ~

今気付いたのは、このブログ、「下書き保存」の必要性が思い当たらないな。

常に「公開する」で、後で編集して行けば良いのでは?

《昨日学んだこと》 混乱にも種類があって、3 種類に分けられそう。

なので、「混乱した 😵‍💫」となるよりも、「これはどの種類の混乱なんだ? 知識不足? 情報不足? 処理能力不足?」と分析できるようになると良さそう。

なお、この 3 つのうち、最後の「処理能力不足」が頭に思い浮かばなかった。出せるようになりたい。

全っ然関係ないのだけど、今朝、寝床でどうしても「義務」にあたる英単語が思い浮かべられなかった。

「義務教育」→ "XXXX education", で当て嵌まるものをどうにか思い浮かべようとしたものの、mandatory という単語しか思い浮かばず、違ったような気がしつつも諦めたのだった。

なのに、今そのことを思い出したら、compulsory という単語を(スペリングは考えていなかったが)思い出せた。

少し寝かせただけなのに、想起のプロセスとは不思議なものだ。

あと、これも関係ないのだけど、昨日学んだことのもう 1 つに、JS での Array.from の使い方があった。

思い出せるか、今書いてみよう。

arr = Array.from( { length: 31}, (v, i) => ({ id: i, title: "title #{i}" }) )

↑ これで合っているか確認したところ、Array.from の使い方は概ね正しい(index が 0 始まりなのが頭から抜けていた)ものの、テンプレートリテラルの使い方が Ruby になっている…。

title: `title ${i + 1}`

とすべき。

1.2 コーディングに影響を与えるさまざまな認知プロセス

なるほど、

知識不足 → 長期記憶の問題

情報不足 → 短期記憶の問題

処理能力不足 → ワーキングメモリの問題

a.k.a

問題   原因

知識   長期記憶

情報   短期記憶

処理能力 ワーキングメモリ

ということか。

英語だと、長期記憶、短期記憶、ワーキングメモリのどれも "memory" で終わるのに、日本語にするとワーキングメモリだけ別物感が出てしまっているな。

ここまでで既に、本書のプレゼンができるな。

「皆さんも、プログラミングで行き詰まることがあるかもしれません。しかし、その行き詰まりを分類すると…」的な。

「このような経験はありませんか? いや、プログラミング経験者なのですから、全員ありますよね、分かっています。」

1.2.1 長期記憶とプログラミング

1.2.2 短期記憶とプログラミング

ここまで読んでいて、あまりピンと来ていないのは、短期記憶とワーキングメモリとの違いだ。

それぞれ、情報不足と処理能力不足という問題に対応付けられていたけれども。

  • 短期記憶
    • 1 ダース以上は記憶できない
      • マジックナンバー 7」みたいなヤツだ。± 2 ぐらいしか短期的に記憶に保持できない、という。
    • プログラミングの文脈だと、以下のようなものが該当
      • キーワード
      • 変数名
      • 利用されているデータ構造

プログラマー脳 ① 1.1 コードにおけるさまざまな種類の混乱

プログラマー脳』を読み直していく。

前回は英語で読み、7 割位読んだところで飽きてやめてしまった。

今回の目標は、雑でも良いので、とにかく最後まで一回読み通すこと。

「こんなことが書いてあった」をもう少し把握したい。

ザッと読み進めたとしても、一回は目を通しているのだから、頭に入ってくるだろう。

Chapter 1 コーディング中の混乱を紐解く

3 つの認知プロセス。

短期記憶と長期記憶とは分かっているが、ワーキングメモリには、あまり馴染みがない。

また「認知プロセス」という語にも。

そして、それぞれの種類に別の混乱が伴うとのこと。

「自分が相対している混乱は、このパターンのものだな」と分析できるようになるだけでも楽になりそうな気が。

1.1 コードにおけるさまざまな種類の混乱

1.1.1 混乱のタイプ その 1:知識不足

T みたいな形の記号が担う処理。

1.1.2 情報不足

→ ある関数が、関数名だけでは中の処理が分からないから、その定義元まで見に行かないと何とも言えない、というケース。

1.1.3 処理能力の不足

メモを取ったりしないと認識できない、というケース。

頭のキャパオーバー。

今日は、やっただけ偉い。