# Соглашения и code style

# Общие рекомендации

  1. Работая с кодом, стремитесь повышать его качество. Если быстрый фикс ухудшает качество кода, запланируйте рефакторинг.
  2. Помните, ваш код должен быть понятен не только вам, но и коллегам. Красота скрывается в простоте.
  3. Предпочитайте композицию вместо наследования.
  4. Остерегайтесь сразу создавать переиспользуемые компоненты (Reusable components)]. Лишний слой абстрации переусложнит его использование сейчас.

# Комментирование

  • Комментарии пишем на русском языке.
  • Пишите в комментариях моменты, которые не очевидны при чтении кода, пеерчисление сайд-эффектов.
  • Высокоуровневые комментарии класса/модуля не должны описывать детали реализации. Если у класса есть отдельно интерфейс, комментарии пишите в интерфейсе.
  • Низкоуровневые комментарии описывают описывают код и должны отвечать на вопросы: "Что?" и "Почему?", а не "Как?".
  • Если багфикс требует написание сложного кода, в комментарии поставьте также номер задачи из JIRA.
  • Обновляйте комментарии одновременно с кодом, не дублируйте.

# API

# REST API

# Документирование

Используем swagger/openapi формат.

# Версионирование

Номер версии указываем в префиксе:

GET /api/v1/
GET /api/v2/

Используем только мажорные версии. Недопустимо переименовывать методы или параметры в рамках одной версии.

Если необходимо поменяется параметр, номер версии должен быть повышен и предусмомотрена обратная совместимость в предыдущей версии API.

# Именование endpoint'ов

Имя коллекций в множественном числе:

GET /campaigns
GET /campaigns/123

Используйте вложенность, чтобы показать связанность объектов:

GET /campaigns/123/webhook/1

# Методы endpoint'ы

В именах endpoint'ов должны быть только существительные. Действие определяют http-методы:

HEAD /offers/123    # возвращает только HTTP заголовки, без body
GET /offers/123     # запрос оффера с ID 123
DELETE /offers/123  # удаление оффера
POST /offers        # создание нового оффера
PUT /offers/123     # модификация оффера ID 123
PATCH /offers/123   # модификация только определенных параметров оффера

Если над объектом производится специфические действия, допустимо добавлять глаголы:

PUT /offers/123/disable

# Заголовки

Используем стандартные HTTP коды. Наиболее используемые:

200 - все ок
202 - действие принято, но будет выполнено позже
400 - в запросе переданы некорректные параметры
401 - необходима авторизация
402 - оплаченный период закончен или данное действие недоступно в текущей редакции
403 - с текущей авторизацией доступ к объекту запрещен
404 - endpoint'а или объекта не существует
405 - передан некорректный метод для endpoint'аe
406 - неприемлемый запрос, ошибка валидации, переданы некорректные данные
429 - превышен лимит запросов

# Ошибки

Передавайте в ответе текст ошибки:

{
    "error" => "This campaign is already started"
}

Расширенный вариант:

{
    "error" => "This campaign is already started",
    "code" => "campaign_started",
    "documentation_url": "https://developer.github.com/v3"
}

# Параметры:

  • sort - сортировка (по умолчанию asc):

    GET /offers?sort=name

    GET /offers?sort=name:asc GET /offers?sort=name:desc

    GET /offers?sort=name:asc,country:desc

  • offset и limit для пагинации:

    GET /offers?offset=10&limit=10

  • filter для фиграции:

    GET /offers?filter

Даты в формате ISO 8601: YYYY-MM-DDTHH:MM:SSZ.

# Лимитирование запросов

Если у API есть лимит запросов, в ответе нужно передавать следующие заголовки:

  • X-RateLimit-Limit - какое есть ограничение (число)
  • X-RateLimit-Remaining - сколько осталось до достижение лимита (число)
  • X-RateLimit-Reset - сколько секунд осталось до сброса ограничений

# Логирование

  • Обязательно должен вестись лог запросов к API и ответов. Все персональные данные и пароли нужно фильтровать.

# Мониторинг

# Health-checks

  • Опишите entryoint для проверки состояния приложения (читайте о livenessPrope)
  • Если приложению нужно время для разогрева прежде, чем он сможет обслуживать трафик, опишите readinessProbe

# Бизнес метрики

Читайте про выгрузку метрик в Prometheus.

WARNING

Убедитесь, что метрики недоступны извне и запрещен к ним доступ через ingress.

# JavaScript

Смотрите /dev/cs/js.html

# PHP

Следуем соглашению PSR-2

В рамках проекта Keitaro, добавляются особенности:

  1. Имена приватных переменных класса пишем с подчеркиванием private $_somePrivateVar;.
  2. Имена приватных методов пишем с подчеркиванием private function _somePrivateMethod() {}.

Содержимое phpcs.xml для PHP_CodeSniffer:

<?xml version="1.0"?>
<ruleset name="PSR2C">
    <rule ref="PSR2"/>
    <arg name="colors"/>
    <description>Apliteni Coding Standard</description>
    <exclude-pattern>vendor/*</exclude-pattern>

    <rule ref="PSR2.Methods.MethodDeclaration.Underscore">
        <type>warning</type>
    </rule>
    <rule ref="PSR2.Classes.PropertyDeclaration.Underscore">
        <type>warning</type>
    </rule>
	<rule ref="PSR1.Methods.CamelCapsMethodName">
        <exclude-pattern>tests/*</exclude-pattern>
    </rule>
</ruleset>

# Strict Types и Type Hinting

Включаем строгую типизацию:

declare(strict_types=1);

Список type hinting по версиям PHP https://mlocati.github.io/articles/php-type-hinting.html.

# Ruby

A community-driven Ruby coding style guide.

# Golang

# Рекомендации по коду

  • Используем Go Modules.
  • Вендерим зависимости..
  • Используем GolangCI Lint.
  • Тесты храним в тех же директориях, что и код. Т.е. не в tests/.
  • Именовать папки предпочитаем по соглашению golang-standards/project-layout.
  • Подключите в проекте пакет uber-go/automaxprocs.
  • Чтобы избежать циклических зависимостей для связи между пакетов используем интерфейсы, модели и константы
  • Для работы со внешними источниками используем адаптеры. Они не должны содержать бизнес логику, только методы повторяющие методы на внешних компонентах. К адаптерам пишем интерфейсы и используя интерфейсы инжектим их там где они нужны.
  • Для сложных конструкторов пишем фабрики.
  • Сервисы пишем отдельно и весь код в сервисах должен быть чистыми функциями.
  • Для работы с данными используем репозитории. При этом инжектим внутрь репозитория источник данных.
  • Модели должны быть тонкими, не содержать бизнес логику.
  • Избегайте глобальных переменных.

# Рекомендуемые пакеты

  • Для логирования https://github.com/sirupsen/logrus
  • Для роутинга https://github.com/gorilla/mux
  • Для работы с env переменными https://github.com/caarlos0/env и https://github.com/joho/godotenv
  • Для генерации интерфейсов https://github.com/vburenin/ifacemaker
  • Для генерации моков к интерфейсам https://github.com/vektra/mockery
  • Для проверки значений в тестах https://godoc.org/github.com/stretchr/testify/assert
  • Для использования моков https://godoc.org/github.com/stretchr/testify/mock (Если есть mock SomeStructMock делаем SomeStructMock.On("SomeMethod", mock.AnythingOfType("*models.ParamTypeStruct")).Return(mockedValue, err).Once() )

Почитать:

# Shell

Google Shell Style Guide.

# Makefile

  1. Рекомендуем заводить Makefile в каждом проекте, с унифицированными командами make dev, make test.
  2. Рекомендуемое имя файла Makefile.
  3. Имя таргетов через -. Например, run-tests. Начинаем с глагола: apply-, create-, install- и т.д..
  4. Переменные окружения пишем в верхнем регистре. Пример, PROJECT_PATH
  5. Локальные переменные в нижнем с разделителем _. Пример, build_dir = $(PROJECT_PATH)/build
  6. Добавьте команду make help:
help:  ## Display this help
    @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n  make \033[36m<target>\033[0m\n\nTargets:\n"} /^[a-zA-Z_-]+:.*?##/ { printf "  \033[36m%-10s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST)

test:  ## Run tests
    go test ./..

# CoffeeScript

CoffeeScript Style Guide

# Книги

  1. A Philosophy of Software Design