diff --git a/README.md b/README.md index 49dce7c9..5de81b74 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ 1. [Instalação do Go](primeiros-passos-com-go/instalacao-do-go.md) - Prepare o ambiente para produtividade. 2. [Olá, mundo](primeiros-passos-com-go/hello-world.md) - Declarando variáveis, constantes, declarações `if`/`else`, switch, escreva seu primeiro programa em Go e seu primeiro teste. Sintaxe de subteste e closures. 3. [Inteiros](primeiros-passos-com-go/integers.md) - Mais conteúdo sobre sintaxe de declaração de função e aprenda novas formas de melhorar a documentação do seu código. -4. [Iteração](primeiros-passos-com-go/iteration.md) - Aprenda sobre `for` e benchmarking. +4. [Iteração](primeiros-passos-com-go/iteracao.md) - Aprenda sobre `for` e benchmarking. 5. [Arrays e slices](primeiros-passos-com-go/arrays-and-slices.md) - Aprenda sobre arrays, slices, `len`, varargs, `range` e cobertura de testes. 6. [Estruturas, métodos e interfaces](primeiros-passos-com-go/structs-methods-and-interfaces.md) - Aprenda sobre `structs`, métodos, `interface` e testes orientados a tabela \(table driven tests\). 7. [Ponteiros e erros](primeiros-passos-com-go/pointers-and-errors.md) - Aprenda sobre ponteiros e erros. diff --git a/SUMMARY.md b/SUMMARY.md index 77e9ad3f..cfcd9a7d 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,4 +1,4 @@ -# Table of contents +# Índice - [Introdução](README.md) - [Aprenda Go com Testes](gb-readme.md) @@ -8,7 +8,7 @@ - [Instalação do Go](primeiros-passos-com-go/instalacao-do-go.md) - [Olá, mundo](primeiros-passos-com-go/hello-world.md) - [Inteiros](primeiros-passos-com-go/integers.md) -- [Iteração](primeiros-passos-com-go/iteration.md) +- [Iteração](primeiros-passos-com-go/iteracao.md) - [Arrays e slices](primeiros-passos-com-go/arrays-and-slices.md) - [Structs, métodos e interfaces](primeiros-passos-com-go/structs-methods-and-interfaces.md) - [Ponteiros e erros](primeiros-passos-com-go/pointers-and-errors.md) diff --git a/build.books.sh b/build.books.sh index 2382d438..9e40ed9f 100755 --- a/build.books.sh +++ b/build.books.sh @@ -8,6 +8,7 @@ docker run -v `pwd`:/source jagregory/pandoc -o aprenda-go-com-testes.pdf --late primeiros-passos-com-go/instalacao-do-go.md \ primeiros-passos-com-go/hello-world.md \ primeiros-passos-com-go/integers.md \ + primeiros-passos-com-go/iteracao.md \ primeiros-passos-com-go/arrays-and-slices.md \ primeiros-passos-com-go/structs-methods-and-interfaces.md \ primeiros-passos-com-go/pointers-and-errors.md \ @@ -35,6 +36,7 @@ docker run -v `pwd`:/source jagregory/pandoc -o aprenda-go-com-testes.epub --lat primeiros-passos-com-go/instalacao-do-go.md \ primeiros-passos-com-go/hello-world.md \ primeiros-passos-com-go/integers.md \ + primeiros-passos-com-go/iteracao.md \ primeiros-passos-com-go/arrays-and-slices.md \ primeiros-passos-com-go/structs-methods-and-interfaces.md \ primeiros-passos-com-go/pointers-and-errors.md \ diff --git a/for/v1/repeat.go b/for/v1/repeat.go index 5971d210..b1793104 100644 --- a/for/v1/repeat.go +++ b/for/v1/repeat.go @@ -1,6 +1,6 @@ package iteration -// Repeat returns character repeated 5 times +// Repeat retorna o caracter repetido 5 vezes func Repeat(character string) string { var repeated string for i := 0; i < 5; i++ { diff --git a/for/v2/repeat.go b/for/v2/repeat.go index fd554a1b..463be4ca 100644 --- a/for/v2/repeat.go +++ b/for/v2/repeat.go @@ -2,7 +2,7 @@ package iteration const repeatCount = 5 -// Repeat returns character repeated 5 times +// Repeat retorna o caracter repetido 5 vezes func Repeat(character string) string { var repeated string for i := 0; i < repeatCount; i++ { diff --git a/for/vx/repeat.go b/for/vx/repeat.go index fd554a1b..463be4ca 100644 --- a/for/vx/repeat.go +++ b/for/vx/repeat.go @@ -2,7 +2,7 @@ package iteration const repeatCount = 5 -// Repeat returns character repeated 5 times +// Repeat retorna o caracter repetido 5 vezes func Repeat(character string) string { var repeated string for i := 0; i < repeatCount; i++ { diff --git a/primeiros-passos-com-go/arrays-and-slices.md b/primeiros-passos-com-go/arrays-and-slices.md index 94933c85..db1a1f2f 100644 --- a/primeiros-passos-com-go/arrays-and-slices.md +++ b/primeiros-passos-com-go/arrays-and-slices.md @@ -4,7 +4,7 @@ Arrays allow you to store multiple elements of the same type in a variable in a particular order. -When you have an array, it is very common to have to iterate over them. So let's use [our new-found knowledge of `for`](iteration.md) to make a `Sum` function. `Sum` will take an array of numbers and return the total. +When you have an array, it is very common to have to iterate over them. So let's use [our new-found knowledge of `for`](iteracao.md) to make a `Sum` function. `Sum` will take an array of numbers and return the total. Let's use our TDD skills @@ -32,8 +32,8 @@ func TestSum(t *testing.T) { Arrays have a _fixed capacity_ which you define when you declare the variable. We can initialize an array in two ways: -* \[N\]type{value1, value2, ..., valueN} e.g. `numbers := [5]int{1, 2, 3, 4, 5}` -* \[...\]type{value1, value2, ..., valueN} e.g. `numbers := [...]int{1, 2, 3, 4, 5}` +- \[N\]type{value1, value2, ..., valueN} e.g. `numbers := [5]int{1, 2, 3, 4, 5}` +- \[...\]type{value1, value2, ..., valueN} e.g. `numbers := [...]int{1, 2, 3, 4, 5}` It is sometimes useful to also print the inputs to the function in the error message and we are using the `%v` placeholder which is the "default" format, which works well for arrays. @@ -143,13 +143,13 @@ This does not compile The problem here is we can either -* Break the existing API by changing the argument to `Sum` to be a slice rather +- Break the existing API by changing the argument to `Sum` to be a slice rather - than an array. When we do this we will know we have potentially ruined + than an array. When we do this we will know we have potentially ruined - someone's day because our _other_ test will not compile! + someone's day because our _other_ test will not compile! -* Create a new function +- Create a new function In our case, no-one else is using our function so rather than having two functions to maintain let's just have one. @@ -486,21 +486,22 @@ $ go test We have covered -* Arrays -* Slices - * The various ways to make them - * How they have a _fixed_ capacity but you can create new slices from old ones +- Arrays +- Slices - using `append` + - The various ways to make them + - How they have a _fixed_ capacity but you can create new slices from old ones - * How to slice, slices! -* `len` to get the length of an array or slice -* Test coverage tool -* `reflect.DeepEqual` and why it's useful but can reduce the type-safety of your code + using `append` + + - How to slice, slices! + +- `len` to get the length of an array or slice +- Test coverage tool +- `reflect.DeepEqual` and why it's useful but can reduce the type-safety of your code We've used slices and arrays with integers but they work with any other type too, including arrays/slices themselves. So you can declare a variable of `[][]string` if you need to. [Check out the Go blog post on slices](https://blog.golang.org/go-slices-usage-and-internals) for an in-depth look into slices. Try writing more tests to demonstrate what you learn from reading it. Another handy way to experiment with Go other than writing tests is the Go playground. You can try most things out and you can easily share your code if you need to ask questions. [I have made a go playground with a slice in it for you to experiment with.](https://play.golang.org/p/ICCWcRGIO68) - diff --git a/primeiros-passos-com-go/iteracao.md b/primeiros-passos-com-go/iteracao.md new file mode 100644 index 00000000..0cdcd093 --- /dev/null +++ b/primeiros-passos-com-go/iteracao.md @@ -0,0 +1,132 @@ +# Iteração + +**[Você pode encontrar todo o código desse capítulo aqui](https://github.com/larien/learn-go-with-tests/tree/master/for)** + +Para fazer coisas repetidamente em Go, você precisará do `for`. Go não possui nenhuma palavra chave do tipo `while`, `do` ou `until`. Você pode usar apenas `for`, o que é uma coisa boa! + +Vamos escrever um teste para uma função que repete um caractere 5 vezes. + +Não há nenhuma novidade até aqui, então tente escrever você mesmo para praticar. + +## Escreva o teste primeiro + +```go +package iteration + +import "testing" + +func TestRepeat(t *testing.T) { + repeated := Repeat("a") + expected := "aaaaa" + + if repeated != expected { + t.Errorf("expected '%s' but got '%s'", expected, repeated) + } +} +``` + +## Execute o teste + +`./repeat_test.go:6:14: undefined: Repeat` + +## Escreva a quantidade mínima de código para o teste rodar e verifique o erro na saída + +_Mantenha a disciplina!_ Você não precisa saber nada de diferente agora para fazer o teste falhar apropriadamente. + +Tudo o que foi feito até agora é o suficiente para compilar, para que você possa verificar se escreveu o teste corretamente. + +```go +package iteration + +func Repeat(character string) string { + return "" +} +``` + +Não é legal saber que você já conhece o bastante em Go para escrever testes para problemas simples? Isso significa que agora você pode mexer no código de produção o quanto quiser sabendo que ele se comportará da maneira que você desejar. + +`repeat_test.go:10: expected 'aaaaa' but got ''` + +## Escreva código o suficiente para fazer o teste passar + +A sintaxe do `for` é muito fácil de lembrar e segue a maioria das linguagens baseadas em `C`: + +```go +func Repeat(character string) string { + var repeated string + for i := 0; i < 5; i++ { + repeated = repeated + character + } + return repeated +} +``` + +Ao contrário de outras linguagens como `C`, `Java` ou `Javascript`, não há parênteses ao redor dos três componentes do `for`. No entanto, as chaves `{ }` são obrigatórias. + +Execute o teste e ele deverá passar. + +Variações adicionais do loop `for` podem ser vistas [aqui](https://gobyexample.com/for). + +## Refatoração + +Agora é hora de refatorarmos e apresentarmos outro operador de atribuição: o `+=`. + +```go +const repeatCount = 5 + +func Repeat(character string) string { + var repeated string + for i := 0; i < repeatCount; i++ { + repeated += character + } + return repeated +} +``` + +O operador adicionar & atribuir `+=` adiciona o valor que está à direita no valor que esta à esquerda e atribui o resultado ao valor da esquerda. Também funciona com outros tipos, como por exemplo, inteiros (`integer`). + +### Benchmarking + +Escrever [benchmarks](https://golang.org/pkg/testing/#hdr-Benchmarks) em Go é outro recurso disponível nativamente na linguagem e é tão facil quanto escrever testes. + +```go +func BenchmarkRepeat(b *testing.B) { + for i := 0; i < b.N; i++ { + Repeat("a") + } +} +``` + +Você notará que o código é muito parecido com um teste. + +O `testing.B` dará a você acesso a `b.N`. + +Quando o benchmark é rodado, ele executa `b.N` vezes e mede quanto tempo leva. + +A quantidade de vezes que o código é executado não deve importar para você. O framework irá determinar qual valor é "bom" para que você consiga ter resultados decentes. + +Para executar o benchmark, digite `go test -bench=.` no terminal (ou se estiver executando do PowerShell do Windows, `go test-bench="."`) + +```bash +goos: darwin +goarch: amd64 +pkg: github.com/quii/learn-go-with-tests/for/v4 +10000000 136 ns/op +PASS +``` + +`136 ns/op` significa que nossa função demora cerca de 136 nanossegundos para ser executada (no meu computador). E isso é ótimo! Para chegar a esse resultado ela foi executada 10000000 (10 milhões de vezes) vezes. + +_NOTA_ por padrão, o benchmark é executado sequencialmente. + +## Exercícios para praticar + +- Altere o teste para que a função possa especificar quantas vezes o caractere deve ser repetido e então corrija o código para passar no teste. +- Escreva `ExampleRepeat` para documentar sua função. +- Veja também o pacote [strings](https://golang.org/pkg/strings). Encontre funções que você considera serem úteis e experimente-as escrevendo testes como fizemos aqui. Investir tempo aprendendo a biblioteca padrão irá te recompensar com o tempo. + +## Resumindo + +- Mais praticás de TDD +- Aprendemos o `for` +- Aprendemos como escrever benchmarks diff --git a/primeiros-passos-com-go/iteration.md b/primeiros-passos-com-go/iteration.md deleted file mode 100644 index 4f582c76..00000000 --- a/primeiros-passos-com-go/iteration.md +++ /dev/null @@ -1,133 +0,0 @@ -# Iteração - -[**You can find all the code for this chapter here**](https://github.com/quii/learn-go-with-tests/tree/master/for) - -To do stuff repeatedly in Go, you'll need `for`. In Go there are no `while`, `do`, `until` keywords, you can only use `for`. Which is a good thing! - -Let's write a test for a function that repeats a character 5 times. - -There's nothing new so far, so try and write it yourself for practice. - -## Write the test first - -```go -package iteration - -import "testing" - -func TestRepeat(t *testing.T) { - repeated := Repeat("a") - expected := "aaaaa" - - if repeated != expected { - t.Errorf("expected '%s' but got '%s'", expected, repeated) - } -} -``` - -## Try and run the test - -`./repeat_test.go:6:14: undefined: Repeat` - -## Write the minimal amount of code for the test to run and check the failing test output - -_Keep the discipline!_ You don't need to know anything new right now to make the test fail properly. - -All you need to do right now is enough to make it compile so you can check your test is written well. - -```go -package iteration - -func Repeat(character string) string { - return "" -} -``` - -Isn't it nice to know you already know enough Go to write tests for some basic problems? This means you can now play with the production code as much as you like and know it's behaving as you'd hope. - -`repeat_test.go:10: expected 'aaaaa' but got ''` - -## Write enough code to make it pass - -The `for` syntax is very unremarkable and follows most C-like languages. - -```go -func Repeat(character string) string { - var repeated string - for i := 0; i < 5; i++ { - repeated = repeated + character - } - return repeated -} -``` - -Unlike other languages like C, Java, or JavaScript there are no parentheses surrounding the three components of the for statement and the braces { } are always required. - -Run the test and it should pass. - -Additional variants of the for loop are described [here](https://gobyexample.com/for). - -## Refactor - -Now it's time to refactor and introduce another construct `+=` assignment operator. - -```go -const repeatCount = 5 - -func Repeat(character string) string { - var repeated string - for i := 0; i < repeatCount; i++ { - repeated += character - } - return repeated -} -``` - -`+=` the Add AND assignment operator, adds the right operand to the left operand and assigns the result to left operand. It works with other types like integers. - -### Benchmarking - -Writing [benchmarks](https://golang.org/pkg/testing/#hdr-Benchmarks) in Go is another first-class feature of the language and it is very similar to writing tests. - -```go -func BenchmarkRepeat(b *testing.B) { - for i := 0; i < b.N; i++ { - Repeat("a") - } -} -``` - -You'll see the code is very similar to a test. - -The `testing.B` gives you access to the cryptically named `b.N`. - -When the benchmark code is executed, it runs `b.N` times and measures how long it takes. - -The amount of times the code is run shouldn't matter to you, the framework will determine what is a "good" value for that to let you have some decent results. - -To run the benchmarks do `go test -bench=.` \(or if you're in Windows Powershell `go test -bench="."`\) - -```text -goos: darwin -goarch: amd64 -pkg: github.com/quii/learn-go-with-tests/for/v4 -10000000 136 ns/op -PASS -``` - -What `136 ns/op` means is our function takes on average 136 nanoseconds to run \(on my computer\). Which is pretty ok! To test this it ran it 10000000 times. - -_NOTE_ by default Benchmarks are run sequentially. - -## Practice exercises - -* Change the test so a caller can specify how many times the character is repeated and then fix the code -* Write `ExampleRepeat` to document your function -* Have a look through the [the strings](https://golang.org/pkg/strings) package. Find functions you think could be useful and experiment with them by writing tests like we have here. Investing time learning the standard library will really pay off over time. - -## Wrapping up - -* More TDD practice -* Learned `for` -* Learned how to write benchmarks -