Magicode logo
Magicode
5 min read

リーダブルコードの演習課題を作ってみる②

https://cdn.apollon.ai/media/notebox/c7ca543e-d9b8-49a4-bc28-f224ce5ce355.jpeg

はじめに

後輩のプログラミング教育をしていて、リーダブルコード※を読んでもらっても、読んだだけでは定着していなかった。
コードレビューで定着を試みているが、今後も後輩が増えていくことを考えて、何か対応策を講じようと思い、試しに演習課題を作ってみることにした。
リーダブルコードの2章以降から、気になったテクニックに対して、演習課題を作っていく。
今回は、「2.4 名前に情報を追加する」を題材にする。
なお、プログラミング言語はpythonとする。

書籍の内容

前にも言ったけど、名前は短いコメントのようなものだ。変数名に詰め込める情報はあまり多くない。だけど、名前につけた情報は変数を見るたびに目に入ってくる。 だから、もし絶対に知らせなきゃいけない大切な情報があれば、「単語」を変数名に追加すればいい。
変数名は、その変数を使う度に目にする情報源だ。だから、 絶対に知っておいて欲しい情報 を変数名に含めると良い。
では、 絶対に知っておいて欲しい情報 とはなんだろうか?
ひとつは、単位である。1 sec と1000 msec は同じ時間の長さだ。だが、例えば速さを計算するときに、sec なのかmsecなのか分かっていないと、計算結果が3桁変わってしまう。
# 良くない
def calc_velocity(distance: float, time: float) -> float:
    return distance / time

# 改善後
def calc_velocity_mps(distance_m: float, time_sec: float) -> float:
    return distance / time
他には、危険性や注意を喚起する場面でも使う。 暗号化していないことを、 plaintext_password などと表現することで、セキュリティなどで注意すべきことを読み手に伝えることができる。暗号化以外にも、エスケープやエンコードなどのデータ形式の変換も考えられる。

演習課題

下記を意識して読んでみてほしい。
  • 変数やプロパティ、メソッド名に情報を付与した方がいいか?
  • それはどういうケースか?※
  • 付与するならどんな情報か?
※ つまり、一概に悪いものとはいえないことに注意してほしい。

課題1

weather: str = “sunny”
temperature: int = 20
humidity: int = 50

課題2

class Product:
    def __init__(self, name: str, price: float):
        self._id: UUID = uuid4()
        self._name: str = name
        self._price: float = price

    @property
    def price(self) -> float:
        return self._price + self.tax

    @property
    def tax(self) -> float:
        #  一律10%に簡略化
        return self._price * 0.1

課題3

import json
import urllib.request

url = 'https://example.com/api/users'

req = urllib.request.Request(url)
with urllib.request.urlopen(req) as res:
    body = json.load(res)

解答例

課題1

いきなりだがケースバイケースな問題である。
日本で、日本人のみが使うコードならいいが、温度の単位は摂氏・華氏がある。よくアメリカだと華氏表記が使われていると聞く。摂氏・華氏の双方を使う場合などに、わかりやすくしようとするなら、摂氏なのか華氏なのか書くと良いだろう。
湿度(humidity)に関しては、定義上、割合になるので問題ないだろう。強いて言えば、0 ~ 100なのか0 ~ 1なのかは分かれそうだが、普段の生活では0 ~ 100が一般的ではないだろうか。わかりにくいと思うなら、0~1の時は正規化された:normalizedなどをつけるのはどうだろうか?
weatherに関しては問題ないだろう。最近のIDEならstrなどの型情報はわかるので型の情報を詰める必要もない。強いて言えば、enumにすればタイポなどのミスがしにくくなる。
weather: str = “sunny”
temperature_celsius: int = 20 # or temperature_fahrenheit
humidity: int = 50

課題2

この問題では先の問題のように、国や地域の問題としてpriceの話も考えられるが、taxが入ったことによるわかりにくさに着目する。
priceプロパティが税込価格を返しているが、これは中身をみないとわからない。tax_inclueded_priceの方がいいだろう。また、taxだけでも税率なのか税額なのかわかりにくいので、tax_price にする。最後に細かいことを言うと、税率がマジックナンバーになっているので直しておく。
TAX_RATE: float = 0.1

class Product:
    def __init__(self, name: str, price: float):
        self._id: UUID = uuid4()
        self._name: str = name
        self._price: float = price

    @property
    def tax_included_price(self) -> float:
        return self._price + self.tax_price

    @property
    def tax_price(self) -> float:
        #  一律10%に簡略化
        return self._price * TAX_RATE

課題3

bodyが一見どういうデータか分かりにくい。bodyという名前だと、バイナリか文字列に見える。しかし、ここではjson.load()しているのでdictionaryかlistのはずである。それを示すなら、json_decoded_bodyなどがある。一方で、usersというapiにアクセスしているので、そのことがわかる変数名にしてもよさそう。
import json
import urllib.request

url = 'https://example.com/api/users'

req = urllib.request.Request(url)
with urllib.request.urlopen(req) as res:
    users = json.load(res)

終わりに

リーダブルコードの「2.4 名前に情報を追加する」を題材に演習問題を作ってみた。
問題に関しては、やってみるとなかなか難しかった。間違っているとか、こう書いた方がいいのでは?などあったら是非コメントして欲しい。

Discussion

コメントにはログインが必要です。