qtatsuの週報

初心者ですわぁ

読書感想文: リーダブルコード

個人的総括

  • この本でいう"リーダブル"は何か、どうすれば達成できるのか?
  • 修正しやすい == 保守しやすいコード => 後から参加したメンバーや遠い未来の自分も保守できるくらい。
    • 改修に必要な情報は目立たせて理解させる。不要な情報は、混乱, 疲弊の元。-> 見えないor見なくていいとわかるようにする、書かない。
    • (修正できるくらいの深さまで)"理解"し易い
      • 単純に読むのが楽(-> 見た目(命名など), ロジック(「説明」に沿った形))
      • 分離している (ある変更において読むべき場所が少ない)
        • プロジェクトのロジックを追いやすい
        • 修正箇所が一箇所でいい。
    • 実際に修正, 機能追加しやすい
      • 関数を再利用しやすい(繰り返さない)
      • 読めるだけでなく、機能追加が簡単にできるか?を意識する
      • 書いた時はシンプルに見えても、機能追加で複雑度が増すような構造はNG : 関数への分離で解決することが多い
      • 「頭がいいコード」は、同じ書き方で機能追加が絶望的に難しい
        • 統一感が消える。
        • 統一感がなくなると、読めないしどの方法で書き足すかも不明になる。
  • 章をまたいで繰り返されたアドバイス
    • 一つのモノには1つの仕事をさせる。複数詰め込まない。
    • 他人の視点を考える("他人" -> 半年後の自分自身かもしれない)
    • ひどいコードとは、"触りたくない"(読む, 修正, テスト追加, 等)コードのこと。
    • コードを、他のコードになるべく依存させない(分割, 変数のスコープを小さく, 標準API使う)
そのためのアドバイスの個人的分類
  • 1部: 表面上の改善
  • 情報量/読解のエネルギー(文字数,見やすさ) のratioを高くすること が基本的な方針。その具体的なアドバイス

    • 読んでから理解するまでの時間を短くできる(1章の目標)。
    • コメントは文字数を増やす代償以上に情報を与えないとダメ(コードだけでわかる変数名ならそれが一番いい。)
  • 2部: ループとロジックの単純化

  • 気がかりなことを残したまま、読み進めるコードは避ける が基本的な方針。大事なことは先にいう

    • 比較では対象を先(左)に書く。
    • if/elseで単純、重要、肯定条件を先に書く
    • do/whileを避ける(条件は先に見る)
    • ガード節をつかう。: returnで早く返す -> 最後まで読まないと返り値が分からないのは辛い!
    • 一度に考える変数を減らす(コード分割, スコープ利用: クロージャは飾りじゃない)
      • 説明変数 <-> 中間コード トレードオフの関係っぽい
      • staticメソッドは伊達じゃない(クラス変数と無関係だと明示できる)
  • 3部: コードの再構成

  • 修正において読むべき部分を減らす(関係ない部分の隠蔽, そもそもコードを減らす, デフラグ)指針を述べてる。
  • ひどいコード」は修正しづらいコード = 保守しづらいコード:: 無関係の下位問題を抽出する!
    • 大切でない情報は隠す,大切な情報は目立たせる: 人間が持てる荷物は限られてるからね。concentrate.
    • e.g)国の名前をプリント元のやつ-> そんな悪くないと思ったけど、条件追加を考えると厳しい。
    • 分離-> 無関係な下位問題があると変更難しくなる。
      • 触ったらアカンとこはまとめたほうが変更し易い
      • 関係ないからってイメージでスルーして追加しやすくなる。
      • プロジェクト自体のコードだけにダイエットできてるから、プロジェクトのコードを追加しやすい
    • 最低限であるほどよい-> contextと、general, specific, 必要十分の話。
      • 余分なコードはゼロではなくマイナス。
      • 書くだけでなく、保守やDoc化の手間も意識する。>> 保守し易いコード
    • コードを説明するのではなく、説明をコードにする
    • テストし易いコードを書く-> 疎結合, 1:1が実現し易い。-> RESTってこれっってことやんな?
      1. 明確なインターフェイス
      2. セットアップ, ステートに依存しない

1. 理解しやすいコード

  • 他人が読んで理解するまでにかかる時間が短いことを指標として書く。

2. 名前に情報を詰め込む

  • Q: generalよりspecificを選ぶ ということっぽい。機能をより特定できた方がいい。(よって、長い名前にもなりうる。)
  • Q: 複数形大事。複数形の引数なら、listをとるとか予測できる。

  • 明確な単語を選ぶ。

# 明確な単語を選ぶ。
getPage()        # NO. どこからPageをgetするかよく分からない。
fetchPage()      # Yes. ネットから取ってくる。
downloadPage()   # Yes. 同上。

size()           # NO. なんのサイズか不明。
height()         # YES
NumNodes()       # YES
MemoryBytes()    # YES

Stop()           # No.  止まることしかわからん(情報 x 1)
Kill()           # YES. 止まるし、消えることがわかる。
Pause()          # YES. 再開可能だとわかる。
  1. tmpなどの汎用的なものを避ける。

  2. 左右の値を入れ替えるような、「一時的によけておくだけ」という変数ならtmpでいい。一時的によける、以外の機能がないことを示せてるので良い名前。

    • p165: 抽象化して、dbのカラム名stock_time -> t1 のようにrenameする例。
    • 関数としてくくって抽象化したとき、こういう名前の方が良い。"iterの一つ目"以外の意味はないから。
  3. 保持しているものにそれ以外の意味があるなら、それを名前にするんや。
  4. イテレータi, j, kはよい。「イテレータです」って意味になるから。

    • でも、membersならmi, menbers_iとかにする方がわかりやすい。
  5. 抽象より具体的な名前がいい。

  6. TCP/IPポートがリッスン可能か調べる関数

    • OK: CanListenOnPort() 具体的!
    • NO: ServerCanStart() それ以外の目的でもつかうかもしれん
  7. 直行する概念をまとめてはいけない 個人的に重要. Unixっぽい思想?一つのモノに完璧な一つの仕事をさせる。

    • No: localテストのため、localのDBをつかいdebugを表示するコマンド: --run_locally
    • Yes: localのDBをつかう--use_local_dbとdebugを表示する--extra_logging
  8. 名前に情報を追加する

  9. 値の型や単位を間違えると危険なところに使う。

    • hex_id: idが16進数であることが重要な場合。
    • start_ms: ミリ秒、単位を追加する.計算する時などは単位を変数につける。
    • delay_secs: 秒。
    • size_mb : これはメガバイトつけたから、sizeってつけてもいいのかな?
  10. 名前の長さ

  11. 変数を使うスコープが広いほど長い名前でいい!! 旅行は遠くへ行くほど荷物が多くなる。

  12. でも可能なら短い方がいい!
    • 不要な情報を捨てる: ConvertToString() -> ToString() これでもわかる!
  13. 省略形は、慣習的なもののみつかう(document-> doc)

  14. 名前のフォーマットを守る

  15. pythonならPEP8守る。全て大文字なら定数、とかね。

  16. js: jQueryのオブジェクトを束縛する変数は$から始める $all_images = $("img") など。
  17. html: idはアンダースコア、クラスはハイフンで区切る まじ?

3. 誤解されない名前

  • filter(x < 0)は悪い名前らしい : filterして、0以下をとるのか、0以下を除外したのか不明だから。

    • OK : select(): filterして0以下を選んでる
    • OK : exclude(): filterして0以下を除外してる
  • textの最後を指定文字数消して「...」をつける

    • NO: Clip(text, length) : lengthだけ削るのか、lengthだけ残すのか不明。
    • YES: Truncate(text, max_chars) : max_charsだけ残すとわかる。また、charにしたので文字数だとわかる
  • 範囲を表す奥義

    1. 限界値はMAX, MINを先頭につける! max_items_in_cart : 許容される値(=<)を示す。
    2. 範囲はfirst, lastを使う! first=1, last=4なら、1,2,3,4 の集合。
      • start, stopだと、stop=4のとき、1,2,3か1,2,3,4がよくわからない。(4を処理して止まる?4を見て止まる?)
    3. スライス的な(最初含み、最後含まず)範囲は、begin, endを使うという慣習がある!!
      • 英語には、スライスでよくやる「最後」含まずの表現がない。この時の引数はbegin/endを使うと決まっている!
      • この表現は例えば、「16日のイベント」を、16日0:00~16日23:59 とするより、 16日- 17日(end)の方が「16日全体」を表しやすいという理由で使われとるらしい。包含/排他的範囲っていうらしい。
  • Bool値はを持つときは、先頭にis, has, can, shouldをつけるとよい。

    • 誤解を避けるため、is...がTrue、みたいに読めるようにする。
    • boolに否定語は避ける。disable_sslなど。否定の否定になると読みにくい。 use_sslにしする。
  • イディオムが存在する

    • get(え、つかうんかget..)は軽量な取得って慣習があるらしい。
    • 計算して返すなら、computeをつける

4. 美しさ

  • これはPythonの強いところ。文法通りに書けばそれだけで綺麗だし、PEP8守ればもっと綺麗。

  • 読み手が読み慣れてるパターンと一貫したレイアウトを使う(自然とできる)

  • 似たコードは似てる見た目にする(!!!)
  • 関連するコードはまとめてブロックにする
    • たとえばimportするときに種別でブロック分ける、とかそういう処理の分類を空行入れるような作業。
    • たとえばある一連の処理で、区切りごとに空行とコメントを入れる # dataをwebから取得する とか。

5. コメントすべきことを知る

  • コメントの目的は書き手の意図を伝えること。
  • コメントは「コードを増やす」という代償を払っているので、代償に見合うリターンを持たせないといけない!

    • コードから""""""すぐに""""""わかることをコメントに書かない
      • コメント読んだら早く理解できるなら、書くことを検討できる(コード自体を分かり易くした方がいいけど。)
      • 優れたコード >> ひどいコード+優れたコメント
  • コードを書いているときに持っている、大切な考えを入れる!!!

    • "このデータだと、ハッシュテーブルよりバイナリツリーが40%早かった"
    • "このクラスは汚くなっている", "...で整理した方がいいかもしれない"
    • 上記は優れたコメントらしい。 後から見た人にとって役立つ情報だから。(これがなければ、考えることに余計な時間つかっちゃう。)
  • コードの欠陥にコメントをつけるイディオム
  • これからコードをどうしたいのかを書くのが大切。

    • TODO: 後で手をつける
    • FIXME 既知の不具合がある
    • HACK あまり綺麗じゃない解決策
    • XXX 危険。大きな問題がある。
  • 定数へのコメント

    • わいの書いたorder に1000(実質ラストになる)みたいなのはokらしい。
    • コメントの書き方も、「最後に来る十分大きな数」みたいなんでokぽい。
    • 定数を決めたとき、頭の中で考えていたことを書くのは重要、と述べている。
  • 全体像のコメント

    • ファイルの最初とかに書く。特に、これは単なるキャッシュとか、そういう情報があると読み手は嬉しい。
    • Q: documentの説明書ってやつやな。
p67. 例: 処理ブロックにコメントを書くとよい。コメントの内容を関数名にして処理を分けるとさらに良い.
  • ⬇︎Good!!
def generate_user_report():
    # このユーザのロックを獲得する
    ....
    # ユーザの情報をDBから読み込む
    ...
    # 情報をファイルに書き出す
    ...
    # ユーザのロックを解放する
  • ⬇︎Best!
def generate_user_report():
    obtain_user_lock()
    retrieve_user_info_from_db()
    write_to_file()
    release_user_lock()
  • WHATよりWHYを書くというアドバイス

    • 本書では、役にたつならなんでも書こう というスタンス。
  • 推敲を推奨している.

    • コメントも、まずはクソ文を書いて、それを推敲すると手が進むことを述べている。

6. コメントは正確で簡潔に

  • ratioが大切。 情報量 / 領域(文字数) :: これprincipalだな。
  • dockstringを進めてる!(処理の例示) C++ではdocstrはないので、普通のコメントという形になる。
  • わいも思ってるけど、pythonとか引数名を渡せる言語では、関数呼び出し時に引数を明示した方がいい.
    • C++とかではインラインコメントをつかう。 Connect(/* timeout_ms = */ 10)  など。
  • ジャーゴンを推奨している。 短くて正確, 密度の高い専門用語をコメントで使うよう推奨している。

7. 制御フローを読みやすくする

  • 比較の順番

    • 左が調査対象(変化する), 右が比較対象(変化しない, ただの定数)
    • while(bytes_revieved < bytest_expected) など。
    • 英語の語順と同じにする(対象値がless than 10なら..., 10がmore than 対象値なら...)
    • 英語的には「 < 」の記号も自然言語的に読むことが起因してるぽい。
    • これ英語特有の問題じゃね..?
  • if/elseの条件と処理の順番

    1. 以下は両立しないこともあるので、絶対ではない。
    2. (a != b)や(!a)よりも(a == b)や(a)を使う!(!aを見ると、aを考えてしまう。なのに!aを先に処理するのはNG)
    3. 単純な処理の条件を先に書く.(処理内容が短い方を先に読みたい)
    4. 関心を引く条件、目立つ条件を先に。(e.g. if not file: ..... など。否定だが、fileないときの方がまず知りたい。)
      • 処理が長いならfileない条件も後に来る。
      • ファイルがない時の処理がエラーログ出力だけ(単純な処理)なら先。
      • つまり、3つの原則でより多くを満たす方にすりゃええんやね。
  • 三項演算子

    • 三項演算子が「処理をうまく表してる」ときに使う。そうでなければif/elseでかく。
  • do/whileはダメ というのが本書のスタンス。

    • 条件は前もって知らされる方がいい。
    • 他の章でも言ってるが、不確定な情報をもったまま読むことを避けたいという意志が強い。(if/elseの条件の話や、比較の順: 見たい値が何か知らないまま定数を心のメモリに入れたくない。)
  • 関数から早く返す

    • returnはいくつ書いてもいい。とにかく早く返す。
    • 早く返すことにより、ifのネストを減らせる可能性も高い -> ガード節
    • ガード節 :(多分) 簡単なケース(処理の対象外のケース?)を関数の一番上で処理-> returnやcontinue, breakしておいて、後からチェックしないといけないifの条件文を減らす手法。
    • 「ガード節」という書き方。 - Qiita](https://qiita.com/kouyan/items/7b8b456b626447a1e24e)
  • 関数のクリーンナップコード

    • 関数中で絶対実行したいコード-> これを、returnを最後にすることで実装するのはほんまにクソ。
    • pythonには try-finally および withというクリーンナップ文ある

8. 巨大な式を"""分割"""する

  • 説明変数 : 一度いい名前の変数に束縛して、それを比較に使うなど。
    • ('username = line.split()[0].strip()')など。
    • 式の結果が"userのname"だとよくわかる。
    • ダメな例: now = datatime.datetime.now() 素のままでもわかりやすかった。無駄に変数ふやした。(9章)
  • 要約変数 : ⬆︎は式の説明だが、これは長い条件式をまとめる のが目的
    • user_owns_document = req.user.id == doc.woner.id としして
    • if(user_owns_document) -> 説明は不要( == 型も見ればわかる)けど、何度か使うならこれ。(読む量減る!!)
  • ドモルガンの法則をうまく使う

    • ん?これわかりやすいかな...?
  • 「頭がいい」コード(自己満足の複雑な1 lineコード)は絶対書かない。

    • ここはcheckIOじゃねーのです。
    • もちろん、簡潔にかけるならOK. if (object && object-> method())みたいな束縛とかね。あれば使う、が明快。
    • わいのよくやるa = b or c or dは, python, js, Rubyで使えるらしい。最初に真なのを返す。
  • 小さい範囲なら、読みやすくするためにそのスコープ用の短縮系を宣言することもあり。

    • 短縮系をそのままに、長いoriginalバージョンの名前を変更(一箇所で済む!)できるメリットもある
      • 改修のしやすさがここでも出てくる。関数化は、改修の時変更箇所を減らせるのです。
  • 問題を「反対」にしてみたりして、ロジック自体を単純にすることを試みる(いつもやっとるわ)

9. 変数と読みやすさ

  • 中間コードを保持しすぎない。
    • 説明変数の対立概念。タスクは早く完了した方がわかりやすい.
    • 中間コードのままでわかるなら、変数つけない方がいい。
    • 値をその場でreturnすることで中間変数は減らせる
  • 制御フロー変数を削除する
    • わいが"フラグ"やと思ってるbooleanや。
    • フローの制御のためだけの変数は、ロジック改善して消し炭にする。
  • 変数のスコープを縮める
    • その変数が効いてる範囲は小さい方がいい(globalは最悪: 書いた人は"ここでのみ使う"と思っても、読む人はfileの最後までその変数のことを気にしなくてはならない!)
    • 一度に考える変数は少ない方がいい 3つ以内とか。
      • Q: 変数をたくさん定義してるなら、多分そこは分離して小さなスコープにまとめられると思う!
    • クラスの変数(メンバ変数)はミニグローバルで危険
      • 全てのmethodが見えうるので、追うのがクソ大変(使える範囲(行数)がクソ長くなりうる)
      • 可能なら使用メソッド内部のみのlocal変数にscopeの格下げするのがよい。
      • staticメソッドは意味がある 「メンバ変数と無関係なメソッド」だとわかるので.(クラス内の他のメソで利用する(self.static_fucn())が、メンバ変数は使わない..みたいな状況かな)
    • p118 jsのクロージャを使ってのスコープ極小化は重要(global変数をプライベート変数にする)
      • globalで使うと、この箇所でしか使ってなくても、読み手はfileの最後までこの変数を気にせなあかんくなる。
      • このjs例の、クロージャの外側関数を定義->即実行()ってのpythonでもやるんか?
      • Q: そもそもPythonも、クロージャ外側の関数の変数を記憶した関数という文脈でつかうぽい。【Python】クロージャ(関数閉方)とは - Qiita
      • 外側の関数で定義した変数を、内側の関数に覚えさせておくという見方がわかりやすい?(内側の関数で、変数で渡した値がハードコードされたようなしくみになる。)
      • Pythonだと、内側の関数(こっちがクロージャという)内部でnonlocal val宣言しておくと、外側関数(エンクロージャ)の変数を読むだけでなく書きができるようになるやつやね。ステートありなのでclassと同じ概念か。
      • pythonでは即実行ってどうやる?lambdaか?
submitted = false;  // こうするとglobal変数になるらしい(varなし)

var submit_form = function (form_name) {
    if (submitted) {
        return;     // 二重投稿を防ぐ(初回のみ実行)
    }
    ....
    submitted = true;// 値を変更しとく
}
var submit_form = (function () {
    var submitted = false;  // 下の内側関数だけがsbumittedにアクセスできる。
    
    return function (form_name) {  // 内側のfunctionの結果が返ってsubmit_formに束縛される
        if (submitted) {           // pythonと同じく、外側関数の定義スコープでのみ"submitted"が使える。
            return;
        }   
        ....
        submitted = true;
    };      

} ()  );  // この()に注目。 function() {} () って形で定義後即実行になってる。
  • 変数のスコープを縮める(続き)

    • (p120)pythonの、ifとかのブロック後でも定義した変数がずっと残る問題への対処
    • 明確に定義する。 example = Noneを処理的に不要でもbaseブロックに書くのは、宣言不要といえども意味がある。
    • 中間コードをなくす(処理を関数にまとめ、値を保持せず即実行すれば変数宣言しなくて良い)
  • 変数は一度だけ書き込む : jsのconst、有能やんけ!!

    • pythonでも、変数は書き換えない方がいい。
    • immutableなものを使えるときは, immutableなものをつかう!!
    • フラグ的な変数も、その意味で(変更前提の定義)、あんまり使わん方がいい。

10. 無関係の下位問題を抽出する!

  • プロジェクト独自のコードから、汎用的なコードを除く。
    • プロジェクトコードを読むときは、プロジェクトのことだけ書いてあるといいね!
  • これは、積極的にやるべき行為らしい。
  • 分割しすぎはよくないけれど、意味のある塊なら抽出する。
    • Q: 処理ベースじゃなくて、目的ベースやと思った。抽出したヤツに名前がつくなら多分OKやと思う。
  • 方法

    1. 関数やコードブロックの高レベルの目標を見つける-> 関数名。実現したいこと。
    2. コードの各行を見る。
      • 高レベルの目標を直接みるコード-> そのまま
      • 無関係の下位問題をみるコード -> 検討の余地あり。
    3. 無関係の下位問題をみるコードがある程度あれば抽出する。
  • 無関係の下位問題: args-> rturnできる小さなスコープの問題。高レベル問題を解く際の自己完結した部品部分。

    • Q: これいうたらブロック中で段落にまとめられる、処理の一単位やね。
      • その中でも、自己完結しているもの、だな。
      • 文字列や数値の加工だよね、ほとんどの場合。
    • e.g. 最近接距離をarrayから求める際の、余弦定理部分。
    • e.g. 文字のformat整理部分(pretty print-> format_pretty()関数を作ると良い)
  • 可読性以外のメリット

    1. 関数を独立させることで、テストや改善がやりやすい。
  • utilを作る?!

    • util/をまとめること進めてるけど、それってYO!どうやって管理するんだYO!
  • プロジェクトとの関係

    • プロジェクトに依存しない(外部ライブラリにもできそうな)util関数はめちゃめちゃGOOD.最高。
      • プロジェクト自体のコードを小さくできる!
    • プロジェクトに特化してても、分離に意味はある。
      • p137pythonコードはかなーり勉強になる。
        1. CHARS_TO_REMOVE = re.compile(r"['\.']+")file上部で定義してる。
        2. make_url_friendly()は、projectのその場所で特化した文字列処理。(usernameをurlにする)
        3. make_url_friendly()は、utilにおいてもいいし、元のファイルと同じ場所においてもいい。
          • これは後から決めてもいいらしい。とにかく抽出するのが大事とのこと。
  • インターフェイスを綺麗にする.e.g.) cookie.

    • 自分がやりたい1アクションを理想的なwrapper関数にする」感じかな。
  • グルーコード: Glue Code: 互換性がない部分を結合するためのコード。ORMとか。glue: 接着剤
    • 関数の事前/事後処理など。
    • これは積極的に抽出すべき。

11. 一度に一つのことを....

  • (わいもやってしまうけど)一つの関数やブロックは、一つの処理(Q: 命名可能?)だけ扱うべきや。
  • コードのデフラグという見方!!
  • 関数に限らない。ブロック中の、一段落のロジックにも言える。
  • タスクは異なる関数、もしくは領域に分割する。

ちょっとよりみち

  • 順番に値を見ていき、最初の奴を使う。全部外れなら、defaultを使う。
    • こういう動作は関数にしたら良いかも知れん。ロジックで書くときはdefaultを定義->書き換えをやる
    • 「デフォルト値設定」ってのは、そういうタスクなので、複数あれば全部まとめて最初に書くのがいいらしい。
var second_half = 'Planet Earth';  //デフォルト値
if (country) {
    second_half = country;
}
if (state && country === "USA") {
    second_half = state;
}
`

12. コードに想いを込める

  • 読み手に「わかりやすく」説明するコードについて、そのほかのような区分。
  • コードを説明するのではなく、説明に合わせてコードを書く。説明しやすいコードを書く。
  • 説明しやすさを優先して、先述のif文のルール(気になるモノを先に返す)を破ることもあるぽい
  • 数値のハードコードにつながる
    • page += 1 「次のページ」という説明とズレる。
    • page = current_tip.next() 「次のtipに移動する」メソッドだとわかる感じになってる。
  • p162 え?iteratorって、要素にアクセスするだけでnext...いや、呼ばれへんわ
  • ラバーダッキング

13. 短いコードを書く

  • 使わないでいいコードは絶対に書かない かいてしまいがち。
    • 書いて終わりちゃうんやぞ?
    • 保守やDoc化の労力、デバッグの労力がある。少ないことはいいことだ!!!!
  • この章、generalとspecific, contextの話だ!!!
    • 自分が使う文脈にspedificな処理を書くべきで、generalである必要はないということや。
    • それが最小限の労力ということになる(保守やDoc化! 書くのは簡単だとしてもね)
  • 標準ライブラリや、サードパーティライブラリをしっかり知る!
  • Unixツールボックスを使う.
    • pythonだと、wrapperクラスあるよね。

14. テストと読みやすさ 

  • 本書的にはテストは読みやすくあるべきという立場。テストを公式文書と考えてもいいくらい。
  • 保守しやすいテストをオススメしている。
    • 追加, 変更が簡単にできること! これは本当に、常に重要。
  • POINST: 大切でない情報は隠す。大切な情報は目立たせる
  • p183: 最小のテストを作る: CheckScoresBeforeAfter("...", "...")がある。
    • これ、PythonのUnittest系なら、self.assertEqual()を内部で呼ぶ関数を作ることになるのかな...
    • 複数の値を順に試すのは、Fixture使うんかね。
    • とにかく、入力値を変えるだけでなんどもテストできる関数をどこかで定義する方法を考えた方がいい。
  • コードを"完全に"テストする、""最も単純な""入力値の組み合わせを考えないといけない!
    • たとえば、"負の数"の例に"-1"以外を使うのはダメ!!(余計な情報となる)
      • 逆に読むときは、"-1"は負の数の例、負の数でありさえすればいいという例になる。
    • 一つのテストで一つのケース
      • 負の数の処理の時はそれだけを。降順ソートならそれだけを。
      • そういうテストを、複数並べるのが良いテスト。(行数は増えるが、「理解が短時間でできる」)
      • 芸術的な組み合わせはNG!
    • テスト関数の名前は長くなっていい。なぜなら、他の関数から呼ばれまくったりしないから。
      • 単なるそのテストのドキュメント(コメント)としてテスト関数は名付ける!
  • テストしやすいコードを書く

    • テストしやすいコードは明確なインターフェイスがある
    • テストしやすいコードはセットアップやstateがない
    • ⬆︎この二つ満たしてるからREST APIってクッソテストしやすいんやな...!!!!
  • 疎結合の意味とは

    • それぞれで完結しているオブジェクトにすると、そいつのテストが描きやすい.
    • テストしにくそうなものは、書く前に立ち止まってロジックを練り直す。p194は良い例
    • 外部コンポーネントは本書では否定的。
      • 外部コンポーネントが落ちると、システムが死ぬ。
      • 影響を食らう。
      • テストの時のセットアップが面倒-> これはpytestなどでfixtureの観点から改善されとるやろーね
    • クラスは小さくする。
      • stateが多いとテストしづらい!!

15. 分、時間カウンタを設計実装する。

  • インターフェイスを先に決める
    • クラス名, メソッド名を先に決定できるし、これならごちゃごちゃすることを先に防げる。テストも楽。
    • コメントやメソッド名のリファクタリングもこの時点でしてしまう!
    • 同僚に、クラスとメソッド名とコメントを見せて聞く。 「これはどんなメソッドだと思う?」
  • for文でのiterはiでいいけど、逆回しならritとか、"r"を最初につけるとよい。
  • 50行の読みにくいコードより、100行の読みやすいコードが優れている
    • 理解するまでの時間!!なんどもいうけど!
  • タイムスタンプの例では、やはり機能を追加可能か?という観点からリファクタしてる。
  • コミットも、「一つの変更」について「1コミット」がよい!!
    • れいのGitLabの提案モードを使ったリファクタはかなり重要なのでは?!
      • 本書では"提案コミット"といって、新しくコミットすることをすすめとる。

質問/ メモ

  • 分割した関数ってどこに置けばいい?とくにPythonやJSでそういう慣習をまとめた本ある??ってかいいライブラリある?(構成が美しくて読むと勉強になるライブラリ)

p135

汎用コードをたくさん作る

  • Projectのutil関数って、まとめた後どうやってその"存在"を報せればいいんや??

    • 僕もコード書いていて、「こういう処理」が欲しいと考えはしたり、他のview関数のコードを見ている時に便利なutilを見つけたりはしたけれど、そこを見てなければ自分で定義してた
    • READMEか、なにか城跡的にか、すでに作られたutil関数みたいなのはどこで見つけられるんや...
    • 究極この手の問題は、全て外部ライブラリに依存した方がいいのか?
  • staticメソッドって、結局classの外に定義したらあかんの?どんな時にclass内部に定義するのん?--Pythonの「@staticmethod」はどのように役立つのか - モジログ

    • inheritする時、staticメソに定義しておけばそのstaticメソだけoverrideすれば良いという利点がある(instance,class メソッドでもいいけど、そこはリーダブルコードのようにinstanceの変数使ってないことを明示できる利点があるね!)
  • いうて、「ダメ」と書かれた名前つことるときもあるし、使うにしても他の観点から読みやすくしたり(規則を作ったりね)しとる。