Skip to content

Latest commit

 

History

History
260 lines (185 loc) · 8.79 KB

CONTRIBUTING.md

File metadata and controls

260 lines (185 loc) · 8.79 KB

Contributing

File Structure

Frontend

General

⚠️ In progress.

src/
  ├ api/                                                    # Tests
  ├ domain/                                                 # Tests
  │   ├ slices/                                             # Redux slices
  │   │   └ aDomain.ts
  │   └ use_cases/                                          # Redux reducers
  │       └ aDomain/
  │          ├ __tests__/                                   # Tests
  │          │   ├ getOne.test.ts
  │          │   └ updateOne.test.ts
  │          │ getOne.ts
  │          └ updateOne.ts
  ├ features/                                               # React components
  ├ libs/                                                   # Shared utility classes (one per file)
  ├ utils/                                                  # Shared utility functions (one per file)
  ├ constants.ts                                            # Shared constants and enums
  └ utils.ts                                                # Utility functions

React Components

A big component could look like that:

MySuperComponent/
  ├ __tests__/                                              # Tests
  │   ├ aUtilityFunction.test.ts
  │   └ anotherUtilityFunction.test.ts
  ├ index.tsx                                               # Main code
  └ utils.ts                                                # Utility functions

Best Practices

Javascript / Typescript

Use undefined instead of null

null is considered to be the most expensive mistake in the history of programmation by its own creator.

Sindresorhus did it.

Use named exports instead of default ones

Names exports enforce a consistent naming accross the database (helping code lookup) and ensures tree shaking.

Use import types and export types for types

Here is a good explanation of why. In short, it ensures that no type is being accidentally trasnpiled, it eases refactoring and fasten transpilers work.

React

Avoid using useEffect()

Excepted for first data loading and direct DOM manipulation when no better logic is available (nost often events).

Avoid using expressions in JSX props

It makes the component logic easier to understand when we separate concerns between JSX rendering / props passing and the code logic contained above.

Named functions also ease debugging stacks in comparison with expressions in props.

Exclusively use Redux instead of local states for horizontal state dependencies

If multiple components must react to common state property and that components' props can't easily be passed, we must use Redux selectors / dispatches and only them to handle that state.

Local component states must be absolutely isolated. Excepted during their initialization via the component props (and nothing else!).

If internal component constants must derive from this state value during their initialization, we can use useRef(). If some internal component constants must derive from this state value for each change, we can use useMemo().

Extract component calculation and transformation code into utility functions

A React component is a DOM listener and renderer. Its code should only orchestrate its state changes in order to achieve these 2 roles.

Most should be extracted into small utility functions within either a local utils.ts file or within the global utils/ directory if they are shared by more than one component.

Not only does it lighten our components code but more importantly, it helps us unit-testing component code logic while avoiding the not-so-fun task of testing the component itself.

Actions should be imported with a domain namespaced import * as

It helps avoiding naming conflicts with internal functions and easily differenciate what should be called from what should be dispatched.

Example:

import * as domainActions from "...";

Naming Conventions

General

File names should match main function or Class name and case

⚠️ In progress.

React

Start uplifter props name with on

It has been a forever convention for both ECMAScript and Node.js to use on for any exposed listening function expecting a callback. React native uplifter props follow this convention themselves.

Recommended IDE Configurations

Visual Studio Code

.vscode/settings.json

{
  "editor.codeActionsOnSave": {
    "source.fixAll": true
  },
  "editor.defaultFormatter": "dbaeumer.vscode-eslint",
  "editor.formatOnSave": true,
  "eslint.codeActionsOnSave.mode": "all",
  "eslint.format.enable": true,
  "eslint.packageManager": "npm",
  "eslint.workingDirectories": ["./frontend"],
  "[json]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  }
}

Development

Database

Backup and restore database

Local development

In local development, the backup config file is already set up there.

You can just run the following commands:

Backup:

make dev-backup-db

Restore:

# This will recreate the database container and its volume before restoring the dump:
make dev-restore-db TAG=YYYY-MM-DD-[daily|weekly]

Example, to restore a dump directory from ./.backups/2024-04-13-daily:

make dev-restore-db TAG=2024-04-13-daily

Remote deployment

In a remote deployment, if not done already, you need to copy and customize the backup config file:

cp infra/remote/backup/pg_backup.config.example infra/remote/backup/pg_backup.config

The remote server database is automatically backed up using this crontab file. This generates daily and weekly dumps in the backup directory defined via the BACKUP_DIR var declared in infra/remote/backup/pg_backup.config (ex: 2024-04-12-weekly, 2024-04-13-daily, etc).

Backup:

make backup-db

Restore:

Important

  • Stop all applications from connecting to the dababases.
  • The database container and its volume must be cleared (removed and recreated) before restoring a dump.
make restore-db TAG=YYYY-MM-DD-[daily|weekly]

Example, to restore a dump directory from [YOUR_CONFIG_BACKUP_PATH]/2024-04-13-daily/:

make dev-restore-db TAG=2024-04-13-daily

Restoring a remote dump locally (for debugging purposes)

On the remote server:

# Dump the databases:
make backup-db
# Compress the dump directory:
cd YOUR_CONFIG_BACKUP_PATH
tar -cvzf YYYY-MM-DD-[daily|weekly].tar.gz YYYY-MM-DD-[daily|weekly]

Then use SCP to download the dump locally into the .backups/ directory and restore it on your local machine:

tar -xvzf ./.backups/YYYY-MM-DD-[daily|weekly].tar.gz -C ./.backups
make dev-restore-db TAG=YYYY-MM-DD-[daily|weekly]