Skip to content

Code Guidelines

Simona Domnisoru edited this page Sep 20, 2021 · 3 revisions

This is the place where Guidelines and Conventions of the project are captured.

Exporting Javascript modules

Export all the modules from the index.js file

When there is a module living in a folder we would use an index.js file in the root of that folder to export the elements that will be used outside of the scope of the folder.

For example if there is a method called addDays in the dateUtilities folder and we would like it to be used in another part of the software we would add an export in the dateUtilities/index.js file.

Exporting from the index.js file will allow the developers to create a border between the module and the rest of the application.

Use unique names

When there are elements exported in an index.js file as mentioned above we would like to name the uniquely.

For example in a scenario where we are export from the RegisterEvent/index.js an object that is holding the actionTypes, we would export the element with a unique name that reflects the correlation between the actionsTypes and the RegisterEvent eg registerEventActionTypes.

Unique name will allow the developers to better search and find where those elements are used in the rest of the codebase.

Exporting React components

Having consistent names for the components and for the different cases that are created is what this section is about. In our project we use Redux. We also use material-ui and its internal withStyles high order function to style components. Not all components need to use these two libraries but some components have to.

Now let’s imagine we have a component called Document. This creates the following cases in terms of exporting and naming.

Case 1. Component without withStyles and without Redux connect

In this case there is only one file, which would be named Document.component.js. From this file the exported React component will be exported as a const and will called Document.

For instance

export const Document = (props) => <div>/* your JSX goes here */</div> 

Case 2. Component withStyles but without Redux connect

Since there is no Redux connected to the component there is also no Document.container.js file. This leaves us again with one file which will be named again Document.component.js. And the exported component will be called again Document.

The difference in this case lies in the internals of the Document.component.js file. In the file there is another React component. This one is not exported but is wrapped in the withStyles high order function. We name this component DocumentPlain.

For instance

const yourStyles = {/*styles go here*/}

const DoumentPlain = (props) => <div>/* your JSX goes here */</div> 
export const Document = withStyles(youStyles)(DoumentPlain)

Case 3. Component without withStyles but with Redux connect

In this case we use two files. One called Document.container.js where all the Redux related logic lies. The other one is called Document.component.js and is where the React component lies.

From the Document.container.js the component which will be used all around the project is exported. In our example this component will be named again Document and as always is exported as a const.

The Document.component.js exports one React component called DocumentComponent. This is then imported in the Document.container.js.

For instance

// Document.component.js
export const DocumentComponent = (props) => <div>/* your JSX goes here */</div> 
// Document.container.js
import { DocumentComponent } from './Document.component'

/* your container logic goes here */

export const Document = connect(/* arguments go here */)(DocumentComponent)

Case 4. Component withStyles and with Redux connect

In this case again we use two files. One called Document.container.js where all the Redux related logic lies. The other one is called Document.component.js and is where the React component lies.

Same as in the previous case, from the Document.container.js the component which will be used around the project is exported. In our example this component will be named as always Document and is exported as a const.

The Document.component.js exports one React component called DocumentComponent. This is then imported in the Document.container.js.

The difference in this case lies in the internals of the Document.component.js file. In the file there is another React component. This one is not exported but is wrapped in the withStyles high order function. We name this component DocumentPlain.

// Document.component.js
const yourStyles = {/*styles go here*/}

const DoumentPlain = (props) => <div>/* your JSX goes here */</div> 
export const DocumentComponent = withStyles(youStyles)(DoumentPlain)
// Document.container.js
import { DocumentComponent } from './Document.component'

/* your container logic goes here */

export const Document = connect(/* arguments go here */)(DocumentComponent)

Flow types

Organising types

Each concept (e.g. WorkingLists) exposes its types to the outside "world" through the index file in the base folder. Within the concept file structure, each folder can have its own types subfolder. This subfolder contains types "accessible" from the base folder and its children. The ´types´ folder should include an index file, giving the developer the freedom to organize the types into files in whatever pattern they see fit. In addition, each file can have its own correlated type file (e.g. components).

Naming guideline

Why: The purpose of this naming guideline is to help create a human-readable code base that is easier to mantain and understand.

Folders name

  1. Folders should not have the exact name as their folder parent.

Files name

  1. The pattern is camelCase or PascalCase.
  2. One of the pattens we currently use is <componentName>.<functionality>.js. For example:
EnrollmentPage
├── EnrollmentPage.actions.js 
├── EnrollmentPage.component.js 
├── EnrollmentPage.constants.js 
├── EnrollmentPage.container.js 
├── Enrollmentpage.epics.js 
└── EnrollmentPage.types.js 

Variables name

  1. The pattern is camelCase. The exceptions are:
    • global constants and acronyms pattern is UPPERCASE.
  2. Use concise, human-readable, semantic names. It shouldn't be necessary to add a comment for additional documentation to the variable.
  3. Avoid abbreviation if the length is smaller than 25 characters.
  4. Use a unique name for the actionTypes object, e.g. eventWorkingListsActionTypes. This will make it easy to figure out where the actions are used (and really simplify a potential refactor). Prefix the actionType, i.e [Domain].[ActionType] (for example: EventWorkingLists.AddTemplate).
const eventWorkingListsActionTypes = {
    ADD_TEMPLATE: EventWorkingLists.AddTemplate,
}
  1. Give meaningful names to variables inside functional methods (map, forEach, reduce, every, some, ...). For example:
// not good
options.map(o => /* do something */)

// better
options.map(option => /* do something */)
  1. Give meaningful names to variables when initialise new object instance. For example:
// not good
new DataElement((o) => {
    o.id = 'something';
})

// better
new DataElement((element) => {
    element.id = 'something';
})

Functions name

  1. The pattern is camelCase
  2. For system functions use the pattern <verb><Noun>. Every function is an action, so the name should contain at least one verb as a prefix. This verb as prefix can be anything (e.g. get, fetch, push, apply, calculate, compute, post).
  3. For user interaction functions use the pattern <on><Verb>. For example: onUpdateValue, onExitSearch, onClick etc.
  4. Avoid duplicate names for exported functions. Functions with identical names create a lot of confusion. Consider what is the difference between the functions and reflect it in the function name.