athena-test/docs/Workflow/Development rules.md

312 lines
9.9 KiB
Markdown

# Development rules
## Project configuration rules
> If you create your own project, do not forget to write a runbook. It should contain detailed instructions on how to run your project.
Runbook example:
````markdown
## Service build information
There are different stages of building the application for this service. Based on the environment you want to deploy we have different ways to build the application. following information may help with building the service.
### Regular user
```bash
npm install
npm run build
npm run test:ci
npm start:{dev || debug || prod}
```
### Advanced user
```bash
cd scripts
bash run.sh -h
2022.05.30.14.43
Usage: $(basename "${BASH_SOURCE[0]}") [-h] [-buildDocker] [-runDocker] [-runApp] [-runDoc] [-packageHelm]
This script helps you to run the application in different forms. below you can get the full list of available options.
Available options:
-h, --help Print this help and exit
-buildDocker Build the docker image called "imageName:latest"
-runDocker Build the docker image and run on local machine
-runApp Run application with npm in usual way for development
-runDoc Generate the code documentation
-packageHelm makes a helm package from the helm chart.
```
````
### package.json configuration
`package.json` example:
```json
{
"name": "My favourite microservice",
"version": "0.0.1",
"description": "Microservice not responsible for anything",
"author": "Dipal Team",
"private": true,
"license": "Apache 2.0",
"scripts": {
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:pipeline": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"compodoc": "./node_modules/.bin/compodoc -p tsconfig.json -w -s -r 8005 --theme 'readthedocs'",
"rei": "rm -r node_modules/ dist/ package-lock.json && npm i "
},
"dependencies": {},
"devDependencies": {},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
```
> If you install package that not supposed on production (like compodoc, faker or types for TS) add it in `devDependencies`, not `dependencies`. It can be the reason why you can not pass deploying on pipeline.
### Enviromental variables file
Environment variables offer information on the process's operating environment (producton, development, build pipeline, and so on). Environment variables in Node are used to store sensitive data such as passwords, API credentials, and other information that should not be written directly in code. Environment variables must be used to configure any variables or configuration details that may differ between environments.
You should always provide `.env.example` with all the enviromental variables with empty values. This is an example:
```text
DB_USERNAME=
DB_PASSWORD=
DB_HOST=
DB_PORT=
DB_NAME=
```
> Do not forget **to add** `.env` file inside the `.gitignore` file.
Inside your code you should import environment variables using the `dotenv` lib. You must do this _**before**_ all your code, especially importing configs in the `main.js` file:
```js
import * as dotenv from "dotenv";
dotenv.config();
import { config } from "./infrastructure/config/config";
```
### Compodoc
NestJS, like Angular, supports Compodoc to automatically create documentation based on developers' comments. This is internal documentation for backend developers. In it you can see the project structure, modules, endpoints, variables, functions, etc.
You need to set the port inside package.json and be sure that it is free:
```text
"compodoc": "./node_modules/.bin/compodoc -p tsconfig.json -w -s -r 8005 --theme 'readthedocs'",
```
So always write comments on your code.
### Lint
ESLint statically analyzes your code to quickly find problems in JS/TS code. You can integrate it inside your VSCode.
We have a `.eslintrc.json` file with standart rules:
```json
{
"env": {
"browser": false,
"es2021": true
},
"extends": [
"prettier",
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"overrides": [],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": ["@typescript-eslint"],
"rules": {
"indent": ["warn", 2],
"linebreak-style": ["warn", "unix"],
"quotes": ["warn", "double"],
"semi": ["warn", "always"]
}
}
```
And the `.prettierrc` file":
```json
{
"arrowParens": "avoid",
"bracketSpacing": false,
"endOfLine": "lf",
"insertPragma": false,
"singleAttributePerLine": false,
"bracketSameLine": true,
"printWidth": 120,
"proseWrap": "always",
"quoteProps": "as-needed",
"requirePragma": false,
"semi": true,
"singleQuote": false,
"tabWidth": 2,
"trailingComma": "es5",
"useTabs": false,
"parser": "typescript"
}
```
## Coding style
In our company we keep a close eye on the quality of the code. Since we do not have much time for refactoring, your code must follow to all principles and be _**easy to read**_ for all members of our team. _**Configure your VSCode**_ according on style that we have.
You can find coding style rules [here](https://google.github.io/styleguide/tsguide.html).
## HTTP REST
You need to write standartized requests and return correct responses with your APIs.
You can find HTTP requests and responses rules [here](https://aws.amazon.com/what-is/restful-api/).
## Test-driven development
We stick to test-driven development (TDD) because we need to be 100% sure that our code works perfectly and there are no silly bugs in it. You alone are responsible for unit tests of your code. When you write tests first, you can better understand the functionality you are implementing. While writing tests, you must think as a user of your module. You should predict all the situations that can happen and check if the code works correctly.
Here are the common rules you must follow writing unit tests:
One test checks one thing. Create mocks and stubs for dependencies. Try as many different types of input as possible. Create a factory for input and output information.
Test example:
```typescript
it("Should encrypt according to args", async () => {
let algorithm: any, securityKey: any, initVector: any, data: any;
const args = test_cases.crypto.args;
const expectation = test_cases.crypto.expectation;
jest.spyOn(crypto, "createCipheriv").mockImplementation((x: any, y: any, z: any) => {
algorithm = x;
securityKey = y;
initVector = z;
return {
update: (_x: any, _y: any, _z: any) => {
data = _x;
return expectation.update;
},
final: (_x: any) => expectation.final,
} as Cipher;
});
let result = service.encrypt(args.data, args.initVector, args.algorithm);
expect(result).toBe(expectation.update + expectation.final);
expect(algorithm).toBe(args.algorithm);
expect(initVector).toBe(args.initVector);
expect(data).toBe(args.data);
expect(securityKey).toBeDefined();
expect(crypto.createCipheriv).toBeCalledTimes(1);
});
});
```
When you start writing code, all the tests will fail. Your task is to make them successful.
## NestJS application architecture and rules for module creation
For clean code, we use Domain-Driven design. The simple structure of project is:
* Application.
* Controllers. Handle incoming requests and returning responses to the client
* DTOs. Define how the data will be sent over the network.
* Domain.
* Decorators.
* Constants.
* Enums.
* Filters. Process all unhandled exceptions across an application.
* Guards. Determine whether a given request will be handled by the route handler or not (for example, authefication).
* Interceptors. Process the request before handling and the response after handling.
* Interfaces.
* Modules.
* Repositories. Mediate between the domain and data mapping layers.
* Services. Implement business logic.
> Always write a _**Swagger**_ documentation for your endpoints.
> When you write DTO, validate all the fields with `class-validator`.
DTO example:
```ts
export class SetRegistrationTokenDTO {
/**
* Registration token for the user's app
*/
@IsNotEmpty()
@IsString()
@Matches(/[A-Za-z0-9\-_]{22}:[A-Za-z0-9\-_]{140}/)
@ApiProperty({
description: "Registration firebase token",
example:
"fwcHeh8bSh6KRGQPd-6B2H:APA91bEV1KGorVt7bPHcgbuRCJrxWVmgXdUZvVmnOfB9rYhDGAudTtSvZu8qwT_hErYp0ONWR8MQIzpN6B7FlwdpMMYG2vjU1T1KXE0NEKhZc1d8hc9YwKWqXqNgyMnRuhN074Wziw9Q",
})
registration_token: string;
}
```
> Don't forget to use NestJS features (e.g. filters) and design patterns.
> When creating any new environment variable _**always**_ notify your supervisor.
You can read full NestJS documentation [here](https://docs.nestjs.com/).
## MongoDB and query rules
You can read full MongoDB documentation [here](https://webimages.mongodb.com/_com_assets/cms/kuyjf3vea2hg34taa-horizontal_default_slate_blue.svg?auto=format%252Ccompress).
## Documentation and comments writing rules
* Follow the rules of the English language.
* Don't write a lot of text, write as concisely and clearly as possible.
* Put the Swagger documentation in a separate file in the `docs` folder.
* You can see code documentation using `compodoc`.
Good comments example:
```js
/**
** matches US social security number
**/
let pattern = Pattern("^\\{3}-\\d{2}-\\d{4}$")
//=============================================================================================================
// use this thing to divide different functions and methods
// TODO: implement functionality
```