$30 off During Our Annual Pro Sale. View Details »

無用な認知負荷を減らしてお手入れしやすいコードを書こう / Reduce unnecessary cognitive load and write maintainable code

ShinkuFencer
November 09, 2023
1.2k

無用な認知負荷を減らしてお手入れしやすいコードを書こう / Reduce unnecessary cognitive load and write maintainable code

After Kaigi on Rails LT Nightで喋ったスライドです。

【資料内参考したものリンク】

プログラマー脳 ~優れたプログラマーになるための認知科学に基づくアプローチ https://www.shuwasystem.co.jp/book/9784798068534.html​​

認知負荷および認知負荷理論 (Cognitive Load Theory) をもう少し正確に理解するための心理学研究・知見の紹介
https://zenn.dev/kangetsu_121/articles/6b31565dda6053

「快適な」学習のために〜認知負荷理論入門|教育のスゴい論文
https://note.com/sugo_ron/n/na8d0916b1f55

102. A Philosophy of Software Design (3/3) w/ twada | fukabori.fm
https://fukabori.fm/episode/102

ShinkuFencer

November 09, 2023
Tweet

More Decks by ShinkuFencer

Transcript

  1. 無用な認知負荷を減らして
    お手入れしやすいコードを書こう
    After Kaigi on Rails LT Night
    2023/11/09
    しんくう@shinkufencer

    View Slide

  2. 今回しゃべること
    2
    ● 認知負荷理論の考え方と「課題外在性負荷」に関しての概念
    を説明します。
    ● その上で、コード上の「課題外在性負荷」の例を紹介して、
    RubyやRailsで減らすプラクティスを紹介しようと思います。

    View Slide

  3. ざっくり知る認知負荷理論
    3

    View Slide

  4. 認知負荷理論の前に多重貯蔵モデルとワーキングメモリ
    4
    ● 認知負荷理論は「多重貯蔵モデル」と「ワーキングメモリ」という考え方
    が前提となった考え方になっている。
    ● 「多重貯蔵モデル」は人の記憶の考え方の一つ。
    ● 「多重貯蔵モデル」に処理をするための考え方として「ワーキングメモ
    リ」という考え方が加わっている。
    ● ふたつの考え方から成り立つものなので、今回はそれをミックスして簡易
    版として説明する。

    View Slide

  5. 多重貯蔵モデルとワーキングメモリのイメージ図
    5
    感覚記憶
    Sensory Memory
    ⻑期記憶
    Long Term Memory (LTM)
    ワーキングメモリ
    Working Memory (WM)
    短期記憶
    Short Term Memory (STM)
     情報のインプット
    選択的注意
    で分別
    ⽬や⽿で取得した情報から
    気を払った(≒注意した)ものだけ
    短期記憶として取得する ワーキングメモリ*¹で
    処理を⾏う
    必要に応じて⻑期記憶から
    情報を検索したり
    情報を保存したりする
    *1 ワーキングメモリ=短期記憶とするパターンもありますが、今回は隣接するものとしてイメージ図化しました

    View Slide

  6. 多重貯蔵モデルとワーキングメモリ
    6
    感覚記憶
    Sensory Memory
    短期記憶
    Short Term Memory (STM)
    ⻑期記憶
    Long Term Memory (LTM)
    記憶容量が少ない 記憶容量が多い
    短期記憶は記憶容量が少ない

    View Slide

  7. 多重貯蔵モデルとワーキングメモリ
    7
    短期記憶は記憶容量が少ない
    なのでワーキングメモリは長期記憶と連動して処理効率をあげる
    ⻑期記憶
    Long Term Memory (LTM)
    ワーキングメモリ
    Working Memory (WM)
    短期記憶
    Short Term Memory (STM)

    View Slide

  8. 認知負荷理論(Cognitive Load Theory,CLT)とは
    8
    ● ワーキングメモリをどうやって活用すると理解がよりよく行われるかとい
    う研究が進められてきた
    ● 認知負荷理論は「ワーキングメモリ」と「長期記憶」の関係性を基軸に
    ワーキングメモリにかかる学習負荷(理解するための負荷)がどう処理さ
    れているかを捉える考え方
    ● 認知負荷を3つに分類して負荷の考え方を説明している

    View Slide

  9. 認知負荷理論の3つの認知負荷
    9
    課題内在性負荷
    Intrinsic Cognitive Load
    取り扱う学習内容がもとから
    備えている”本質的な”負荷。
    学習者がもとから備えている
    ⻑期記憶に備えた知識などで
    負荷の量は変化する。
    課題外在性負荷
    Intrinsic Cognitive Load
    取り扱う学習内容には直接関
    係ない”余計な”負荷。学習の
    ためには不要な負荷なので、
    ないことが望ましい。
    学習関連負荷
    Germane Cognitive Load
    単純な課題解決のための負荷
    とは別の学習を通してより深
    い理解に近づけることができ
    る”適切な”負荷。

    View Slide

  10. 認知負荷理論の3つの認知負荷
    10
    課題内在性負荷
    Intrinsic Cognitive Load
    解くべき課題そのものの負荷
    「10÷20×20×9 を解けとい
    う問題を考える」など
    課題外在性負荷
    Intrinsic Cognitive Load
    課題の本質とは無関係の負荷
    「問題説明をジョークを交え
    ながら話す」*²など
    学習関連負荷
    Germane Cognitive Load
    算数を上達するうえでの負荷
    「同じ数をかけて割る場合は
    無視できる理屈の理解」など
    算数問題を解くことに例えてみると…
    10÷20×20×9
    20が二重にあるね!!!
    二重に二重苦だ
    *2 ジョークなどで身近な話題に変換することで負荷を下げるという話もあるのでジョークが一概に悪い訳では無い

    View Slide

  11. 認知負荷理論と”効率のよい脳の使い方”
    11
    ● ワーキングメモリは有限であり、かけられる負荷は限られているので、配
    分をうまく行いたい。
    ● 「課題内在性負荷」は学習内容の本質的な負荷なので、学習者がレベル
    アップしない限りは減らせない。
    ● レベルアップのためには「学習関連負荷」の比率を上げたい。
    ● 残る「課題外在性負荷」は少ないことに越したことはない負荷なので挙げ
    た3つの中では最も減らしたい負荷となる。
    ● なので”認知負荷を減らす”というときは第一に課題外在性負荷を減らして
    いくのがまずは大事*³
    *3 長期記憶をうまく使ったり自身のレベルアップができると課題内在性負荷を減らしたりすることもできるので
    他の負荷の2種類の負荷も減らせないわけではない

    View Slide

  12. 認知負荷理論と”効率のよい脳の使い方”
    12
    課題内在性負荷
    課題外
    在性負

    学習関連負荷
    効率のよい学習者のワーキングメモリ負荷割合
    課題内在性負荷
    課題外在性負荷 学習関連負荷
    効率が悪い学習者のワーキングメモリ負荷割合(キャパオーバー)
    ワーキングメモリにかけられる負荷には限りがあるので
    一番不要な課題外在性負荷を減らすことは大事

    View Slide

  13. コードを書く上での
    課題外在性負荷とは何か
    13

    View Slide

  14. コードを書く上での課題外在性負荷
    ● 「課題外在性負荷」は”本質的な難しさ”でもなく、”成長のために乗り越
    えなければならない難しさ”でもないものがあたる
    ● 今回は私の観点で、日々コードを書く上での課題外在性負荷にあたりそう
    なコード例と負荷軽減方法をいくつか紹介します。
    14

    View Slide

  15. バラバラな記述方法が負荷になるので整える
    ● 左のコードは金額を引数にとって消
    費税10%を含んだ金額を返すs_tax
    というメソッド。スペースは特に意
    味があるわけではない。
    ● スペースの配置に統一感がなく、逆
    に「このスペースの置き方は他と異
    なるのでなにか特別な意味があるの
    ではないか?」と考えるようになる
    のでその過程で認知負荷が増える
    ● 一定のルールに整えるのはrubocop
    などのlinterで解決ができる
    15
    def calc_st(p)
    tp = 0.1
    t= p * tp
    return t + p
    end
    def calc_st(p)
    tp = 0.1
    t = p * tp
    return t + p
    end

    View Slide

  16. 日常的に利用している言葉を取り入れて負荷を減らす
    ● 「長期記憶をうまく使うことで認知
    負荷を減らすことができる」という
    仕組みに基づいた考え方
    ● 日頃利用している英単語などは長期
    記憶にあるので認知負荷軽減に寄与
    する
    ● 左記の例だとstが消費税込みの価格
    のことだったり、pが価格(price)
    になっているなど都度脳内で変換を
    挟んでいるのでストレートな言葉に
    置き換えて脳内変換コストを下げる
    ことに貢献できる
    16
    def calc_in_tax_price(base_price)
    tax_percentage = 0.1
    tax = base_price * tax_percentage
    return tax + base_price
    end
    def calc_st(p)
    tp = 0.1
    t = p * tp
    return t + p
    end

    View Slide

  17. 日常的に利用している言葉を取り入れて負荷を減らす
    ● Railsの場合はよりActiveSupportを使えばより自然にかける
    ● また、Rubyであれば “?” を使うことでbooleanを返すものは自然に読みや
    すくなり、自然に読めることで本質的な課題に取り組める
    17
    def available_date?(target_datetime)
    now_time = Time.zone.now
    now_time.yesterday <= target_datetime && target_datetime <= now_time.tomorrow
    end
    def is_available_date(target_datetime)
    now_time = Time.zone.now
    yesterday = DateTime.new(now_time.year,now_time.month,now_time.day - 1)
    tomorrow = DateTime.new(now_time.year,now_time.month,now_time.day + 1)
    return yesterday <= target_datetime && target_datetime <= tomorrow
    end

    View Slide

  18. 意味のある単位を近づけて負荷を減らす
    ● 「関連のある事柄が分割されてしまうと認知負荷があがる」*⁴ということ
    に基づいた考え方
    ● プログラミングにおいては処理の単位を遠ざけないようにする
    18
    def building_object(base_data)
    flags_hash = {}
    item_array = []
    object = {}
    if base_data[:list].size == 0
    flags_hash[:size_zero] = true
    else
    base_data[:list].each do |item|
    item_array << item
    end
    object[:item_list] = item_array
    end
    object[:flags_hash] = flags_hash
    return object
    end
    flags_hashが確定するのが最後なので
    メソッドの最初から最後まで
    考えておかないといけない
    item_arrayが登場するのは
    ネストの中なのに
    宣⾔⾃体はメソッドの最初で⾏われている
    *4 Split-Attention Effect と呼ばれる効果

    View Slide

  19. 意味のある単位を近づけて負荷を減らす
    ● 「関連のある事柄が分割されてしまうと認知負荷があがる」*⁴ということ
    に基づいた考え方
    ● プログラミングにおいては処理の単位を遠ざけないようにする
    19
    def building_object(base_data)
    flags_hash = {}
    item_array = []
    object = {}
    if base_data[:list].size == 0
    flags_hash[:size_zero] = true
    else
    base_data[:list].each do |item|
    item_array << item
    end
    object[:item_list] = item_array
    end
    object[:flags_hash] = flags_hash
    return object
    end
    def building_object(base_data)
    return {:flags_hash=>{:size_zero=>true}} if base_data[:list].size == 0
    result_list = base_data[:list]
    { item_list: result_list, flags_hash: {} }
    end
    flags_hashもitem_arrayも
    返却するobjectの⼀部なので修正して
    メソッド名どおりobjectをbuildでまとめる
    *1 Split-Attention Effect と呼ばれる効果

    View Slide

  20. 再代入を避けてイミュータブルにして負荷を減らす
    ● 「関連のある事柄が分割されてしまうと認知負荷があがる」というところ
    の別の切り口の考え方
    ● 同じ変数に何度も代入するのは最新状態が不明瞭で認知負荷があがる
    20
    def response_build(params_hash)
    success_flag = true
    result_array = []
    if params_hash[:error_messages].size > 0
    success_flag = false
    end
    params_hash[:value_array].each do |value|
    if value > MAX_VALUE_SIZE
    success_flag = false
    else
    result_array << value
    end
    end
    success_flag = true if params_hash[:skip_error_check] == true
    return { data: result_array , is_success: success_flag }
    end
    success_flagは途中で何度も変わるので
    最終的な値がわかりづらく
    短期記憶やワーキングメモリを消耗する

    View Slide

  21. 再代入を避けてイミュータブルにして負荷を減らす
    ● 「関連のある事柄が分割されてしまうと認知負荷があがる」というところ
    の別の切り口の考え方
    ● 同じ変数に何度も代入するのは最新状態が不明瞭で認知負荷があがる
    21
    def response_build2(params_hash)
    result_array = []
    params_hash[:value_array].each do |value|
    next if value > MAX_VALUE_SIZE
    result_array << value
    end
    has_no_error_message = params_hash[:error_messages].size == 0
    has_no_over_value = params_hash[:value_array].all? { |value| value <= MAX_VALUE_SIZE }
    is_skip_error_check = params_hash[:skip_error_check]
    is_success = is_skip_error_check || (has_no_error_message && has_no_over_value)
    return { data: result_array, is_success: is_success }
    end
    再代⼊を無くすことで
    内容を明瞭にする

    View Slide

  22. 課題外在性負荷を考えながらコーディングする
    ● 「課題外在性負荷」になりそうな負荷は探すと色々ある
    ● 認知負荷って何があるかなと考えながらコードを書いていくことで自然と
    きれいになっていく
    ● 『どういうコードが負荷をさげられるのかわからない!』という方は「プ
    ログラマー脳」で取り上げられているので、そこを中心に見ていくといい
    かもしれません。
    22

    View Slide

  23. まとめ
    23
    ● 認知負荷理論では3つの負荷分類があり、その中でも課題外在
    性負荷を減らすことで本質的な負荷だけに頭のリソースを使
    うことができる
    ● プログラムコードを書く上で余計な負荷を減らす方法は色々
    ある
    ● RubyやRailsは減らしやすい書き方があるので活用してみては

    View Slide

  24. 24
    プログラマー脳 ~優れたプログラマーになるための認知科学に基づくアプローチ
    https://www.shuwasystem.co.jp/book/9784798068534.html
    認知負荷および認知負荷理論 (Cognitive Load Theory) をもう少し正確に理解するための心理学研究・知見の紹介
    https://zenn.dev/kangetsu_121/articles/6b31565dda6053
    「快適な」学習のために〜認知負荷理論入門|教育のスゴい論文
    https://note.com/sugo_ron/n/na8d0916b1f55
    102. A Philosophy of Software Design (3/3) w/ twada | fukabori.fm
    https://fukabori.fm/episode/102
    Thanks!
    参考にしたサイト/書籍など:
    オススメ
    しんくう / shinkufencer
      @shinkufencer
    コード日進月歩 https://shinkufencer.hateblo.jp/

    View Slide