Best practices and code standards in the Mobile code

License

This boilerplate is to be used on every file written by Totara Learning Solutions.

License
/**
 * This file is part of Totara Enterprise.
 *
 * Copyright (C) {{year}} onwards Totara Learning Solutions LTD
 *
 * Totara Enterprise is provided only to Totara Learning Solutions
 * LTD’s customers and partners, pursuant to the terms and
 * conditions of a separate agreement with Totara Learning
 * Solutions LTD or its affiliate.
 *
 * If you do not have an agreement with Totara Learning Solutions
 * LTD, you may not access, use, modify, or distribute this software.
 * Please contact [sales@totaralearning.com] for more information.
 */

Code style and best practices

We will be adapting the default Javascript and Typescript code style of the Jetbrains with some adjustments:

  • Changing the spacing of tab size, indents, and continuation indents from 4 to 2 - most current style guides now use 2 spaces, mainly because there are more closures and lambdas now (e.g. https://github.com/airbnb/javascript#whitespace)
  • Add spaces within "Object literals braces" and "ES6 import/export braces", consistent with most 3rd party code as well as VS Code's default
  • Organise imports in the following order; 3rd party import, @totara/package, and relative path import
  • Export modules at the bottom of the file when practical
  • Use as much of ES6 features as possible, especially deconstruction for function params and react props

We will be adopting some of MS Typescript guidelines (https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines), specifically; Names, Components, Types, null and undefined, and General Assumptions.

Name conventions

In general, for Javascript/Typescript:

  • Variable names: Camel case
  • Function/methods names: Camel case
  • Module/packages names: Camel case
  • React components: Pascal case 
  • Typescript interfaces and types: Pascal case
  • Index file name: Camel case

For Assets(images/icons):

  • general file name: Snake case
  • json file names: Snake case

Directory structure and file names in general:

  • Folders: Camel case
  • Filename (not from react components): Camel case (includes utilities and theme files)
  • For folders and non react components: Camel case

Just a reminder, please ensure that React components are pascal case.

CaseDescriptionExample
Camel caseThe first letter is lower case, there are no spaces between words and instead, new words are indicated through the use of capitals.camelCase
Pascal caseThere are no spaces between words and the first letter of each word is capitalised.PascalCase
Snake caseAll words are written in lower case and underscores are used to replace spacessnake_case

JavaScript (TypeScript) and Node

JavaScript should be readable, modular, and splittable. Take advantage of functional programming and if you find business logic that can be shared, generally put inside a utility file.

Project structure (for JS/Typescript/React Native)

We accept directories named with widgets group, for instance, buttons.ts should be added to components folder, whenever possible.

We discourage name files "_feature_.component.js" or "_feature_.container.js".

Formatting

We delegate that to [Prettier](https://prettier.io/).

Make sure your text editor has [that extension](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode), and that it's configured to auto-format on save.

Here is the exact settings.json file that we use and we strongly suggest you use it in setup for VSCode or some equivalent settings for your favourite IDE:

{
  "editor.tabSize": 2,
  "editor.formatOnSave": false,
  "[typescriptreact]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode",
      "editor.formatOnSave": true
  },
  "[typescript]": { 
      "editor.defaultFormatter": "esbenp.prettier-vscode"
      "editor.formatOnSave": true
  },
  "[javascriptreact]": {
      "editor.formatOnSave": true
  },
  "[javascript]": {
      "editor.defaultFormatter": "esbenp.prettier-vscode",
      "editor.formatOnSave": true
  }
}

Pro hints

React components

Each component should have its own file preferably. Try to avoid lots of components in the same file. For instance:

//Button.tsx
const Button () => (
  <View><Icon name={iconName}/></View>
)

//This icon should be extracted so you promote reusability
const Icon = () => (<View />);

//nice default export
//we dont normally export two components
export default Button;

Undefined and null check

Javascript already has the `undefined` type to indicate the absence of value, so there is no need to have a second type that represents the same concept. Said that, avoid the use of null. Yet sometimes the server returns it, therefore you still have to check.

//if the parameter is not a number, then this should be good
if ( param ) then ...

//if the parameter is a number, then we need to do this
if ( param !== null && param !== undefined ) then ...

Function parameters

Multiple arguments vs. options object:

// bad
function example(nodeList, callback, thisObject, fromIndex, toIndex){
    //...
}

// good. That is better because it more readable when you call the function
function example({ nodeList, callback, thisObject, fromIndex, toIndex }){
    //...
}

Modules

Use a single component export default per file.

Troubleshooting

When switching branches and suspecting that there were native code changes(e.g: dependencies additions or upgrades), this sequence should help you:

  1. Kill RN packager server (the little window that opens when you run the app).
  2. Run clean script (npm run clear:all).

This will clean all the builds and caches on both Android and iOS, and reinstall all the dependencies. Then run your platform script again.

Other useful commands

Device listing

  • Both platforms: yarn devices:ios      
  • For iOS only: yarn devices:ios  or  xcrun xctrace list devices
  • For Android only: yarn devices:android  or  adb devices