新刊ピックアップ
可読性向上の必勝パターンは存在するのか
ソフトウェア開発において,
可読性の向上において一番大切なことは,
強力なテクニック ——早期リターン——
「早期リターン」
- ハッピーパス 関数の主な目的を達成できるケース
- アンハッピーパス エラーなどで,
主な目的を達成できないケース
ハッピーパスの処理が関数中のどこにあるかが分かりやすいと,
fun someFunction() {
if (!isNetworkAvailable()) {
showNetworkUnavailableDialog()
return
}
val queryResult = queryToServer()
if (!queryResult.isValid) {
showInvalidResponseDialog()
return
}
... // ハッピーパスの実装
}
fun someFunction() {
if (isNetworkAvailable()) {
val queryResult = queryToServer()
if (queryResult.isValid) {
... // ハッピーパスの実装
} else {
showInvalidResponseDialog()
}
} else {
showNetworkUnavailableDialog()
}
}
まずは,if
によるネストの深い場所にハッピーパスがあるため,
また,isNetworkAvailable
がfalse
である)」ことに対応する処理は,if
のボディの下にあるelse
を辿ってみるまで分かりません。コード1ではアンハッピーパスと対応する処理が近くにあるため,
このように,
アンハッピーを取り除けばハッピーか?
強力なテクニックであるはずの
アンチパターン1:分かりにくい場所からのリターン
制御構造のネストの深い場所で早期リターンを行ったり,when
やswitch
の条件分岐の一部だけでリターンしたりすると,when
の一部に入ってしまっているため,
enum class ThemeType { LIGHT, DARK, INVALID }
fun setThemeBackgroundColor(themeType: ThemeType) {
val argbColor = when (themeType) {
ThemeType.LIGHT -> WHITE_ARGB_COLOR
ThemeType.DARK -> BLACK_ARGB_COLOR
ThemeType.INVALID -> return
// このreturnは見落とされやすい。
}
someView.setBackgroundColor(argbColor)
anotherView.setBackgroundColor(argbColor)
yetAnotherView.setBackgroundColor(argbColor)
}
コード3では,themeType
がINVALID
の場合においてのみ,return
を見落とすことは少ないかもしれません。しかし,return
を見落としやすいコードになってしまうでしょう。
早期リターンを行っているかどうかは,return
の部分を目立たせるべきです。方法はいくつか考えられますが,ThemeType
が変更可能なら,
ThemeType
からINVALID
を削除する関数の引数として,INVALID
の代わりにnull
で受け取るとコード4のように,ThemeType?
は,ThemeType
の型という意味です。
enum class ThemeType { LIGHT, DARK }
fun setThemeBackgroundColor(themeType: ThemeType?) {
if (themeType == null) {
return
}
val argbColor = when (themeType) {
ThemeType.LIGHT -> WHITE_ARGB_COLOR
ThemeType.DARK -> BLACK_ARGB_COLOR
}
...
}
このように,return
をうまく解消できることがあります。
アンチパターン2:不要なアンハッピーパス
もう1つのアンチパターンとして,List
の各要素に対して処理をするmap
やforEach
といった関数は,map
やforEach
を使う多くの場合,if (list.
といった早期リターンは不要でしょう。
コード3とコード4では,INVALID
はあくまでもアンハッピーパスとして扱っていました。もし,INVALID
はLIGHT
にフォールバックするという仕様であるならば,コード5のようにINVALID
もハッピーパスとして取り扱うことができます。
fun setThemeBackgroundColor(themeType: ThemeType) {
val argbColor = when (themeType) {
ThemeType.DARK -> BLACK_ARGB_COLOR
ThemeType.LIGHT, ThemeType.INVALID ->
WHITE_ARGB_COLOR
}
...
}
今実装している機能の価値に大きく影響しないならば,
プログラミング原則やテクニックに対する考え方
「早期リターン」
書籍
記事中で紹介した書籍
-
読みやすいコードのガイドライン ―持続可能なソフトウェア開発のために
開発が大規模化・長期化するほど,コードを「読む」コストは増大していきます。そのため「読みやすさ」の向上は,生産性を改善し,プロダクトの成長限界を引き上げる重...