-
Notifications
You must be signed in to change notification settings - Fork 24
Code Guidelines
This is the place where Guidelines and Conventions of the project are captured.
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.
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.
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.
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>
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)
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)
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)
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).
Why: The purpose of this naming guideline is to help create a human-readable code base that is easier to mantain and understand.
- Folders should not have the exact name as their folder parent.
- The pattern is
camelCase
orPascalCase
. - 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
- The pattern is
camelCase
. The exceptions are:- global constants and acronyms pattern is
UPPERCASE
.
- global constants and acronyms pattern is
- Use concise, human-readable, semantic names. It shouldn't be necessary to add a comment for additional documentation to the variable.
- Avoid abbreviation if the length is smaller than 25 characters.
- 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,
}
- 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 */)
- 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';
})
- The pattern is
camelCase
- 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). - For user interaction functions use the pattern
<on><Verb>
. For example:onUpdateValue
,onExitSearch
,onClick
etc. - 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.