情報
- Amazonのurl: https://amzn.asia/d/eBfqNOR
ざっくり要約
クリックして開く
Part1 コードをよりよく読むために
Chapter 1 コーディング中の混乱を紐解く
コードを読むときに利用される脳のプロセス
- 長期記憶
- 短期記憶
- ワーキングメモリ
それぞれの弊害となるもの
-
知識不足=長期記憶
-
情報不足=短期記憶
-
処理能力の不足=ワーキングメモリの問題
-
長期記憶を取り出すためには、何かの手掛かりが必要
- 手掛かりが具体的であればあるほど、正しい記憶が見つかる可能性が向上する
-
短期記憶は6つまで保存可能
Chapter 2 コードを速読する (短期記憶について)
- 短期記憶は、2〜6個の要素を保持できる。
- 1つにおける要素はチャンク(抽象化)することが可能
- チャンクの単位で読むことで早く読むことができる
- 見慣れたものや習得している技能でチャンクすることも可能
Chapter3 プログラミング言語の文法を素早く習得する方法 (長期記憶について)
記憶のメカニズムを理解する
- 情報を記憶する2つの形態
- 貯蔵強度
- 特定の何かが長期記憶にどれだけきちんと保持されているか
- 検索強度
- 特定の何かを思い出すのがいかに簡単か
- 貯蔵強度
効果的な学習方法
- フラッシュカードを使って文法を覚える
- IMO: 生成AIを活用して、フラッシュカード形式で出題してもらうといいかもしれない
- 記憶を定着させるには「感覚をあけて繰り返す」ことが重要
- 8週間の一定間隔で26回学習する
- 1年12ヶ月なので、1年で6回行う。それを4年行う。
- 長い時間をかけて勉強した方が、記憶に残る
- 覚えたと思ったものでも「知識を再確認したり、無理矢理にでも考えない限り」記憶はどんどん失われてしまう
- 8週間の一定間隔で26回学習する
記憶の定着を促進する技術
- 想起練習
- 積極的に何かを思い出そうとする
- 推敲
- 新しい知識を既存の記憶と直接的に結びつける
- 精緻化
- 覚えたいことを考え、それを既存の記憶と関連付け、新しい記憶を長期記憶にすでに保存されているスキーマに適合させること
Chapter 4 複雑なコードの読み方 (ワーキングメモリについて)
認知負荷の種類
- 課題内在性負荷
- その問題自体がどのくらい複雑か
- 課題外在性負荷
- その問題の妨げとなる外部要因
- 学習関連負荷
- 考えたことを長期記憶に保持する際に引き起こされる認知的負荷
認定的負荷を軽減するテクニック
- ドメイン知識の学習
- 複雑な問題を長期記憶に保持しておくことで、「課題内在性負荷」が軽減される
- 認知的リファクタリング
- 自分が認知できやすいコードにすることで、「課題外在性負荷」が軽減される
- 学習のためのものなので、学習後はコードを元に戻す
- ワーキングメモリに負荷がかかっているときに使える記憶補助ツール
- 依存関係グラフ
- 全ての変数をまるで囲む
- 同じ、あるいは関連した変数を線でつなぐ
- 全てのメソッド/関数の呼び出しを丸で囲む
- メソッド/関数呼び出しをその定義場所と線で繋ぐ
- クラスのインスタンスをすべて丸で囲む
- クラス定義とそのインスタンスの間に線を引く
- 状態遷移表
- 全ての変数の一覧を作る
- 表を作り、全ての変数の列を作成する
- コードの実行の区切りとなる部分ごとに表に行を追加する
- コードを頭の中で実行し、各変数が持つ値を状態遷移表のそれぞれの行に書き込む
- 依存関係グラフ
- ワーキングメモリの消費を抑えるため、適切な名前と適切なチャンク化を行う
Part2 コードについて考える
Chapter 5 コードの深い理解に到達する
変数の11の役割
- 固定値
- 初期化後に値が変化しない変数。数学定数や読み込んだデータなどに利用される。
- ステッパー
- ループごとに連続的または規則的に値が変化する変数。forループのカウンタや半分ずつ探索範囲を縮める二分探索の変数などが該当。
- フラグ
- ある条件の真偽を示す変数。is_error、is_availableなどの名前が典型。真偽値以外も場合によっては使用される。
- ウォーカー
- データ構造の走査に使われる変数で、どのように移動するかが事前に固定されていないもの。リストや木構造、スタックなどを巡回する際に用いられる。
- 直近の値の保持者
- 連続して入力されるデータや処理結果など、「現在処理中の最新値」を保持する変数。
- 最も重要な値の保持者
- 処理の目的となる値を保持する変数。最小値や最大値、特定条件を満たす値などが該当。
- 収集車(ギャザラー)
- ループなどを通じて、複数の値を1つの変数に集約していく変数。
- コンテナ
- 複数のデータ要素を保持し、追加・削除ができるデータ構造(リスト・配列・スタック・ツリーなど)。
- フォロワー
- 他の変数とセットで使われ、前後の要素や値を追跡するための変数。リンクリストの前ノードを指すポインタなどが代表例。
- オーガナイザー
- データを別の形式に変換・並べ替えするためだけに使われる変数。変換や整理を目的とした一時変数などが該当。
- テンポラリ
- 短期間だけ使用する変数。値の一時保存や入れ替えなど、さまざまな場面で臨時的に利用される。
プログラムを理解に関する様々な段階
- フォーカルポイントを見つける
- コードを読むときに重要な概念
- main()の時もあるし、バグが発生している関数の場合もある
- コードを読むときに重要な概念
- そのフォーカルポイントから知識を拡張していく
- 関連している要素から、そのコードに利用されている概念を理解する
- 複数の要素を横断して利用されている概念を理解する
より深くコードを理解する
- 活性化: 関連する事柄を直接的に考え、過去の知識を活性化させる
- コード全体をスキャンする
- ワーキングメモリが、長期記憶の関連情報を見つけ、手元のコードを理解する手口にできる
- コード全体をスキャンする
- 監視: 文章の理解度を把握し続ける
- 理解している箇所としていない箇所にチェックをつける。
- コードに対するメモを取る
- 重要性の判断: 文章のどの部分が最も関連性が高いかを判断する
- 重要だと思った行に感嘆符を書き込む
- 推論: 文章にはっきりと書かれていない事実を補完する
- 変数名、クラス名、シグネチャから推論する
- 可視化: 読んだ文章の内容を図解して理解を深める
- 「識別子名, 関連する操作」の表を作る
- 自問自答: その文章について、質問を作り、それに応える
- コードの中で用いられる最も重要な事柄を5つ挙げてください。ここでいう「事柄」には、識別子名、テーマ、クラス、コメントに書かれている情報などが含まれます。
- その重要な事柄を特定するには、どんな手法を用いたでしょうか?例えば、メソッド名やドキュメント、変数名などを調べたり、そのシステムに関する自分の知識を利用したでしょうか?
- コードの中で用いられている最も重要なコンピュータサイエンスに関する事柄を5つ挙げてください。ここでいう「事柄」には、アルゴリズム、データ構造、何らかの仮説、技術的なテクニックなどがふくまれます。
- コードの作成者が下した何らかの決断を特定することができたでしょうか?特定のアルゴリズムやデザインパターンの実装、何らかのライブラリやAPIの利用などが該当します。
- それらの決断の特定は、どのような仮説をもとに行ったのでしょうか?
- それらの決断には、どんなメリットがあったのでしょうか?
- それらの決断には、どんなデメリットの可能性があるでしょうか?
- その決断とは別の同じ問題を解決する方法を挙げられるでしょうか?
- 要約: 文章の短い要約を作成する
- コードの目的: このコードが達成したい目的は何か
- 最も重要な行はどこか
- 最も関連深いビジネス領域の概念は何か
- 最も関連深いプログラムの構造は何か
- コード作者の下した決定は何か
Chapter 6 プログラミングに関する問題をよりうまく解決するには
- モデルを利用する
- 情報を他の人に伝えることが容易
- 認知的負荷を下げることができる
- 2種類のモデル
- メンタルモデル
- 目の前の問題について推論するために、ワーキングメモリの中で概念を抽象化するもの
- 想定マシン
- コンピュータがどのように動作するかの説明
- メンタルモデル
Chapter 7 誤認識: 思考に潜むバグ
- 「学習の転移」により、学習が容易になる
- 熟練度
- 類似度
- コンテクスト
- 重要な性質に関する知識
- 関連性
- 感情
- 「負の転移」も存在し、これが原因でバグが発生する可能性がある
- 学習の邪魔になる
- 誤っているものを正しいと認識してしまう
- 対処法
- ペアプログラミング、モブプログラミング
- テストを書く
- ドキュメントを書く
Part3 よりよいコードを書くために
Chapter 8 より良い命名を行う方法
なぜ名前が重要なのか
- 名前はコードの大部分を占める
- コードレビューにおける名前の役割
- 名前は最もアクセスしやすいドキュメントである
- 名前はビーコンとして機能する
- 初期の命名の慣習は永続的な影響を与える
変数名に含まれている3つの意味
- ドメイン知識
- プログラミングそのものに関する知識 (tree構造など)
- 変数名そのものが、長期記憶に保持された情報と関連づけられている(i、jなど)
よりよい名前を選ぶには
- 覚えやすい命名
- ユビキタス言語を使う
- コード全体で頻出している単語を使う
Chapter 9 汚いコードとそれによる認知的負荷を避けるための2つのフレームワーク
- 構造的アンチパターン
- コードに書かれている処理は正しく動作するものの、脳が処理しやすい構造になっていないケース
- コードの臭い
- 言語的アンチパターン
- コード内の言語的要素(コメント、シグネチャ、変数、ドキュメント)とその役割の間の不整合であるケース
Chapter 10 複雑な問題をより上手に解決するために
- 問題解決において重要な役割をになる2種類の記憶
- 手続き記憶(潜在記憶)
- 筋肉が覚える記憶
- 宣言的記憶(顕在記憶)
- エピソード記憶
- 意味記憶
- 手続き記憶(潜在記憶)
- 問題解決を楽にする
- 「自動化」
- 認知的段階
- 目の前のタスクについて説明的に考える
- 連合的段階
- パターンに反応できるようになるまで、新しいコードを対象として繰り返し作業する
- 自律的段階
- 自動化の完了
- 認知的段階
- 他の人がどのように問題を解決したかをじっくりと研究する
- 課題内在性負荷(問題そのものがもたらす)と課題外在性負荷(問題表現がもたらす)を軽減させ、脳が学習関連負荷(長期記憶に戻して保存するのにかかる負荷)に耐えられるようにする
- レシピ(思考のフレームワーク・ツール・攻略法)を学ぶ
- 同僚と共同作業する
- GitHubを探検する
- ソースコードに関する本やブログ記事を読む
- 「自動化」
Part4 コーディングにおける共同作業
Chapter 11 コードを書くという行為
-
プログラミング中に行う作業(CDN(cognitive dimensions of notation)で説明されているもの)
- 検索
- コード内を調べ、特定の情報を探す作業のことを指す
- 短期記憶に負荷がかかる
- 理解
- コードを読んで実行し、その機能を把握することを意味する
- そのコードが何をするのかの詳細をよく理解していない状態であることが前提
- ワーキングメモリに負荷がかかる
- 転写
- 単にコードを書く
- 長期記憶に負荷がかかる
- 増強
- 増強は、検索と理解、転写をすべて組み合わせたもの
- 新しい機能を追加するという意味
- 「短期記憶・ワーキングメモリ・長期記憶」に負荷がかかる
- 探索
- スケッチを描くようにコードを書くこと
- 「短期記憶・ワーキングメモリ・長期記憶」に負荷がかかる
- 検索
-
プログラミング中の割り込みに備える方法
-
作業が中断された後、コードの編集を開始できるまでには約25分かかる
- 割り込みは生産性を低下させる
- コメントやドキュメントなどに「メンタルモデル」を保存する
- 展望記憶を補助する方法
- TODOコメントをつける
- TODOコメントは永久に残る可能性があるのですぐに片付ける
- TODOコメントをつける
- 下位目標のラベル付け
- 例えばコードを書くときに下記のコメントをつけたから実装を行う
# テキストを解析する # 木構造を取得する # 木構造をフィルタリングする # 木構造をテキスト形式に戻す
-
-
認知的負荷が低いときは割り込みが発生しないようにする
- Slackのステータスを変更しておく
Chapter 12 より大きなシステムの設計と改善
システム開発における特性
- エラーの発生しやすさ
- 型が必須の言語か否か
- コーディング規約の不徹底
- ドキュメントの不足
- 名前の曖昧さ
- 一貫性
- 同じような事柄がどれくらい同じように表現されているのか
- 拡散性
- 必要以上に複雑な書き方をする
- 1つのメソッドに多くの機能をつめこうもうとする
- 隠れた依存関係
- 依存関係がどの程度までユーザーに見えるようになっているか
- 暫定性
- 走りながら考えることがどれくらい容易にできるのか
- 「下位目標のラベル付け」によって和らげることができる
- 粘性
- 現在のシステムのコードがいかに変更するのが難しいかを表す特性
- 段階的評価
- 与えられたシステムにおいて、部分的な作業をチェックしたり実行したりすることがどれだけ簡単なのか
- 役割表現力
- コード中の様々な部分において、その役割をどれだけ簡単に理解できるか
- マッピングの近接度
- プログラミング言語やコードの内容が、問題を解決しようとしているビジネス領域にどれだけ近いか
- コードの構造と識別子をビジネス領域(ドメイン)に一致しているか
- ハードな心的操作
- ユーザーがかなり頑張って思考し、システム外において非常にハードな心的操作が必要であること
- 副次的表記
- プログラマーが、正式な仕様として決められていない、余計な意味をコードに追加する可能性を表す特性
- 抽象化
- システムの利用者が、そのシステムに元からある抽象化と同等の抽象化を行えるかどうか
- 視認性
- システムの様々な部分をどれだけ簡単に見ることができるか
設計上の処置とそのトレードオフ
- エラーの発生しやすさと粘性
- 暫定性と段階的評価 vs エラーの発生しやすさ
- 役割表現力 vs 拡散性
特性がそれぞれの活動に与える影響
- 検索
- 悪影響
- 隠れた依存関係
- 拡散性
- 好影響
- 副次的表記
- 悪影響
- 理解
- 悪影響
- 視認性が低いこと
- 好影響
- 役割表現力
- 悪影響
- 転写
- 悪影響
- 一貫性
- より多くの心的努力を有するため
- 長い目で見れば好影響になる
- 一貫性
- 悪影響
- 増強
- 悪影響
- 粘性
- 好影響
- ビジネス領域へのマッピング近接値
- 悪影響
- 探索
- 悪影響
- ハードな心的操作
- 抽象化
- 好影響
- 暫定性
- 段階的評価
- 悪影響
Chapter 13 新しい開発者のオンボーディング
-
問題点
- 新規参入者に一気に情報を投げがち
- コードが対象とするビジネス領域
- 開発ワークフロー
- コードベースの内容
- 小さなバグ修正や小さな機能開発のタスクを与えるが、シニア開発者本人は、それを非常に簡単なタスクだと考えがち
- ビジネス領域やプログラミング言語における関連するチャンクの不足、あるいは関連するスキルが完全に自動化されていないがゆえに、高い認知的負荷を引き起こし、カーネルパニックが起こる
- 新規参入者に一気に情報を投げがち
-
専門知識の呪い(curse of expertise)
- 何かのスキルや知識を十分に習得してしまうと、その修得がいかに大変だったかを忘れてしまうことを意味する
-
新規参画した時
- 情報をチャンク化する
- 知識を長期記憶にインストールする
-
情報の伝え方
- 意味はに乗っとる
- 一般的な概要として、それが何をするものなのかざっくりと理解させる
- アンパッキング
- 抽象から具体へと進んで説明する
- リパッキング
- 抽象でしめて思考のチャンク化を促す
- 、過去に知っている知識の間の共通点を明確に質問として尋ねることなどで後押しが可能
- 意味はに乗っとる
-
オンボーディングプロセスを改善するための活動
- 5つの活動の中から1つを選びやってもらう
- 探索: コードベースを見渡して、その全体像を把握する
- 検索: 特定のインターフェイスを実装しているクラスを探す
- 転写: 新人に作業の具体的な手順について明確な計画を伝える
- 理解: 特定のメソッドを自然言語で要約するなど、コードの内容を理解する
- 増強: 既存クラスへの機能追加(計画の作成も含む)
- 記憶をサポートする
- 長期記憶のサポート: 関連情報を説明する
- 短期記憶のサポート: 小さくて1つのことだけに特化したタスクを用意する
- 理解は開発よりも歓迎すべきタスクである
- ワーキングメモリのサポート: ダイアグラムを描く
- コードを一緒に読む
- 活性化: 関連する事柄を積極的に考え、過去の知識を活性化させる
- 重要性の判断: 文章のどの部分が最も関連性が高いかを判断する
- 推論: 文章にはっきりと書かれていない事実を補完する
- 監視: 文章の理解度を把握し続ける
- 可視化: 読んだ文章の内容を図解して理解を深める
- 自問自答: その文章についての質問に回答する
- 要約: 文章の短い要約を作成するあ
- 5つの活動の中から1つを選びやってもらう
感想
「認知負荷が低いコード」が「良いコード」だと思っている。
認知負荷が低いコードは保守性に優れ、機能拡張もしやすくなり、何より朗らかな気持ちで仕事ができる。
開発スピードも上がり、フィードバックサイクルを早く回せるためプロダクトに関わる人全てを幸せにすると思っている。
この書籍は、「認知負荷が低いコード」とは何なのか、どうしたら認知負荷が低くなるのかが、とてもわかりやすく書かれている。
また、それだけにとどまらず認知科学的に効率のいいコードリーディングの仕方や、自分自身の能力向上、チームとしての開発生産性・開発者体験の高め方まで幅広く書いてある。
また読もうと思う。
お気に入り度
⭐️⭐️⭐️⭐️⭐️