読者です 読者をやめる 読者になる 読者になる

Konifar's WIP

親方!空からどらえもんが!

考えることを減らすという指針

最近チームメンバーが増えてコードレビューの数も増えてきました。

レビューでお互いが納得できるような説明を何度もするのも嫌だし、『よいコードとは何か』ということについて自分の思考を整理すべきかなぁと考えていました。

よいコードについてはすでに議論されつくされていて、最後は好みの問題という人もいるしケースバイケースだという人もいると思います。たしかにそうだなぁとも思うんですが、レビューで指摘する際にそのように伝えてしまうと相手は次から何をどう考えてコードを書けばいいかわからなくなってしまうし、最低限自分なりの指針を明確にしておく必要があります。

で、自分の指針を整理した結果、 考えることを減らす に落ち着きました。

この指針に沿って、考えたことをまとめておこうと思います。項目とか綺麗にまとまってないですが、このブログはタイトルの通りwork-in-progressなのでまぁいいかなぁと言い訳してみたり。。。

DRYの原則

Do Not Repeat Yourself、同じコードは2度書かないというわかりやすい原則ですが、これも考えることを減らすためと考えるとしっくりきます。実際に書いている時には頭を使っているので 将来考えることを減らすための原則だと言えます。

例えばバグ修正の時に1箇所修正したら他にもう1箇所コピペがあって修正漏れたみたいなミスをなくすためですね。

逆に、同じコードでも2箇所に書いた方が考えることが減るのであれば、重複させるのもありかなと思います。例えば、変更する可能性が高くて、分けておいた方が後で影響範囲考えなくてもいいという場合などです。

メソッドの分割

1行のみで1箇所からしか呼ばれない処理を別メソッドに分ける人もいますが、これは考えることを減らすという指針に照らすとよくない気がします。

ちょっと極端ですが、以下に例を示します。

    if (isTen(number)) {
        // 略...
    }
}

private boolean isTen(int number) {
    return number == 10;
}

イコール演算子よりもis~というメソッドで書かれていたほうが可読性が高いという理由で分割しているかもしれないですが、これは逆に考えることを増やす可能性があります。なぜかというと、メソッドの中の処理がどうなっているか確認しないと間違っている可能性があるからです。

もちろん処理が複雑でメソッドを分割した方がよいケースも多いですが、そのまま書いた方が考えることが減る場合は分割しない方がいいです。

メソッドや変数の命名

名前は超重要だと思っています。 コードを読む上で考えることを劇的に減らせるからです。 そのため、レビューでも結構口うるさく指摘することが多いです。

以下に例を示します。

private boolean checkIfNetworkValid() {
    //...
}

これだと返り値がネットワークが正しい時にtrueなのかfalseなのかハッキリわかりません。

private boolean hasNetworkConnection() {
    //...
}

この方が、ネットワーク接続がある時にtrueになるのかとわかりやすいです。

メソッドの命名に関してはこちらの記事が参考になります。

うまくメソッド名を付けるための参考情報

スコープを小さくする

これもまさに考えることを減らすための意識すべきことです。

/*
 * publicだと他のクラスから呼ばれる可能性があるが、
 * privateにしておけばこのクラスからしか参照されないのでコードを読む人が考えなくてすむ。
 */
private void hoge() {
    //...
}

ただし、Javaの場合はprotectedやデフォルトスコープを意識するよりもパッケージ構成のわかりやすさを優先した方が考えることが減るかもしれません。

Immutable

変更の可能性を限定することで、変数がどこからセットされるかを考えなくてすみます。これは堅牢なコードを書く上でもとても大事なことです。

オブジェクト指向言語、例えばjavaではfinal修飾子をうまく活用することで実現できます。関数型言語ではそもそも変数の書き換えを許さない制約を課していることも多いですね。

コードスタイル

フォーマットが揃っていると読みやすくコードを読む上で余計なことを考えずにすみます。 横幅の最大文字数やインデントなど、細かいところですが地味に重要です。 Squareのコードスタイルも、インデントを2文字分にしてコードがコンパクトに収まるようにしたりしています。

既存のコードに倣う

明らかに間違っているコード以外は、元あるコードに習って書くべきじゃないかと思います。

例えばデータ取得のロジックはModelクラスにまとめているのに、Daoクラスを作った方がいいからと言って個々人が好き勝手に書き出すと、どこに何を書いてあるか統一されず考えることが増えてしまうからです。

もちろん既存のコードがベストとは限らなくて、理想的にはどういうコードであるべきなのかベストプラクティスを勉強しておくのはとても重要です。そういう努力の積み重ねも、将来考えることを減らしてくれるはずです。

コメント

将来の自分、あるいは他のメンバーが考えることが減るかどうかで判断するとよいです。

『コードには何を書く、コメントには何故を書く』という言葉がありますが、書かなくてもわかるようなら何故を書く必要もありません。半年後の自分が読んだと想像して、将来の自分のためにコメントが必要かどうかを判断しましょう。

言語の選定

キャッチアップコストの問題で いつ考えることが減るかという話です。

うちのチームには「AndroidでKotlinやScalaを採用しようよ」と言ってくれるメンバーもいます。それ自体はすごくいいのですが、新しい言語をチームで導入すると考えることが増えます。

言語はある程度極めて自然と手が動くくらいでなければ辛くなります。わざわざググりながら書いていては、本当に考えなければならないところを考える時間が減ってしまうからです。

キャッチアップすれば状況は変わるので、要はその損益分岐点をどう捉えるかという話ですが、よほどのメリットか情熱がない限り言語を変更するのは抵抗あるなぁという意見です。

実装スピードとのトレードオフ

考えることを減らすという指針が作用するのは、ほとんどのケースにおいては現在ではなく未来の話になります。

要は、将来考えなくてすむように今考えてコードを書くということです。ただ、将来は未知数な部分もあるので、無駄に考えすぎないことも重要です。実装スピードと将来考えることのトレードオフを意識して、うまく両立させるように工夫しましょう。