Is this the Result Pattern / Operation Result Pattern? Or something different (if so, what?)
Result Pattern: From what I can see, the Result Pattern's intent is to return status, not substantive data/objects. Is that right, or can this pattern return actual data as well?
The pattern...
Problem: you have code that expects to return some kind of object, but you anticipate that there will be times when the object is not returned and you will get some other response (like an error or validation message).
Solution: you return the desired object within a "result" object. In addition to the desired "sunny day" object/result, it also has another member (e.g. a string) that contains the "rainy day" result.
public class AnimalResult
{
public string StatusMessage = string.Empty;
public MyCustomAnimalClass animalInformation = null;
}
public class MyApplication
{
public static string HowHeavyIsaGiraffe()
{
AnimalResult giraffeResult = SomeService.GiraffeInfoService();
if (giraffeResult.StatusMessage.Equals(string.Empty))
{
// Do something with the data/object.
return "This Giraffe weighs: " + giraffeResult.animalInformation.WeightInKGs;
}
else
{
// Do something with the status message.
return "We encountered an issue: " + giraffeResult.StatusMessage;
}
}
}
Background Info
Feel free to comment on this if you like, but it's not essential to my question.
When I have used this in the past (hobby projects) I tend to have created dedicated Result objects per datatype/class that I want returned, as there has never been so many that it would be come a maintenance issue.
I found using a string for the "Status" was a simple approach because you bascially get string.Empty = "ok to use object"
, otherwise if !string.Empty
then you know there's an issue. You could make this more complex as needed - e.g. explicitly declaring a member for exception info (which I have never done).
There's this https://medium.com/@cummingsi1993/the-operation-result-pattern-a-simple-guide-fe10ff959080 from Isaac Cummings, but the intent here seems to be to get only the "did this execute correctly" type information, and not to actually return a substantive value like a domain object, DTO, etc.
The purpose of the Operation Result Pattern, is to Identify the possibility of failures in the contract of a function
Based on what you described, it sounds to me like you are looking for the Result type.
The main idea of the approach is not to throw exceptions, but to create some object with 3 fields: success
(bool), value
, error
. And always fill in success
and fill in one of the other fields depending on the result of the method execution.
In general, this is not a very good approach from a design point of view, especially if your tools allow you to not mix different responses in one object.
Programming languages such as C# and Java explicitly introduce an exception mechanism that allows you to separate and handle different results of method execution. Example of code in Java (in C# the code will be similar except for the explicit listing of exceptions thrown by the client
method in the class Clients
):
class Client {
// constructors, fields, methods
}
class ClientNotFoundException extends Exception {
// constructors, fields, methods
}
class InvalidClientIdException extends Exception {
// constructors, fields, methods
}
class Clients {
// constructors, fields, methods
Client client(String id) throws ClientNotFoundException, InvalidClientIdException {
// return client or throws one of exceptions
}
}
class Bank {
private Clients clients;
// constructors
public void transfer(String fromClientId, String toClientId) {
try {
Client clientFrom = clients.client(fromClientId);
Client clientTo = clients.client(toClientId);
// work with clientFrom and clientTo
} catch (ClientNotFoundException e) {
// logic if a ClientNotFoundException occurred (work with e)
} catch (InvalidClientIdException e) {
// logic if an InvalidClientIdException occurred (work with e)
}
}
}
REST design best practices also recommend separating different response objects for different HTTP response codes.
Proponents of the pattern emphasize performance over design. But think about it this way: you'll only have a slowdown if there's an error, but in real life the error rate is negligible compared to the success rate, making it pointless from a performance standpoint.