Adaptive Code 読書ログ
4.2.1 Null Object
難しい、使うべきかどうかという意味で
GetId()
したときにNullUser型が返ってくる可能性があるのは嬉しいのかな、Nullだろうがどのみちそのあとの処理をするというのが直感的に納得いかない
どっちかというと代数的データのResult型とかの方が分かりやすいイメージあるけど
「何もしない」をさせる実装って、テストとかでは全然使えるけど、普通に返り値の可能性として「何もしない」があるのは少し怖い気もするけど大丈夫なのか分からん
GetById()
で見つからないならそもそも見つからなかったという情報が返ってくるのが一番わかりやすい気がしている、NullObjectは見つからなかったということの直接的な表現になっているとは言いづらい
Resultでやるなら
public abstract record UserGetResult;
public sealed record UserFound(User user) : UserGetResult;
public sealed record UserNotFound : UserGetResult;
まあC#の代数的データ型ってあんまり賢くはない(switchが網羅されていることをコンパイルレベルで保証できないので結局人間次第で分岐漏れのバグが出る)し、クライアント側のコードがswitch文使わないといけない形になるっていうデメリットはどうしても存在する
4.2.2 Adapter
継承の悪いポイントとして、継承はホワイトボックスの再利用であることが挙げられている、なるほど
継承はサブクラスをクラスの実装にも依存させる
要はメソッドの実装内容が基本的に一意になってしまう
なら普通はクラス分ければいいんじゃないかというのが継承を嫌ったアプローチ
ベースクラスでの実装をoverrideしてサブクラス側で実装を変えることもできるが、それをやりだすとベースクラスの期待した動作と乖離する可能性があり、改修が難しくなる
あと個人的には継承はスコープがデカくなりすぎるというデメリットもあると思う
継承は1つしかできない性質上、どうしてもそのクラスにすべてを詰め込まないといけなくなることが多い
それによってインターフェースなら分離しろと怒られるようなコードでも継承ならしょうがなく成立してしまう可能性が高い
インターフェースでの実装はより抽象に寄っている
つまり、実装の内容は知らなくても動作するように設計してね、という暗黙のルールが課される
これがあるからインターフェースの方がクライアントが利用しやすいコードになりやすい
Object Apapter パターンではTargetクラス実行部に対して、クライアントはAdapterとその実装インターフェースを介して呼び出すようにする
これでクライアントはインターフェースに依存できる状態を作れるが、実装部は変更しなくていい体制が作れるというテクニック
要は実装部をいじれないけどインターフェース化したい場合や、実装部に今さらインターフェースを付けて回るのはやばいというときに(あまり乗り気でなく)使うという感じかな…?
5.3.2 ユニットテストの意図
Builderパターンで生成意図を明確にする
メソッドチェーンを利用してプロダクトの生成を補助することで、生成系の意図を明確にし、テストをしやすくする意図がある
6.3 レガシーコード
レガシーコード = テストがないコードのこと
テストがないコードのリファクタリングは危険だけど必要
まずはユニットテストを作るべき