From 71fc3ea50685330ac25046a43d20d7268edc1484 Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Tue, 30 Jul 2019 22:29:20 -0300 Subject: [PATCH 1/5] =?UTF-8?q?In=C3=ADcio=20de=20tradu=C3=A7=C3=A3o=20de?= =?UTF-8?q?=20inje=C3=A7=C3=A3o=20de=20depend=C3=AAncia?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- di/v1/di.go | 16 -- di/v2/di_test.go | 18 -- injecao-de-dependencia/v1/id.go | 16 ++ injecao-de-dependencia/v1/id_test.go | 18 ++ {di => injecao-de-dependencia}/v2/di.go | 0 .../v2}/di_test.go | 0 .../dependency-injection.md | 218 ----------------- .../injecao-de-dependencia.md | 225 ++++++++++++++++++ 8 files changed, 259 insertions(+), 252 deletions(-) delete mode 100644 di/v1/di.go delete mode 100644 di/v2/di_test.go create mode 100644 injecao-de-dependencia/v1/id.go create mode 100644 injecao-de-dependencia/v1/id_test.go rename {di => injecao-de-dependencia}/v2/di.go (100%) rename {di/v1 => injecao-de-dependencia/v2}/di_test.go (100%) delete mode 100644 primeiros-passos-com-go/dependency-injection.md create mode 100644 primeiros-passos-com-go/injecao-de-dependencia.md diff --git a/di/v1/di.go b/di/v1/di.go deleted file mode 100644 index 0f556065..00000000 --- a/di/v1/di.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "fmt" - "io" - "os" -) - -// Greet sends a personalised greeting to writer -func Greet(writer io.Writer, name string) { - fmt.Fprintf(writer, "Hello, %s", name) -} - -func main() { - Greet(os.Stdout, "Elodie") -} diff --git a/di/v2/di_test.go b/di/v2/di_test.go deleted file mode 100644 index 4514e1f1..00000000 --- a/di/v2/di_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "bytes" - "testing" -) - -func TestGreet(t *testing.T) { - buffer := bytes.Buffer{} - Greet(&buffer, "Chris") - - got := buffer.String() - want := "Hello, Chris" - - if got != want { - t.Errorf("got '%s' want '%s'", got, want) - } -} diff --git a/injecao-de-dependencia/v1/id.go b/injecao-de-dependencia/v1/id.go new file mode 100644 index 00000000..50d5891d --- /dev/null +++ b/injecao-de-dependencia/v1/id.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" + "io" + "os" +) + +// Cumprimenta envia um cumprimento personalizado ao escritor +func Cumprimenta(escritor io.Writer, nome string) { + fmt.Fprintf(escritor, "Olá, %s", nome) +} + +func main() { + Cumprimenta(os.Stdout, "Elodie") +} diff --git a/injecao-de-dependencia/v1/id_test.go b/injecao-de-dependencia/v1/id_test.go new file mode 100644 index 00000000..d51e6350 --- /dev/null +++ b/injecao-de-dependencia/v1/id_test.go @@ -0,0 +1,18 @@ +package main + +import ( + "bytes" + "testing" +) + +func TestCumprimenta(t *testing.T) { + buffer := bytes.Buffer{} + Cumprimenta(&buffer, "Chris") + + resultado := buffer.String() + esperado := "Olá, Chris" + + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) + } +} diff --git a/di/v2/di.go b/injecao-de-dependencia/v2/di.go similarity index 100% rename from di/v2/di.go rename to injecao-de-dependencia/v2/di.go diff --git a/di/v1/di_test.go b/injecao-de-dependencia/v2/di_test.go similarity index 100% rename from di/v1/di_test.go rename to injecao-de-dependencia/v2/di_test.go diff --git a/primeiros-passos-com-go/dependency-injection.md b/primeiros-passos-com-go/dependency-injection.md deleted file mode 100644 index 472b2a36..00000000 --- a/primeiros-passos-com-go/dependency-injection.md +++ /dev/null @@ -1,218 +0,0 @@ -# Injeção de dependência - -[**You can find all the code for this chapter here**](https://github.com/quii/learn-go-with-tests/tree/master/di) - -It is assumed that you have read the structs section before as some understanding of interfaces will be needed for this. - -There is _a lot_ of misunderstandings around dependency injection around the programming community. Hopefully, this guide will show you how - -* You don't need a framework -* It does not overcomplicate your design -* It facilitates testing -* It allows you to write great, general-purpose functions. - -We want to write a function that greets someone, just like we did in the hello-world chapter but this time we are going to be testing the _actual printing_. - -Just to recap, here is what that function could look like - -```go -func Greet(name string) { - fmt.Printf("Hello, %s", name) -} -``` - -But how can we test this? Calling `fmt.Printf` prints to stdout, which is pretty hard for us to capture using the testing framework. - -What we need to do is to be able to **inject** \(which is just a fancy word for pass in\) the dependency of printing. - -**Our function doesn't need to care** _**where**_ **or** _**how**_ **the printing happens, so we should accept an** _**interface**_ **rather than a concrete type.** - -If we do that, we can then change the implementation to print to something we control so that we can test it. In "real life" you would inject in something that writes to stdout. - -If you look at the source code of `fmt.Printf` you can see a way for us to hook in - -```go -// It returns the number of bytes written and any write error encountered. -func Printf(format string, a ...interface{}) (n int, err error) { - return Fprintf(os.Stdout, format, a...) -} -``` - -Interesting! Under the hood `Printf` just calls `Fprintf` passing in `os.Stdout`. - -What exactly _is_ an `os.Stdout`? What does `Fprintf` expect to get passed to it for the 1st argument? - -```go -func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { - p := newPrinter() - p.doPrintf(format, a) - n, err = w.Write(p.buf) - p.free() - return -} -``` - -An `io.Writer` - -```go -type Writer interface { - Write(p []byte) (n int, err error) -} -``` - -As you write more Go code you will find this interface popping up a lot because it's a great general purpose interface for "put this data somewhere". - -So we know under the covers we're ultimately using `Writer` to send our greeting somewhere. Let's use this existing abstraction to make our code testable and more reusable. - -## Write the test first - -```go -func TestGreet(t *testing.T) { - buffer := bytes.Buffer{} - Greet(&buffer,"Chris") - - got := buffer.String() - want := "Hello, Chris" - - if got != want { - t.Errorf("got '%s' want '%s'", got, want) - } -} -``` - -The `buffer` type from the `bytes` package implements the `Writer` interface. - -So we'll use it in our test to send in as our `Writer` and then we can check what was written to it after we invoke `Greet` - -## Try and run the test - -The test will not compile - -```text -./di_test.go:10:7: too many arguments in call to Greet - have (*bytes.Buffer, string) - want (string) -``` - -## Write the minimal amount of code for the test to run and check the failing test output - -_Listen to the compiler_ and fix the problem. - -```go -func Greet(writer *bytes.Buffer, name string) { - fmt.Printf("Hello, %s", name) -} -``` - -`Hello, Chris di_test.go:16: got '' want 'Hello, Chris'` - -The test fails. Notice that the name is getting printed out, but it's going to stdout. - -## Write enough code to make it pass - -Use the writer to send the greeting to the buffer in our test. Remember `fmt.Fprintf` is like `fmt.Printf` but instead takes a `Writer` to send the string to, whereas `fmt.Printf` defaults to stdout. - -```go -func Greet(writer *bytes.Buffer, name string) { - fmt.Fprintf(writer, "Hello, %s", name) -} -``` - -The test now passes. - -## Refactor - -Earlier the compiler told us to pass in a pointer to a `bytes.Buffer`. This is technically correct but not very useful. - -To demonstrate this, try wiring up the `Greet` function into a Go application where we want it to print to stdout. - -```go -func main() { - Greet(os.Stdout, "Elodie") -} -``` - -`./di.go:14:7: cannot use os.Stdout (type *os.File) as type *bytes.Buffer in argument to Greet` - -As discussed earlier `fmt.Fprintf` allows you to pass in an `io.Writer` which we know both `os.Stdout` and `bytes.Buffer` implement. - -If we change our code to use the more general purpose interface we can now use it in both tests and in our application. - -```go -package main - -import ( - "fmt" - "os" - "io" -) - -func Greet(writer io.Writer, name string) { - fmt.Fprintf(writer, "Hello, %s", name) -} - -func main() { - Greet(os.Stdout, "Elodie") -} -``` - -## More on io.Writer - -What other places can we write data to using `io.Writer`? Just how general purpose is our `Greet` function? - -### The internet - -Run the following - -```go -package main - -import ( - "fmt" - "io" - "net/http" -) - -func Greet(writer io.Writer, name string) { - fmt.Fprintf(writer, "Hello, %s", name) -} - -func MyGreeterHandler(w http.ResponseWriter, r *http.Request) { - Greet(w, "world") -} - -func main() { - http.ListenAndServe(":5000", http.HandlerFunc(MyGreeterHandler)) -} -``` - -Run the program and go to [http://localhost:5000](http://localhost:5000). You'll see your greeting function being used. - -HTTP servers will be covered in a later chapter so don't worry too much about the details. - -When you write an HTTP handler, you are given an `http.ResponseWriter` and the `http.Request` that was used to make the request. When you implement your server you _write_ your response using the writer. - -You can probably guess that `http.ResponseWriter` also implements `io.Writer` so this is why we could re-use our `Greet` function inside our handler. - -## Wrapping up - -Our first round of code was not easy to test because it wrote data to somewhere we couldn't control. - -_Motivated by our tests_ we refactored the code so we could control _where_ the data was written by **injecting a dependency** which allowed us to: - -* **Test our code** If you can't test a function _easily_, it's usually because of dependencies hard-wired into a function _or_ global state. If you have a global database connection pool for instance that is used by some kind of service layer, it is likely going to be difficult to test and they will be slow to run. DI will motivate you to inject in a database dependency \(via an interface\) which you can then mock out with something you can control in your tests. -* **Separate our concerns**, decoupling _where the data goes_ from _how to generate it_. If you ever feel like a method/function has too many responsibilities \(generating data _and_ writing to a db? handling HTTP requests _and_ doing domain level logic?\) DI is probably going to be the tool you need. -* **Allow our code to be re-used in different contexts** The first "new" context our code can be used in is inside tests. But further on if someone wants to try something new with your function they can inject their own dependencies. - -### What about mocking? I hear you need that for DI and also it's evil - -Mocking will be covered in detail later \(and it's not evil\). You use mocking to replace real things you inject with a pretend version that you can control and inspect in your tests. In our case though, the standard library had something ready for us to use. - -### The Go standard library is really good, take time to study it - -By having some familiarity with the `io.Writer` interface we are able to use `bytes.Buffer` in our test as our `Writer` and then we can use other `Writer`s from the standard library to use our function in a command line app or in web server. - -The more familiar you are with the standard library the more you'll see these general purpose interfaces which you can then re-use in your own code to make your software reusable in a number of contexts. - -This example is heavily influenced by a chapter in [The Go Programming language](https://www.amazon.co.uk/Programming-Language-Addison-Wesley-Professional-Computing/dp/0134190440), so if you enjoyed this, go buy it! - diff --git a/primeiros-passos-com-go/injecao-de-dependencia.md b/primeiros-passos-com-go/injecao-de-dependencia.md new file mode 100644 index 00000000..d8cc65e3 --- /dev/null +++ b/primeiros-passos-com-go/injecao-de-dependencia.md @@ -0,0 +1,225 @@ +# Injeção de dependência + +[**Você pode encontrar todos os códigos para esse capítulo aqui**](https://github.com/larien/learn-go-with-tests/tree/master/injecao-de-dependencia) + +Presume-se que você tenha lido a seção de `structs` antes, já que será necessário saber um pouco sobre interfaces para entender esse capítulo. + +Há muitos mal entendidos relacionados à injeção de dependência na comunidade de programação. Se tudo der certo, esse guia vai te mostrar que: + +- Você não precisa de uma framework +- Não torna seu design complexo demais +- Facilita seus testes +- Permite que você escreva funções ótimas para própósitos diversos. + +Queremos criar uma função que cumprimenta alguém, assim como a que fizemos no capítulo [Olá, mundo](https://github.com/larien/learn-go-with-tests/tree/master/hello-world), mas dessa vez vamos testar o _print de verdade_. + +Para recapitular, a função era parecida com isso: + +```go +func Cumprimenta(nome string) { + fmt.Printf("Olá, %s", nome) +} +``` + +Mas como podemos testar isso? Chamar `fmt.Printf` imprime na saída, o que torna a captura com a ferramenta de testes bem difícil para nós. + +O que precisamos fazer é sermos capazes de **injetar** (que é só uma palavra chique para passar) a dependência de impressão. + +**Nossa função não precisa se preocupar com** _**onde**_ **ou** _**como**_ **a impressão acontece, então vamos aceitar uma** _**interface**_ **ao invés de um tipo concreto.** + +Se fizermos isso, podemos mudar a implementação para imprimir algo que controlamos para poder testá-lo. Na "vida real", você iria injetar em algo que escreve na saída. + +Se dermos uma olhada no código fonte do `fmt.Printf`, podemos ver uma forma de começar: + +```go +// Printf retorna o número de bytes escritos e algum erro de escrita encontrado. +func Printf(format string, a ...interface{}) (n int, err error) { + return Fprintf(os.Stdout, format, a...) +} +``` + +Interessante! Por baixo dos panos, o `Printf` só chama o `Fprintf` passando o `os.Stdout`. + +O que exatamente _é_ um `os.Stdout`? O que o `Fprintf` espera que passe para ele como primeiro argumento? + +```go +func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { + p := newPrinter() + p.doPrintf(format, a) + n, err = w.Write(p.buf) + p.free() + return +} +``` + +Um `io.Writer`: + +```go +type Writer interface { + Write(p []byte) (n int, err error) +} +``` + +Quanto mais você escreve código em Go, mais vai perceber que essa interface aparece bastante, pois é uma ótima interface de uso geral para "colocar esses dados em algum lugar". + +Logo, sabemos que por baixo dos panos estamos usando o `Writer` para enviar nosso cumprimento para algum lugar. Vamos usar essa abstração existente para tornar nosso código testável e mais reutilizável. + +## Escreva o teste primeiro + +```go +func TestCumprimenta(t *testing.T) { + buffer := bytes.Buffer{} + Cumprimenta(&buffer, "Chris") + + resultado := buffer.String() + esperado := "Olá, Chris" + + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) + } +} +``` + +O tipo `buffer` do pacote `bytes` implementa a interface `Writer`. + +Logo, vamos utilizá-lo no nosso teste para enviá-lo como nosso `Writer` e depois podemos verificar o que foi escrito nele quando chamamos `Cumprimenta`. + +## Execute o teste + +O teste não vai compilar: + +```bash +./id_test.go:10:7: too many arguments in call to Cumprimenta + have (*bytes.Buffer, string) + want (string) +``` + +```bash +./id_test.go:10:7: muitos argumentos na chamada de Cumprimenta + obteve (*bytes.Buffer, string) + esperado (string) +``` + +## Escreva o mínimo de código possível para fazer o teste rodar e verifique a saída do teste que tiver falhado + +_Preste atenção no compilador_ e corrija o problema. + +```go +func Cumprimenta(escritor io.Writer, nome string) { + fmt.Printf("Olá, %s", nome) +} +``` + +`Olá, Chris id_test.go:16: resultado '', esperado 'Olá, Chris'` + +O teste falha. Note que o nome está sendo impresso, mas está indo para a saída. + +## Escreva código o suficiente para fazer o teste passar + +Use o escritor para enviar o cumprimento para o buffer no nosso teste. Lembre-se que o `fmt.Fprintf` é parecido com o `fmt.Printf`, com a diferença de que leva um `Writer` em que a string é enviada, enquanto que o`fmt.Printf` redireciona para a saída por padrão. + +```go +func Cumprimenta(escritor io.Writer, nome string) { + fmt.Fprintf(escritor, "Olá, %s", nome) +} +``` + +Agora o teste vai passar. + +## Refatoração + +Antes, o compilador nos disse para passar um ponteiro para um `bytes.Buffer`. Isso está tecnicamente correto, mas não é muito útil. + +Para demonstrar isso, tente utilizar a função `Cumprimenta` em uma aplicação Go onde queremos que imprima na saída. + +```go +func main() { + Cumprimenta(os.Stdout, "Elodie") +} +``` + +`./id.go:14:7: cannot use os.Stdout (type *os.File) as type *bytes.Buffer in argument to Cumprimenta` + +`não é possível utilizar os.Stdout (tipo *os.File) como tipo *bytes.Buffer no argumento para Cumprimenta` + +Como discutimos antes, o `fmt.Fprintf` te permite passar um `io.Writer`, que sabemos que o `os.Stdout` e `bytes.Buffer` implementam. + +Se mudarmos nosso código para usar uma interface de propósito mais geral, podemos usá-la tanto nos testes quanto na nossa aplicação. + +```go +package main + +import ( + "fmt" + "os" + "io" +) + +func Cumprimenta(escritor io.Writer, nome string) { + fmt.Fprintf(escritor, "Olá, %s", nome) +} + +func main() { + Cumprimenta(os.Stdout, "Elodie") +} +``` + +## Mais sobre io.Writer + +Quais outros lugares podemos escrever dados usando `io.Writer`? Para qual propósito geral nossa função `Cumprimenta` é feita? + +### A internet + +Execute o seguinte: + +```go +package main + +import ( + "fmt" + "io" + "net/http" +) + +func Greet(writer io.Writer, name string) { + fmt.Fprintf(writer, "Hello, %s", name) +} + +func MyGreeterHandler(w http.ResponseWriter, r *http.Request) { + Greet(w, "world") +} + +func main() { + http.ListenAndServe(":5000", http.HandlerFunc(MyGreeterHandler)) +} +``` + +Run the program and go to [http://localhost:5000](http://localhost:5000). You'll see your greeting function being used. + +HTTP servers will be covered in a later chapter so don't worry too much about the details. + +When you write an HTTP handler, you are given an `http.ResponseWriter` and the `http.Request` that was used to make the request. When you implement your server you _write_ your response using the writer. + +You can probably guess that `http.ResponseWriter` also implements `io.Writer` so this is why we could re-use our `Greet` function inside our handler. + +## Resumo + +Our first round of code was not easy to test because it wrote data to somewhere we couldn't control. + +_Motivated by our tests_ we refactored the code so we could control _where_ the data was written by **injecting a dependency** which allowed us to: + +- **Test our code** If you can't test a function _easily_, it's usually because of dependencies hard-wired into a function _or_ global state. If you have a global database connection pool for instance that is used by some kind of service layer, it is likely going to be difficult to test and they will be slow to run. DI will motivate you to inject in a database dependency \(via an interface\) which you can then mock out with something you can control in your tests. +- **Separate our concerns**, decoupling _where the data goes_ from _how to generate it_. If you ever feel like a method/function has too many responsibilities \(generating data _and_ writing to a db? handling HTTP requests _and_ doing domain level logic?\) DI is probably going to be the tool you need. +- **Allow our code to be re-used in different contexts** The first "new" context our code can be used in is inside tests. But further on if someone wants to try something new with your function they can inject their own dependencies. + +### What about mocking? I hear you need that for DI and also it's evil + +Mocking will be covered in detail later \(and it's not evil\). You use mocking to replace real things you inject with a pretend version that you can control and inspect in your tests. In our case though, the standard library had something ready for us to use. + +### The Go standard library is really good, take time to study it + +By having some familiarity with the `io.Writer` interface we are able to use `bytes.Buffer` in our test as our `Writer` and then we can use other `Writer`s from the standard library to use our function in a command line app or in web server. + +The more familiar you are with the standard library the more you'll see these general purpose interfaces which you can then re-use in your own code to make your software reusable in a number of contexts. + +This example is heavily influenced by a chapter in [The Go Programming language](https://www.amazon.co.uk/Programming-Language-Addison-Wesley-Professional-Computing/dp/0134190440), so if you enjoyed this, go buy it! From 15a2fb939d8fe2ff3273a6dd24caad9eb5880e75 Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Tue, 30 Jul 2019 22:44:08 -0300 Subject: [PATCH 2/5] =?UTF-8?q?Tradu=C3=A7=C3=A3o=20at=C3=A9=20Resumo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- injecao-de-dependencia/v2/di.go | 25 --------------- injecao-de-dependencia/v2/di_test.go | 18 ----------- injecao-de-dependencia/v2/id.go | 25 +++++++++++++++ injecao-de-dependencia/v2/id_test.go | 18 +++++++++++ .../injecao-de-dependencia.md | 32 +++++++++++-------- 5 files changed, 61 insertions(+), 57 deletions(-) delete mode 100644 injecao-de-dependencia/v2/di.go delete mode 100644 injecao-de-dependencia/v2/di_test.go create mode 100644 injecao-de-dependencia/v2/id.go create mode 100644 injecao-de-dependencia/v2/id_test.go diff --git a/injecao-de-dependencia/v2/di.go b/injecao-de-dependencia/v2/di.go deleted file mode 100644 index 8176fca6..00000000 --- a/injecao-de-dependencia/v2/di.go +++ /dev/null @@ -1,25 +0,0 @@ -package main - -import ( - "fmt" - "io" - "net/http" -) - -// Greet sends a personalised greeting to writer -func Greet(writer io.Writer, name string) { - fmt.Fprintf(writer, "Hello, %s", name) -} - -// MyGreeterHandler says Hello, world over HTTP -func MyGreeterHandler(w http.ResponseWriter, r *http.Request) { - Greet(w, "world") -} - -func main() { - err := http.ListenAndServe(":5000", http.HandlerFunc(MyGreeterHandler)) - - if err != nil { - fmt.Println(err) - } -} diff --git a/injecao-de-dependencia/v2/di_test.go b/injecao-de-dependencia/v2/di_test.go deleted file mode 100644 index 4514e1f1..00000000 --- a/injecao-de-dependencia/v2/di_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "bytes" - "testing" -) - -func TestGreet(t *testing.T) { - buffer := bytes.Buffer{} - Greet(&buffer, "Chris") - - got := buffer.String() - want := "Hello, Chris" - - if got != want { - t.Errorf("got '%s' want '%s'", got, want) - } -} diff --git a/injecao-de-dependencia/v2/id.go b/injecao-de-dependencia/v2/id.go new file mode 100644 index 00000000..d4c337e8 --- /dev/null +++ b/injecao-de-dependencia/v2/id.go @@ -0,0 +1,25 @@ +package main + +import ( + "fmt" + "io" + "net/http" +) + +// Cumprimenta envia um cumprimento personalizado ao escritor +func Cumprimenta(escritor io.Writer, nome string) { + fmt.Fprintf(escritor, "Olá, %s", nome) +} + +// HandlerMeuCumprimento diz Olá, mundo via HTTP +func HandlerMeuCumprimento(w http.ResponseWriter, r *http.Request) { + Cumprimenta(w, "mundo") +} + +func main() { + err := http.ListenAndServe(":5000", http.HandlerFunc(HandlerMeuCumprimento)) + + if err != nil { + fmt.Println(err) + } +} diff --git a/injecao-de-dependencia/v2/id_test.go b/injecao-de-dependencia/v2/id_test.go new file mode 100644 index 00000000..d51e6350 --- /dev/null +++ b/injecao-de-dependencia/v2/id_test.go @@ -0,0 +1,18 @@ +package main + +import ( + "bytes" + "testing" +) + +func TestCumprimenta(t *testing.T) { + buffer := bytes.Buffer{} + Cumprimenta(&buffer, "Chris") + + resultado := buffer.String() + esperado := "Olá, Chris" + + if resultado != esperado { + t.Errorf("resultado '%s', esperado '%s'", resultado, esperado) + } +} diff --git a/primeiros-passos-com-go/injecao-de-dependencia.md b/primeiros-passos-com-go/injecao-de-dependencia.md index d8cc65e3..e369881d 100644 --- a/primeiros-passos-com-go/injecao-de-dependencia.md +++ b/primeiros-passos-com-go/injecao-de-dependencia.md @@ -181,36 +181,40 @@ import ( "net/http" ) -func Greet(writer io.Writer, name string) { - fmt.Fprintf(writer, "Hello, %s", name) +func Cumprimenta(escritor io.Writer, nome string) { + fmt.Fprintf(escritor, "Olá, %s", nome) } -func MyGreeterHandler(w http.ResponseWriter, r *http.Request) { - Greet(w, "world") +func HandlerMeuCumprimento(w http.ResponseWriter, r *http.Request) { + Cumprimenta(w, "mundo") } func main() { - http.ListenAndServe(":5000", http.HandlerFunc(MyGreeterHandler)) + err := http.ListenAndServe(":5000", http.HandlerFunc(HandlerMeuCumprimento)) + + if err != nil { + fmt.Println(err) + } } ``` -Run the program and go to [http://localhost:5000](http://localhost:5000). You'll see your greeting function being used. +Execute o programa e vá para [http://localhost:5000](http://localhost:5000). Você erá sua função de cumprimento ser utilizada. -HTTP servers will be covered in a later chapter so don't worry too much about the details. +Falaremos sobre servidores HTTP em um próximo capítulo, então não se preocupe muito com os detalhes. -When you write an HTTP handler, you are given an `http.ResponseWriter` and the `http.Request` that was used to make the request. When you implement your server you _write_ your response using the writer. +Quando se cria um handler HTTP, você recebe um `http.ResponseWriter` e o `http.Request` que é usado para fazer a requisição. Quando implementa seu servidor, você _escreve_ sua resposta usando o escritor. -You can probably guess that `http.ResponseWriter` also implements `io.Writer` so this is why we could re-use our `Greet` function inside our handler. +Você deve ter adivinhado que o `http.ResponseWriter` também implementa o `io.Writer` e é por isso que podemos reutilizar nossa função `Cumprimenta` dentro do nosso handler. ## Resumo -Our first round of code was not easy to test because it wrote data to somewhere we couldn't control. +Nossa primeira rodada de código não foi fácil de testar porque escrevemos dados em algum lugar que não podíamos controlar. -_Motivated by our tests_ we refactored the code so we could control _where_ the data was written by **injecting a dependency** which allowed us to: +_Graças aos nossos testes_, refatoramos o código para que pudéssemos controlar para _onde_ os dados eram escritos **injetando uma dependência** que nos permitiu: -- **Test our code** If you can't test a function _easily_, it's usually because of dependencies hard-wired into a function _or_ global state. If you have a global database connection pool for instance that is used by some kind of service layer, it is likely going to be difficult to test and they will be slow to run. DI will motivate you to inject in a database dependency \(via an interface\) which you can then mock out with something you can control in your tests. -- **Separate our concerns**, decoupling _where the data goes_ from _how to generate it_. If you ever feel like a method/function has too many responsibilities \(generating data _and_ writing to a db? handling HTTP requests _and_ doing domain level logic?\) DI is probably going to be the tool you need. -- **Allow our code to be re-used in different contexts** The first "new" context our code can be used in is inside tests. But further on if someone wants to try something new with your function they can inject their own dependencies. +- **Testar nosso código**: se você não consegue testar uma função _de forma simples_, geralmente é porque dependências estão acopladas em uma função _ou_ estado global. Se você tem um pool de conexão global da base de dados, por exemplo, é provável que seja difícil testar e vai ser lento para ser execudado. A injeção de dependência te motiva a injetar em uma dependência da base de dados (através de uma interface), para que você possa criar um mock com algo que você possa controlar nos seus testes. +- _Separar nossas preocupações_, desacoplando _onde os dados vão_ de _como gerá-los_. Se você já achou que um método/função tem responsabilidades demais (gerando dados _e_ escrevendo na base de dados? Lidando com requisições HTTP _e_ aplicando lógica a nível de domínio?), a injeção de dependência provavelmente será a ferramenta que você precisa. +- **Permitir que nosso código seja reutilizado em contextos diferentes**: o primeiro contexto "novo" do nosso código pode ser usado dentro dos testes. No entanto, se alguém quiser testar algo novo com nossa função, a pessoa pode injetar suas próprias dependências. ### What about mocking? I hear you need that for DI and also it's evil From 7bc03e010940564724a4addf0e6e8d9bd4844d2f Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Wed, 31 Jul 2019 20:55:15 -0300 Subject: [PATCH 3/5] =?UTF-8?q?Termino=20de=20tradu=C3=A7=C3=A3o=20de=20ID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- injecao-de-dependencia/v2/id.go | 6 +++--- primeiros-passos-com-go/injecao-de-dependencia.md | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/injecao-de-dependencia/v2/id.go b/injecao-de-dependencia/v2/id.go index d4c337e8..50cda263 100644 --- a/injecao-de-dependencia/v2/id.go +++ b/injecao-de-dependencia/v2/id.go @@ -11,13 +11,13 @@ func Cumprimenta(escritor io.Writer, nome string) { fmt.Fprintf(escritor, "Olá, %s", nome) } -// HandlerMeuCumprimento diz Olá, mundo via HTTP -func HandlerMeuCumprimento(w http.ResponseWriter, r *http.Request) { +// ManipuladorMeuCumprimento diz Olá, mundo via HTTP +func ManipuladorMeuCumprimento(w http.ResponseWriter, r *http.Request) { Cumprimenta(w, "mundo") } func main() { - err := http.ListenAndServe(":5000", http.HandlerFunc(HandlerMeuCumprimento)) + err := http.ListenAndServe(":5000", http.HandlerFunc(ManipuladorMeuCumprimento)) if err != nil { fmt.Println(err) diff --git a/primeiros-passos-com-go/injecao-de-dependencia.md b/primeiros-passos-com-go/injecao-de-dependencia.md index e369881d..f0310162 100644 --- a/primeiros-passos-com-go/injecao-de-dependencia.md +++ b/primeiros-passos-com-go/injecao-de-dependencia.md @@ -216,14 +216,14 @@ _Graças aos nossos testes_, refatoramos o código para que pudéssemos controla - _Separar nossas preocupações_, desacoplando _onde os dados vão_ de _como gerá-los_. Se você já achou que um método/função tem responsabilidades demais (gerando dados _e_ escrevendo na base de dados? Lidando com requisições HTTP _e_ aplicando lógica a nível de domínio?), a injeção de dependência provavelmente será a ferramenta que você precisa. - **Permitir que nosso código seja reutilizado em contextos diferentes**: o primeiro contexto "novo" do nosso código pode ser usado dentro dos testes. No entanto, se alguém quiser testar algo novo com nossa função, a pessoa pode injetar suas próprias dependências. -### What about mocking? I hear you need that for DI and also it's evil +### Mas e o mock? Ouvi falar que precisa disso para trabalhar com injeção de dependência e que também é do demonho -Mocking will be covered in detail later \(and it's not evil\). You use mocking to replace real things you inject with a pretend version that you can control and inspect in your tests. In our case though, the standard library had something ready for us to use. +Vamos falar mais sobre mocks depois (e não é do demonho). Você mocka para substituir coisas reais que você injeta com uma versão falsa que você pode controlar e examinar nos seus testes. No entanto, no nosso caso a biblioteca padrão já tinha algo pronto para usarmos. -### The Go standard library is really good, take time to study it +### A biblioteca padrão do Go é muito boa, leve um tempo para estudá-la -By having some familiarity with the `io.Writer` interface we are able to use `bytes.Buffer` in our test as our `Writer` and then we can use other `Writer`s from the standard library to use our function in a command line app or in web server. +Ao termos familiaridade com a interface `io.Writer`, somos capazes de usar `bytes.Buffer` no nosso teste como nosso `Writer` para que depois possamos usar outros `Writer` da biblioteca padrão para usar na nossa função em uma aplicação de linha de comando ou em um servidor web. -The more familiar you are with the standard library the more you'll see these general purpose interfaces which you can then re-use in your own code to make your software reusable in a number of contexts. +Quanto mais familiar você for com a biblioteca padrão, mais vai ver essas interfaces de propósito geral que você pode reutilizar no seu próprio código para tornar o software reutilizável em vários contextos diferentes. -This example is heavily influenced by a chapter in [The Go Programming language](https://www.amazon.co.uk/Programming-Language-Addison-Wesley-Professional-Computing/dp/0134190440), so if you enjoyed this, go buy it! +Esse exemplo teve grande influência de um capítulo de [A Linguagem de Programação Go](https://www.amazon.com.br/dp/8575225464/ref=cm_sw_r_tw_dp_U_x_0HIqDbYP7VSN5). Logo, se gostou, vá adquiri-lo! \ No newline at end of file From 2f35d4ad0bb493197b8ceb32c0cf0c4413b06201 Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Wed, 31 Jul 2019 20:57:44 -0300 Subject: [PATCH 4/5] =?UTF-8?q?Atualiza=C3=A7=C3=A3o=20de=20refer=C3=AAnci?= =?UTF-8?q?as?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.books.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.books.sh b/build.books.sh index 16819d0e..48f9b92a 100755 --- a/build.books.sh +++ b/build.books.sh @@ -13,7 +13,7 @@ docker run -v `pwd`:/source jagregory/pandoc -o aprenda-go-com-testes.pdf --late primeiros-passos-com-go/structs-methods-and-interfaces.md \ primeiros-passos-com-go/pointers-and-errors.md \ primeiros-passos-com-go/maps.md \ - primeiros-passos-com-go/dependency-injection.md \ + primeiros-passos-com-go/injecao-de-dependencia.md \ primeiros-passos-com-go/mocking.md \ primeiros-passos-com-go/concurrency.md \ primeiros-passos-com-go/select.md \ @@ -41,7 +41,7 @@ docker run -v `pwd`:/source jagregory/pandoc -o aprenda-go-com-testes.epub --lat primeiros-passos-com-go/structs-methods-and-interfaces.md \ primeiros-passos-com-go/pointers-and-errors.md \ primeiros-passos-com-go/maps.md \ - primeiros-passos-com-go/dependency-injection.md \ + primeiros-passos-com-go/injecao-de-dependencia.md \ primeiros-passos-com-go/mocking.md \ primeiros-passos-com-go/concurrency.md \ primeiros-passos-com-go/select.md \ From d371a972ea5cf416405f6d74c589990ec54dc69b Mon Sep 17 00:00:00 2001 From: Lauren Ferreira Date: Wed, 7 Aug 2019 18:16:14 -0300 Subject: [PATCH 5/5] Text review fixes --- primeiros-passos-com-go/injecao-de-dependencia.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/primeiros-passos-com-go/injecao-de-dependencia.md b/primeiros-passos-com-go/injecao-de-dependencia.md index f0310162..40f28ff2 100644 --- a/primeiros-passos-com-go/injecao-de-dependencia.md +++ b/primeiros-passos-com-go/injecao-de-dependencia.md @@ -2,14 +2,14 @@ [**Você pode encontrar todos os códigos para esse capítulo aqui**](https://github.com/larien/learn-go-with-tests/tree/master/injecao-de-dependencia) -Presume-se que você tenha lido a seção de `structs` antes, já que será necessário saber um pouco sobre interfaces para entender esse capítulo. +Presume-se que você tenha lido a seção de `structs` antes, já que será necessário saber um pouco sobre interfaces para entender este capítulo. Há muitos mal entendidos relacionados à injeção de dependência na comunidade de programação. Se tudo der certo, esse guia vai te mostrar que: - Você não precisa de uma framework - Não torna seu design complexo demais - Facilita seus testes -- Permite que você escreva funções ótimas para própósitos diversos. +- Permite que você escreva funções ótimas para propósitos diversos. Queremos criar uma função que cumprimenta alguém, assim como a que fizemos no capítulo [Olá, mundo](https://github.com/larien/learn-go-with-tests/tree/master/hello-world), mas dessa vez vamos testar o _print de verdade_. @@ -198,7 +198,7 @@ func main() { } ``` -Execute o programa e vá para [http://localhost:5000](http://localhost:5000). Você erá sua função de cumprimento ser utilizada. +Execute o programa e vá para [http://localhost:5000](http://localhost:5000). Você verá sua função de cumprimento ser utilizada. Falaremos sobre servidores HTTP em um próximo capítulo, então não se preocupe muito com os detalhes. @@ -226,4 +226,4 @@ Ao termos familiaridade com a interface `io.Writer`, somos capazes de usar `byte Quanto mais familiar você for com a biblioteca padrão, mais vai ver essas interfaces de propósito geral que você pode reutilizar no seu próprio código para tornar o software reutilizável em vários contextos diferentes. -Esse exemplo teve grande influência de um capítulo de [A Linguagem de Programação Go](https://www.amazon.com.br/dp/8575225464/ref=cm_sw_r_tw_dp_U_x_0HIqDbYP7VSN5). Logo, se gostou, vá adquiri-lo! \ No newline at end of file +Esse exemplo teve grande influência de um capítulo de [A Linguagem de Programação Go](https://www.amazon.com.br/dp/8575225464/ref=cm_sw_r_tw_dp_U_x_0HIqDbYP7VSN5). Logo, se gostou, vá adquiri-lo!