リーダブルコード読書メモ~その7(最後)~

こちらの続きです。

hatek47320.hatenablog.com

14章を取り上げます。若干ボリューミーなので、14章のみです。なお、リーダブルコード読書メモはこれで最後です。本当は15章があるのですが、1~14章に対する問題演習みたいな位置づけのため、ノウハウまとめとしては15章は触れず、14章までとします。

14章はテストコードに関する話題です。通常のビジネスロジックとは異なり、テストコードにはテストコードなりの読みやすさ、保守のしやすさなどがあるので、そのあたりを中心に扱っていきます。

14章

  • テストコードの読みやすさ

    • 通常のビジネスロジックと同じくらいの可読性、保守性が求められる。
    • テストコードは仕様理解のための非公式ドキュメントという考え方もある。
      • そのため、読みやすければ、仕様理解の促進につながる。
  • テストを読みやすくする

    • 大事なことを目立たせる
      • テストデータでは独自で変数や定数を定義する。これらがハードコードされていて、変に目立っていないか
      • このテストは何をしているのかを最小限でコーディングする(12章のやり方)
      • 細かくメソッド化する、ヘルパーメソッドを作成するなどで工夫する
  • エラーメッセージを読みやすくする

    • assertメソッドについて、ライブラリ標準のものは大体優れているのでそれをうまく活用する
    • 入力、出力、具体的にどれがまずいか、がしっかり明示されているかがポイント
    • メッセージ表示のメソッドを独自で作ってしまってもいい
  • テストの入力データ

    • テストはきれいで単純な値を選ぶ
      • 不必要に桁数の多い数値、テストの目的とはかけ離れている複雑な文字列、などはNG
    • 負荷テストなど、大量のデータが必要な場合はテスト生成用のメソッドを作るといい
    • 入力データが複雑になりがちの場合、一つの機能やメソッドで複数のテストをしている傾向がある。分割すること
      • 分割したほうが保守の面でもいい
  • テストの機能に名前を付ける

    • テストで利用するメソッドやクラスには通常のビジネスロジックと同様の名前を付けること
      • Railsの場合は命名規約で色々縛られるので、強制的に意識させられるはず。
  • 元のコードがテストしやすいように書かれているか

    • 元のコードがテストしにくいコードであれば、テストコードも汚くなる
      • 簡潔かつ明確なインタフェースがあるなど
    • ただ、テストコードを意識しすぎて、元のコードの読みやすさを犠牲にするのも問題

終わりに

テストについて色々書きました。結局テストコードも、13章までのノウハウに気を付けてね、という話でした。

突破力を読んだ感想的な

本屋で目に留まったかつ、今の自分に弱いところだと思ったので買いました。

私は普段こういう自己啓発本とかは読んでも無駄、と思っていますが、Daigoさんは非常に科学的に、論理的なメンタルコントロールの情報を提供してくれます。自己啓発本というジャンルの中では数少ない汎用的に使えるメンタルコントロールの手法を書く方だなと思っているので、これまでも何冊か読んだことがあります。

本のタイトルからして「殻をぶち破るんだ!」みたいな本と思いがちですが、まず「殻をぶち破るなんてことは非常に困難」ということを述べたうえで、殻があると錯覚させる「バイアス」という存在について、その種類とバイアスから抜け出す方法を細かく述べています。

私は結構ネガティブで心配性な性格なので、本の中からその観点でいくつかピックアップして紹介します。

  • ネガティブ感情とは参照点をずらして向き合う

    • 上司に怒られた、クライアントに怒られた、のであれば以前上司に褒められたり、クライアントに感謝されたりしたことを思い出すことで、自信を取り戻すことができる
    • 同じネガティブにも比較の観点を持ち込む
  • バリードリコール

    • 例えば「大勢の前で近々スピーチをしたいが、前のトラウマでまた失敗するのではと不安に思う」みたいなとき。その場合は過去の似たような失敗をたくさん思い出し「あれよりはマシだ」と考えることで、気持ちを落ち着かせる
  • 他人への頼みごとが苦手な場合の対応

    • 依頼事は相手の負担になるので、相手はいい思いをしないのでは、という考えは捨てる
      • 頼み事されたら信頼されているんだ、とむしろ好印象なはず
    • いきなりハードルの高いお願いではなく、最初は些細なお願いから始めてみる
      • ~~の資料作成
    • 断られても最低2回はお願いする
      • 一回断られた相手に再度お願いを頼むのは気が引けるが、実は一度断られた相手のほうが再度のお願いは了承してくれる可能性が高い(過去に断った罪悪感が潜在的に残るため)
    • 依頼するときには「いつ」「なにを」「どのように」を単刀直入に話したほうがかえって依頼を受けてくれる確率は上がる

特に最後の他人への頼み事は結構私苦手なので、参考になりました。

この本は、hontoの電子書籍で購入、閲覧しました。全商品に使える10,20%クーポンから、出版社、ジャンル別に使える50%クーポンなど、毎日のようにクーポンが充実しているので、非常にお得に購入できます。

リーダブルコード読書メモ~その6~

こちらの続きです。11章、12章、13章を見ていきます。

hatek47320.hatenablog.com

これらの章は、割と当然のことをケーススタディを用いてどうする?ということを説明している感じです。 そのため「読書メモ」としてはだいぶあっさり目です。(当然のことができないから困るんですけどねw)

11章では「一度に複数のことをしない」という点でコードを変えていきます。

11章

  • コードは一つずつタスクを行うようにする

    • ざっくりでいいので、コードが何をするかを列挙する。
    • タスクをできる限り異なるメソッドに分ける
  • タスクを小さくする

  • 投票ボタンがあって、UPボタンとDOWNボタンでスコアが変わる、という機能を考える

    • 投票前後のスコアを保持して、UPかDOWNかにより、スコアを増減させる、というちょっと複雑そうなロジック。一つのメソッドで実現するのはわかりにくそう。
    • やりたいことは「前後のスコアを数値にパース」「スコア更新」だけであるので、これら二つのメソッドをそれぞれ作ればいい
  • オブジェクトを抽出する

    • 四つのデータディクショナリから文字列を二つ取り出し、結合するケースを考える。
      • 四つの中からどの文字列を結合するかは、条件に従う(書籍ではこの辺ちゃんと書いているが、書くの面倒なので略)
      • ただし、結合される文字列が存在しない場合もあり、その場合はデフォルト値とする
    • この場合「データディクショナリの値を抽出」「どの文字列を結合するかの判定」「文字列の代入。なければデフォルト」「文字列を結合する」というタスクに分かれるのでそれぞれで関数を分ける
    • if文がごちゃごちゃしてきたら、並べ替えたりして簡易にならないか検討してみる(ドモルガンの法則とか役に立つのではと思います)

見にくいコードに対して「このコードは何をしているのか」を列挙して、その単位でまとめるといいことがあるよ、みたいな感じだったと思います。 11章はそこまで言いたいことが多くなく、同じテーマをケーススタディ的に「こういう時はこうする」みたいな感じに書いているように見えました。なのでまとめもあっさり目です。

12章では、コードをより簡単に書く方法について触れています。

12章

自分よりも知識が少ない人がわかるように物事を説明できるようになるべき。ソースコードも一緒。 * コードの動作を簡単な言葉で同僚に説明する * 説明時のキーワードに注目 * 説明に合わせてコードを書く

えーっと12章はこれくらいです。変にコードを意識してわかりにくいロジック、コードにするのではなく、言葉で説明してみる、それをコードにする、ということを重要視する感じでしょうか。その説明をケーススタディで色々していた印象でした。

次は13章です。

端的に言うと、コードを書くな、ということです。バグをなくすためにはコードを書かないこと、というのは有名?な話ですが、それに通ずる話ですね。

  • 要求分析

    • 言われたことをそのまま実装するのではなく、要求をしっかり分析して、実装する、しないをわけること
  • コードは小さく保つ

    • なるべく汎用的な共通コードを使う。OSや言語のライブラリに任せられる場合はできる限りそうする。
    • 未使用のコードや不要な機能は削除する
    • プロジェクトをサブプロジェクトに分ける
    • コードは軽量にする(おそらく使いまわせるようにする、とかシンプルに保つ、ということだと思います。)

終わりに

11~13章と一気に駆け抜けました。普通のプログラマならああそうだよね、というような話ばかりだったので、これまでと比べると少々薄く、真新しいことはなかったのではと思います。 ただ、当然のことをやるのは案外難しかったりするので、PR出すときに最終チェックの観点として押さえておきたいですね。

暗記数学について

前から思っているんですが「暗記数学」という言葉はどうも世間一般に曲解されている気がしているので、持論を書いてみようかなと思いました。

暗記数学については、以下の通りです。

ja.wikipedia.org

和田秀樹さんが提唱した受験数学の勉強法です。10年以上前に私が受験生だった時に実は↑に挙げられている書籍を読んだことがあります。まあ実践はしませんでしたが、単純な興味ですw

暗記数学って簡単に言うと「チャート式の例題を暗記する」ということなんですがこの「暗記」という言葉がよくなくて色々と物議をかもしていると考えます。

私の受験時代の経験などをもとにした、本当の意味での暗記数学はこれだ、というのを私なりに解釈したのが以下です。

  • チャート式の例題と解答を暗記する。ここで言う暗記というのは単に解答を知識として覚える、ということではなく、解答の論理展開すべてについて、なぜその論理で解答が導かれるのか、ということを理解する。

    • 逆に、ただの丸暗記では、できた、ということにならない
    • 不明点などは教師や友人に聞く、教科書など他教材を参照するなどして、その例題に対して不明点を残さないようにする。
  • 理解の定着を確認するため、後日その例題を再度解く。

  • 上記をひたすら繰り返す。

何が言いたいかというとただの丸暗記は暗記数学とは言わないよ、ということでした。この認識であれば、大体の人は賛同してくれるのでは、と思います。あと個人的に重要だと思う点を2点ほど挙げます。

まず一つ目、この暗記数学の前提は「教科書に書いてある内容はしっかり押さえてあること」です。これは具体的には「公式、定理について知っている。更に、その導出や証明も含めて理解している、そして、自力で再現することができる」「例題、練習問題、章末問題が解ける」の2点です。 暗記数学の教材として有名な「青チャート」は、教科書レベルの理解はできている前提で作られているからです。逆に言うと、このレベルがあやふやだと、暗記数学が成立せず、それこそ「ただの丸暗記」となってしまいます。

そして二つ目、これが重要です。例題完璧にしたからこれで数学OK、んなわけないです。そんなに大学入試は甘くないです。実際の試験問題では、この問題は2次関数だよ、とか確率だよ、とか教えてくれないです。ひょっとしたら、2次関数と確率が組み合わさった問題かもしれません。限られた試験時間の中で、初見の問題を理解し、どういう解法を適用するか、ということを判断し、答案を作成する必要があります。実は暗記数学だけではこの「初見の問題を理解し、どういう解法を適用するか」という訓練が足りないです。というかしてないです。

だから、暗記数学の次のステップとしてこういった訓練をみっちり必要とします。一般的には志望校の過去問だったり、また別の難易度が高い問題集をやりこんだりだったりしますが、これは志望校のレベルとかその人の理解度とかによるでしょうね。

(確か和田秀樹さんの別の本にこの手の話も書いていたかと思います)

というわけで、暗記数学というものに対する私の理解は上記の通りです。最後のほうは暗記数学というより単に受験勉強のやり方、という感じになってしまいましたが。。。

暗記数学に関する記事とか見るんですがどうもそのネーミングからか「解答を丸暗記」みたいな話だったりするんですが、そもそもそれは違うよ、というところから、暗記数学の議論をしたほうがいいかなと思います。

あと、暗記数学=解答丸暗記、と信じ込んで勉強している中高生やそのように生徒に指導をしている教育関係者の方は、即刻その考え方改めたほうがいいです。はっきり言ってそんなもの意味がないですし、それで受験成功できるほど甘くないですし、大学以降の勉強ってそんなのではついていけないと思いますよ。

P.S もちろんチャート式の例題だけしっかり押さえるだけで戦える大学もある、ということはわかりきっています。あくまで上記は一般論です。

「最速で考える力」を東大の現代文で手に入れるを読む

図書館いったら見つけたので読んでみました。

僕自身もともと現代文ってすごく苦手だったのですが、何年か前にふとセンター試験の現代文といたら結構合ってて、あー社会人になって相当鍛えられたんだな、って思いましたwだから、国語の力って社会人のスキルとしてすごく大事なんです。Twitterとかやってると僕よりも国語力がない人がたくさんいて困るw

センターの現代文も教材や問題としては非常に優れている、というのは耳にしますが、東大の現代文も中々いい、というのも聞いたことがあります。

実際本を取って読んでみると、この文章のこことここをまとめて、こうかな、と答えめいたものは出せるのですが、本が示している答えとは違う、みたいなことがあって、さすが東大だな、一段深い思考や表現が重要なんだな、と思いました。答えめいたものが出せた点でまあ東大の問題に食らいつけたのかな、ということで。

ただ、解答はちょっとこなれすぎている感が非常に強かったです。試験場でここまでの回答が求められるのかな、自分の回答でも丸は来るのではないか、と思いましたが、私は教育業界の人間ではないしましてや国語はわからないので、何とも言えないです。図書館で本を読んだ後に本屋で赤本の同じ問題の解答をいくつか見ましたが、本の解答とはニュアンスが違っていたりしていました。実際書籍の中でも「東大の現代文の解答はなく、採点時に色んな先生が話し合って、点数をつける」という話があるので、これが解答!みたいなものはなく、ポイントやキーワードが抑えられていればOKなのかもしれないですね。

一応ビジネス書扱いですが、東大受験に興味があるけどがっつり問題集とか過去問をやるのが気が引ける中高生、理系受験で国語が必要な受験生がそれこそ「最速で」対策する向けなのかなと思いました。 ビジネス書、という観点で言えば、正直他の「文章の読み方」とか「大人の国語力」本的なものに書いてある内容とほぼ一緒な感じでした。その点で言えば以下の本のほうが社会人向きかもしれないです。

ただ、この本は問題演習で結構考えるし、量もそんなに多くないので、その点ではいいのかもしれないです。↑の本にも問題演習はありますが、量が多くまあまあ難しかったりしますw

hontoでは、一部商品について、購入済の紙の本を電子書籍で購入した場合半額になったりするので、両方持ちたいという人には非常にお得と思います。

リーダブルコード読書メモ~その5~

こちらの続きです。9章、10章を見ていきます。

hatek47320.hatenablog.com

9章は変数についてです。8章で変数を適度に定義する、という話をしましたが、目的が微妙だったり、そもそもいらなかったりする変数はないほうがいい、ということで、そのあたりをどうすればいいか、が出ています。

9章

  • 不要な変数は削除する
    • 無意味に代入している変数 以下のnowは別に分ける必要もないですよね。
  now = datetime.now()
  hoge.last_view_time = now

だから1行にする

  hoge.last_view_time = datetime.now()
  • 中間結果的に使う変数の削減

    • その中間結果は本当に必要か吟味する
      • 「配列に対して、ループで条件に当てはまった配列要素を削除する」という場合「条件に当てはまったインデックスを中間的に変数で保持→後にそのインデックスの要素を削除」するのではなく「条件に当てはまった配列要素を直接削除」すればよい。
        • インデックスを中間的に保持するのは不要(ループ変数をインデックスに合わせて削除していけばいい)
  • 変数のスコープを縮める

    • グローバル変数を避けるのはもちろんのこと
    • ローカル変数について、クラス全体の定義をメソッド内に何とか落とし込めないかを検討する。
      • 例えばメソッドの引数をうまく使う
    • いっそのこと、クラスを分割してみる、なども考えてみる。
    • 変数は先頭に一気に定義するのではなく、使う直前で定義すると、コードを行ったり来たりしなくていい
  • 変数は一度だけ書き込むようにする

    • constなど定数定義をうまくつかう(定数にすることで、書き換えてはいけない、ということを明示できる)

次10章です。無関係の下位問題の抽出、というタイトルです。端的に言うと、メソッドとして細かく切り分けていきますが、その際に「メソッドがやりたいことと、中の処理の関係性」に着目します。

10章

  • 別メソッドに切り出してもいい場合(例えばループ内における値の算出など)は切り出すことでコードの見通しがよくなる

    • さらに、そのメソッド単独でテストもできる
  • ユーティリティコード

    • 標準ライブラリの不足を補うようなコードも同様(ファイルを読み取り時にちょっとした独自処理をしたいケースなど)
      • プロジェクト全体の共通コードとしても利用できる
  • インタフェースを簡潔にする

    • ラッパー関数を作るといい。引数は少なく、簡潔なものとする

終わりに

9,10章と駆け抜けました。量もそんなに多くなく、一般的に言われていることが中心でした。そのため記載もあっさり目ですw

9章では、適切に変数を設定する、ということが中心でした。条件式の中で複雑な計算をしない、不要な変数は削減するなどは言うは易しですが、心がけないと中々難しいのかなと思いました。

10章は複雑な処理はメソッドに切り出す、という内容でした。これも言っていることは当然ですが、中々気を付けないと厳しいところになります。新規開発より保守をしていると、気がついたら一つのメソッドが膨れ上がる、みたいなことに陥るので特に注意ですね。

リーダブルコード読書メモ~その4~

こちらの続きです8章から見ていきます

https://blog.hatena.ne.jp/hatek47320/hatek47320.hatenablog.com/edit?entry=26006613775078778hatek47320.hatenablog.com

今回は複雑な式を分割し、理解しやすいコードにする、という話です。

前提:人間は一度に3~4のものしか考えられない。一度に考えることを少なくすることを意識してコードを書くこと。

  • 変数の工夫
    • 例えば条件分岐では変数を細かく定義して理解しやすくする。
      if hoge.split[0] == 'hoge'
      end

上記はif文の変数が一瞬何を示しているかがわかりにくい。そのため、条件の変数を別に定義する(条件を説明するための変数)

     hogeflag = hoge.split[0]
     if hogeflag
     end
  • 条件分岐で変数がたくさん出てくるときは要約できないか考える
   if hoge == hogeflag
     hoge
   end
   if hoge == !hogeflag
     fuga
   end

flagがtrueかfalseかで条件を書いているが、これを一つにまとめる(hogeがtrueかfalseかを変数に持たせ、それで条件分岐する)

  hoge == hogeflag
  if hoge
    hoge
  end
  if !hoge
    fuga
  end

ja.wikipedia.org

  if(!(hoge && !fuga)) return hoge

これはドモルガンの法則により以下の通りになる

  if (!hoge || fuga) return hoge
  • なんでも短くしようとしない
    • 条件判定で1行ですべて収めようとしたくなるが、複数行でわかりやすさを重視すること
    • 以下のコードは1行で完結しているが、()が多すぎたり、メソッド、変数が3,4種類あったり、など理解するのに時間がかかりそう
  assert((!(bucket = FindBucket(key))) || !bucket->isOccupied());

以下は2行になっているが、読むほうにしてみれば上のコードよりスムーズと思われる。

  bucket = FindBucket(key);
  if (bucket != NULL) assert(!bucket->IsOccupied());
  • 余事象的な発想を試みる
    • 判定ロジックが複雑な場合は、真正面から正直に書くのではなく、裏をかいて「いくつかの判定をかいくぐってきた残り」という考え方で乗り切れないか考える。

https://ja.wiktionary.org/wiki/%E4%BD%99%E4%BA%8B%E8%B1%A1

  • 補足:リーダブルコードでは「複雑なロジックと格闘する」というサブタイトルでした。Rangeクラスというある値がクラスで定義された値の外、中かを判定するようなものを改善していますが、 説明が冗長でちょっとわかりにくかったので、勝手に「余事象的」と解釈しました。確率の問題では、ある事象Aが起こる確率について、真正面からその確率を求めるより「100%から事象Aが起こらない確率を引く」というほうがすんなり求まるケースがあります。こういう考え方をでコードを書くとまたわかりやすいのかなと思いました。

終わりに

巨大な式を分割する、というタイトルの章でしたが、総じて言いたいことは「式が分かりにくそうな場合は、細かく変数を定義し、それを使う」ということかなと思いました。「こういう判定のための変数」とか「こういう意味を持つ変数」という変数を定義し、そこに取得した値により式を組みたて、代入するほうが可読性は上がります。コードが長くなるというデメリットがありますが、わかりやすさを取ったほうがいいでしょう。