はじめに
この記事では
- 基本型と業務で扱う値の範囲の違いについて
- 扱う値の範囲を表現することで値を扱う側をシンプルに
これらについてまとめました。
動画でもまとめたのでご覧ください。
基本型の値の範囲と業務で扱う値の範囲の違い
例えば、
システムで金額を取り扱う場合、
取り扱える金額としてマイナスが許容されず、
100万円までの取引が可能だった場合
どのように業務で取り扱う金額を表現するのが良いでしょうか。
基本型であるintはマイナス21億〜プラス21億までの値の範囲を扱えます。
つまりintで表現すると
マイナスを許容して
プラス100万円より大きな値を許容することになります。
val transactionAmount: Int = 1_000_001
業務で扱う値をシステム内で存在させてしまうと、
使う側は、
業務で取り扱っていい値なのかを常に気にしなければなりません。
if(transactionAmount < 0 || transactionAmount > 1_000_000) {
throw IllegalArgumentException("取引金額が不正です")
}
使う側というのはたいてい複数箇所あるので、
複数箇所で同じように気にすることになるでしょう。
では、
もしシステムリリース後しばらくして、
業務で取り扱う値の範囲が変更になったらどうでしょう。
業務で取り扱う値の範囲を気にしていた箇所
を全て変更して回ることになります。
扱う値の範囲を表現することで値をシンプルに扱う
ここからは、
先ほどの悪い例をどのように改善すれば良いか
サンプルコードで見ていきます。
改善する方法は、
業務で扱う値の範囲しか取り扱えないクラスを作って、
それを値のように利用するだけです。
data class TransactionAmount(
val amount: Int,
) {
init {
if(amount < 0 || amount > 1_000_000) {
throw IllegalArgumentException("取引金額が不正です")
}
}
}
class 使う側クラス() {
val transactionAmount = TransactionAmount(1_000_000)
// 以降の処理でtransactionAmountの値の範囲を疑う必要がない!!
}
TransactionAmountという業務で扱う金額を表現するクラスは、
インスタンス生成の時に、
0~1,000,000の範囲外では生成できなくしています。
これによって使う側は値が作れた(インスタンス化成功)場合は
必ず業務で取り扱える0~1,000,000の範囲内なので、
余計な疑いを持たずに値が利用できます。
(至る所での値の範囲チェック不要)
もし仕様変更で取り扱う値の範囲が変わっても、
変更する箇所(影響箇所)は、
TransactionAmountクラスだけになり、
仕様変更による変更も楽になります。
このように、業務で扱う値の範囲を正確に表現できると、
値を扱う側がシンプルになり、
変更時の影響範囲も限定的にできます。
実はこのTransactionAmountの持っているamountは値をvalで不変にしていて、
例えば1という値の意味が途中で2に変わらないのと同じように、
インスタンス化した値は途中で変更できないようにしています。
これによって副作用が起きにくく、
システムが安定します。
が、この辺りはまた別記事でまとめようと思います。
まとめ
業務で取り扱う値の範囲と
intなどの基本型が取り扱う範囲は異なる。
無理やり基本型で業務で扱う値を表現するのではなく、
業務で扱う値の範囲に特化したクラスで表現すると、
使う側がシンプルで、仕様変更にも強くなる。
今回のテーマは以上です。
初めて設計をされる方向けに記事を作りました。
サンプルコードや図を入れてまとめたので是非ご覧ください。
初めてソフトウェア設計をする方に向けて|新人プログラマー時代の自分に伝えたいこと参考文献
第1章 小さくまとめてわかりやすくする
現場で役立つシステム設計の原則 〜変更を楽で安全にするオブジェクト指向の実践技法