Operation Result Design Pattern でサーバからの戻り値の扱いを共通化する

# 前提

ASP.NETで、サーバ側はC#、クライアント側はJavascriptとします。
ただ、考え方自体はシンプルなので、他の言語やフレームワークでも適用可能だと思います。
DataAnnotationsフレームワークを使わない、汎用的なパターンです。

# 目的

- 任意の型（AValue型とする）のデータ取得をサーバに依頼してJSONで受け取りたい
- 処理結果がOKかNGか、エラーならばエラー情報、例えばエラーメッセージなど（OperationResult型とする）も受け取りたい
- 上記2点をまとめて受け取る方法をフレームワークとして規定したい
- その為のベストプラクティスを知りたい

# よくないパターン（Anti-Pattern）

AValue型にOperationResult型のプロパティを追加する。
![Anti-OperationResultPattern.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207038/0b11ebcb-a278-8eb5-14a5-2a95759c3c45.png)

## 利点

- 扱うデータ型に処理結果プロパティを1つ追加するだけなのでわかりやすい

## 欠点

- OperationResult型のプロパティ名に制約を付けられない（各クラスで異なるプロパティ名、例えばある場所ではErrorInfo、ある場所ではErrorResult、ある場所ではResultInfoになる可能性があり、処理共通化の妨げとなる）
- 処理結果NGでデータ自体を返す必要がない時でも空のデータを返さなければならない
- AValue型自体には直接関係のない「処理結果」という情報がAValue型に紛れ込んでおり、関心の分離ができていない

## 具体的なコード（C#とJavascript）

```C#:OperationResult.cs
class OperationResult {
	
	public IList<Error> Errors {get; set; } = new List<Error>();
	
	public bool Success {
		get => Errors.Count > 0;
	}
}
```

```C#:User.cs
class User {

	public string Name {get; set;}
	
	public OperationResult Result {get; set;} = new OperationResult();
}
```

```C#:UserController.cs

public ActionResult GetData(string id, IUserDao userDao) {
	try {
		User user = userDao.Get(id);
		return Json(user);
	}
	catch (Exception ex) {
		User user = new User();
		user.Result.Errors.Add( new Error( ex.Mesasge ) );
		return Json(user);
	}
}
```

```Javascript:ブラウザ側
const user = await fetch("http://localhost/User/GetData", {method:"POST", body:JSON.stringify({id:"123"})})
	.then(response => response.json());

if (user.Result.Success) {
	alert(user.Name);
}
else {
	const error = user.Result.Errors[0];
	alert(error.Message);
}
```

# Operation Result Design Pattern

処理結果を表すOperationResultをジェネリクスOperationResult\<T\>を用意する。OperationResult\<T\>のプロパティとしてT型のValueを持つ。CallerにはAValueの代わりにOperationResult\<AValue\>型を返す。
![OperationResult Design Pattern.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/207038/562bcbbc-4076-a427-b77e-1d02e85cf70c.png)

## 利点

- 戻り値自体がOperationResult型なので、戻り値の型に影響されずにエラー処理を共通化できる
- 処理結果NGでデータ自体を返す必要がない時はValueにnullを返せばよい
- AValue型がOperationResult型から独立しており、関心の分離を行える

## 欠点

- 戻り値からデータを取り出す為にValueプロパティを参照する必要がある。

## 具体的なコード（C#とJavascript）

```C#:OperationResult.cs
class OperationResult<T> : IOperationResult {
	
	public IList<Error> Errors {get; set; } = new List<Error>();
	
	public bool Success {
		get => Errors.Count > 0;
	}
	
	public T Value {get; set;}
	
	public Object GetValue() {
		return Value;
	}
}

interface IOperationResult {
	IList<Error> Errors {get; set;}
	bool Success { get; }
	Object GetValue();
}

// おまけ。処理結果以外のデータが不要な場合に使う。
class OperationResult : OperationResult<Object> {}

```

```C#:UserController.cs

public ActionResult GetData(string id, IUserDao userDao) {
	var result = new OperationResult<User>;
	
	try {
		result.Value = userDao.Get(id);
		return Json(result);
	}
	catch (Exception ex) {
		result.Errors.Add( new Error( ex.Mesasge ) );
		return Json(result);
	}
}
```

```Javascript:ブラウザ側
const result = await fetch("http://localhost/User/GetData", {method:"POST", body:JSON.stringify({id:"123"})})
	.then(response => response.json());

if (result.Success) {
	const user = result.Value;
	alert(user.Name);
}
else {
	const error = result.Errors[0];
	alert(error.Message);
}
```