As you will learn working with us, we hold some software engineering principles close to our hearts especially the separation of concerns.
Respecting these principles allow us to be relatively fast and efficient while building and shipping features but this comes at a price: some constraints are to be respected.
The goal of this document is to explain how we work and the choices we made.
We hope that once you get familiar with the codebase and acquire these reflexes, coding will be as enjoyable as possible for you 😌
The front-end code is grouped by Domains.
A domain very loosely designates either a product feature (available to the user) or a helper functionality (a suite of utils fonctions achieving a particular role).
When you work on a particular functionality, chances are you will only edit files in a single domain. This is good for keeping technical debt in check .
If you find yourself editing a large number of files across multiple directories, chances are you need to refactor your code into a new domain. Creating new domains is allowed and encouraged!
Every domain contains very specific files which are the following:
index.ts: the entry point for every domain
api.ts: communication with the server
linkedin.ts: communication with LinkedIn server
logic.ts: interaction with the pages and complex logic
components.ts: React components or HTML populated templates
types.ts: TypeScript types (available publicly)
utils.tsfor bits of logic that don’t fit in
Outside of the domains, the files
utilsApi.ts contain small utility functions and are available globally.
/appdirectory, other important files are: -
inject.ts, the starting point of every page reload -
inject.scssinjecting all the styles located in
popup.ts, code related to the extension popup However the large majority of the logic is located in
/appand this is the primary focus of this document.
Organizing the code by domains is good for grouping related bits together and avoids having to switch across multiple parts of the repository while coding.
However we found that another way to constraint our system and therefore making it more scalable was controlling where dependency injections happen .
Each domain enables a private scope,
index.ts is the only possible access point from the outside.
This enables us to import functions in the following fashion:
import * as contact from /Contact
And use them in the following way:
Which makes for cleaner and more readable code.
However, and this is the part when things can get a bit tedious, you have to manually export your functions in
index.ts to make them available to the rest of the application.
This won’t be done automatically and is a necessary step for each pull request you will submit.
The exact rules
- Files from one domain (including
index.ts) should only import:
- global files OR
- files from its own domain OR
index.tsfrom other domains OR
- types from anywhere
(which basically means you can import from anything you want except “private” files from other domains, ie
Here are some tech talks that go more in depth in the underlying concepts of the decisions we took:
-  Adam Tornhill - Prioritizing Technical Debt as if Time and Money Matters
-  Monica Lent - Building Resilient Frontend Architecture
-  Simon Brown - Modular Monoliths
-  Stefan Tilkov - "Good Enough" Architecture