From 748a65b37921456811a1c851eb243a41020735b9 Mon Sep 17 00:00:00 2001 From: litleleprikon Date: Thu, 5 Mar 2020 22:34:53 +0300 Subject: [PATCH] feat(l5): Add lesson 5 slides --- l5/Lesson5.slide | 164 +++++++++ l5/img/qrcode-6.svg | 425 ++++++++++++++++++++++++ l5/src/packages/first/main.go | 13 + l5/src/packages/first/math/math.go | 10 + l5/src/packages/first/math/math_test.go | 64 ++++ 5 files changed, 676 insertions(+) create mode 100644 l5/Lesson5.slide create mode 100644 l5/img/qrcode-6.svg create mode 100644 l5/src/packages/first/main.go create mode 100644 l5/src/packages/first/math/math.go create mode 100644 l5/src/packages/first/math/math_test.go diff --git a/l5/Lesson5.slide b/l5/Lesson5.slide new file mode 100644 index 0000000..57f178b --- /dev/null +++ b/l5/Lesson5.slide @@ -0,0 +1,164 @@ +Go Beginners Innopolis +Занятие 5: Пакеты и повторное использование кода, Тестирование +5 Mar 2020 +Tags: go, innopolis + +Emil Sharifullin +Senior Software Engineer, SKB Kontur +iam@litleleprikon.me +@litleleprikon + +* В прошлых сериях + +- Как получить значение поля экземпляра структуры? +- Как создать функцию, которая будет методом структуры? +- Что такое получатель метода? +- В чем разнича получателя по значению и получателя по указателю? +- Что такое встраивание типов? +- Что такое интерфейс? +- Как создать горутину? +- Что такое канал? +- Что делает оператор select? + +* Пакеты и повторное использование кода + +* Пакеты и повторное использование кода + +*DRY* — «Don't Repeat Yourself» — (акроним, в переводе с английского) — «не повторяйтесь!». + +Go поддерживает ещё один механизм для повторного использования кода, кроме функций — пакеты. + + import "fmt" + +Пакеты удобны, потому что позволяют: + +- Снизить вероятность дублирование имён функций, что позволяет именам быть простыми и краткими +- Организовывать код для упрощения поиска повторно используемых конструкций +- Ускорить компиляцию, так как мы должны перекомпилировать только части программы. Несмотря на то, что мы используем пакет fmt, мы не должны перекомпилировать его при каждом использовании + +* Создание пакета + +.code src/packages/first/math/math.go HL01 + +.play src/packages/first/main.go HL01 + +* Создание пакета +*math* является встроенным пакетом, но так как пакеты Go используют иерархические наименование, мы можем перекрыть уже используемое наименование, в данном случае настоящий пакет *math* и будет называться *math*, а наш — *github.com/GDG-Cloud-Innopolis/Go-begginners/l5/src/packages/first/math*. + +Когда мы импортируем библиотеку, мы используем её полное наименование import *"github.com/GDG-Cloud-Innopolis/Go-begginners/l5/src/packages/first/math"*, но внутри файла main.go мы используем только последнюю часть названия — *package* *math*. + +Мы используем только краткое имя math когда мы обращаемся к функциям в нашем пакете. Если же мы хотим использовать оба пакета, то мы можем использовать псевдоним: + + import m "golang-book/chapter11/math" + +* Доступ к сущностям в пакете + +Возможно вы заметили, что каждая функция в пакете начинается с заглавной буквы. Любая сущность языка Go, которая начинается с заглавной буквы, означает, что другие пакеты и программы могут использовать эту сущность. Если бы мы назвали нашу функцию average, а не Average, то наша главная программа не смогла бы обратиться к ней. + +Рекомендуется делать явными только те сущности нашего пакета, которые могут быть использованы другими пакетами, и прятать все остальные служебные функции, не используемые в других пакетах. Данный подход позволяет производить изменения в скрытых частях пакета без риска нарушить работу других программ, и это облегчает использование нашего пакета + +Имена пакетов совпадают с директориями, в которых они размещены. Данное правило можно обойти, но делать это нежелательно. + +* Работа с пакетами + +Изначально пакеты скачивались из любого гит репозитория из ветки master + +Делаем *go* *get* - скачивается свежий код из мастера подключаемого пакета + +Легко и просто работать с пакетами, так же легко сломать билд новой версией пакета + +Пакеты скачавались в *$GOPATH* и проекты можно было запускать только внутри *$GOPATH* + +Фиксируем исходники всех зависимостей в папке vendor или используем сторонний тулинг для управления зависимостями + +* Модули + +Были представлены в 2018 году и поддерживают версионирование + + $ go mod init github.com/GDG-Cloud-Innopolis + +Модуля должен быть файл *go.mod*, в котором содержится описание модуля и также его зависимости + +.code ../go.mod + + $ git tag v1.0.0 + $ git push --tags + +При изменении мажорной версии пакета, он получает новое имя, к примеру: + + github.com/googleapis/gax-go @ master branch + /go.mod → module github.com/googleapis/gax-go + /v2/go.mod → module github.com/googleapis/gax-go/v2 + +* Документация к коду + +Go позволяет автоматически создавать документацию к пользовательским пакетам так же, как и документировать стандартные пакеты. Запустите эту команду в терминале: + + $ go doc github.com/GDG-Cloud-Innopolis/Go-begginners/l5/src/packages/first/math Average + +И получим такой вот ответ + + package math // import "github.com/GDG-Cloud-Innopolis/Go-begginners/l5/src/packages/first/math" + + func Average(xs []float64) float64 + Average is a function that count average between numbers + +.link https://pkg.go.dev/github.com/GDG-Cloud-Innopolis/Go-begginners@v1.4.0 + +* Тестирование + +* Тестирование + +Писать программы — не просто. Даже самые лучшие программисты, зачастую, не в состоянии написать программу так, чтобы она работала как положено в любых случаях. Поэтому, важной частью процесса разработки является тестирование. Написание тестов для нашего кода является отличным способом повышения его качества и стабильности. + +Go содержит специальные инструменты, призванные облегчить написание тестов, так что давайте напишем несколько тестов для пакета, который мы создали в предыдущей главе. В папке создайте файл под именем math_test.go, который будет содержать следующее: + +* Тестирование + +.code src/packages/first/math/math_test.go /START ONE /,/END ONE/ + + $ go test + === RUN TestAverage + --- PASS: TestAverage (0.00s) + PASS + ok github.com/GDG-Cloud-Innopolis/Go-begginners/l5/src/packages/first/math 0.101s + +* Тестирование + +.code src/packages/first/math/math_test.go /START TWO /,/END TWO/ + +* Тестирование + +.code src/packages/first/math/math_test.go /END TWO /,/END THREE/ + + go test -v + === RUN TestAverage + --- PASS: TestAverage (0.00s) + === RUN TestAverage1 + === RUN TestAverage1/Two_numbers + === RUN TestAverage1/Equal_numbers + --- PASS: TestAverage1 (0.00s) + --- PASS: TestAverage1/Two_numbers (0.00s) + --- PASS: TestAverage1/Equal_numbers (0.00s) + PASS + ok github.com/GDG-Cloud-Innopolis/Go-begginners/l5/src/packages/first/math 0.473s + +* Бенчмарки + +.code src/packages/first/math/math_test.go /START FOUR /,/END FOUR/ + + go test -bench=. + goos: darwin + goarch: amd64 + pkg: github.com/GDG-Cloud-Innopolis/Go-begginners/l5/src/packages/first/math + BenchmarkAverage10-8 100000000 10.5 ns/op + PASS + ok github.com/GDG-Cloud-Innopolis/Go-begginners/l5/src/packages/first/math 1.523s + +* Задачка + +Вынести функцию Calc из третьего урока в Модуль(https://play.golang.org/p/G6YMZMHnotU). Покрыть модуль тестами и написать документацию. Написать в Go Playground программу, которая использует вашу функцию + +.link https://play.golang.org/p/_6SP-Dj79fY + +.image img/qrcode-6.svg 300 _ diff --git a/l5/img/qrcode-6.svg b/l5/img/qrcode-6.svg new file mode 100644 index 0000000..81bff97 --- /dev/null +++ b/l5/img/qrcode-6.svg @@ -0,0 +1,425 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/l5/src/packages/first/main.go b/l5/src/packages/first/main.go new file mode 100644 index 0000000..2650e1d --- /dev/null +++ b/l5/src/packages/first/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "fmt" + + "github.com/GDG-Cloud-Innopolis/Go-begginners/l5/src/packages/first/math" // HL01 +) + +func main() { + xs := []float64{1, 2, 3, 4} + avg := math.Average(xs) + fmt.Println(avg) +} diff --git a/l5/src/packages/first/math/math.go b/l5/src/packages/first/math/math.go new file mode 100644 index 0000000..c00c82e --- /dev/null +++ b/l5/src/packages/first/math/math.go @@ -0,0 +1,10 @@ +package math // HL01 + +// Average is a function that count average between numbers +func Average(xs []float64) float64 { + total := float64(0) + for _, x := range xs { + total += x + } + return total / float64(len(xs)) +} diff --git a/l5/src/packages/first/math/math_test.go b/l5/src/packages/first/math/math_test.go new file mode 100644 index 0000000..e51b750 --- /dev/null +++ b/l5/src/packages/first/math/math_test.go @@ -0,0 +1,64 @@ +//START ONE OMIT +package math + +import ( + "testing" +) + +func TestAverage(t *testing.T) { + var v float64 + v = Average([]float64{1, 2}) + if v != 1.5 { + t.Error("Expected 1.5, got ", v) + } +} + +// END ONE OMIT + +// //START TWO OMIT + +func TestAverage1(t *testing.T) { + type args struct { + xs []float64 + } + tests := []struct { + name string + args args + want float64 + }{ + { + name: "Two numbers", + args: args{ + xs: []float64{1, 2}, + }, + want: 1.5, + }, + { + name: "Equal numbers", + args: args{ + xs: []float64{1, 1, 1, 1, 1, 1}, + }, + want: 1, + }, + } + // END TWO OMIT + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := Average(tt.args.xs); got != tt.want { + t.Errorf("Average() = %v, want %v", got, tt.want) + } + }) + } +} + +// END THREE OMIT + +// START FOUR OMIT +func BenchmarkAverage10(b *testing.B) { + // run the Average function b.N times + for n := 0; n < b.N; n++ { + Average([]float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}) + } +} + +// END FOUR OMIT