【備忘録】コードを書くときに気をつけること(3)
前回に引き続き「良いコード/悪いコードで学ぶ設計入門」で学んだことを備忘録をとして書いていく。
退化コメント
良くない例
コードにコメントを残す際によくやってしまうのが、分岐条件や処理内容をそのまま言語化してしまうことだ。これは可読性の悪い部分をコメントで補っているように見えるため、良いコメントのように感じてしまう。
# 在庫があって商品が公開されており、なおかつ、会員限定販売商品ではないもの
if (self.stock != 0 and self.published and not self.member_only) {
もちろん、コードの可読性が若干上がっているため読み手の効率は少し良くなる。しかし、それ以上に大きなデメリットが存在する。
良くないところ
正確性に欠ける
条件分岐や処理内容についてコメントが書いてあったとしても、実際に動いているのはコードであってコメントではない。そのため、処理内容と異なるコメントが存在した場合が非常に危険となる。
更新が必要な部分が増える
上の「正確性に欠ける」と関連するが、条件分岐や処理内容を更新した際にコメントを更新する必要があるため、余計な手間が増えてしまう。(更新すること自体は手間ではないが、「どこかに更新するべきコメントがあるかもしれない」と考えながら作業するのは非常に効率が悪い)
改善方法
上記のようなコメントを改善するには以下の二つの方法があると考えている。
実装の背景を書く
これは書籍には書いていない内容だが、個人的に今感じていることとして書いておく。
上記の例では「分岐条件のロジック」をそのまま書いているだけなため、同じ情報でコード量をかさまししているのと同義だ。そのため、実装だけでは分からない「実装の背景」を書くことで実装の理解も早めることが出来ると考えている。
# クーポン適用するための条件で、販売可能かを判別する
# 参考:https://...
if (self.stock != 0 and self.published and not self.member_only) {
こうすることで「何のための条件なのか」が分かりやすく、なおかつ、条件の内容が変わったとしてもコメントを更新する必要がない(背景という本質的な情報なのであまり変更がない)
運用・変更の注意点を書く
こっちが書籍に書いていた方法で、コメントにはロジックの内容などは書かずに「運用・変更する際の注意点」を記述する。
# クーポン適用条件を変更する際にはこちらのロジックを変更する
if (self.stock != 0 and self.published and not self.member_only) {
この方法であれば実装と同時にコメントまで編集する必要がない。そのため、正確性が欠けることもなく、なおかつ、更新の手間も増えることがない。
複数目的のモデリング
良くない例
動作原理やしくみを簡単に理解・せつめいするために、物事の特徴や関係性を図式化したものをモデル、モデルをつくる活動をモデリングと呼びます。
良いコード/悪いコードで学ぶ設計入門の第13章より引用。
モデリングをする際にやってはいけないこととして、「複数目的を一つにしたモデル」を作成してしまうことだ。よくある例としてはUserクラスという様々な機能から使用されるクラスで、一つのクラスに複数の目的の情報が含まれてしまうことがある。
class User(object):
def __init__(self, id, name, email, password):
self.id = id
self.name = name
self.email = email
良くないところ
存在・概念をモデル化している
User(ユーザ)とは利用者、つまり存在を表している。モデリングでは現実世界の存在・概念をそのままモデルにしてしまうと複数の目的が含まれるようになり、依存するクラスが増えて低凝集に陥ってしまう。
単一責任の原則
複数目的が含まれるクラスは複数の責任を担ってしまうことが多い。そのため、単一責任の原則を守るためにはクラス内に単一の目的のみ存在させることが重要となる。
改善方法
改善方法としてはクラスを単一目的にすることなのだが、具体的な気を付ける行動のようなものはあまりない。ただ、目的駆動名前設計に気を付けると、何かしらの目的に特化したクラスになるはずなので、自然と単一目的なクラス設計となる可能性が高い。
# 認証関係
class Account:
def __init__(self, id, name, email, password):
self.id = id
self.name = name
self.email = email
self.password = password
# プロフィール
class Profile:
def __init__(self, address, tel):
self.address = address
self.tel = tel
# スキル
class Skill:
def __init__(self, language):
self.language = language
Discussion