Environment setup
Introduction
A system could crash because of a bug in its code. A regression could be introduced in a change made to the code by a developper. That's why we introduce failsafes as continuous integration to vet changes made in code.
However, configuration data could easily bring a system down.
While the code is rigorouly managed and tested, what of configuration ?
Environment data as code
First, let's clarify what we call "environment data". We believe what makes 4ME specific in a certain center falls into this category. We're talking list of elementary sectors, list of sector groups, what the control room layout is, etc.
We believe this should be treated as code, versionned as code, integrated in code artifacts (docker images in our case).
However, environment data holds a special place in 4ME. For the sake of this example, we'll talk about a list of elementary sectors. Multiple services might need to access this list. We don't want to duplicate this list in code as this will increase our maintenance burden. We could also abstract this list in a dedicated service, but this will introduce a bottleneck in our ecosystem.
If we were to write requirements, they would look like this :
- Validated in CI
- Accessible to all service requiring it
- DRY
We took the way of encapsulating this data in a package called @4me/env
. That way, packages can embed this data in their code, while saving us the hassle of maintaining and keeping in sync multiple lists.
@4me/env library
From the point of view of a package in the ecosystem, @4me/env
is a third party javascript library.
The library exposes data about 4ME users (Reims, Bordeaux, Brest, etc ...) through the same interface and the same data models.
Consummer applications are then configured to use an identifier referencing a specific dataset (LFEE for Reims data for instance).
Writing your own environment
Work in progress
Making sure your environment is consistent and valid
Let's say we're working on a TEST
environment, consiting of 3 elementary sectors: A
, B
and C
.
Surely we'll be defining those elemtary sectors. A second step would be to define collapsed sectors. Elementary sector (ES) A
when combined with ES B
is called AB
and we'd like 4ME to know that.
// Pseudo code
const collapsedSectors = [
// ...
{
name: 'AB',
elementarySectors: ['A', 'B '],
},
];
So far so good. The keen eyes have already spotted the mistake. We define a collapsed sector referencing an elementary sector B<space>
. This elementary sector does not exist.
These mistakes happen, and should be caught as early as possible instead of breaking running production systems.
Enter two tools: Jest and Flow which roles are to catch typos, incoherent environment data as early as possible.
Flow is a static type checker. Amongst other things, we leverage it to ensure objects have the required properties, of a required type.
Jest is a test runner. We wrote quite a lot of tests to ensure that an environment is deemed consistent and valid.
These tools are run in CI on every commit. The iteration cycle is quite long (waiting for the pipeline to fail, changing stuff, waiting again, etc ...), so these tools are available locally and can be run by a developper on its local machine.
Provided node and yarn are installed, dependancies bootstrapped, navigate to <4me path>/packages/env
and run those two commands :
$ yarn flow
$ yarn test
Alternatively, these tests can be run without installing node and yarn on your machine. Simply run :
$ cd <4me path>
$ dev/test-env.sh