Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

バラバラな記述方法が負荷になるので整える ● 左のコードは金額を引数にとって消 費税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

Slide 16

Slide 16 text

日常的に利用している言葉を取り入れて負荷を減らす ● 「長期記憶をうまく使うことで認知 負荷を減らすことができる」という 仕組みに基づいた考え方 ● 日頃利用している英単語などは長期 記憶にあるので認知負荷軽減に寄与 する ● 左記の例だと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

Slide 17

Slide 17 text

日常的に利用している言葉を取り入れて負荷を減らす ● 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

Slide 18

Slide 18 text

意味のある単位を近づけて負荷を減らす ● 「関連のある事柄が分割されてしまうと認知負荷があがる」*⁴ということ に基づいた考え方 ● プログラミングにおいては処理の単位を遠ざけないようにする 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 と呼ばれる効果

Slide 19

Slide 19 text

意味のある単位を近づけて負荷を減らす ● 「関連のある事柄が分割されてしまうと認知負荷があがる」*⁴ということ に基づいた考え方 ● プログラミングにおいては処理の単位を遠ざけないようにする 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 と呼ばれる効果

Slide 20

Slide 20 text

再代入を避けてイミュータブルにして負荷を減らす ● 「関連のある事柄が分割されてしまうと認知負荷があがる」というところ の別の切り口の考え方 ● 同じ変数に何度も代入するのは最新状態が不明瞭で認知負荷があがる 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は途中で何度も変わるので 最終的な値がわかりづらく 短期記憶やワーキングメモリを消耗する

Slide 21

Slide 21 text

再代入を避けてイミュータブルにして負荷を減らす ● 「関連のある事柄が分割されてしまうと認知負荷があがる」というところ の別の切り口の考え方 ● 同じ変数に何度も代入するのは最新状態が不明瞭で認知負荷があがる 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 再代⼊を無くすことで 内容を明瞭にする

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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/