summaryrefslogtreecommitdiff
path: root/content/pages/gostyleguide/google/best-practices.md
diff options
context:
space:
mode:
author2026-02-02 18:57:20 +0300
committer2026-02-02 18:57:20 +0300
commit6c4cbf8578d8a94964ca7327a7826c7c094f94fc (patch)
tree07c5dc52358b5725805a465310bbdfa1f4da82bb /content/pages/gostyleguide/google/best-practices.md
parentБольшая чистка блога (diff)
downloadblog-6c4cbf8578d8a94964ca7327a7826c7c094f94fc.tar.gz
blog-6c4cbf8578d8a94964ca7327a7826c7c094f94fc.tar.bz2
blog-6c4cbf8578d8a94964ca7327a7826c7c094f94fc.tar.xz
blog-6c4cbf8578d8a94964ca7327a7826c7c094f94fc.zip
Fix images
Diffstat (limited to 'content/pages/gostyleguide/google/best-practices.md')
-rw-r--r--content/pages/gostyleguide/google/best-practices.md863
1 files changed, 409 insertions, 454 deletions
diff --git a/content/pages/gostyleguide/google/best-practices.md b/content/pages/gostyleguide/google/best-practices.md
index 4fc59b1..f7a42c7 100644
--- a/content/pages/gostyleguide/google/best-practices.md
+++ b/content/pages/gostyleguide/google/best-practices.md
@@ -1,15 +1,12 @@
---
-order: 1
-title: Google Go Style Guide — Лучшие практики
+weight: 30
+title: Лучшие практики
---
# Лучшие практики стиля Go (Go Style Best Practices)
Оригинал: https://google.github.io/styleguide/go/best-practices
-[Обзор](https://neonxp.ru/pages/gostyleguide/google/) | [Руководство](https://neonxp.ru/pages/gostyleguide/google/guide) | [Решения](https://neonxp.ru/pages/gostyleguide/google/decisions) |
-[Лучшие практики](https://neonxp.ru/pages/gostyleguide/google/best-practices)
-
**Примечание:** Это часть серии документов, описывающих [Стиль Go (Go
Style)](https://neonxp.ru/pages/gostyleguide/google/) в Google. Данный документ **не является ни [нормативным
(normative)](https://neonxp.ru/pages/gostyleguide/google/#normative), ни [каноническим (canonical)](https://neonxp.ru/pages/gostyleguide/google/#canonical)**,
@@ -44,14 +41,13 @@ Style)](https://neonxp.ru/pages/gostyleguide/google/) в Google. Данный д
будет прочитано. Рассмотрите следующие рекомендации, чтобы избежать избыточного
[повторения (repetition)](https://neonxp.ru/pages/gostyleguide/google/decisions/#repetition) в месте вызова (call site):
-* Следующее, как правило, можно опустить в именах функций и методов:
-
- * Типы входных и выходных данных (если нет конфликта)
- * Тип получателя (receiver) метода
- * Является ли входной или выходной параметр указателем (pointer)
+- Следующее, как правило, можно опустить в именах функций и методов:
+ - Типы входных и выходных данных (если нет конфликта)
+ - Тип получателя (receiver) метода
+ - Является ли входной или выходной параметр указателем (pointer)
-* Для функций не следует [повторять имя
- пакета](https://neonxp.ru/pages/gostyleguide/google/decisions/#repetitive-with-package).
+- Для функций не следует [повторять имя
+ пакета](https://neonxp.ru/pages/gostyleguide/google/decisions/#repetitive-with-package).
```go
// Плохо:
@@ -67,7 +63,7 @@ Style)](https://neonxp.ru/pages/gostyleguide/google/) в Google. Данный д
func Parse(input string) (*Config, error)
```
-* Для методов не следует повторять имя получателя метода.
+- Для методов не следует повторять имя получателя метода.
```go
// Плохо:
@@ -79,7 +75,7 @@ Style)](https://neonxp.ru/pages/gostyleguide/google/) в Google. Данный д
func (c *Config) WriteTo(w io.Writer) (int64, error)
```
-* Не повторяйте имена переменных, передаваемых в качестве параметров.
+- Не повторяйте имена переменных, передаваемых в качестве параметров.
```go
// Плохо:
@@ -91,7 +87,7 @@ Style)](https://neonxp.ru/pages/gostyleguide/google/) в Google. Данный д
func Override(dest, source *Config) error
```
-* Не повторяйте имена и типы возвращаемых значений.
+- Не повторяйте имена и типы возвращаемых значений.
```go
// Плохо:
@@ -118,8 +114,8 @@ func (c *Config) WriteBinaryTo(w io.Writer) (int64, error)
Существуют и другие общие соглашения при выборе имен для функций и методов:
-* Функции, которые что-то возвращают, получают имена, похожие на
- существительные.
+- Функции, которые что-то возвращают, получают имена, похожие на
+ существительные.
```go
// Хорошо:
@@ -134,15 +130,15 @@ func (c *Config) WriteBinaryTo(w io.Writer) (int64, error)
func (c *Config) GetJobName(key string) (value string, ok bool)
```
-* Функции, которые что-то делают, получают имена, похожие на глаголы.
+- Функции, которые что-то делают, получают имена, похожие на глаголы.
```go
// Хорошо:
func (c *Config) WriteDetail(w io.Writer) (int64, error)
```
-* Идентичные функции, которые отличаются только типами, включают имя типа в
- конце имени.
+- Идентичные функции, которые отличаются только типами, включают имя типа в
+ конце имени.
```go
// Хорошо:
@@ -174,8 +170,7 @@ func (c *Config) WriteBinaryTo(w io.Writer) (int64, error)
образом, если ваш код использует фейки или другой вид тестового дубля.
[именование]: guide#naming
-[тестовые дубли (test doubles)]:
- https://abseil.io/resources/swe-book/html/ch13.html#basic_concepts
+[тестовые дубли (test doubles)]: https://abseil.io/resources/swe-book/html/ch13.html#basic_concepts
Предположим, у вас есть хорошо сфокусированный пакет, предоставляющий
production-код, подобный этому:
@@ -212,7 +207,7 @@ func (s *Service) Charge(c *Card, amount money.Money) error { /* опущено
#### Создание вспомогательных тестовых пакетов (Creating test helper packages)
Предположим, вы хотите создать пакет, содержащий тестовые дубли для другого
-пакета. Воспользуемся `package creditcard` (из примера выше):
+пакета. Воспользуемся `package creditcard` (из примера выше):
Один из подходов — создать новый Go-пакет на основе production-пакета для
тестирования. Безопасный выбор — добавить слово `test` к оригинальному имени
@@ -274,8 +269,8 @@ go_library(
См. также:
-* [Go Tip #42: Authoring a Stub for
- Testing](https://google.github.io/styleguide/go/index.html#gotip)
+- [Go Tip #42: Authoring a Stub for
+ Testing](/pages/gostyleguide/google/index.html#gotip)
<a id="naming-doubles-multiple-behaviors"></a>
@@ -436,8 +431,8 @@ func TestProcessor(t *testing.T) {
### Затенение (Shadowing)
-**Примечание:** Это объяснение использует два неформальных термина, *stomping* и
-*shadowing*. Они не являются официальными концепциями в спецификации языка Go.
+**Примечание:** Это объяснение использует два неформальных термина, _stomping_ и
+_shadowing_. Они не являются официальными концепциями в спецификации языка Go.
Как и во многих языках программирования, в Go есть изменяемые переменные:
присваивание переменной меняет ее значение.
@@ -454,7 +449,7 @@ func abs(i int) int {
При использовании [короткого объявления переменных (short variable
declarations)] с оператором `:=` в некоторых случаях новая переменная не
-создается. Мы можем назвать это *stomping* (затирание). Это допустимо, когда
+создается. Мы можем назвать это _stomping_ (затирание). Это допустимо, когда
исходное значение больше не нужно.
```go
@@ -477,7 +472,7 @@ func (s *Server) innerHandler(ctx context.Context, req *pb.MyRequest) *pb.MyResp
```
Однако будьте осторожны с использованием короткого объявления переменных в новой
-области видимости: это вводит новую переменную. Мы можем назвать это *shadowing*
+области видимости: это вводит новую переменную. Мы можем назвать это _shadowing_
(затенение) исходной переменной. Код после конца блока ссылается на оригинал.
Вот ошибочная попытка условно сократить срок действия (deadline):
@@ -536,8 +531,7 @@ func LongFunction() {
}
```
-[короткого объявления переменных (short variable declarations)]:
- https://go.dev/ref/spec#Short_variable_declarations
+[короткого объявления переменных (short variable declarations)]: https://go.dev/ref/spec#Short_variable_declarations
<a id="util-packages"></a>
@@ -549,7 +543,7 @@ func LongFunction() {
Имена пакетов Go должны быть [связаны с тем, что предоставляет
пакет](https://neonxp.ru/pages/gostyleguide/google/decisions/#package-names). Называть пакет просто `util`, `helper`,
`common` или подобным обычно плохой выбор (хотя это может быть использовано как
-*часть* имени). Неинформативные имена затрудняют чтение кода, и если они
+_часть_ имени). Неинформативные имена затрудняют чтение кода, и если они
используются слишком широко, они могут вызывать ненужные [конфликты
импорта](https://neonxp.ru/pages/gostyleguide/google/decisions/#import-renaming).
@@ -592,12 +586,12 @@ b := helper.Marshal(curve, x, y)
Пользователи видят [godoc] для пакета на одной странице, и любые
экспортированные методы типов, предоставляемых пакетом, группируются по их типу.
Godoc также группирует конструкторы вместе с типами, которые они возвращают.
-Если *клиентскому коду* (client code) вероятно потребуется, чтобы два значения
+Если _клиентскому коду_ (client code) вероятно потребуется, чтобы два значения
разных типов взаимодействовали друг с другом, может быть удобно для пользователя
иметь их в одном пакете.
Код внутри пакета имеет доступ к неэкспортированным идентификаторам пакета. Если
-у вас есть несколько связанных типов, *реализация* которых тесно связана,
+у вас есть несколько связанных типов, _реализация_ которых тесно связана,
размещение их в одном пакете позволяет достичь этой связи без загрязнения
публичного API этими деталями. Хороший тест для этой связи — представить
гипотетического пользователя двух пакетов, где пакеты охватывают тесно связанные
@@ -611,7 +605,7 @@ Godoc также группирует конструкторы вместе с
предоставление ему собственного небольшого пакета может облегчить его
использование. Короткое имя пакета, известное клиентам, вместе с именем
экспортированного типа работают вместе, чтобы создать значимый идентификатор:
-например, `bytes.Buffer`, `ring.New`. [Пост об именах пакетов][blog-pkg-names]
+например, `bytes.Buffer`, `ring.New`. [Пост об именах пакетов][blog-pkg-names]
содержит больше примеров.
Стиль Go гибок относительно размера файлов, потому что сопровождающие могут
@@ -637,64 +631,54 @@ Godoc также группирует конструкторы вместе с
Несколько неканонических справочных примеров, чтобы помочь продемонстрировать
эти идеи на практике:
-* маленькие пакеты, содержащие одну связную идею, которая не требует
- добавления или удаления чего-либо еще:
-
- * [пакет `csv`][package `csv`]: кодирование и декодирование данных CSV с
- разделением ответственности соответственно между [reader.go] и
- [writer.go].
- * [пакет `expvar`][package `expvar`]: "белый ящик" (whitebox) телеметрии
- программы, полностью содержащийся в [expvar.go].
-
-* пакеты умеренного размера, содержащие одну большую предметную область и
- несколько связанных с ней ответственностей:
-
- * [пакет `flag`][package `flag`]: управление флагами командной строки,
- полностью содержащееся в [flag.go].
-
-* большие пакеты, которые разделяют несколько тесно связанных предметных
- областей по нескольким файлам:
-
- * [пакет `http`][package `http`]: ядро HTTP: [client.go][http-client],
- поддержка HTTP-клиентов; [server.go][http-server], поддержка
- HTTP-серверов; [cookie.go], управление куками.
- * [пакет `os`][package `os`]: кроссплатформенные абстракции операционной
- системы: [exec.go], управление подпроцессами; [file.go], управление
- файлами; [tempfile.go], временные файлы.
+- маленькие пакеты, содержащие одну связную идею, которая не требует
+ добавления или удаления чего-либо еще:
+ - [пакет `csv`][package `csv`]: кодирование и декодирование данных CSV с
+ разделением ответственности соответственно между [reader.go] и
+ [writer.go].
+ - [пакет `expvar`][package `expvar`]: "белый ящик" (whitebox) телеметрии
+ программы, полностью содержащийся в [expvar.go].
+
+- пакеты умеренного размера, содержащие одну большую предметную область и
+ несколько связанных с ней ответственностей:
+ - [пакет `flag`][package `flag`]: управление флагами командной строки,
+ полностью содержащееся в [flag.go].
+
+- большие пакеты, которые разделяют несколько тесно связанных предметных
+ областей по нескольким файлам:
+ - [пакет `http`][package `http`]: ядро HTTP: [client.go][http-client],
+ поддержка HTTP-клиентов; [server.go][http-server], поддержка
+ HTTP-серверов; [cookie.go], управление куками.
+ - [пакет `os`][package `os`]: кроссплатформенные абстракции операционной
+ системы: [exec.go], управление подпроцессами; [file.go], управление
+ файлами; [tempfile.go], временные файлы.
См. также:
-* [Пакеты тестовых дублей (Test double packages)](#naming-doubles)
-* [Organizing Go Code (Blog Post)]
-* [Organizing Go Code (Presentation)]
+- [Пакеты тестовых дублей (Test double packages)](#naming-doubles)
+- [Organizing Go Code (Blog Post)]
+- [Organizing Go Code (Presentation)]
[blog-pkg-names]: https://go.dev/blog/package-names
[пакет `bytes`]: https://go.dev/src/bytes/
[Organizing Go Code (Blog Post)]: https://go.dev/blog/organizing-go-code
[Organizing Go Code (Presentation)]: https://go.dev/talks/2014/organizeio.slide
[пакет `csv`]: https://pkg.go.dev/encoding/csv
-[reader.go]:
- https://go.googlesource.com/go/+/refs/heads/master/src/encoding/csv/reader.go
-[writer.go]:
- https://go.googlesource.com/go/+/refs/heads/master/src/encoding/csv/writer.go
+[reader.go]: https://go.googlesource.com/go/+/refs/heads/master/src/encoding/csv/reader.go
+[writer.go]: https://go.googlesource.com/go/+/refs/heads/master/src/encoding/csv/writer.go
[пакет `expvar`]: https://pkg.go.dev/expvar
-[expvar.go]:
- https://go.googlesource.com/go/+/refs/heads/master/src/expvar/expvar.go
+[expvar.go]: https://go.googlesource.com/go/+/refs/heads/master/src/expvar/expvar.go
[пакет `flag`]: https://pkg.go.dev/flag
[flag.go]: https://go.googlesource.com/go/+/refs/heads/master/src/flag/flag.go
[godoc]: https://pkg.go.dev/
[пакет `http`]: https://pkg.go.dev/net/http
-[http-client]:
- https://go.googlesource.com/go/+/refs/heads/master/src/net/http/client.go
-[http-server]:
- https://go.googlesource.com/go/+/refs/heads/master/src/net/http/server.go
-[cookie.go]:
- https://go.googlesource.com/go/+/refs/heads/master/src/net/http/cookie.go
+[http-client]: https://go.googlesource.com/go/+/refs/heads/master/src/net/http/client.go
+[http-server]: https://go.googlesource.com/go/+/refs/heads/master/src/net/http/server.go
+[cookie.go]: https://go.googlesource.com/go/+/refs/heads/master/src/net/http/cookie.go
[пакет `os`]: https://pkg.go.dev/os
[exec.go]: https://go.googlesource.com/go/+/refs/heads/master/src/os/exec.go
[file.go]: https://go.googlesource.com/go/+/refs/heads/master/src/os/file.go
-[tempfile.go]:
- https://go.googlesource.com/go/+/refs/heads/master/src/os/tempfile.go
+[tempfile.go]: https://go.googlesource.com/go/+/refs/heads/master/src/os/tempfile.go
<a id="imports"></a>
@@ -708,8 +692,8 @@ Godoc также группирует конструкторы вместе с
их межъязыковой природы. Соглашение для переименованных импортов proto основано
на правиле, которое сгенерировало пакет:
-* Суффикс `pb` обычно используется для правил `go_proto_library`.
-* Суффикс `grpc` обычно используется для правил `go_grpc_library`.
+- Суффикс `pb` обычно используется для правил `go_proto_library`.
+- Суффикс `grpc` обычно используется для правил `go_grpc_library`.
Часто используется одно слово, описывающее пакет:
@@ -722,9 +706,9 @@ import (
```
Следуйте рекомендациям по стилю для [имен
-пакетов](https://google.github.io/styleguide/go/decisions#package-names).
+пакетов](/pages/gostyleguide/google/decisions#package-names).
Предпочитайте целые слова. Короткие имена хороши, но избегайте неоднозначности.
-В случае сомнений используйте имя пакета proto до _go с суффиксом pb:
+В случае сомнений используйте имя пакета proto до \_go с суффиксом pb:
```go
// Хорошо:
@@ -751,9 +735,9 @@ import (
В Go [ошибки — это значения (errors are values)]; они создаются кодом и
потребляются кодом. Ошибки могут быть:
-* Преобразованы в диагностическую информацию для отображения человеку
-* Использованы сопровождающим
-* Интерпретированы конечным пользователем
+- Преобразованы в диагностическую информацию для отображения человеку
+- Использованы сопровождающим
+- Интерпретированы конечным пользователем
Сообщения об ошибках также появляются на самых разных поверхностях, включая
сообщения журнала (log messages), дампы ошибок и отрисованные пользовательские
@@ -766,35 +750,34 @@ import (
тема, и трудно дать категоричные рекомендации. Используйте свое суждение, но
учитывайте следующие соображения:
-* Создавая значение ошибки, решите, придавать ли ему какую-либо
- [структуру](#error-structure).
-* Обрабатывая ошибку, рассмотрите возможность [добавления
- информации](#error-extra-info), которая есть у вас, но которой может не быть
- у вызывающей и/или вызываемой стороны.
-* См. также рекомендации по [логированию ошибок](#error-logging).
+- Создавая значение ошибки, решите, придавать ли ему какую-либо
+ [структуру](#error-structure).
+- Обрабатывая ошибку, рассмотрите возможность [добавления
+ информации](#error-extra-info), которая есть у вас, но которой может не быть
+ у вызывающей и/или вызываемой стороны.
+- См. также рекомендации по [логированию ошибок](#error-logging).
Хотя обычно нецелесообразно игнорировать ошибку, разумным исключением из этого
является оркестрация связанных операций, где часто только первая ошибка полезна.
Пакет [`errgroup`] предоставляет удобную абстракцию для группы операций, которые
могут завершиться ошибкой или быть отменены как группа.
-[ошибки — это значения (errors are values)]:
- https://go.dev/blog/errors-are-values
+[ошибки — это значения (errors are values)]: https://go.dev/blog/errors-are-values
[`errgroup`]: https://pkg.go.dev/golang.org/x/sync/errgroup
См. также:
-* [Effective Go об ошибках](https://go.dev/doc/effective_go#errors)
-* [Пост в блоге Go об ошибках](https://go.dev/blog/go1.13-errors)
-* [Пакет `errors`](https://pkg.go.dev/errors)
-* [Пакет
- `upspin.io/errors`](https://commandcenter.blogspot.com/2017/12/error-handling-in-upspin.html)
-* [GoTip #89: When to Use Canonical Status Codes as
- Errors](https://google.github.io/styleguide/go/index.html#gotip)
-* [GoTip #48: Error Sentinel
- Values](https://google.github.io/styleguide/go/index.html#gotip)
-* [GoTip #13: Designing Errors for
- Checking](https://google.github.io/styleguide/go/index.html#gotip)
+- [Effective Go об ошибках](https://go.dev/doc/effective_go#errors)
+- [Пост в блоге Go об ошибках](https://go.dev/blog/go1.13-errors)
+- [Пакет `errors`](https://pkg.go.dev/errors)
+- [Пакет
+ `upspin.io/errors`](https://commandcenter.blogspot.com/2017/12/error-handling-in-upspin.html)
+- [GoTip #89: When to Use Canonical Status Codes as
+ Errors](/pages/gostyleguide/google/index.html#gotip)
+- [GoTip #48: Error Sentinel
+ Values](/pages/gostyleguide/google/index.html#gotip)
+- [GoTip #13: Designing Errors for
+ Checking](/pages/gostyleguide/google/index.html#gotip)
<a id="error-structure"></a>
@@ -868,9 +851,9 @@ func handlePet(...) {
}
```
-Не пытайтесь различать ошибки на основе их строковой формы. (См. [GoTip #13:
+Не пытайтесь различать ошибки на основе их строковой формы. (См. [GoTip #13:
Designing Errors for
-Checking](https://google.github.io/styleguide/go/index.html#gotip) для получения
+Checking](/pages/gostyleguide/google/index.html#gotip) для получения
дополнительной информации.)
```go
@@ -891,9 +874,9 @@ func handlePet(...) {
Могут использоваться и другие структуры ошибок, например, структура проекта,
содержащая код ошибки и строку с деталями. [Пакет `status`][status] —
распространенная инкапсуляция; если вы выбираете этот подход (вы не обязаны это
-делать), используйте [канонические коды (canonical codes)]. См. [GoTip #89:
+делать), используйте [канонические коды (canonical codes)]. См. [GoTip #89:
When to Use Canonical Status Codes as
-Errors](https://google.github.io/styleguide/go/index.html#gotip) чтобы понять,
+Errors](/pages/gostyleguide/google/index.html#gotip) чтобы понять,
является ли использование кодов статуса правильным выбором.
[`os.PathError`]: https://pkg.go.dev/os#PathError
@@ -901,8 +884,7 @@ Errors](https://google.github.io/styleguide/go/index.html#gotip) чтобы по
[`errors.As`]: https://pkg.go.dev/errors#As
[`package cmp`]: https://pkg.go.dev/github.com/google/go-cmp/cmp
[status]: https://pkg.go.dev/google.golang.org/grpc/status
-[канонические коды (canonical codes)]:
- https://pkg.go.dev/google.golang.org/grpc/codes
+[канонические коды (canonical codes)]: https://pkg.go.dev/google.golang.org/grpc/codes
<a id="error-extra-info"></a>
@@ -961,21 +943,20 @@ errors)](https://go.dev/blog/go1.13-errors#whether-to-wrap) с помощью
встраивает строковое представление ошибки (то, что возвращает ее метод
`Error()`) в новое значение ошибки, отбрасывая любую структурированную
информацию из исходной ошибки. Примеры использования `%v`:
+ - Добавление интересного, не избыточного контекста: как в примере выше.
- * Добавление интересного, не избыточного контекста: как в примере выше.
-
- * Логирование или отображение ошибок: Когда основная цель — представить
- удобочитаемое сообщение об ошибке в журналах или пользователю, и вы не
- планируете, чтобы вызывающая сторона программно проверяла ошибку с
- помощью `errors.Is` или `errors.As` (Примечание: `errors.Unwrap` здесь,
- как правило, не рекомендуется, так как он не обрабатывает множественные
- ошибки (multi-errors)).
+ - Логирование или отображение ошибок: Когда основная цель — представить
+ удобочитаемое сообщение об ошибке в журналах или пользователю, и вы не
+ планируете, чтобы вызывающая сторона программно проверяла ошибку с
+ помощью `errors.Is` или `errors.As` (Примечание: `errors.Unwrap` здесь,
+ как правило, не рекомендуется, так как он не обрабатывает множественные
+ ошибки (multi-errors)).
- * Создание новых, независимых ошибок: Иногда необходимо преобразовать
- ошибку в новое сообщение об ошибке, тем самым скрывая специфику исходной
- ошибки. Эта практика особенно полезна на границах систем, включая,
- помимо прочего, RPC, IPC и хранилища, где мы переводим
- доменно-специфичные ошибки в каноническое пространство ошибок.
+ - Создание новых, независимых ошибок: Иногда необходимо преобразовать
+ ошибку в новое сообщение об ошибке, тем самым скрывая специфику исходной
+ ошибки. Эта практика особенно полезна на границах систем, включая,
+ помимо прочего, RPC, IPC и хранилища, где мы переводим
+ доменно-специфичные ошибки в каноническое пространство ошибок.
```go
// Хорошо:
@@ -1008,63 +989,63 @@ errors)](https://go.dev/blog/go1.13-errors#whether-to-wrap) с помощью
1. **`%w` (wrap) для программной проверки и цепочки ошибок (error chaining)**
- Глагол `%w` специально предназначен для оборачивания ошибок (error
- wrapping). Он создает новую ошибку, которая предоставляет метод `Unwrap()`,
- позволяя вызывающим сторонам программно проверять цепочку ошибок с помощью
- `errors.Is` и `errors.As`. Примеры использования `%w`:
+ Глагол `%w` специально предназначен для оборачивания ошибок (error
+ wrapping). Он создает новую ошибку, которая предоставляет метод `Unwrap()`,
+ позволяя вызывающим сторонам программно проверять цепочку ошибок с помощью
+ `errors.Is` и `errors.As`. Примеры использования `%w`:
+ - Добавление контекста с сохранением исходной ошибки для программной
+ проверки: Это основной случай использования во вспомогательных функциях
+ (helpers) вашего приложения. Вы хотите обогатить ошибку дополнительным
+ контекстом (например, какая операция выполнялась, когда она завершилась
+ неудачей), но при этом позволить вызывающей стороне проверить, является
+ ли лежащая в основе ошибка конкретной сторожевой ошибкой или типом.
+
+ ```go
+ // Хорошо:
+ func (s *Server) internalFunction(ctx context.Context) error {
+ // ...
+ if err != nil {
+ return fmt.Errorf("couldn't find remote file: %w", err)
+ }
+ }
+ ```
- * Добавление контекста с сохранением исходной ошибки для программной
- проверки: Это основной случай использования во вспомогательных функциях
- (helpers) вашего приложения. Вы хотите обогатить ошибку дополнительным
- контекстом (например, какая операция выполнялась, когда она завершилась
- неудачей), но при этом позволить вызывающей стороне проверить, является
- ли лежащая в основе ошибка конкретной сторожевой ошибкой или типом.
+ Это позволяет функции более высокого уровня выполнить `errors.Is(err,
- ```go
- // Хорошо:
- func (s *Server) internalFunction(ctx context.Context) error {
- // ...
- if err != nil {
- return fmt.Errorf("couldn't find remote file: %w", err)
- }
- }
- ```
+ fs.ErrNotExist)`, даже если исходная ошибка была обернута.
- Это позволяет функции более высокого уровня выполнить `errors.Is(err,
- fs.ErrNotExist)`, даже если исходная ошибка была обернута.
+ В точках, где ваша система взаимодействует с внешними системами, такими
+ как RPC, IPC или хранилище, часто лучше переводить доменно-специфичные
+ ошибки в стандартизированное пространство ошибок (например, коды статуса
+ gRPC), а не просто оборачивать исходную ошибку с помощью `%w`. Клиента
+ обычно не волнует точная внутренняя ошибка файловой системы; их волнует
+ канонический результат (например, `Internal`, `NotFound`,
+ `PermissionDenied`).
- В точках, где ваша система взаимодействует с внешними системами, такими
- как RPC, IPC или хранилище, часто лучше переводить доменно-специфичные
- ошибки в стандартизированное пространство ошибок (например, коды статуса
- gRPC), а не просто оборачивать исходную ошибку с помощью `%w`. Клиента
- обычно не волнует точная внутренняя ошибка файловой системы; их волнует
- канонический результат (например, `Internal`, `NotFound`,
- `PermissionDenied`).
-
- * Когда вы явно документируете и тестируете лежащие в основе ошибки,
- которые вы раскрываете: Если API вашего пакета гарантирует, что
- определенные лежащие в основе ошибки могут быть развернуты и проверены
- вызывающими сторонами (например, "эта функция может вернуть
- `ErrInvalidConfig`, обернутый в более общую ошибку"), то `%w` уместен.
- Это становится частью контракта вашего пакета.
+ - Когда вы явно документируете и тестируете лежащие в основе ошибки,
+ которые вы раскрываете: Если API вашего пакета гарантирует, что
+ определенные лежащие в основе ошибки могут быть развернуты и проверены
+ вызывающими сторонами (например, "эта функция может вернуть
+ `ErrInvalidConfig`, обернутый в более общую ошибку"), то `%w` уместен.
+ Это становится частью контракта вашего пакета.
См. также:
-* [Соглашения по документации ошибок (Error Documentation
- Conventions)](#documentation-conventions-errors)
-* [Пост в блоге об оборачивании ошибок](https://blog.golang.org/go1.13-errors)
+- [Соглашения по документации ошибок (Error Documentation
+ Conventions)](#documentation-conventions-errors)
+- [Пост в блоге об оборачивании ошибок](https://blog.golang.org/go1.13-errors)
<a id="error-percent-w"></a>
### Размещение `%w` в ошибках (Placement of %w in errors)
-Предпочитайте размещать `%w` в конце строки ошибки *если* вы используете
+Предпочитайте размещать `%w` в конце строки ошибки _если_ вы используете
[оборачивание ошибок (error wrapping)](https://go.dev/blog/go1.13-errors) с
глаголом форматирования `%w`.
Ошибки могут быть обернуты с помощью глагола `%w` или путем помещения их в
[структурированную
-ошибку](https://google.github.io/styleguide/go/index.html#gotip), которая
+ошибку](/pages/gostyleguide/google/index.html#gotip), которая
реализует `Unwrap() error` (например,
[`fs.PathError`](https://pkg.go.dev/io/fs#PathError)).
@@ -1133,40 +1114,39 @@ fmt.Println(err3) // err3-1 err2-1 err1 err2-2 err3-2
своим вызывающим сторонам. Логирование — очевидный выбор здесь; но будьте
внимательны к тому, что и как вы логируете.
-* Как и [хорошие сообщения о неудачных тестах (good test failure messages)],
- сообщения журнала должны четко выражать, что пошло не так, и помогать
- сопровождающему, включая соответствующую информацию для диагностики
- проблемы.
+- Как и [хорошие сообщения о неудачных тестах (good test failure messages)],
+ сообщения журнала должны четко выражать, что пошло не так, и помогать
+ сопровождающему, включая соответствующую информацию для диагностики
+ проблемы.
-* Избегайте дублирования. Если вы возвращаете ошибку, обычно лучше не
- логировать ее самостоятельно, а позволить вызывающей стороне обработать ее.
- Вызывающая сторона может выбрать логирование ошибки или, возможно,
- ограничить частоту логирования с помощью [`rate.Sometimes`]. Другие варианты
- включают попытку восстановления или даже [остановку программы]. В любом
- случае, предоставление контроля вызывающей стороне помогает избежать спама в
- журналах.
+- Избегайте дублирования. Если вы возвращаете ошибку, обычно лучше не
+ логировать ее самостоятельно, а позволить вызывающей стороне обработать ее.
+ Вызывающая сторона может выбрать логирование ошибки или, возможно,
+ ограничить частоту логирования с помощью [`rate.Sometimes`]. Другие варианты
+ включают попытку восстановления или даже [остановку программы]. В любом
+ случае, предоставление контроля вызывающей стороне помогает избежать спама в
+ журналах.
Однако обратной стороной этого подхода является то, что любое логирование
записывается с использованием координат строк вызывающей стороны.
-* Будьте осторожны с [PII]. Многие приемники журналов (log sinks) не являются
- подходящими местами назначения для конфиденциальной информации конечных
- пользователей.
+- Будьте осторожны с [PII]. Многие приемники журналов (log sinks) не являются
+ подходящими местами назначения для конфиденциальной информации конечных
+ пользователей.
-* Используйте `log.Error` скупо. Логирование уровня ERROR вызывает сброс
- (flush) и является более дорогостоящим, чем более низкие уровни логирования.
- Это может серьезно повлиять на производительность вашего кода. Принимая
- решение между уровнями error и warning, учитывайте лучшую практику:
- сообщения на уровне error должны быть actionable (то есть требовать
- действий), а не просто "более серьезными", чем warning.
+- Используйте `log.Error` скупо. Логирование уровня ERROR вызывает сброс
+ (flush) и является более дорогостоящим, чем более низкие уровни логирования.
+ Это может серьезно повлиять на производительность вашего кода. Принимая
+ решение между уровнями error и warning, учитывайте лучшую практику:
+ сообщения на уровне error должны быть actionable (то есть требовать
+ действий), а не просто "более серьезными", чем warning.
-* Внутри Google у нас есть системы мониторинга, которые можно настроить для
- более эффективного оповещения, чем просто запись в файл журнала в надежде,
- что кто-то его заметит. Это похоже, но не идентично стандартной библиотеке
- [пакету `expvar`].
+- Внутри Google у нас есть системы мониторинга, которые можно настроить для
+ более эффективного оповещения, чем просто запись в файл журнала в надежде,
+ что кто-то его заметит. Это похоже, но не идентично стандартной библиотеке
+ [пакету `expvar`].
-[хорошие сообщения о неудачных тестах (good test failure messages)]:
- https://google.github.io/styleguide/go/decisions#useful-test-failures
+[хорошие сообщения о неудачных тестах (good test failure messages)]: /pages/gostyleguide/google/decisions#useful-test-failures
[остановку программы]: #checks-and-panics
[`rate.Sometimes`]: https://pkg.go.dev/golang.org/x/time/rate#Sometimes
[PII]: https://en.wikipedia.org/wiki/Personal_data
@@ -1180,9 +1160,9 @@ fmt.Println(err3) // err3-1 err2-1 err1 err2-2 err3-2
может быть полезно для разработки и трассировки. Установление соглашения об
уровнях детализации может быть полезным. Например:
-* Записывайте небольшое количество дополнительной информации на `V(1)`
-* Трассируйте больше информации на `V(2)`
-* Выводите большие внутренние состояния на `V(3)`
+- Записывайте небольшое количество дополнительной информации на `V(1)`
+- Трассируйте больше информации на `V(2)`
+- Выводите большие внутренние состояния на `V(3)`
Чтобы минимизировать стоимость детального логирования, вы должны убедиться, что
случайно не вызываете дорогие функции, даже когда `log.V` выключен. `log.V`
@@ -1251,8 +1231,7 @@ log.V(2).Infof("Handling %v", sql.Explain())
большие трассировки стека, которые остаются необработанными. Избегайте этой
ловушки в своих серверах.
-[решении против паник (decision against panics)]:
- https://google.github.io/styleguide/go/decisions#dont-panic
+[решении против паник (decision against panics)]: /pages/gostyleguide/google/decisions#dont-panic
[`net/http` server]: https://pkg.go.dev/net/http#Server
<a id="when-to-panic"></a>
@@ -1345,14 +1324,13 @@ func answer(i int) string {
См. также:
-* [Handling panics](https://go.dev/ref/spec#Handling_panics) и [Run-time
- Panics](https://go.dev/ref/spec#Run_time_panics) в спецификации языка
-* [Defer, Panic, and Recover](https://go.dev/blog/defer-panic-and-recover)
-* [On the uses and misuses of panics in
- Go](https://eli.thegreenplace.net/2018/on-the-uses-and-misuses-of-panics-in-go/)
+- [Handling panics](https://go.dev/ref/spec#Handling_panics) и [Run-time
+ Panics](https://go.dev/ref/spec#Run_time_panics) в спецификации языка
+- [Defer, Panic, and Recover](https://go.dev/blog/defer-panic-and-recover)
+- [On the uses and misuses of panics in
+ Go](https://eli.thegreenplace.net/2018/on-the-uses-and-misuses-of-panics-in-go/)
-[Go Tip #81: Avoiding Resource Leaks in API Design]:
- https://google.github.io/styleguide/go/index.html#gotip
+[Go Tip #81: Avoiding Resource Leaks in API Design]: /pages/gostyleguide/google/index.html#gotip
<a id="documentation"></a>
@@ -1379,9 +1357,9 @@ func answer(i int) string {
Не каждый параметр должен быть перечислен в документации. Это относится к:
-* параметрам функций и методов
-* полям структур (struct fields)
-* API для опций (options)
+- параметрам функций и методов
+- полям структур (struct fields)
+- API для опций (options)
Документируйте подверженные ошибкам или неочевидные поля и параметры, объясняя,
почему они интересны.
@@ -1419,13 +1397,11 @@ func Sprintf(format string, data ...any) string
См. также:
-* [GoTip #41: Identify Function Call Parameters]
-* [GoTip #51: Patterns for Configuration]
+- [GoTip #41: Identify Function Call Parameters]
+- [GoTip #51: Patterns for Configuration]
-[GoTip #41: Identify Function Call Parameters]:
- https://google.github.io/styleguide/go/index.html#gotip
-[GoTip #51: Patterns for Configuration]:
- https://google.github.io/styleguide/go/index.html#gotip
+[GoTip #41: Identify Function Call Parameters]: /pages/gostyleguide/google/index.html#gotip
+[GoTip #51: Patterns for Configuration]: /pages/gostyleguide/google/index.html#gotip
<a id="documentation-conventions-contexts"></a>
@@ -1456,7 +1432,7 @@ func (Worker) Run(ctx context.Context) error
Когда поведение контекста отличается или неочевидно, его следует прямо
задокументировать, если верно любое из следующего.
-* Функция возвращает ошибку, отличную от `ctx.Err()`, когда контекст отменен:
+- Функция возвращает ошибку, отличную от `ctx.Err()`, когда контекст отменен:
```go
// Хорошо:
@@ -1466,8 +1442,8 @@ func (Worker) Run(ctx context.Context) error
func (Worker) Run(ctx context.Context) error
```
-* Функция имеет другие механизмы, которые могут ее прервать или повлиять на
- время жизни:
+- Функция имеет другие механизмы, которые могут ее прервать или повлиять на
+ время жизни:
```go
// Хорошо:
@@ -1482,8 +1458,8 @@ func (Worker) Run(ctx context.Context) error
func (Worker) Stop()
```
-* Функция имеет особые ожидания относительно времени жизни контекста, его
- происхождения (lineage) или прикрепленных значений (attached values):
+- Функция имеет особые ожидания относительно времени жизни контекста, его
+ происхождения (lineage) или прикрепленных значений (attached values):
```go
// Хорошо:
@@ -1536,7 +1512,7 @@ func (*Buffer) Grow(n int)
Настоятельно рекомендуется документировать, если верно любое из следующего.
-* Непонятно, является ли операция доступной только для чтения или мутирующей:
+- Непонятно, является ли операция доступной только для чтения или мутирующей:
```go
// Хорошо:
@@ -1552,7 +1528,7 @@ func (*Buffer) Grow(n int)
состояние LRU-кэша мутирует. Как это реализовано, может быть неочевидно для
всех читателей.
-* Синхронизация предоставляется API:
+- Синхронизация предоставляется API:
```go
// Хорошо:
@@ -1568,8 +1544,8 @@ func (*Buffer) Grow(n int)
**Примечание:** Если API является типом и API предоставляет синхронизацию в
целом, по соглашению только определение типа документирует семантику.
-* API потребляет пользовательские реализации типов или интерфейсов, и
- потребитель интерфейса имеет особые требования к параллелизму:
+- API потребляет пользовательские реализации типов или интерфейсов, и
+ потребитель интерфейса имеет особые требования к параллелизму:
```go
// Хорошо:
@@ -1632,10 +1608,9 @@ func (c *Client) Get(url string) (resp *Response, err error)
См. также:
-* [GoTip #110: Don’t Mix Exit With Defer]
+- [GoTip #110: Don’t Mix Exit With Defer]
-[GoTip #110: Don’t Mix Exit With Defer]:
- https://google.github.io/styleguide/go/index.html#gotip
+[GoTip #110: Don’t Mix Exit With Defer]: /pages/gostyleguide/google/index.html#gotip
<a id="documentation-conventions-errors"></a>
@@ -1706,10 +1681,10 @@ package os
См. также:
-* [Go Tip #106: Error Naming
- Conventions](https://google.github.io/styleguide/go/index.html#gotip)
-* [Go Tip #89: When to Use Canonical Status Codes as
- Errors](https://google.github.io/styleguide/go/index.html#gotip)
+- [Go Tip #106: Error Naming
+ Conventions](/pages/gostyleguide/google/index.html#gotip)
+- [Go Tip #89: When to Use Canonical Status Codes as
+ Errors](/pages/gostyleguide/google/index.html#gotip)
<a id="documentation-preview"></a>
@@ -1729,7 +1704,7 @@ Go имеет [сервер
[Godoc] предоставляет специальный синтаксис для [форматирования документации].
-* Требуется пустая строка для разделения абзацев:
+- Требуется пустая строка для разделения абзацев:
```go
// Хорошо:
@@ -1738,8 +1713,8 @@ Go имеет [сервер
// См. some/shortlink для подробностей о формате файла конфигурации.
```
-* Файлы тестов могут содержать [запускаемые примеры (runnable examples)],
- которые появляются прикрепленными к соответствующей документации в godoc:
+- Файлы тестов могут содержать [запускаемые примеры (runnable examples)],
+ которые появляются прикрепленными к соответствующей документации в godoc:
```go
// Хорошо:
@@ -1757,8 +1732,8 @@ Go имеет [сервер
}
```
-* Отступ строк на два дополнительных пробела форматирует их буквально
- (verbatim):
+- Отступ строк на два дополнительных пробела форматирует их буквально
+ (verbatim):
```go
// Хорошо:
@@ -1786,9 +1761,9 @@ Go имеет [сервер
// "env" если присутствует, будет заполнен системным окружением.
```
-* Одна строка, которая начинается с заглавной буквы, не содержит знаков
- препинания, кроме скобок и запятых, и за которой следует другой абзац,
- форматируется как заголовок:
+- Одна строка, которая начинается с заглавной буквы, не содержит знаков
+ препинания, кроме скобок и запятых, и за которой следует другой абзац,
+ форматируется как заголовок:
```go
// Хорошо:
@@ -2004,8 +1979,7 @@ var (
)
```
-[составные литералы (composite literal)]:
- https://golang.org/ref/spec#Composite_literals
+[составные литералы (composite literal)]: https://golang.org/ref/spec#Composite_literals
<a id="vardeclsize"></a>
@@ -2039,12 +2013,11 @@ var (
**Предупреждение:** Предварительное выделение больше памяти, чем нужно, может
тратить память в парке (fleet) или даже вредить производительности. В случае
-сомнений см. [GoTip #3: Benchmarking Go Code] и по умолчанию используйте
+сомнений см. [GoTip #3: Benchmarking Go Code] и по умолчанию используйте
[инициализацию нулевым значением](#vardeclzero) или [объявление составным
литералом](#vardeclcomposite).
-[GoTip #3: Benchmarking Go Code]:
- https://google.github.io/styleguide/go/index.html#gotip
+[GoTip #3: Benchmarking Go Code]: /pages/gostyleguide/google/index.html#gotip
<a id="decl-chan"></a>
@@ -2082,8 +2055,7 @@ func sum(values chan int) (out int) {
См. также доклад Брайана Миллса "Rethinking Classical Concurrency Patterns":
[слайды][rethinking-concurrency-slides] [видео][rethinking-concurrency-video].
-[rethinking-concurrency-slides]:
- https://drive.google.com/file/d/1nPdvhB0PutEJzdCq5ms6UI58dp50fcAN/view?usp=sharing
+[rethinking-concurrency-slides]: https://drive.google.com/file/d/1nPdvhB0PutEJzdCq5ms6UI58dp50fcAN/view?usp=sharing
[rethinking-concurrency-video]: https://www.youtube.com/watch?v=5zXAHh5tJqQ
[направление канала (channel direction)]: https://go.dev/ref/spec#Channel_types
@@ -2114,7 +2086,7 @@ API, к которым предъявляются более высокие ст
механизации (least mechanism)].
См. также: [Go Tip #24: Use Case-Specific
-Constructions](https://google.github.io/styleguide/go/index.html#gotip)
+Constructions](/pages/gostyleguide/google/index.html#gotip)
[структуры опций (option struct)]: #option-structure
[вариативных опций (variadic options)]: #variadic-options
@@ -2132,14 +2104,14 @@ Constructions](https://google.github.io/styleguide/go/index.html#gotip)
Использование структуры опций имеет ряд преимуществ:
-* Литерал структуры включает как поля, так и значения для каждого аргумента,
- что делает их самодокументированными и затрудняет их перестановку.
-* Несущественные или "значения по умолчанию" поля могут быть опущены.
-* Вызывающие стороны могут совместно использовать структуру опций и писать
- вспомогательные функции для работы с ней.
-* Структуры обеспечивают более чистую документацию для каждого поля, чем
- аргументы функций.
-* Структуры опций могут расти со временем без влияния на места вызова.
+- Литерал структуры включает как поля, так и значения для каждого аргумента,
+ что делает их самодокументированными и затрудняет их перестановку.
+- Несущественные или "значения по умолчанию" поля могут быть опущены.
+- Вызывающие стороны могут совместно использовать структуру опций и писать
+ вспомогательные функции для работы с ней.
+- Структуры обеспечивают более чистую документацию для каждого поля, чем
+ аргументы функций.
+- Структуры опций могут расти со временем без влияния на места вызова.
Вот пример функции, которую можно улучшить:
@@ -2199,11 +2171,11 @@ func foo(ctx context.Context) {
Этот вариант часто предпочтителен, когда применимо одно из следующих условий:
-* Все вызывающие стороны должны указать одну или несколько опций.
-* Большому количеству вызывающих сторон необходимо предоставить множество
- опций.
-* Опции используются совместно несколькими функциями, которые будет вызывать
- пользователь.
+- Все вызывающие стороны должны указать одну или несколько опций.
+- Большому количеству вызывающих сторон необходимо предоставить множество
+ опций.
+- Опции используются совместно несколькими функциями, которые будет вызывать
+ пользователь.
<a id="variadic-options"></a>
@@ -2215,20 +2187,19 @@ func foo(ctx context.Context) {
опции (если есть), а возвращаемое замыкание принимает изменяемую ссылку (обычно
указатель на тип struct), которая будет обновлена на основе входных данных.
-[вариативный (`...`) параметр]:
- https://golang.org/ref/spec#Passing_arguments_to_..._parameters
+[вариативный (`...`) параметр]: https://golang.org/ref/spec#Passing_arguments_to_..._parameters
Использование вариативных опций может предоставить ряд преимуществ:
-* Опции не занимают места в месте вызова, когда конфигурация не нужна.
-* Опции все еще являются значениями, поэтому вызывающие стороны могут делиться
- ими, писать вспомогательные функции и накапливать их.
-* Опции могут принимать несколько параметров (например,
- `cartesian.Translate(dx, dy int) TransformOption`).
-* Функции опций могут возвращать именованный тип, чтобы группировать опции
- вместе в godoc.
-* Пакеты могут разрешать (или запрещать) сторонним пакетам определять (или
- запрещать определение) свои собственные опции.
+- Опции не занимают места в месте вызова, когда конфигурация не нужна.
+- Опции все еще являются значениями, поэтому вызывающие стороны могут делиться
+ ими, писать вспомогательные функции и накапливать их.
+- Опции могут принимать несколько параметров (например,
+ `cartesian.Translate(dx, dy int) TransformOption`).
+- Функции опций могут возвращать именованный тип, чтобы группировать опции
+ вместе в godoc.
+- Пакеты могут разрешать (или запрещать) сторонним пакетам определять (или
+ запрещать определение) свои собственные опции.
**Примечание:** Использование вариативных опций требует значительного количества
дополнительного кода (см. следующий пример), поэтому их следует использовать
@@ -2327,15 +2298,15 @@ func foo(ctx context.Context) {
Предпочитайте этот вариант, когда применимо большинство из следующего:
-* Большинству вызывающих сторон не нужно указывать никакие опции.
-* Большинство опций используется редко.
-* Существует большое количество опций.
-* Опции требуют аргументов.
-* Опции могут завершиться неудачей или быть установлены неправильно (в этом
- случае функция опции возвращает `error`).
-* Опции требуют большого количества документации, которую трудно уместить в
- структуре.
-* Пользователи или другие пакеты могут предоставлять пользовательские опции.
+- Большинству вызывающих сторон не нужно указывать никакие опции.
+- Большинство опций используется редко.
+- Существует большое количество опций.
+- Опции требуют аргументов.
+- Опции могут завершиться неудачей или быть установлены неправильно (в этом
+ случае функция опции возвращает `error`).
+- Опции требуют большого количества документации, которую трудно уместить в
+ структуре.
+- Пользователи или другие пакеты могут предоставлять пользовательские опции.
Опции в этом стиле должны принимать параметры, а не использовать наличие
(presence) для сигнализации своего значения; последнее может значительно
@@ -2360,10 +2331,8 @@ func foo(ctx context.Context) {
См. [оригинальный пост в блоге Роба Пайка] и [доклад Дейва Ченея] для более
глубокого изучения того, как эти опции могут быть использованы.
-[оригинальный пост в блоге Роба Пайка]:
- http://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html
-[доклад Дейва Ченея]:
- https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
+[оригинальный пост в блоге Роба Пайка]: http://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html
+[доклад Дейва Ченея]: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
<a id="complex-clis"></a>
@@ -2379,18 +2348,16 @@ func foo(ctx context.Context) {
Однако, если вам нужны другие функции, которые она не предоставляет, выберите
один из других вариантов.
-* **[cobra]**
-
- * Соглашение о флагах: getopt
- * Распространена за пределами кодовой базы Google.
- * Много дополнительных функций.
- * Подводные камни в использовании (см. ниже).
-
-* **[subcommands]**
+- **[cobra]**
+ - Соглашение о флагах: getopt
+ - Распространена за пределами кодовой базы Google.
+ - Много дополнительных функций.
+ - Подводные камни в использовании (см. ниже).
- * Соглашение о флагах: Go
- * Проста и с ней легко работать правильно.
- * Рекомендуется, если вам не нужны дополнительные функции.
+- **[subcommands]**
+ - Соглашение о флагах: Go
+ - Проста и с ней легко работать правильно.
+ - Рекомендуется, если вам не нужны дополнительные функции.
**Предупреждение**: функции команд cobra должны использовать `cmd.Context()` для
получения контекста, а не создавать свой собственный корневой контекст с помощью
@@ -2423,17 +2390,17 @@ decisions#mark-test-helpers. Цель не в том, чтобы повторя
Go различает "тестовые помощники (test helpers)" и "помощники утверждений
(assertion helpers)":
-* **Тестовые помощники** — это функции, которые выполняют задачи настройки или
- очистки. Все сбои, которые происходят в тестовых помощниках, ожидаемо
- являются сбоями окружения (а не тестируемого кода) — например, когда
- тестовая база данных не может быть запущена, потому что на этой машине
- больше нет свободных портов. Для таких функций часто уместно вызывать
- `t.Helper`, чтобы [пометить их как тестовый помощник]. См. [обработку ошибок
- в тестовых помощниках] для более подробной информации.
+- **Тестовые помощники** — это функции, которые выполняют задачи настройки или
+ очистки. Все сбои, которые происходят в тестовых помощниках, ожидаемо
+ являются сбоями окружения (а не тестируемого кода) — например, когда
+ тестовая база данных не может быть запущена, потому что на этой машине
+ больше нет свободных портов. Для таких функций часто уместно вызывать
+ `t.Helper`, чтобы [пометить их как тестовый помощник]. См. [обработку ошибок
+ в тестовых помощниках] для более подробной информации.
-* **Помощники утверждений** — это функции, которые проверяют правильность
- системы и завершают тест с ошибкой, если ожидание не выполняется. Помощники
- утверждений [не считаются идиоматичными] в Go.
+- **Помощники утверждений** — это функции, которые проверяют правильность
+ системы и завершают тест с ошибкой, если ожидание не выполняется. Помощники
+ утверждений [не считаются идиоматичными] в Go.
Цель теста — сообщить о условиях прохождения/непрохождения тестируемого кода.
Идеальное место для завершения теста с ошибкой — внутри самой функции `Test`,
@@ -2446,7 +2413,7 @@ Go различает "тестовые помощники (test helpers)" и "
По мере роста вашего тестового кода может стать необходимым вынести некоторую
функциональность в отдельные функции. Стандартные соображения программной
-инженерии все еще применяются, поскольку *тестовый код — это все еще код*. Если
+инженерии все еще применяются, поскольку _тестовый код — это все еще код_. Если
функциональность не взаимодействует с тестовым фреймворком, то применяются все
обычные правила. Однако, когда общий код взаимодействует с фреймворком,
необходимо соблюдать осторожность, чтобы избежать распространенных подводных
@@ -2457,21 +2424,21 @@ Go различает "тестовые помощники (test helpers)" и "
организуйте тест одним из следующих способов вместо использования помощников
утверждений или сложных функций валидации:
-* Встройте логику (и валидацию, и завершение с ошибкой) в функцию `Test`, даже
- если это повторяется. Это лучше всего работает в простых случаях.
-* Если входные данные похожи, рассмотрите возможность объединения их в
- [табличный тест (table-driven test)], сохраняя логику встроенной в цикл. Это
- помогает избежать повторения, сохраняя валидацию и завершение с ошибкой в
- `Test`.
-* Если есть несколько вызывающих сторон, которым нужна одна и та же функция
- валидации, но табличные тесты не подходят (обычно потому, что входные данные
- недостаточно просты или валидация требуется как часть последовательности
- операций), организуйте функцию валидации так, чтобы она возвращала значение
- (обычно `error`), а не принимала параметр `testing.T` и использовала его для
- завершения теста с ошибкой. Используйте логику внутри `Test`, чтобы решить,
- завершать ли тест с ошибкой, и предоставить [полезные сообщения об ошибках
- теста]. Вы также можете создать тестовые помощники для выноса общего
- шаблонного кода настройки.
+- Встройте логику (и валидацию, и завершение с ошибкой) в функцию `Test`, даже
+ если это повторяется. Это лучше всего работает в простых случаях.
+- Если входные данные похожи, рассмотрите возможность объединения их в
+ [табличный тест (table-driven test)], сохраняя логику встроенной в цикл. Это
+ помогает избежать повторения, сохраняя валидацию и завершение с ошибкой в
+ `Test`.
+- Если есть несколько вызывающих сторон, которым нужна одна и та же функция
+ валидации, но табличные тесты не подходят (обычно потому, что входные данные
+ недостаточно просты или валидация требуется как часть последовательности
+ операций), организуйте функцию валидации так, чтобы она возвращала значение
+ (обычно `error`), а не принимала параметр `testing.T` и использовала его для
+ завершения теста с ошибкой. Используйте логику внутри `Test`, чтобы решить,
+ завершать ли тест с ошибкой, и предоставить [полезные сообщения об ошибках
+ теста]. Вы также можете создать тестовые помощники для выноса общего
+ шаблонного кода настройки.
Дизайн, описанный в последнем пункте, сохраняет ортогональность. Например,
[пакет `cmp`] не предназначен для завершения тестов с ошибкой, а для сравнения
@@ -2581,10 +2548,8 @@ type FS interface {
реализацию как черный ящик (blackbox), чтобы убедиться, что она соблюдает самые
основные части контракта `io/fs`.
-[приемочным тестированием (acceptance testing)]:
- https://en.wikipedia.org/wiki/Acceptance_testing
-[инверсии управления (inversion of control)]:
- https://en.wikipedia.org/wiki/Inversion_of_control
+[приемочным тестированием (acceptance testing)]: https://en.wikipedia.org/wiki/Acceptance_testing
+[инверсии управления (inversion of control)]: https://en.wikipedia.org/wiki/Inversion_of_control
[`io/fs`]: https://pkg.go.dev/io/fs
[`testing/fstest`]: https://pkg.go.dev/testing/fstest
[`fstest.TestFS`]: https://pkg.go.dev/testing/fstest#TestFS
@@ -2619,9 +2584,8 @@ type FS interface {
Тест должен отмечать, какие инварианты нарушены и как. Ваш дизайн может
выбрать одну из двух дисциплин для сообщения о сбоях:
-
- * **Завершение при первой ошибке (Fail fast)**: возвращать ошибку, как
- только реализация нарушает инвариант.
+ - **Завершение при первой ошибке (Fail fast)**: возвращать ошибку, как
+ только реализация нарушает инвариант.
Это самый простой подход, и он хорошо работает, если ожидается, что
приемочный тест будет выполняться быстро. Простые [сторожевые ошибки
@@ -2639,8 +2603,8 @@ type FS interface {
}
```
- * **Агрегация всех сбоев (Aggregate all failures)**: собирать все сбои и
- сообщать о них всех.
+ - **Агрегация всех сбоев (Aggregate all failures)**: собирать все сбои и
+ сообщать о них всех.
Этот подход напоминает рекомендацию [продолжать выполнение (keep going)]
и может быть предпочтительнее, если ожидается, что приемочный тест будет
@@ -2712,10 +2676,9 @@ func TestAcceptance(t *testing.T) {
}
```
-[сторожевые ошибки (sentinels)]:
- https://google.github.io/styleguide/go/index.html#gotip
-[пользовательские типы]: https://google.github.io/styleguide/go/index.html#gotip
-[агрегирует ошибки]: https://google.github.io/styleguide/go/index.html#gotip
+[сторожевые ошибки (sentinels)]: /pages/gostyleguide/google/index.html#gotip
+[пользовательские типы]: /pages/gostyleguide/google/index.html#gotip
+[агрегирует ошибки]: /pages/gostyleguide/google/index.html#gotip
<a id="use-real-transports"></a>
@@ -2734,14 +2697,10 @@ func TestAcceptance(t *testing.T) {
double)](https://abseil.io/resources/swe-book/html/ch13.html#basic_concepts)
(например, моку, заглушке или фейку) [OperationsServer].
-[тестовому двойнику (test double)]:
- https://abseil.io/resources/swe-book/html/ch13.html#basic_concepts
-[долго выполняющихся операций (long running operations)]:
- https://pkg.go.dev/google.golang.org/genproto/googleapis/longrunning
-[OperationsClient]:
- https://pkg.go.dev/google.golang.org/genproto/googleapis/longrunning#OperationsClient
-[OperationsServer]:
- https://pkg.go.dev/google.golang.org/genproto/googleapis/longrunning#OperationsServer
+[тестовому двойнику (test double)]: https://abseil.io/resources/swe-book/html/ch13.html#basic_concepts
+[долго выполняющихся операций (long running operations)]: https://pkg.go.dev/google.golang.org/genproto/googleapis/longrunning
+[OperationsClient]: https://pkg.go.dev/google.golang.org/genproto/googleapis/longrunning#OperationsClient
+[OperationsServer]: https://pkg.go.dev/google.golang.org/genproto/googleapis/longrunning#OperationsServer
Это рекомендуется вместо ручной реализации клиента из-за сложности правильной
имитации поведения клиента. Используя production-клиент с тестовым сервером, вы
@@ -2765,11 +2724,11 @@ double)](https://abseil.io/resources/swe-book/html/ch13.html#basic_concepts)
затрагивают одну запись в таблице теста и делают невозможным продолжение работы
с этой записью, должны сообщаться следующим образом:
-* Если вы не используете подтесты `t.Run`, используйте `t.Error`, за которым
- следует оператор `continue` для перехода к следующей записи таблицы.
-* Если вы используете подтесты (и вы внутри вызова `t.Run`), используйте
- `t.Fatal`, который завершает текущий подтест и позволяет вашему тестовому
- случаю перейти к следующему подтесту.
+- Если вы не используете подтесты `t.Run`, используйте `t.Error`, за которым
+ следует оператор `continue` для перехода к следующей записи таблицы.
+- Если вы используете подтесты (и вы внутри вызова `t.Run`), используйте
+ `t.Fatal`, который завершает текущий подтест и позволяет вашему тестовому
+ случаю перейти к следующему подтесту.
**Предупреждение:** Не всегда безопасно вызывать `t.Fatal` и подобные функции.
[Подробнее здесь](#t-fatal-goroutine).
@@ -2834,8 +2793,8 @@ func addGameAssets(t *testing.T, dir string) error {
**Совет:** Go 1.14 представила функцию [`t.Cleanup`], которую можно использовать
для регистрации функций очистки, которые запускаются при завершении вашего
-теста. Функция также работает с тестовыми помощниками. См. [GoTip #4: Cleaning
-Up Your Tests](https://google.github.io/styleguide/go/index.html#gotip) для
+теста. Функция также работает с тестовыми помощниками. См. [GoTip #4: Cleaning
+Up Your Tests](/pages/gostyleguide/google/index.html#gotip) для
рекомендаций по упрощению тестовых помощников.
Сниппет ниже в вымышленном файле `paint_test.go` демонстрирует, как
@@ -2904,9 +2863,9 @@ FAIL
Правильное использование `(*testing.T).Helper` гораздо лучше определяет
местоположение сбоя, когда:
-* вспомогательные функции растут
-* вспомогательные функции вызывают другие вспомогательные функции
-* количество использований вспомогательных функций в тестовых функциях растет
+- вспомогательные функции растут
+- вспомогательные функции вызывают другие вспомогательные функции
+- количество использований вспомогательных функций в тестовых функциях растет
**Совет:** Если вспомогательная функция вызывает `(*testing.T).Error` или
`(*testing.T).Fatal`, предоставьте некоторый контекст в строке формата, чтобы
@@ -3122,10 +3081,8 @@ testmain]. Это может произойти, если ресурс, треб
[*амортизация общей настройки теста*] или обычного [тестового помощника] для
ваших нужд.
-[пользовательскую точку входа testmain]:
- https://golang.org/pkg/testing/#hdr-Main
-[функциональных тестов (functional tests)]:
- https://en.wikipedia.org/wiki/Functional_testing
+[пользовательскую точку входа testmain]: https://golang.org/pkg/testing/#hdr-Main
+[функциональных тестов (functional tests)]: https://en.wikipedia.org/wiki/Functional_testing
[*амортизация общей настройки теста*]: #t-setup-amortization
[тестового помощника]: #t-common-setup-scope
@@ -3186,9 +3143,9 @@ func TestMain(m *testing.M) {
Использование `sync.Once` может быть уместным, хотя и не обязательно, если все
из следующего верно для общей настройки:
-* Она дорогая.
-* Она применяется только к некоторым тестам.
-* Она не требует очистки.
+- Она дорогая.
+- Она применяется только к некоторым тестам.
+- Она не требует очистки.
```go
// Хорошо:
@@ -3250,11 +3207,11 @@ func TestRegression682831(t *testing.T) {
Есть несколько способов конкатенации строк в Go. Некоторые примеры включают:
-* Оператор "+"
-* `fmt.Sprintf`
-* `strings.Builder`
-* `text/template`
-* `safehtml/template`
+- Оператор "+"
+- `fmt.Sprintf`
+- `strings.Builder`
+- `text/template`
+- `safehtml/template`
Хотя не существует универсального правила, какой выбрать, следующие рекомендации
описывают, когда каждый метод предпочтителен.
@@ -3318,8 +3275,8 @@ for i, d := range digitsOfPi {
str := b.String()
```
-**Примечание:** Для более подробного обсуждения см. [GoTip #29: Building
-Strings Efficiently](https://google.github.io/styleguide/go/index.html#gotip).
+**Примечание:** Для более подробного обсуждения см. [GoTip #29: Building
+Strings Efficiently](/pages/gostyleguide/google/index.html#gotip).
<a id="string-constants"></a>
@@ -3362,8 +3319,7 @@ state)](https://en.wikipedia.org/wiki/Global_variable). Им рекоменду
критично для поставщиков инфраструктуры, которые предлагают библиотеки,
интеграции и сервисы другим командам.
-[глобальное состояние (global state)]:
- https://en.wikipedia.org/wiki/Global_variable
+[глобальное состояние (global state)]: https://en.wikipedia.org/wiki/Global_variable
[уровне пакета (package level)]: https://go.dev/ref/spec#TopLevelDecl
```go
@@ -3402,18 +3358,18 @@ func main() {
См. также:
-* [Go Tip #5: Slimming Your Client
- Libraries](https://google.github.io/styleguide/go/index.html#gotip)
-* [Go Tip #24: Use Case-Specific
- Constructions](https://google.github.io/styleguide/go/index.html#gotip)
-* [Go Tip #40: Improving Time Testability with Function
- Parameters](https://google.github.io/styleguide/go/index.html#gotip)
-* [Go Tip #41: Identify Function Call
- Parameters](https://google.github.io/styleguide/go/index.html#gotip)
-* [Go Tip #44: Improving Time Testability with Struct
- Fields](https://google.github.io/styleguide/go/index.html#gotip)
-* [Go Tip #80: Dependency Injection
- Principles](https://google.github.io/styleguide/go/index.html#gotip)
+- [Go Tip #5: Slimming Your Client
+ Libraries](/pages/gostyleguide/google/index.html#gotip)
+- [Go Tip #24: Use Case-Specific
+ Constructions](/pages/gostyleguide/google/index.html#gotip)
+- [Go Tip #40: Improving Time Testability with Function
+ Parameters](/pages/gostyleguide/google/index.html#gotip)
+- [Go Tip #41: Identify Function Call
+ Parameters](/pages/gostyleguide/google/index.html#gotip)
+- [Go Tip #44: Improving Time Testability with Struct
+ Fields](/pages/gostyleguide/google/index.html#gotip)
+- [Go Tip #80: Dependency Injection
+ Principles](/pages/gostyleguide/google/index.html#gotip)
API, которые не поддерживают явную передачу зависимостей, становятся хрупкими с
увеличением числа клиентов:
@@ -3480,53 +3436,54 @@ func TestRegression_InvalidUser(t *testing.T) {
Использование глобального состояния создает проблемы, на которые нет простых
ответов для вас и клиентов API:
-* Что произойдет, если клиенту нужно использовать разные и отдельно работающие
- наборы `Plugin` (например, для поддержки нескольких серверов) в одном
- процессе?
+- Что произойдет, если клиенту нужно использовать разные и отдельно работающие
+ наборы `Plugin` (например, для поддержки нескольких серверов) в одном
+ процессе?
-* Что произойдет, если клиент захочет заменить зарегистрированный `Plugin`
- альтернативной реализацией в тесте, например, [тестовым двойником]?
+- Что произойдет, если клиент захочет заменить зарегистрированный `Plugin`
+ альтернативной реализацией в тесте, например, [тестовым двойником]?
Что произойдет, если тестам клиента требуется герметичность между
экземплярами `Plugin` или между всеми зарегистрированными плагинами?
-* Что произойдет, если несколько клиентов `Register` плагин `Plugin` под одним
- и тем же именем? Кто победит, если вообще победит?
+- Что произойдет, если несколько клиентов `Register` плагин `Plugin` под одним
+ и тем же именем? Кто победит, если вообще победит?
Как следует [обрабатывать](https://neonxp.ru/pages/gostyleguide/google/decisions/#handle-errors) ошибки? Если код
вызывает panic или `log.Fatal`, будет ли это всегда [уместно для всех мест,
в которых может быть вызван API](https://neonxp.ru/pages/gostyleguide/google/decisions/#dont-panic)? Может ли клиент
проверить, что он не делает ничего плохого, прежде чем сделать это?
-* Существуют ли определенные этапы начальной загрузки программы или ее
- жизненного цикла, во время которых можно вызывать `Register`, а когда нет?
+- Существуют ли определенные этапы начальной загрузки программы или ее
+ жизненного цикла, во время которых можно вызывать `Register`, а когда нет?
+
+ Что произойдет, если `Register` будет вызван в неподходящее время? Клиент
+ может вызвать `Register` в [`func
- Что произойдет, если `Register` будет вызван в неподходящее время? Клиент
- может вызвать `Register` в [`func
init`](https://go.dev/ref/spec#Package_initialization), до разбора флагов
- или после `main`. Этап, на котором вызывается функция, влияет на обработку
- ошибок. Если автор API предполагает, что API вызывается *только* во время
- инициализации программы без требования, чтобы это было так, это
- предположение может подтолкнуть автора к проектированию обработки ошибок для
- [завершения программы](https://neonxp.ru/pages/gostyleguide/google/best-practices/#program-init), моделируя API как
- функцию типа `Must`. Завершение не подходит для библиотечных функций общего
+или после `main`. Этап, на котором вызывается функция, влияет на обработку
+ошибок. Если автор API предполагает, что API вызывается _только_ во время
+инициализации программы без требования, чтобы это было так, это
+предположение может подтолкнуть автора к проектированию обработки ошибок для
+[завершения программы](https://neonxp.ru/pages/gostyleguide/google/best-practices/#program-init), моделируя API как
+функцию типа `Must`. Завершение не подходит для библиотечных функций общего
назначения, которые могут использоваться на любом этапе.
-* Что, если потребности в параллелизме клиента и дизайнера не совпадают?
+- Что, если потребности в параллелизме клиента и дизайнера не совпадают?
См. также:
-* [Go Tip #36: Enclosing Package-Level
- State](https://google.github.io/styleguide/go/index.html#gotip)
-* [Go Tip #71: Reducing Parallel Test
- Flakiness](https://google.github.io/styleguide/go/index.html#gotip)
-* [Go Tip #80: Dependency Injection
- Principles](https://google.github.io/styleguide/go/index.html#gotip)
-* Обработка ошибок: [Look Before You
- Leap](https://docs.python.org/3/glossary.html#term-LBYL) против [Easier to
- Ask for Forgiveness than
- Permission](https://docs.python.org/3/glossary.html#term-EAFP)
-* [Unit Testing Practices on Public APIs]
+- [Go Tip #36: Enclosing Package-Level
+ State](/pages/gostyleguide/google/index.html#gotip)
+- [Go Tip #71: Reducing Parallel Test
+ Flakiness](/pages/gostyleguide/google/index.html#gotip)
+- [Go Tip #80: Dependency Injection
+ Principles](/pages/gostyleguide/google/index.html#gotip)
+- Обработка ошибок: [Look Before You
+ Leap](https://docs.python.org/3/glossary.html#term-LBYL) против [Easier to
+ Ask for Forgiveness than
+ Permission](https://docs.python.org/3/glossary.html#term-EAFP)
+- [Unit Testing Practices on Public APIs]
Глобальное состояние имеет каскадные эффекты на [здоровье кодовой базы
Google](https://neonxp.ru/pages/gostyleguide/google/guide/.md#maintainability). К глобальному состоянию следует подходить с
@@ -3544,7 +3501,7 @@ Google](https://neonxp.ru/pages/gostyleguide/google/guide/.md#maintainability).
Ниже перечислены несколько наиболее распространенных проблемных форм API:
-* Переменные верхнего уровня, независимо от того, экспортируются они или нет.
+- Переменные верхнего уровня, независимо от того, экспортируются они или нет.
```go
// Плохо:
@@ -3558,14 +3515,14 @@ Google](https://neonxp.ru/pages/gostyleguide/google/guide/.md#maintainability).
См. [лакмусовые тесты](#globals-litmus-tests), чтобы узнать, когда они
безопасны.
-* Шаблон [локатора служб (service locator
- pattern)](https://en.wikipedia.org/wiki/Service_locator_pattern). См.
- [первый пример](#globals). Сам шаблон локатора служб не является
- проблематичным, а проблема в том, что локатор определен как глобальный.
+- Шаблон [локатора служб (service locator
+ pattern)](https://en.wikipedia.org/wiki/Service_locator_pattern). См.
+ [первый пример](#globals). Сам шаблон локатора служб не является
+ проблематичным, а проблема в том, что локатор определен как глобальный.
-* Реестры для [обратных вызовов
- (callbacks)](https://en.wikipedia.org/wiki/Callback_\(computer_programming\))
- и подобного поведения.
+- Реестры для [обратных вызовов
+ (callbacks)](<https://en.wikipedia.org/wiki/Callback_(computer_programming)>)
+ и подобного поведения.
```go
// Плохо:
@@ -3578,9 +3535,9 @@ Google](https://neonxp.ru/pages/gostyleguide/google/guide/.md#maintainability).
}
```
-* "Толстые" (thick) клиентские синглтоны для таких вещей, как бэкенды,
- хранилища, уровни доступа к данным и другие системные ресурсы. Они часто
- создают дополнительные проблемы с надежностью служб.
+- "Толстые" (thick) клиентские синглтоны для таких вещей, как бэкенды,
+ хранилища, уровни доступа к данным и другие системные ресурсы. Они часто
+ создают дополнительные проблемы с надежностью служб.
```go
// Плохо:
@@ -3598,7 +3555,7 @@ Google](https://neonxp.ru/pages/gostyleguide/google/guide/.md#maintainability).
> **Примечание:** Многие устаревшие API в кодовой базе Google не следуют этому
> руководству; фактически, некоторые стандартные библиотеки Go позволяют
-> настраивать поведение через глобальные значения. Тем не менее, нарушение
+> настраивать поведение через глобальные значения. Тем не менее, нарушение
> этого руководства устаревшим API **[не должно использоваться как
> прецедент](https://neonxp.ru/pages/gostyleguide/google/guide/#local-consistency)** для продолжения шаблона.
>
@@ -3611,31 +3568,31 @@ Google](https://neonxp.ru/pages/gostyleguide/google/guide/.md#maintainability).
[API, использующие шаблоны выше](#globals-forms), небезопасны, когда:
-* Несколько функций взаимодействуют через глобальное состояние при выполнении
- в одной программе, несмотря на то, что в остальном они независимы (например,
- написаны разными авторами в совершенно разных каталогах).
-* Независимые тестовые случаи взаимодействуют друг с другом через глобальное
- состояние.
-* Пользователи API склонны заменять или подменять глобальное состояние для
- целей тестирования, особенно чтобы заменить любую часть состояния [тестовым
- двойником], например, заглушкой, фейком, шпионом или моком.
-* Пользователи должны учитывать особые требования к порядку при взаимодействии
- с глобальным состоянием: `func init`, разобраны ли уже флаги и т.д.
+- Несколько функций взаимодействуют через глобальное состояние при выполнении
+ в одной программе, несмотря на то, что в остальном они независимы (например,
+ написаны разными авторами в совершенно разных каталогах).
+- Независимые тестовые случаи взаимодействуют друг с другом через глобальное
+ состояние.
+- Пользователи API склонны заменять или подменять глобальное состояние для
+ целей тестирования, особенно чтобы заменить любую часть состояния [тестовым
+ двойником], например, заглушкой, фейком, шпионом или моком.
+- Пользователи должны учитывать особые требования к порядку при взаимодействии
+ с глобальным состоянием: `func init`, разобраны ли уже флаги и т.д.
При условии, что вышеуказанные условия избегаются, существует **несколько
ограниченных обстоятельств, при которых эти API безопасны**, а именно, когда
верно любое из следующего:
-* Глобальное состояние логически постоянно
- ([пример](https://github.com/klauspost/compress/blob/290f4cfacb3eff892555a491e3eeb569a48665e7/zstd/snappy.go#L413)).
-* Наблюдаемое поведение пакета является бессостоятельным (stateless).
- Например, общедоступная функция может использовать частную глобальную
- переменную в качестве кэша, но пока вызывающая сторона не может отличить
- попадания в кэш от промахов, функция является бессостоятельной.
-* Глобальное состояние не просачивается в вещи, внешние по отношению к
- программе, такие как sidecar-процессы или файлы в общей файловой системе.
-* Нет ожидания предсказуемого поведения
- ([пример](https://pkg.go.dev/math/rand)).
+- Глобальное состояние логически постоянно
+ ([пример](https://github.com/klauspost/compress/blob/290f4cfacb3eff892555a491e3eeb569a48665e7/zstd/snappy.go#L413)).
+- Наблюдаемое поведение пакета является бессостоятельным (stateless).
+ Например, общедоступная функция может использовать частную глобальную
+ переменную в качестве кэша, но пока вызывающая сторона не может отличить
+ попадания в кэш от промахов, функция является бессостоятельной.
+- Глобальное состояние не просачивается в вещи, внешние по отношению к
+ программе, такие как sidecar-процессы или файлы в общей файловой системе.
+- Нет ожидания предсказуемого поведения
+ ([пример](https://pkg.go.dev/math/rand)).
> **Примечание:**
> [Sidecar-процессы](https://www.oreilly.com/library/view/designing-distributed-systems/9781491983638/ch02.html)
@@ -3653,18 +3610,18 @@ image`](https://pkg.go.dev/image) с его функцией
лакмусовые тесты, примененные к типичному декодеру, например, для обработки
формата [PNG](https://pkg.go.dev/image/png):
-* Множественные вызовы API `package image`, использующие зарегистрированные
- декодеры (например, `image.Decode`), не могут мешать друг другу, аналогично
- и для тестов. Единственное исключение — `image.RegisterFormat`, но это
- смягчается пунктами ниже.
-* Крайне маловероятно, что пользователь захочет заменить декодер [тестовым
- двойником], так как декодер PNG является примером случая, когда предпочтение
- нашей кодовой базы реальным объектам применяется. Однако пользователь с
- большей вероятностью заменит декодер тестовым двойником, если декодер
- состоятельно взаимодействует с ресурсами операционной системы (например,
- сетью).
-* Коллизии при регистрации возможны, хотя на практике они, вероятно, редки.
-* Декодеры являются бессостоятельными, идемпотентными и чистыми (pure).
+- Множественные вызовы API `package image`, использующие зарегистрированные
+ декодеры (например, `image.Decode`), не могут мешать друг другу, аналогично
+ и для тестов. Единственное исключение — `image.RegisterFormat`, но это
+ смягчается пунктами ниже.
+- Крайне маловероятно, что пользователь захочет заменить декодер [тестовым
+ двойником], так как декодер PNG является примером случая, когда предпочтение
+ нашей кодовой базы реальным объектам применяется. Однако пользователь с
+ большей вероятностью заменит декодер тестовым двойником, если декодер
+ состоятельно взаимодействует с ресурсами операционной системы (например,
+ сетью).
+- Коллизии при регистрации возможны, хотя на практике они, вероятно, редки.
+- Декодеры являются бессостоятельными, идемпотентными и чистыми (pure).
<a id="globals-default-instance"></a>
@@ -3714,14 +3671,12 @@ image`](https://pkg.go.dev/image) с его функцией
состояния к известному хорошему значению по умолчанию (например, для
облегчения тестирования).
-[целями сборки бинарников (binary build targets)]:
- https://github.com/bazelbuild/rules_go/blob/master/docs/go/core/rules.md#go_binary
-[библиотеками (libraries)]:
- https://github.com/bazelbuild/rules_go/blob/master/docs/go/core/rules.md#go_library
+[целями сборки бинарников (binary build targets)]: https://github.com/bazelbuild/rules_go/blob/master/docs/go/core/rules.md#go_binary
+[библиотеками (libraries)]: https://github.com/bazelbuild/rules_go/blob/master/docs/go/core/rules.md#go_library
См. также:
-* [Go Tip #36: Enclosing Package-Level
- State](https://google.github.io/styleguide/go/index.html#gotip)
-* [Go Tip #80: Dependency Injection
- Principles](https://google.github.io/styleguide/go/index.html#gotip)
+- [Go Tip #36: Enclosing Package-Level
+ State](/pages/gostyleguide/google/index.html#gotip)
+- [Go Tip #80: Dependency Injection
+ Principles](/pages/gostyleguide/google/index.html#gotip)