сборник договоренностей об оформлении кода и процессов разработки
Go to file
2025-04-14 18:04:33 +03:00
.gitignore added gitignore 2025-04-14 16:09:32 +03:00
API.md Update 2 files 2024-07-06 18:50:59 +00:00
ENVS.md add envs stleguide 2024-12-06 15:46:23 +03:00
README.md Update README.md 2024-11-21 21:19:49 +00:00
REFACTORING.md Update REFACTORING.md 2024-08-19 15:15:00 +00:00
ZAPLOGGERR.md research type zap loggers 2025-04-14 18:04:33 +03:00

codeconv

Соглашение о написании кода для бэкенда на go. Содержит три секции:

  • утверждённое - то, что согласовано, подтвердило свою эффективность и должно быть использовано. Кандидат на добавление в линтер
  • рассматриваемое - то, что находится в статусе эксперимента, оценивается в плане эффективности. Кандидат на добавление в утверждённое
  • предложенное - в эту секцию можно складывать те идеи, которые возникают, но требуют обсуждения, перед тем как начать экспериментировать с их применением в каком-либо проекте

Написанное ниже применять без фанатизма, при несогласии - обсуждать.

Утверждённое

  • Скоро будет переделан. Использовать как рекомендацию, а не как правило лейаут - https://penahub.gitlab.yandexcloud.net/pena-services/docs/-/blob/main/architecture/golang/README.md

  • В случае если у функции больше трёх аргументов, аргументы надо передавать при помощи структуры *Deps, по значению.

  • Если можно не использовать интерфейс, значит он не нужен. Имеется в виду, что интерфейсы создавать и передавать куда либо, только в случае, если сущности одноранговые(например апишки платёжных решений) или же действительно имеют необходимость в дублировании интерфейса с изменённым функционалом.

  • Если можно обойтись без указателя, стоит обойтись без указателя. Мы не боимся распухания стека, но npd ошибки и создание объектов на куче нас пугают. Предварительная оптимизация - зло, поэтому вопросы экономии на передаче по указателю будут подниматься после релиза, по необходимости. На будущее, критериями для замены передачи по значению на передачу по указателю могут являться: escape analisis покажет, что память так же будет выделяться на стеке, уменьшится среднее время выполнения операций - изолированный тест не подходит, ибо тут включается вопрос процессорного кеша и надо понять, будет ли проц чаще обновлять кеш, - количество аллокаций и объём потребляемой памяти.

  • Избегать чрезмерного разбиения на файлы и пакеты. Сейчас по проекту часто можно встретить в рамках пакета файлы, содержащие 1-2 структуры. Или несколько констант. Иногда это оправдано, например модель данных действительно может содержать только 1-2 структуры. Но зачастую это излишне и мешает нормальному ревью, например выносить константы названия полей в модели в отдельный пакет, по одному файлу на каждую сущность

  • Именование: сокращения допустимы только в рамках согласованного списка сокращений

  • Именование: стремимся к оптимальному соотношению сигнал\шум. Т.е. сокращения это зло, но слишком длинное именование - не меньшее зло

  • контекст всегда передавать вне структуры с зависимостями

  • Клиенты к сервису располагать рядом с сервисом, в каталоге /pkg/client

  • Стандартные сокращения: err, ctx, resp, deps, opts

  • Ресиверы сокращать до первой буквы названия типа. НИЧЕГО другого до одной буквы не сокращать.

  • Ветвиться от main или staging можно только в исключительных случаях, если тимлид так сказал. Во всех остальных случаях ветвимся от dev или с верхушки ветки своей последней задачи. Исходим из логики "одна задача - одна ветка"

Рассматриваемое

  • Именование: одно и то же именование не должно соответствовать концептуально разным сущностям. Пример называть все ошибки err нормально, пока они выполняют одну и ту же роль - единственной возвращаемой ошибки, но называть разные ресиверы одним именем вредно

  • Именование: если сущность имеет длинное наименование, но используется почти везде - стоит вынести на обсуждение вопрос о стандартизации сокращения

  • Использовать else только в случае, если обе ветки умещаются в 12 строк. else if не использовать

Предложение

  • Есть мысль, помечать внутренние пакеты суффиксом или префиксом, чтобы при чтении кода быстро определять, что есть что. но она требует рассмотрения на практике

  • Отделять переносами строки разнотипные операции - штука верная, но без фанатизма. Отделять ли объявление переменных от блока кода, в котором они будут использоваться - дело каждого

  • Разбиение на файлы: не вижу технического смысла выносить в отдельный файл сущность, которая чисто техническая и используется только в рамках другой сущности, как например конфиг для приложения, структуры запросов, возвращаемых значений, утилиты, используемые одним пакетом и тому подобное

  • Выбор задачи: сейчас действует установка меток по важности задачи, типа Low, High и так далее. Когда я ставлю задачу, я могу ещё не знать, какой у неё реальный приоритет, потому что на её приоритет могут влиять другие задачи. Например, я могу сегодня поставить задачу с приоритетом Low, потому что там какие-то мелкие правки, но на следующий день прилетит срочная задача с приоритетом High, которую бы сделать после этих мелких правок, чтобы не городить ведро костылей. Поэтому выбор задачи надо производить следующим образом - выбираешь задачу с наивысшим приоритетом, смотришь в список блокирующих задач и если он не пуст, выбираешь одну из них. Почему в Предложеии этот пункт - я не уверен в адекватности и удобстве этого решения