Skip to content

Latest commit

 

History

History
134 lines (98 loc) · 8.08 KB

CONTRIBUTING.md

File metadata and controls

134 lines (98 loc) · 8.08 KB

Contribution Guidelines

To keep consistency along all our services, we define our main guidelines so everybody can collaborate.

Take consideration that every line of code written must be following our guidelines.

Conventions Used in This Document

The requirement level keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" used in this document are to be interpreted as described in RFC 2119.

In this document, such keywords are highlighted using bold font.

Architecture

At the code layer, we should ensure our flexibility and scalability too. We accomplish this with help of a robust architecture. Either Domain-Driven Design (DDD) by Eric Evans or unclebob’s Clean Architecture shall be used to write new services.

Core concepts

Leveraged from the Hexagonal Architecture, the three main concepts that define our business logic are Entities, Repositories, and Interactors.

  • Entities are the domain objects (e.g., a Movie or a Shooting Location) — they have no knowledge of where they’re stored (unlike Active Record in Ruby on Rails or the Java Persistence API).
  • Repositories are the interfaces to getting entities as well as creating and changing them. They keep a list of methods that are used to communicate with data sources and return a single entity or a list of entities. (e.g. UserRepository)
  • Interactors are classes that orchestrate and perform domain actions — think of Service Objects or Use Case Objects. They implement complex business rules and validation logic specific to a domain action (e.g., onboarding a production)

With these three main types of objects, we are able to define business logic without any knowledge or care where the data is kept and how business logic is triggered. Outside of the business logic are the Data Sources and the Transport Layer:

  • Data Sources are adapters to different storage implementations. A data source might be an adapter to a SQL database (an Active Record class in Rails or JPA in Java), an elastic search adapter, REST API, or even an adapter to something simple such as a CSV file or a Hash. A data source implements methods defined on the repository and stores the implementation of fetching and pushing the data.
  • Transport Layer can trigger an interactor to perform business logic. We treat it as an input for our system. The most common transport layer for microservices is the HTTP API Layer and a set of controllers that handle requests. By having business logic extracted into interactors, we are not coupled to a particular transport layer or controller implementation. Interactors can be triggered not only by a controller, but also by an event, a cron job, or from the command line.

Clean architecture From Netflix Engineering, click here.

Therefore, we use our own API architecture implementing a Proxy pattern to hide our transport services implementation (like HTTP).

The following application architecture should be used whenever a new service is created.

Alexandria HTTP Proxy Service architecture

Error handling

We expect to keep consistency in error handling.

In the following section, we show our error handling scenarios by layer.

Domain: Business rule(s) validations

Type Description HTTP Status Code Return value
InvalidID Invalid identifier 400 Exception
RequiredField Missing required request field x 400 Exception
InvalidFieldFormat Request field x has an invalid format, expect value 400 Exception
InvalidFieldRange Request field x is out of range [x, y) 400 Exception

Repository: Data source(s) validations

Type Description HTTP Status Code Return value
EmptyRow Resource(s) not found 404 Null/Nil
Infrastructure SQL/Docstore/API internal error 500 Exception

Interactor: Domain's cases validation

Type Description HTTP Status Code Return value
InvalidID Invalid identifier 400 Exception
RequiredField Missing required request field x 400 Exception
InvalidFieldFormat Request field x has an invalid format, expect value 400 Exception
InvalidFieldRange Request field x is out of range [x, y) 400 Exception
AlreadyExists Resource already exists 409 Exception
EmptyBody Request body is empty 400 Exception

Logging

In the following section, we define our logging official sentences.

Every logger must write in lowercase. (e.g. http service created)

Every logger must specify its layer location separating words with a dot. (e.g. service.transport)

Therefore, every logger shall use the specified sentences.

  • New instance.- “HANDLER_NAME created”, “LAYER_LOCATION” (e.g. "media handler created", "service.transport.handler")
  • New service.- “SERVICE_NAME started”, “service.LAYER_LOCATION” (e.g. "http proxy service started", "service.transport")

Runtime Configuration

In the following section, we define our runtine configuration guideline.

Every configuration must define default values inside code.

Every configuration must have an "alexandria-config.yaml" file containing required keys, it must be stored in the following locations:

  • $HOME/.alexandria/
  • ./config/
  • /etc/alexandria/
  • .

Every configuration system must fetch secrets from AWS KMS or similar. If not available, read configuration from "alexandria-config.yaml" file.

Configuration file example

alexandria:
  info:
    service: "media"
    version: 1.0.0
  persistence:
    dbms:
      url: "postgres://postgres:root@postgres:5432/alexandria_media?sslmode=disable"
      driver: "postgres"
      user: "postgres"
      password: "root"
      host: "postgres"
      port: 5432
      database: "alexandria_media"
    mem:
      network: ""
      host: "redis"
      port: 6379
      password: ""
      database: 0
  service:
    transport:
      http:
        host: "0.0.0.0"
        port: 8080
      rpc:
        host: "0.0.0.0"
        port: 31337

Versioning

For every single release, all software deployed must use Semantic Versioning guidelines to keep consistency and inform every single developer the best way possible.

Specific Guidelines