chore: expand coding standards (#2581)

* chore: expand coding standards

* address comments
This commit is contained in:
Jeremy Elbourn
2017-01-12 13:26:03 -08:00
committed by tinayuangao
parent a1c90b352a
commit a8764ddc46
+113 -9
View File
@@ -12,7 +12,8 @@ ES6 or TypeScript.
### General
#### Write useful comments
Comments that explain what some block of code does are nice; they can tell you something in less time than it would take to follow through the code itself.
Comments that explain what some block of code does are nice; they can tell you something in less
time than it would take to follow through the code itself.
Comments that explain why some block of code exists at all, or does something the way it does,
are _invaluable_. The "why" is difficult, or sometimes impossible, to track down without seeking out
@@ -58,19 +59,122 @@ Keeping modules to a single responsibility makes the code easier to test, consum
ES6 modules offer a straightforward way to organize code into logical, granular units.
Ideally, individual files are 200 - 300 lines of code.
As a rule of thumb, once a file draws near 400 lines (barring abnormally long constants / comments),
start considering how to refactor into smaller pieces.
#### Less is more
Once a feature is released, it never goes away. We should avoid adding features that don't offer
high user value for price we pay both in maintenance, complexity, and payload size. When in doubt,
leave it out.
This applies especially so to providing two different APIs to accomplish the same thing. Always
prefer sticking to a _single_ API for accomplishing something.
prefer sticking to a _single_ API for accomplishing something.
### 100 column limit
All code and docs in the repo should be 100 columns or fewer. This applies to TypeScript, SCSS,
HTML, bash scripts, and markdown files.
### TypeScript
#### Provide function descriptions
For functions that are more complicated than a simple getter/setter, provide at least a brief
sentence explaining what the function does and/or _why_ it does something.
#### Typing
Avoid `any` where possible. If you find yourself using `any`, consider whether a generic may be
appropriate in your case.
For methods and properties that are part of a component's public API, all types must be explicitly
specified because our documentation tooling cannot currently infer types in places where TypeScript
can.
#### Fluent APIs
When creating a fluent or builder-pattern style API, use the `this` return type for methods:
```
class ConfigBuilder {
withName(name: string): this {
this.config.name = name;
return this;
}
}
```
#### Access modifiers
* Omit the `public` keyword as it is the default behavior.
* Use `private` when appropriate and possible, prefixing the name with an underscore.
* Use `protected` when appropriate and possible with no prefix.
* Prefix *library-internal* properties and methods with an underscore without using the `private`
keyword. This is necessary for anything that must be public (to be used by Angular), but should not
be part of the user-facing API. This typically applies to symbols used in template expressions,
`@ViewChildren` / `@ContentChildren` properties, host bindings, and `@Input` / `@Output` properties
(when using an alias).
Additionally, the `@docs-private` JsDoc annotation can be used to hide any symbol from the public
API docs.
#### JsDoc comments
All public APIs must have user-facing comments. These are extracted and shown in the documation
on [material.angular.io](https://material.angular.io).
Private and internal APIs should have JsDoc when they are not obvious. Ultimately it is the purview
of the code reviwer as to what is "obvious", but the rule of thumb is that *most* classes,
properties, and methods should have a JsDoc description.
Properties should have a concise description of what the property means:
```ts
/** The label position relative to the checkbox. Defaults to 'after' */
@Input() labelPosition: 'before' | 'after' = 'after';
```
Methods blocks should describe what the function does and provide a description for each parameter
and the return value:
```ts
/**
* Opens a modal dialog containing the given component.
* @param component Type of the component to load into the dialog.
* @param config Dialog configuration options.
* @returns Reference to the newly-opened dialog.
*/
open<T>(component: ComponentType<T>, config?: MdDialogConfig): MdDialogRef<T> { ... }
```
Boolean properties and return values should use "Whether..." as opposed to "True if...":
```ts
/** Whether the button is disabled. */
disabled: boolean = false;
```
#### Naming
##### General
* Prefer writing out words instead of using abbreviations.
* Prefer *exact* names over short names (within reason). E.g., `labelPosition` is better than
`align` because the former much more exactly communicates what the property means.
* Except for `@Input` properties, use `is` and `has` prefixes for boolean properties / methods.
##### Classes
Classes should be named based on what they're responsible for. Names should capture what the code
*does*, not how it is used:
```
/** NO: */
class RadioService { }
/** YES: */
class UniqueSelectionDispatcher { }
```
Avoid suffixing a class with "Service", as it communicates nothing about what the class does. Try to
think of the class name as a person's job title.
##### Methods
The name of a method should capture the action that is performed *by* that method.
### Angular
#### Host bindings
Prefer using the `host` object in the directive configuration instead of `@HostBinding` and
`@HostListener`. We do this because TypeScript preserves the type information of methods with
decorators, and when one of the arguments for the method is a native `Event` type, this preserved
type information can lead to runtime errors in non-browser environments (e.g., server-side
pre-rendering).
### CSS
@@ -83,8 +187,8 @@ elements like input and button.
#### Use lowest specificity possible
Always prioritize lower specificity over other factors. Most style definitions should consist of a
single element or css selector plus necessary state modifiers. Avoid SCSS nesting for the sake of
code organization. This will allow users to much more easily override styles.
single element or css selector plus necessary state modifiers. **Avoid SCSS nesting for the sake of
code organization.** This will allow users to much more easily override styles.
For example, rather than doing this:
```scss
@@ -123,7 +227,7 @@ The end-user of a component should be the one to decide how much margin a compon
This makes it easier to override styles when necessary. For example, rather than
```scss
:host {
the-host-element {
// ...
.some-child-element {
@@ -134,7 +238,7 @@ This makes it easier to override styles when necessary. For example, rather than
you can write
```scss
:host {
the-host-element {
// ...
color: red;
}