# Соглашения и 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 - сколько секунд осталось до сброса ограничений

# JavaScript

  • Стиль Airbnb, Airnb React. В виде NPM пакетов: tslint-config-airbnb, eslint-config-airbnb
  • Комментирование в формате JSDoc.

# React

Новые проекты создаем с поддержкой typescript:

npx create-react-app  --typescript ./project-name

В проекте подключаем Prettier, Husky, конфиг tslint-config-airbnb:

npm install --save-dev prettier lint-staged tslint tslint-config-airbnb

Добавьте в package.json:

"husky": {
  "hooks": {
    "pre-commit": "lint-staged"
  }
},  
"lint-staged": {
    "{src,test}/**/*.ts*": [
      "prettier --write",
      "git add"
    ]
  },

В .prettierrc:

{
  "singleQuote": true,
  "arrowParens": "always",
  "trailingComma": "all"
}

В tslint.json:

{
  "extends": "tslint-config-airbnb",
  "rules": {
    "variable-name": [
      true,
      "allow-pascal-case"
    ],
    "import-name": [
      false
    ]
  },
  "linterOptions": {
    "exclude": [
      "config/**/*.js",
      "node_modules/**/*.ts",
      "**/*.json",
      "**/*.css",
      "**/*.sass"
    ]
  }
}

Другие рекомендуемые практики

  • PropTypes не нужен, если используете интерфейсы TypeScript. Если же в проекте нет TS, выносите описание объектов (PropTypes.shape) в отдельные файлы.

# Angular.JS

Angular 1 Style Guide

# Vue.js

Official Style Guide

# 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 Linters

Используем GolangCI. Ставится локально таким образом:

$ go get -u github.com/golangci/golangci-lint/cmd/[email protected]
$ golangci-lint run

# Go Modules

В проектах используем Go Modules для работы с зависимостями и "вендирим" все пакеты - коммитим в репозиторий.

go mod init [имя проекта]
go mod vendor

В CI включено по умолчанию GOFLAGS=-mod=vendor, поэтому перед пушем в репозиторий запустите:

# Shell

Google Shell Style Guide.

# Makefile

  1. Рекомендуем заводить Makefile в каждом проекте, с унифицированными командами make dev, make test.

  2. Имя make-файлов Makefile.

  3. Имя таргетов через минус. Например, run-tests.

  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\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