samples: Add wire tutorial#357
Conversation
zombiezen
left a comment
There was a problem hiding this comment.
Nice, I really like this sample! It rounds out the last remaining principles that Go Cloud is introducing.
samples/wire/README.md
Outdated
| values][values], as well as support for [cleanup functions][cleanup]. See the | ||
| [Advanced Features][advanced] section for more. | ||
|
|
||
| [readme]: https://github.com/google/go-cloud/blob/master/wire/README.md |
There was a problem hiding this comment.
Please alphabetize link targets.
samples/wire/README.md
Outdated
| finally we create an event with that greeter. With all the initialization done, | ||
| we're ready to start our event. | ||
|
|
||
| In the design here, we are using dependency injection. We pass in whatever each |
There was a problem hiding this comment.
Link to https://en.wikipedia.org/wiki/Dependency_injection or a blog post? The Wikipedia article is denser than I'd like, but it's a start.
There was a problem hiding this comment.
There's a good discussion on StackOverflow here that's much easier to parse than that of Wikipedia. WDYT?
There was a problem hiding this comment.
Good find. That's a much more approachable explanation.
samples/wire/README.md
Outdated
| The `Start` method holds the core of our small application: it tells the | ||
| greeter to issue a greeting and then prints that message to the screen. | ||
|
|
||
| Now that we have all the components of our application ready, let's wire them |
There was a problem hiding this comment.
Either here or earlier, the prose needs to call out that we're stepping through how a problem would be solved by a Go programmer without Wire.
| three components, so writing the initializer by hand isn't too painful. Imagine | ||
| how useful Wire is for components that are much more complex. | ||
|
|
||
| To show a small part of how Wire handles more complex setups, let's refactor |
There was a problem hiding this comment.
Nice! I really like how just adding the error bit shows that the Wire setup stays the same (more or less) and it just grows to adjust.
(And same as above: this seems like the right place to start a new section heading.)
| code and makes it easy to swap out one dependency with another. The idea of | ||
| dependency injection isn't much more complicated than this. | ||
|
|
||
| One downside to dependency injection is the need for so many initialization |
There was a problem hiding this comment.
This seems like the right place to start a new section heading.
| } | ||
| ``` | ||
|
|
||
| Let's summarize what we have done here. First, we wrote a number of components |
There was a problem hiding this comment.
And one last section heading: Conclusion.
| "os" | ||
| ) | ||
|
|
||
| func main() { |
There was a problem hiding this comment.
If I were coming into this without having the background knowledge of splitting application and setup code, I would be confused as to why main is in its own file. Consider moving this into greeter.go.
There was a problem hiding this comment.
Moved declarations from greeter.go into main.go.
samples/wire/README.md
Outdated
| Let's learn to use Wire by example. The [Wire README][readme] provides thorough | ||
| documentation of the tool's usage. For readers eager to jump right in, the | ||
| [guestbook sample][guestbook] uses Wire to initialize its components. Here we | ||
| are going to build a small greeter CLI to understand how to use Wire. The |
There was a problem hiding this comment.
Consider using the term "program" here instead of "CLI". I know CLI is a fairly common acronym, but I think expanding it out helps inclusivity.
There was a problem hiding this comment.
The same thought occurred to me, as well. Done.
samples/wire/README.md
Outdated
| # Wire Tutorial | ||
|
|
||
| Let's learn to use Wire by example. The [Wire README][readme] provides thorough | ||
| documentation of the tool's usage. For readers eager to jump right in, the |
There was a problem hiding this comment.
s/jump right in/see Wire applied to a cloud server/
By being more precise, we clarify who the audience for this sample is by contrast: this is just Wire by itself.
| } | ||
| return event, nil | ||
| } | ||
| ``` |
There was a problem hiding this comment.
One last thing that would be nice to showcase here: Wire's error messages. It doesn't have to be a long thing, but you could instruct the reader to remove one of the arguments to wire.Build (perhaps the NewGreeter call) and show that Wire points out what is missing. Another nice one to show would be to add in a superfluous function and show that Wire tells you that it is unused.
For someone who is first using Wire, I don't want them to be afraid of error messages. Much like Go compiler error messages, the intent is not to criticize, but to aid the programmer into writing the next function. If they see this being done with intent in the sample (a controlled environment), then it's more likely that when they come across it in practice that they will know that Wire is helping them know what to do next.
There was a problem hiding this comment.
Great point. I'll add your two suggestions.
samples/wire/README.md
Outdated
| } | ||
| ``` | ||
|
|
||
| In the intializer we assign a `Message` field to `Greeter`. Now, we can use the |
samples/wire/README.md
Outdated
| finally we create an event with that greeter. With all the initialization done, | ||
| we're ready to start our event. | ||
|
|
||
| In the design here, we are using dependency injection. We pass in whatever each |
There was a problem hiding this comment.
My gut understanding of DI is it's automatic and done by a framework. Maybe here we should say something like "manual dependency injection"? Reading the SO post, this is DI, it's just not what's normally referred to as DI.
There was a problem hiding this comment.
I think your understanding matches that of many people, i.e., there is a conflation between dependency injection as a design principle and dependency injection frameworks. I'm inclined to call out that we're using the design principle and not a framework, as a qualifier.
samples/wire/README.md
Outdated
| finally we create an event with that greeter. With all the initialization done, | ||
| we're ready to start our event. | ||
|
|
||
| In the design here, we are using dependency injection. We pass in whatever each |
There was a problem hiding this comment.
s/In the design here/In this design/
?
Alternatively, "This uses manual dependency injection."
samples/wire/README.md
Outdated
| In the design here, we are using dependency injection. We pass in whatever each | ||
| component needs. This style of design lends itself to writing easily tested | ||
| code and makes it easy to swap out one dependency with another. The idea of | ||
| dependency injection isn't much more complicated than this. |
There was a problem hiding this comment.
Not sure we need this sentence - it makes me wonder what else is there? What do I not know?
samples/wire/README.md
Outdated
| passing it into the next one, we instead have a single call to `wire.Build` | ||
| passing in the initializers we want to use. In Wire, initializers are known as | ||
| "providers," functions which provide a particular type. We add a zero value for | ||
| `Event` as a return value to satisfy the compiler. This won't be included in |
There was a problem hiding this comment.
Reading this, I might wonder, can I put default values in the Event or does it have to be the zero value? Or is it always ignored?
There was a problem hiding this comment.
Updated to call this out.
samples/wire/README.md
Outdated
|
|
||
| Note, a [build constraint][constraint] requires a blank, trailing line. | ||
|
|
||
| In Wire parlance, `InitializeEvent` is an injector. Now that we have our |
There was a problem hiding this comment.
Minor style comment: I wonder if Wire terms should be italicized, or something similar.
There was a problem hiding this comment.
Following the introduction of providers above, I have quoted a new term at its first appearance.
samples/wire/README.md
Outdated
| } | ||
| ``` | ||
|
|
||
| We have added a `Grumpy` struct field to `Greeter` and if the invocation time |
There was a problem hiding this comment.
"Grumpy field to the Greeter struct"?
samples/wire/README.md
Outdated
| ``` | ||
|
|
||
| We have added a `Grumpy` struct field to `Greeter` and if the invocation time | ||
| of the initializer is an even number of seconds since the epoch, we will create |
| thing inside the generated code: it checks the error and returns early if one | ||
| is present. | ||
|
|
||
| As another improvement, let's look at how Wire generates code based on the |
samples/wire/README.md
Outdated
| As another improvement, let's look at how Wire generates code based on the | ||
| signature of the injector. Presently, we have hard-coded the message inside | ||
| `NewMessage`. In practice, it's much nicer to allow callers to change that | ||
| message however they see fit. So let's change `InitializeEvent` to look like this: |
There was a problem hiding this comment.
Add a sentence like:
"Wire will pass initializer arguments with the same name to any other initializers."
Maybe be a better way to phrase it.
There was a problem hiding this comment.
I've added a sentence clarifying this point, although as I understand Wire decides what goes where based on types rather than names.
| our component initializtion. As long as we tell Wire how to provide (i.e., | ||
| initialize) a component, we may add that component anywhere in the dependency | ||
| graph and Wire will handle the rest. | ||
|
|
There was a problem hiding this comment.
Should we mention when the generation should be done? Should the generated code be checked into git?
There was a problem hiding this comment.
It's a good point. Done.
|
Updated. PTAL @zombiezen, @vangent, @tbpg. |
samples/wire/README.md
Outdated
| Running `wire`, we see the following: | ||
|
|
||
| ``` shell | ||
| // wrapping the error across lines for readability |
No description provided.