You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -16,7 +15,7 @@ Instances are equal if their IDs are equal. Any equatable ID type can be used.
16
15
17
16
## Results
18
17
19
-
### `Result<TData>`
18
+
### `Result<TData>`
20
19
21
20
Represents the result of a domain operation that returns data of type `TData`. It is an abstract type with exactly two concretions: `Success` and `Failure`. It is a specialisation of the more generic `Either` type found in functional programming and is inspired by [Scott Wlaschin's Railway Oriented Programming](https://fsharpforfunandprofit.com/rop/) in F#.
22
21
@@ -41,6 +40,7 @@ public Person GetAdult(int id)
41
40
```
42
41
43
42
This implementation has two major drawbacks:
43
+
44
44
1) From a client's perspective, the API is not expressive enough. The method signature gives no indication that it might throw, so the client would need to peek inside to find that out.
45
45
2) From an implementer's perspective, the error checking, whilst simple enough in this example, can often grow quite complex. This makes the implementation of the method hard to follow due to the number of conditional branches. We may try factoring out the condition checking blocks into separate methods to solve this problem. This would also allow us to share some of this logic with other parts of the code base. These factored-out methods would then have a signature like `void CheckPersonExists(Person person)`. Again, this signature tells us nothing about the fact that the method might throw an exception. Currently, the compiler is also not able to do the flow analysis necessary to determine that the `person` is not `null` after calling such a method and so we may be left with warnings in the original call site about possible null references, even though we know we've checked for that condition.
46
46
@@ -66,7 +66,8 @@ Now we have a much more expressive method signature, which indicates that we mig
66
66
67
67
If the operation has no data to return then a `Result<Unit>` can be used. `Unit` is a special type that indicates the absence of a value, because `void` is not a valid type in C#.
68
68
69
-
Some recommendations on using `Result` types:
69
+
Some recommendations on using `Result` types:
70
+
70
71
* Make all public domain methods return a `Result<TData>`. Most domain operations will have a failure case that the client should be informed about, but even if they don't, by returning `Result` now it can be easily added later without breaking the public API.
71
72
* Once an operation is in "result space", keep it there for as long as possible. `Result` has a fluent API to facilitate this. This is similar to how, once one operation becomes `async` it is best to make all surrounding operations `async` too. This can be re-phrased as, don't match on the result until the last possible moment. For example, in a web API this would mean only unwrapping the result in the Controller.
72
73
@@ -83,6 +84,7 @@ Represents a failed `Result`. When constructed it takes an `Error` which contain
83
84
Like exceptions, errors form a hierarchy, with all errors deriving from the base `Error` type. This library defines a few common domain error types, which are listed below, but it is expected that more specific errors will be defined on a per-domain basis.
84
85
85
86
Some recommendations on designing errors:
87
+
86
88
* Try not to create custom errors that are too granular. Model them as you would entities and use the language of the domain model to guide their creation. The concept should make sense to a domain expert.
87
89
* The title should be the same for all instances of the error. The details are where instance specific information can be provided. If you are creating a custom error, make the title static and only let clients customise the details. See implementations of errors in this library for examples.
88
90
* Only use them for domain errors. Exceptions should still be used for system failures, such as network requests, and programming errors.
0 commit comments