Skip to content

Commit

Permalink
Merge pull request #14 from pabloh/document_steps
Browse files Browse the repository at this point in the history
Add docs for result objects
  • Loading branch information
pabloh committed Oct 6, 2017
2 parents 0939191 + 23bd513 commit d41c5bf
Showing 1 changed file with 32 additions and 10 deletions.
42 changes: 32 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Pathway also aims to be easy to use, stay lightweight and modular, avoid unneces
As mentioned earlier the operation is a crucial concept Pathway leverages upon. Operations not only structure your code (using steps as will be explained latter) but also express meaningful business actions. Operations can be thought as use cases too: they represent an activity -to be perform by an actor interacting with the system- which should be understandable by anyone familiar with the business regardless of their technical expertise.


Operations should ideally don't contain any business rules but instead orchestrate and delegate to other more specific subsystems and services. The only logic present then should be glue code or any adaptations required to make iterations with the inner system layers possible.
Operations should ideally don't contain any business rules but instead orchestrate and delegate to other more specific subsystems and services. The only logic present then should be glue code or any adaptations required to make interactions with the inner system layers possible.

#### Function object protocol (the `call` method)

Expand All @@ -51,10 +51,10 @@ class MyFirstOperation
def call(params)
result = Repository.create(params)

if result.ok?
if result.valid?
Pathway::Result.success(result)
else
Pathway::Result.failure('could not create')
Pathway::Result.failure(:create_error)
end
end
end
Expand All @@ -70,24 +70,46 @@ end

Note first we are not inheriting from any class nor including any module. This won't be the case in general as `pathway` provides classes to help build your operations, but it serves to illustrate how little is needed to implement one.

Also, let's ignore the specifics about `Repository.create(...)`, we just need to know that is a backend that's able to return some value.
Also, let's ignore the specifics about `Repository.create(...)`, we just need to know that is some backend service which can return a value.


We now provide for our class a `call` implementation. It will just check if the result is available and then wrap it into a successful `Result` object when is ok, or a failing one when is not.
And that's it, you can then call the operation object, check whether it was completed correctly with `success?` and get the result value.
We now provide a `call` method for our class. It will just check if the result is available and then wrap it into a successful `Result` object when is ok, or a failing one when is not.
And that's it, you can then call the operation object, check whether it was completed correctly with `success?` and get the resulting value.

By following this protocol, you will be able to uniformly use the same pattern on every HTTP endpoint (or whatever means your app has to communicates with the outside world). The upper layer of the application is now offloading all domain logic to the operation and now only needs to focus on the data transmission details. Maintaining always the same protocol will also be very useful when composing operations.
By following this protocol, you will be able to uniformly apply the same pattern on every HTTP endpoint (or whatever means your app has to communicates with the outside world). The upper layer of the application is now offloading all the domain logic to the operation and only needs to focus on the data transmission details.

Maintaining always the same operation protocol will also be very useful when composing them.


#### Operation result
- Successful
- Failed

As should be evident by now an operation should always return either a successful or failed result. This concepts are represented by following a simple protocol, which `Pathway::Result` subclasses comply.

As we seen before, by querying `success?` on the result we can see if the operation we just ran went well, you can also call to `failure?` for a negated version.

The actual result value produced by the operation is be accessible at the `value` method and the error description (if there's any) at `error` when the operation fails.

To return wrapped values or errors from your operation you can must call to `Pathway::Result.success(value)` or `Pathway::Result.failure(error)`.


It is worth mentioning that when you inherit from `Pathway::Operation` you'll have helper methods at your disposal to create result objects easier, for instance the previous section's example could be written as follows:


```ruby
class MyFirstOperation < Pathway::Operation
def call(params)
result = Repository.create(params)

result.valid? ? success(result) : failure(:create_error)
end
end
```

#### Error objects
#### Initialization and context
#### Steps

Finally the steps, these are the heart of the operation class and the reason you will want to inherit your own from `Pathway::Operation`.
Finally the steps, these are the heart of the `Operation` class and the main reason you will want to inherit your own classes from `Pathway::Operation`.

#### Execution process state
#### Alternative invocation syntaxes and pattern matching DSL
Expand Down

0 comments on commit d41c5bf

Please sign in to comment.