По названию похоже на типичную проходную статью с медиума с околонулевой ценностью, но по факту нахожу эти советы хорошими, и пару раз поймал себя на мысли что я часто указываю в ревью на те же ошибки, что описывает автор, но раньше не выделял их в отдельные паттерны.
Например:
Не дублируй логи - если ловим ошибку - мы ее или логируем, или возвращаем, но не оба сразу
Для код-ревью это хороший паттерн, потому как мысль-то вроде очевидная, но не всегда на это обращаешь внимание. Если где-то в MR на внутреннем уровне кто-то добавил лог, надо проверить, есть ли он на уровне выше. Если есть - удаляем.
Не добавляй интерфейс слишком рано
Я пришел к такому же выводу спустя несколько лет разработки на Go. Вообще, это напоминание другой базовой истины еще из "Чистого кода" - не делай преждевременных оптимизаций. Но, в индустрии во многих компаниях есть правило: любой тип должен быть с интерфейсом. По факту получается так, что в коде несколько сотен интерфейсов, а более одной реализации - у нескольких. Сначала стоит вернуть конкретный тип, а потом, если будет задача на расширение, всегда можно будет добавить интерфейс и реализовать его еще раз.
Сначала mutex, затем каналы
Каналы - это сложный механизм для синхронизации и взаимодействия горутин, и часто его использование слишком избыточно. Если появилась мысль добавить куда-то горутины или каналы, автор советует сделать так:
- сначала, если возможно, пишем синхронный код, решающий задачу
- если профилирование показывает, что это узкое место - добавляем горутины
- для синхронизации горутин sync.Mutex и sync.WaitGroup
- и только если профилирование показывает, что их недостаточно - вводим каналы
Проектировать код лучше без указателей
В Go очень часто возвращаемое значение из функций описывают следующим образом:
MyFunc() (*MyStruct, error)
с логичным намерением: если будет ошибка - мы возвращаем
nil, err для удобства - не нужно писать MyStruct{}, err. Еще изредка можно услышать, что это делается для оптимизации. По факту большинство структур, с которыми мы чаще всего работаем - структуры с несколькими полями. И с точки зрения оптимизации мы не выиграем, если вернем указатель на структуру, а не саму структуру, так как скопировать эти самые несколько полей на стек почти ничего не стоит. А если мы работаем со стеком - мы снижаем нагрузку на GC.
А что мы еще снижаем - это ошибки с обработкой nil. Почти на каждом большом проекте, где я работал, хотя бы раз я с этим сталкивался - кто-то обязательно со временем вернет nil там, где его точно не будет ожидать вызывающий код.
Весь список с множеством полезных деталей можно прочитать тут - https://www.reddit.com/r/golang/comments/1oc5is8/writing_better_go_lessons_from_10_code_reviews/
dev notes | golang digest