考え方
- nullを返してしまうと、それが想定通りなのか考慮漏れでそうなっているのか、判断が難しい
- C#は多くの型がnullとなる可能性がある
- nullが許容される環境だと、nullかどうかを常に気にする必要がある(PGの負荷)
- nullだったらそれはバグ、というプログラミング環境を築くのが幸せな世界だと思う
処理結果がない
- 例えばID検索のように、結果が0件か1件の場合
- 明示的に「みつからなかった」ことを示すクラスを作ると便利
Haskellで言うところのMaybe
使い方
Maybe<Entity> mEntity = FindById(id);
if (result.HasValue)
{
Entity entity = mEntity.Value;
entityを使った処理
}
else
{
見つからなかった場合の処理
}
要素数0のコレクション
- nullでなく空リストの方が嬉しい
- nullチェックを省ける
- 要素数0なので繰り返し処理が結局実行されない
return Array.Empty<string>();
nullを返してしまうと・・・
IEnumerable<string> enum = SomeMethod();
if (enum is not null)
{
foreach (var item in enum) ...
}
処理に失敗した
- よく見かけるのがWeb API呼び出し
失敗したときにログを出してnullを返す、という実装は邪悪だと思う - 失敗を想定するなら、それなりの設計にするのが大事
- アプリ側で処理してほしいなら、失敗を想定した戻り値にする
この場合、原因が分からないと対処しようがないので、nullを返すのでは不足 - ライブラリ側で処理(リトライなど)するなら、最終的な失敗は例外で表現する(プログラムを止める)
悪い例)
HttpResponse res = null;
try
{
res = httpClient.Post(url, data);
}
catch (Exception ex)
{
logger.fatal(ex);
}
return null;
修正版)
return httpClient.Post(url, data);
シンプル!余計な処理いらない!
余談・プログラムを止めることの是非
- nullを返すと、その場では停止しない
- が、これはエラーが表出する箇所と、原因の箇所が離れるため、よくない
- 想定していない例外はアプリで処理するべきでない。これが大原則
- 「例外は味方」「例外は処理系からの恩恵」と考えよう!
DBをSELECTしたときのnull値の扱い
- これが超絶難題
- SELECT結果をエンティティクラスで受け取るのは一般的だが、nullをそのままnullで表現するのは自然
- nullが有り得る項目はMaybeにするのが理想だが、そのようなライブラリはほぼない
- JOINが発生するとnullableなカラムが容易に作り出される
- これはエンティティオリジンで考えるライブラリを作るのがよいと思う
つまり、エンティティのプロパティ型がMaybeでない限り、nullは有り得ないとして処理する
どなたか、良い方法をご存知ならぜひ教えて下さい。
最後に
- (再掲)nullだったらそれはバグ、というプログラミング環境を築くのが幸せな世界だと思う
- つまりHaskellは幸せなせか