Perl Hackers Hub

第71回 ISUCONの実装から最近のPerlを学ぶ ―わかりやすく変更しやすいコードを実現する考え方と方法(1)

この記事を読むのに必要な時間:およそ 4.5 分

本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回のハッカーは小林謙太さんで,テーマは「ISUCONの実装から最近のPerlを学ぶ」です。本稿のサンプルコードは、本誌サポートサイトから入手できます

わかりやすく変更しやすいPerlコードを学ぶ

最初に,ISUCONについて紹介します。公式サイトによると,⁠ISUCONとは,お題となるWebサービスを決められたレギュレーションの中で限界まで高速化を図るチューニングバトル」とあります。2021年のISUCONは11回目の開催だったので,ISUCON11と呼びます。ISUCONのお題であるWebサービスは,参加者が得意なプログラミング言語を使って参加できるように複数の言語による実装を提供していますが,オリジナル実装以外は移植が必要です。筆者はこれまで学ばせてもらった恩返しで,ISUCON11の参考実装のGoからPerlへの移植に応募しました。

ISUCONは処理速度を競うので,公平性の観点で,移植されるコードはオリジナルと乖離かいりしてはいけません。その前提で,限られた競技時間を最大限に活用し,参加される方がつまらない不具合で悩まされない移植を目指しました。オリジナルと乖離してはいけないので,できる工夫は限定的でしたが,幸い読みやすいといった声をいただけてホッとしています。

ISUCONに限らず,ユーザーに価値を届け続けるために,コードのわかりやすさや変更しやすさは重要です。コードがわかりにくいと,目的とは関係のないところで時間を無駄にしたり,多人数で開発をしたときに理解がそろわず,協働しにくくなります。変更しにくいと開発速度が遅くなるだけでなく,変更を入れる恐怖などメンタルの疲弊も起こします。

本稿では,オリジナルのロジックと乖離しない範囲で,Webサービスをわかりやすく変更しやすくする方法を紹介します。具体的には,まずPerlの新機能を4つ紹介し,次にJSONエンコードについて解説します。

それらの解説に入る前に,本節では「わかりやすさ」「変更のしやすさ」について掘り下げます。

わかりやすさとは意味を理解するまでの認知の円滑さ

まず「わかりやすさ」について説明します。

本稿では認知心理学の言葉を借りて,⁠意味を理解するまでの認知の円滑さ」をわかりやすさの定義とします。認知とは,情報を知覚し,一時的に記憶された情報を知識や経験と紐付けて,意味を理解するプロセスを指します。たとえば,コードに色付けすると目で知覚しやすくなるため,わかりやすいと言えます。長大なクラスは記憶しづらく認知の負荷が高いため,わかりづらいと言えます。知覚,記憶などの人間の特性を理解することは,わかりやすいコードを書くためのヒントになると筆者は考えています。

以降では,認知の3ステップ(情報の知覚,記憶,知識や経験との紐付け)について順に説明します。

意識せずに注目を集めるとわかりやすい

まず情報の知覚に関して,コードは目で読む人がほとんどなので,視覚の特性や効果的な視覚化を行うための方法を紹介します。

視覚には「ボトムアップ処理」「トップダウン処理」の2種類があります。ボトムアップ処理は,目を開けているだけで入ってくる大量の情報からパターンを認識して,意味を当てはめていきます。たとえば,赤くて丸いと見えれば,りんごだと推測できます。ほかには,プログラムのイディオムは,パッと見て意味を理解しやすくします。それに対してトップダウン処理は,自ら意識を向けて探す処理のことです。たとえば,りんごを注意して見ると,赤,薄い赤,黄色など複数の色が混ざり,形も丸でないことがわかるはずです。ボトムアップ処理は高速に処理することに向いていますが,情報の解像度は粗いです。トップダウン処理は情報の解像度は上がりますが,処理の負担は重いです。

視覚のこの2つの処理の良いところをとって「意識せず,注目を集める」ことができれば,より効果的な視覚化と言えます。この考えは,コードだけでなく,UIUser Interface設計やデータをグラフにするときにも共通して使える考え方です。

意識せずに注目を集める方法の一つは,周りと比較して,色,形,位置などを変えることです。たとえば,プログラムの定数をすべて大文字で書く慣習は,ほかの小文字変数と意味が違うことを自然に伝えます。ほかには,姿や形のとらえ方の傾向といった視覚認知の法則を説明しているゲシュタルトの法則もヒントになります。たとえば,ゲシュタルトの法則の近接は,⁠近くにあるものは,意味が近い」と感じる法則です。この法則を利用して,意味が近いならば近くに集め,逆ならば近くに集めないコードを書けば,読み手は無意識に意味の関連をくみとってくれます。

記憶容量を節約するとわかりやすい

次に,情報の記憶について説明します。

突然ですが,おつかいを頼まれ,家を出た瞬間には内容を忘れている経験はありませんか。こういった数秒から数十秒程度しか残らない記憶を短期記憶と言い,この短期記憶の容量は数個しか覚えられないと言われます注1⁠。

また,記憶の単位は,桁や文字数ではなく,チャンクでとらえます。たとえば,16642561024といった11桁の数字は覚えにくいですが,16-64-256-1024と区切り,16を4倍ずつしている数だとわかれば,使うチャンクは数字の16と4倍の2つだけで済み,記憶しやすくなります。

これらにより,意味の区切りのわからない冗長なコードは,記憶の容量を無駄に使います。また,複数箇所読まなければ意味が定まらないコードよりも,1ヵ所だけ読めば意味が定まるコードのほうが,記憶容量を節約でき,わかりやすくなります。簡潔なコードが好まれる理由の一つでしょう。

意図や行動を連想できるとわかりやすい

最後は,知識や経験と情報の紐付けについてです。

「さくら」と聞けば,⁠バラの仲間」⁠春」⁠入学式」⁠日本」⁠インターネットの会社」など複数の事柄が思い浮かびます。複数の事柄がつながってツリーやグラフなどの構造を持って,知識は保存されています。私たちは情報から,それが何であるかだけでなく,カテゴリ,出来事,行動なども連想できます。

この特性によって,⁠空が暗い」から「雨が降りそう」⁠傘が必要」など次の行動を連想できます。連想がしづらい例としては,price *= 1.10のようにマジックナンバーを使ったコードが挙げられます。価格を1割増加していることは推測できますが,何の1割なのか,この1割はどういったときに変更すべきなのかを連想しづらいです。知識や経験が豊富な人だったとしても,price *= 1.10だけでは情報不足です。意図や行動を連想できるコードのほうが認知負荷は少なくなります。

また,本稿では,目的達成の障害となる罠をいくつか紹介します。読み手が想像もつかない罠は苦痛です。バッドノウハウで罠を避けるだけでなく,そもそも罠をなくすことができれば,読み手に必要とする知識は少なくなり,認知負荷は下げられます。

注1)
Nelson Cowan, "The magical number 4 in short-term memory:A reconsideration of mental storage capacity",2000

変更しやすくするために,もとに戻しやすくする

コードの「変更のしやすさ」についても説明します。ここでの「変更」とは,ユーザーへの価値提供やシステムのパフォーマンス改善など,Webサービスの価値を増減させる変更を想定しています。

少し突飛な質問ですが,もし太宰治の『走れメロス』に変更を加え,改善してくださいと言われたら,どうでしょうか。内容がわかりやすくても,筆者には変更の想像はつきません。この例から,わかりやすくても,変更しにくいことがあると言えます。そして,変更に備えることを設計だと筆者は考えます。

ISUCONの参考実装では,コードの目的を達しているかを,早く気付ける設計を意識しました。正しい状態がわかれば,間違ってももとに戻せばよく,気軽に変更を加えやすくなります。具体的には,JSONエンコードで期待する型を明示しました。詳細は後述します。

著者プロフィール

小林謙太(こばやしけんた)

2011年に新卒で株式会社モバイルファクトリーに入社。ゲーム開発やプロダクトマネージャーを経て,現在はエンジニア組織開発責任者。エンジニアの育成,採用,組織課題などに取り組む。また,Japan Perl Associationの理事として,YAPC::JapanなどのPerlコミュニティの活動をしている。

GitHub:kfly8
Twitter:@kfly8