コラム

【技術情報配信】機能追加

今回のテーマは「機能追加」です。
既存の関数に新しい処理を追加する場面はよくありますが、
そのまま書き足していくと関数がどんどん肥大化し、
 読みにくく
 変更しにくく
 バグが入りやすい
というコードになってしまいます。

では例を挙げてみます。

機能追加対象となる関数です。
void processUser(User* user) {
validateUser(user);
saveUser(user);
}
シンプルなユーザー処理関数ですね。

ここに以下の機能を追加する作業が発生したとします。
 - メール通知
 - ログ出力

で、完成した関数です。
void processUser(User* user) {
validateUser(user);
saveUser(user);

// 新機能:メール通知
if (user->notify) {
sendEmail(user);
}

// 新機能:ログ出力
if (user->logEnabled) {
writeLog(user);
}
}

ありますね。
よくあります。

一見シンプルに見えますが、
以下のような気になる点があります。
 - 条件分岐が増えた
 - 意図が曖昧になった
 - テストしづらくなった
 - バグが入りやすくなった
 - 行く行くは100行を超える関数に成長しているだろう

じゃあどうしたらいいのか。
こういうのはどうでしょう。
「責務ごとに関数を分ける」

void processUser(User* user) {
validateUser(user);
saveUser(user);
handlePostProcess(user);
}

void handlePostProcess(User* user) {
if (user->notify) {
sendEmail(user);
}
if (user->logEnabled) {
writeLog(user);
}
}

先ほど気になる点として挙げたことはクリアできていそうです。

機能追加のたびに関数を膨らませるのではなく、
 「この処理は別の責務では?」
と一度立ち止まる習慣が大切です。
このような小さな積み重ねが、読みやすく保守しやすいコードにつながります。

※以下のようなことが気になったら関数を分けるサインかと
 - 処理が増えてきた
 - 行数が増えてきた
 - 変数が増えてきた
 - コメントが増えてきた
 - テストしづらくなってきた
 - 関数名を変えたくなってきた
 など

以上