House styles for the dev team here at LaMar Software and all outside collaborators
Table of contents
Add block comments only when necessary; many functions are self-explanatory. Ask yourself, “Does the function explain what I’m doing?”
// Good
/**
* Check the template and update the data model
*/
function performCheck(): void { ... }
// Bad
/**
* Logs the user in
* @param { payload: AuthPayload } Authentication payload
*/
function login(payload: AuthPayload): void { ... }
Always add a space between keywords, operators, clauses, and syntax delimiters
```TypeScript
// Good
if (car.model === ‘F150’) {
this.pickupTruckCount += 1;
}
// Bad
if(car.model ===’F150’){
this.pickupTruckCount+=1;
}
- Always use dot notation to define object properties if possible.
```TypeScript
obj.field = 'This is good';
obj['field'] = 'This is not';
obj['name-with-hyphens'] = 'This is acceptable';
Always add a space when destructuring objects. Never add a space when destructuring arrays.
const [car] = cars;
const { model: carModel } = car;
Always include a verb in boolean variable names.
const hasVehicles; // rather than 'vehicles'
const isLoading; // rather than 'loading'
const shouldUpdate; // rather than 'update'
const didClickAccept; // ...and so on...
Always use err
to name errors, e.g. in a try / catch
block.
try {
...
} catch (err) {
console.log(err);
}
Always use e
to name event objects, e.g. inside a click event handler.
handleClick(e: MouseEvent): void { ... }
Always use a single newline to separate meaningful blocks of code.
```TypeScript
import { Component } from ‘@angular/core’;
import { FlexLayout } from ‘@angular/material’;
const carModel = ‘Ford Focus’;
const carType = ‘Hatchback’;
function getCarManufacture() { … }
function getHorsepower() { … }
- All async statements require an error handler. For example:
```TypeScript
fetch(env.someApiurl)
.then(() => { ... });
.catch(() => { ... });
class CarManufacture {}
// Bad
const bad_example = ‘Snake case’;
const AnotherBadExample = ‘Pascal case’;
const what-are-you-even = ‘Kebab case’;
- Function / method names should always have _descriptive_ verbs and never end with a verb.
```TypeScript
// Good
function createManufacture() { ... }
function fetchAllManufactures() { ... }
// Bad
function doCreate() { ... }
function addManufactureDo() { ... }
const LOCAL_STORAGE_KEY = {
AUTH_TOKEN: 'authToken',
AUTH_EXPIRES: 'authExpires'
};
// Example using Angular
import ... from '@angular/...' // Framework-specific packages
import ... from 'modules/...' // Modules and macros
import ... from 'classes/...' // Classes
import ... from 'services/...' // Services
import ... from 'utils/...' // Utilities
import ... from 'interfaces-and-types/...' // Interfaces and types
import ... from 'environments/...' // Environments
import ... from '...' // Third-party libraries, in alphabetical order
For example:
// Another example using Angular
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { _MixinBase } from './mixins';
import { Model, Car } from './car.class';
import { AuthService } from './services/auth.service';
import { LogError } from './utils';
import { Team } from './interfaces/team.interface';
import { User } from './types/user.types';
import { environment } from './environments/environment';
import * as anime from 'anime';
import * as moment from 'moment';
// SELECT, but longer
await db.query(SELECT
c.id,
c.manufactureId,
c.modelName,
c.serialNumber
FROM car c
WHERE c.id IN (
SELECT id FROM carBookmark WHERE userId = 14
)
);
// INSERT
await db.query(INSERT INTO car (
manufactureId,
modelName,
serialNumber
) VALUES (
7,
'F250',
'5k2gJeA67SLyZoK7'
)
);
## HTML
- Element attributes should follow this convention:
```HTML
<selector
*structuralDirective
#localReference
[(ngModel)]="property"
directive
(event)="handler()"
[property]="expression"
id="id"
class="class-list"
type="type"
placeholder="placeholder">
</selector>
// Bad
.class {
padding: 12px 32px;
z-index 9;
border-radius: 5px;
margin: 0;
}
- Classes and ids should _always_ use kebab case.
```CSS
// Good
.some-long-class-name { ... }
// Bad
.doNotUseCamelCase { ... }
.DoNotUsePascalcase { ... }
.do_not_use_snake_case { ... }
The following flags should be added to the tsconfig.json
file:
forceConsistentCasingInFileNames
noImplicitReturns
strict
noUnusedLocals
The strict
flag covers four other flags which you could add independently if you want to progressively introduce TypeScript to an existing codebase which is the recommended approach. Those flags are:
noImplicitAny
noImplicitThis
strictNullChecks
alwaysStrict
@Input()
public readonly data: Car;
@Output(‘onDataProcessed’)
public readonly onDataProcessedEvent: EventEmitter
// Readonly properties, like environment fields or forms
public readonly environment = environment;
public readonly carForm: FormGroup;
// On-push template data, like an array of entities
public cars: Car[] = [];
// Loaders and other state management properties used in the template
public fetchingData: boolean = false;
public processesingData: boolean = false;
// The constructor
constructor() {}
// Finally, Angular’s lifecycle methods in the order in which they are called
### Angular Material v8+ Imports
- Angular Material v8 introduces a different structure in their material library imports. Rather than destructure multiple objects from a single library index, you are required to destructure a single object from multiple library indexes. For example:
```TypeScript
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
master
branch, marked for immediate integration
<issue_type>-<issue_number>
feat-new-button
fixed ActiveModel::Errors deprecation messages failing when AR was used outside of Rails.
### Pull Requests
- PR titles should follow this convention:
- The issue type should be title case.
## Logging
- Generally, logging should be used sparingly within your codebase. Producing logs is thread-blocking and slow. However, it can be incredibly useful for standalone or fickle processes where there are many opportunities for a process to break; it's useful to know when and where a process broke unexpectedly.
- Use the language's default logger - i.e. `Console`, `System.out`, `cout`, etc.
- Logs should always provide the event name, a description (if applicable), and use proper grammer and punctuation, ending with a period. The convention should be as follows:
#
to identify a specific block within that function. For example:
console.warning(timestamp, ' - Cronjob:Braintree.updateSubscriptionAmount#processTeamBilling\nNo customerID found.');
// 2019-08-14T09:34:38 - NodeApiServer:Braintree.updateSubscriptionAmount#processTeamBilling
// No customerID found.
Some other examples:
console.warning(timestamp, ' - NodeApiServer:Braintree.updateSubscriptionAmount - No payment method found.');
// 2019-08-14T09:34:38 - NodeApiServer:Braintree.updateSubscriptionAmount - No payment method found.
System.out.println(timestamp + " - CronjobNightly:User.sendNotifications - Phone number is " + phoneNumber + ", but no alert sent.");
// 2019-08-15T11:13:49 - CronjobNightly:User.sendNotifications - Phone number is +12093227884, but no alert sent.
CarManufacture
could house car manufactures.Zip
on one table and ZipCode
on another.Cus_AddRef
represent? Custodial Addressee Reference? Customer Additional Refund? Custom Address Referral?DateCached
, DeletedFlag
should always be last// Examples
poolorchard_data_2020-02-06.sql
poolorchard_data_2020-02-06-00085.sql
## Resource Identifiers
- Resource identifier elements should be combined with colons. For example:
MyAccount:RegisteredDevices // could represent /my-account/registered-devices
```