Skip to content

Commit 926199f

Browse files
authored
Run post through grammarly
Neato!
1 parent b23666e commit 926199f

File tree

1 file changed

+20
-20
lines changed

1 file changed

+20
-20
lines changed

_posts/2020-06-24-the-command-pattern.md

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ Forget about whatever language or framework you’re using and try to think abou
2626

2727
Before we start, let’s take a moment to establish our domain.
2828
I’m going to choose the admin dashboard because it’s pretty broadly applicable and most software projects have at least some notion of an admin dashboard.
29-
However, **at a high level**, I think you could apply almost everything below to pretty much any domain you want.
29+
However, **at a high-level**, I think you could apply almost everything below to pretty much any domain you want.
3030

3131
So from here on out, our “program” is an “admin dashboard”.
3232

3333
In my experience an admin dashboard usually serves two main roles:
3434

3535
1. Exposing an insider look at data to aid in debugging and monitoring.
36-
1. Exposing actions that only certain people are able to perform under certain conditions
36+
1. Exposing actions that only certain people can perform under certain conditions
3737

3838
Let’s focus on the second for now.
3939

@@ -47,11 +47,11 @@ Let’s call our command `CancelSubscription`.
4747
Regardless of the naming scheme you choose, try to follow these rules:
4848

4949
1. Name the command after the behavior it implements _(this usually involves a verb)_
50-
1. Do this in such a way that behaviors in the same domain live near one another _(this may evolve over time)_
50+
1. Do this in such a way that behaviors in the same domain live near one another _(expect this to evolve)_
5151

5252
As domains get more mature, they often become more specialized.
5353

54-
Eventually your admin dashboard might have tens of commands related to subscriptions.
54+
Eventually, your admin dashboard might have tens of commands related to subscriptions.
5555
If this is the case, maybe you go with something like `Subscriptions::Cancel` instead.
5656
Renaming or reorganizing shouldn't be a herculean effort.
5757

@@ -61,35 +61,35 @@ Given the admin dashboard (program) and our desire to cancel subscriptions (dire
6161

6262
In this case, our task is concerned with two questions:
6363

64-
1. Are the conditions such that I am able to cancel the subscription?
65-
1. If able, how do I go about cancelling the subscription?
64+
1. Are the conditions such that I can cancel the subscription?
65+
1. If able, how do I go about canceling the subscription?
6666

67-
I really like that the definition uses the words _specific_ task.
67+
I like that the definition uses the words _specific_ task.
6868
In other words, if it doesn’t have to do with either of these two questions, do it somewhere else :)
6969

70-
If we do need a piece of data in order answer either of these questions, we can pass it into our command so long as our command doesn’t know or care where it came from.
70+
If we do need a piece of data to answer either of these questions, we can pass it into our command so long as our command doesn’t know or care where it came from.
7171
This will make your command more re-usable and easier to test.
7272

73-
For instance, our `CancelSubscription` command likely needs a subscription, a date the cancellation is to go into effect, the reason it’s being cancelled, and maybe the administrator that is performing the cancellation.
73+
For instance, our `CancelSubscription` command likely needs a subscription, a date the cancellation is to go into effect, the reason it’s being canceled, and maybe the administrator that is performing the cancellation.
7474

7575
### The Task: Am I Able?
7676

77-
Before we perform the task, we need to make sure we are able to perform the task.
77+
Before we perform the task, we need to make sure we can perform the task.
7878
This is where you implement your business rules.
7979

80-
For instance, a couple usual suspects:
80+
For instance, a couple of usual suspects:
8181

8282
* Only administrators with certain permissions can cancel subscriptions
8383
* The effective date must be between the subscription start date and the subscription end date
8484
* A cancellation reason must be supplied and be one of several defined reasons
8585

8686
There are certainly other libraries out there to choose from for both Ruby and other languages.
8787
I think a lot of this comes down to personal preference and willingness to learn new APIs.
88-
As a heads up, Commands may go by different names such as: Interactors, Mutations, Operations, and others I’m sure.
88+
As a heads up, Commands may go by different names such as Interactors, Mutations, Operations, and others I’m sure.
8989

90-
Whatever they do, they likely do something similar, but vary in syntax/DSL and feature set (e.g type coercion, checking, etc).
90+
Whatever they do, they likely do something similar but vary in syntax/DSL and feature set (e.g type coercion, checking, etc).
9191

92-
When using Ruby I tend to gravitate towards `ActiveModel` (and friends) since it’s _good enough_, almost guaranteed to be present, and usually avoids any sort of holy war, letting us focus on stuff that actually matters (i.e cancelling subscriptions!).
92+
When using Ruby I tend to gravitate towards `ActiveModel` (and friends) since it’s _good enough_, almost guaranteed to be present, and usually avoids any sort of holy war, letting us focus on stuff that matters (i.e canceling subscriptions!).
9393

9494
```ruby
9595
class CancelSubscription
@@ -152,17 +152,17 @@ That’s the beauty of the command.
152152

153153
```ruby
154154
def execute
155-
# Mark subscription as cancelled as of some date
155+
# Mark subscription as canceled as of some date
156156
# Maybe create a cancellation audit record documenting whodunnit/reason
157157
# Maybe send out cancellation email?
158-
# Maybe publish event to external system?
158+
# Maybe publish an event to an external system?
159159
end
160160
```
161161

162162
Sure, ideally it’s expertly modeled code that checks all the boxes that you subscribe to.
163163
In reality, it’s probably less than ideal and that’s okay.
164164

165-
Because we used the command pattern, folks that want to cancel a subscription don’t have to _care_ exactly how a subscription is cancelled — they just need to source the dependencies needed to perform the cancellation.
165+
Because we used the command pattern, folks that want to cancel a subscription don’t have to _care_ exactly how a subscription is canceled — they just need to source the dependencies needed to perform the cancellation.
166166

167167
## Summary
168168

@@ -217,13 +217,13 @@ This frees us up to create representations that aren't 1-1 with database models
217217

218218
We’re better positioned to handle new requirements because we can always make a new command variant or even compose commands with one another.
219219

220-
In addition, we’re able to write high value tests without making a single request/response (you should still write end-to-end tests, just maybe fewer than you otherwise might).
220+
Also, we’re able to write high-value tests without making a single request/response (you should still write end-to-end tests, just maybe fewer than you otherwise might).
221221

222222
### Going a Step Further: Result Objects
223223

224224
Depending on the size and discipline within your codebase, you may want to limit the surface area exposed by your commands.
225225

226-
Rather than expecting folks to initialize the command and call execute on it, you might consider exposing a class level method that does this for you under the covers and returns a result object.
226+
Rather than expecting folks to initialize the command and call execute on it, you might consider exposing a class-level method that does this for you under the covers and returns a result object.
227227

228228
While you can certainly do this in many ways, I usually make a simple object that exposes two methods: `success?` and `payload`.
229229

@@ -254,7 +254,7 @@ def self.run(**kwargs)
254254
end
255255
```
256256

257-
Usually when doing this it’s because I’m exposing something that might be used by another team and I want to control their access to the internals.
257+
Usually, when doing this it’s because I’m exposing something that might be used by another team and I want to control their access to the internals.
258258

259259
This usually means taking extra care to ensure that both the arguments into the command and the result’s payload are POROs.
260260

0 commit comments

Comments
 (0)