# Other languages

# General recommendations

  1. Strive to improve the quality of the code while working with it. If a quick fix degrades the quality of your code, plan a refactoring.
  2. Remember, your code should be understandable both to you and to your colleagues. The beauty is in the simplicity (opens new window).
  3. Prefer composition instead of inheritance (opens new window).
  4. Beware of creating Reusable components from the very beginning. An extra layer of abstraction will complicate its use.
  5. When you get some data from external sources (e.g. database, http call etc) do typechecks right at the beginning. Ideally it should be done inside the adapter. So when data is comming out of adapter, it should already be type checked.
  6. Take care of exceptions. On the low level we should catch them and rethrow some specific exception, at the same time logging message with the error.

# Code comments

  • Write comments in English.
  • Add the comments with the information that is not obvious when reading the code,e.g. describe side effects.
  • High-level comments on a class / module should not describe implementation details. If the class has a separate interface, write comments in the interface.
  • Low-level comments describe the code and should answer the questions: "What?" and "Why?" and not "How?".
  • If a bug fix requires writing complex code, also include the issue number from JIRA in the comment.
  • Update comments at the same time as the code, do not duplicate.

# API

# REST API

# Documentation

We use swagger/openapi format.

# Versioning

Add the version number to the prefix:

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

Use only major versions. It is unacceptable to rename methods or parameters within the same version.

If a parameter needs to be changed, the version number must be raised and there should be backward compatibility with the previous version of the API.

# Endpoints naming

Collections names in plural:

GET /campaigns
GET /campaigns/123

Use nesting to show how the objects relate:

GET /campaigns/123/webhook/1

# Endpoints methods

Endpoint names should contain only nouns. The action is defined by the http-methods:

HEAD /offers/123    # returns only HTTP headers, no body
GET /offers/123     # requesting  an offer with ID 123
DELETE /offers/123  # removing an offer
POST /offers        # creating a new offer
PUT /offers/123     # editing an offer with ID 123
PATCH /offers/123   # editing of only certain parameters of the offer

If specific actions are performed on the object, verbs can be added:

PUT /offers/123/disable

# Headings

We use standard HTTP codes (opens new window). Most used:

200 - everything is OK
202 - action accepted but will be performed later
400 - invalid parameters were passed in the request
401 - authorization required
402 - the paid period is over or this action is not available in the current edition
403 - with the current authorization, access to the object is denied
404 - endpoint or object does not exist
405 - invalid endpoint method is sent
406 - unacceptable request, validation error, incorrect data sent
429 - request limit exceeded

# Errors

Send the error text in the response:

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

Extended variant:

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

# Parameters:

  • sort - sorting (asc by default):

    GET /offers?sort=name

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

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

  • offset and limit for pagination:

    GET /offers?offset=10&limit=10

  • filter for filtration:

    GET /offers?filter

Dates in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ.

# Limiting requests

If the API has a request limit, the following headers must be sent in the response:

  • X-RateLimit-Limit - the rate (number) of the limit
  • X-RateLimit-Remaining - how much is left until the limit is reached (number)
  • X-RateLimit-Reset - how many seconds (opens new window) are left before the restrictions are reset

# Logging

  • A log of API requests and responses must be kept. All personal data and passwords must be filtered.

# Monitoring

# Health-checks

  • Describe entrypoints to check the state of the application. Read about livenessPrope (opens new window).
  • If the application needs time to warm up before it can serve traffic, write readinessProbe (opens new window).
  • General rule is that liveness and readiness probes should be always present and application should have corresponding http routes to serve this requests.

# Business metrics

Read about uploading metrics to Prometheus (opens new window).

WARNING

Make sure that the metrics are not accessible from the outside and that access to them through ingress is denied.

# JavaScript

See /dev/cs/js.html

# PHP

  • Use PHP-CS with @Symfony rules by default. It contains PSR-2 and PSR-12 conventions
  • Use Psalm (opens new window).
  • Use PHPMD.
  • Add declare(strict_types=1); to each php file.
  • Use PHPUnit as test framework.
  • Use swagger to generate API documentation.

# Naming

  • Boolean variables and methods
    • There is a convention to prefix boolean variables and function names with "is" or "has", i.e. isLoggedIn, hasAccess or things like that.
    • Sometimes you have to name the variable to make it grammarly correct. Wrong isResourcesLoaded, correct is isEachResourceLoaded.
    • Do not use use negative affirmations, i.e. isNotLoggedIn.

# Ruby

A community-driven Ruby coding style guide (opens new window).

# Golang

# Code recommendations

# Preferred packages

  • For logging https://github.com/sirupsen/logrus.
  • For routing https://github.com/gorilla/mux.
  • For working with env variables https://github.com/caarlos0/env and https://github.com/joho/godotenv.
  • To generate interfaces https://github.com/vburenin/ifacemaker.
  • To mock interfaces https://github.com/vektra/mockery.
  • To check values in tests https://godoc.org/github.com/stretchr/testify/assert.
  • To use mocks https://godoc.org/github.com/stretchr/testify/mock. If there is a mock SomeStructMock we do SomeStructMock.On("SomeMethod", mock.AnythingOfType("*models.ParamTypeStruct")).Return(mockedValue, err).Once().

For reading:

# Shell

Google Shell Style Guide (opens new window).

# Makefile

  1. We recommend creating a Makefile in every project, with unified commands make dev, make test.
  2. Makefile is a recommended file name.
  3. Target name separated by -, e.g., run-tests. Begin with the verb: apply-, create-, install-.
  4. We write environment variables in uppercase, e.g., PROJECT_PATH.
  5. Local variables in bottomcase with _ delimiter, e.g., build_dir = $(PROJECT_PATH)/build.
  6. Add make help command:
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 ./..

# Books

  1. A Philosophy of Software Design (opens new window)