---
# System prepended metadata

title: Frontend Convention

---

# Frontend Convention

###### tags: Naming, rules
> 為了得到一致且高品質的code space
> 在前端開發時，盡可能的去符合這份文件

[ToC]
## 命名原則

### ==0: 取有意義的名字==

- ❌ Don't
```dart=1
void abc();
List aList =[];

class AAAA{}
```
- ✅ Do
```dart=1
void buildTable();
List productList =[];
List products =[];

class UserRepository{}
```

### 1: 檔案名稱為 'example_example.ext'

- ❌ Don't
```dart
Example Example.ext    // 使用下畫線分隔單字
Example_Example.ext    // 所有單字皆為小寫
```
- ✅ Do
```dart
example_example.ext
```

### 2: 類別（class）名稱為 'ExampleOne'

- ❌ Don't
```dart=1
class exampleOne{}    // 使用大駝峰(UpperCamelCase)
class Example_One{}    // 使用大駝峰(UpperCamelCase)且不使用符號
```
- ✅ Do
```dart=1
class ExampleOne{}    
```

---
## linter 規則

### 1: avoid_single_cascade_in_expression_statements
> 不要單獨使用cascade expression
- ❌ Don't
```dart=1
o..m();
```
- ✅ Do
```dart=1
o.m();
```
### 2: cascade_invocations
> 當使用same reference時，使用cascade expression
- ❌ Don't
```dart=1
SomeClass someReference = SomeClass();
someReference.firstMethod();
someReference.secondMethod();
```

- ❌ Don't
```dart=1
SomeClass someReference = SomeClass();
// ...
someReference.firstMethod();
someReference.aProperty = value;
someReference.secondMethod();;
```

- ✅ Do
```dart=1
SomeClass someReference = SomeClass()
    ..firstMethod()
    ..aProperty = value
    ..secondMethod();
```
- ✅ Do
```dart=1
SomeClass someReference = SomeClass();
// ...
someReference
    ..firstMethod()
    ..aProperty = value
    ..secondMethod();
```
### 3: avoid_classes_with_only_static_members
> 建立有明確意義的class, 並提供class method
> 若需要global 的variable 或是method
> **請直接寫在class 外**
- ❌ Don't
```dart=1
class DateUtils {
  static DateTime mostRecent(List<DateTime> dates) {
    return dates.reduce((a, b) => a.isAfter(b) ? a : b);
  }
}

class _Favorites {
  static const mammal = 'weasel';
}
```
- ✅ Do
```dart=1
DateTime mostRecent(List<DateTime> dates) {
  return dates.reduce((a, b) => a.isAfter(b) ? a : b);
}

const _favoriteMammal = 'weasel';
```
### 4: camel_case_extensions  &&  camel_case_types
> 大寫所有單字的第一個字，並不使用separator
- ✅ Do
```dart=1
extension MyFancyList<T> on List<T> { 
  // ... 
}

extension SmartIterable<T> on Iterable<T> {
  // ...
}
```
- ✅ Do
```dart=1
class SliderMenu {
  // ...
}

class HttpRequest {
  // ...
}

typedef num Adder(num x, num y);
```
### 5: avoid_function_literals_in_foreach_calls
> **避免**使用 forEach()
> forEach loop 是透過lambda function 執行迴圈，在async/await 下會顯得不便
> 在Dart裡，如果你想要iterate seq, 最直接的方法就是使用迴圈

- ❌ Don't
```dart=1
people.forEach((person) {
  // ...
});
```
- ✅ Do
```dart=1
for (var person in people) {
  // ...
}
```
:::info
需要注意的是，規則是寫'function literal'，若你想要傳入已存在的function 給每一個element
forEach() 是可以被接受的
:::
- ✅ Do
```dart=1
void del(person){...}
// ...
people.forEach(print);
people.forEach(del);
```
### 6: directives_ordering
> 把 "dart:" 的import 放在其它import 的前面

- ❌ Don't
```dart=1
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

import 'dart:async';  // LINT
import 'dart:html';  // LINT
```
- ❌ Don't
```dart=1
import 'dart:html';  // OK
import 'package:bar/bar.dart';

import 'dart:async';  // LINT
import 'package:foo/foo.dart';
```
- ✅ Do
```dart=1
import 'dart:async';  // OK
import 'dart:html';  // OK

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
```
> 把 "package:" 的import 放在相對路徑import 之前

- ❌ Don't
```dart=1
import 'a.dart';
import 'b.dart';

import 'package:bar/bar.dart';  // LINT
import 'package:foo/foo.dart';  // LINT
```
- ❌ Don't
```dart=1
import 'package:bar/bar.dart';  // OK
import 'a.dart';

import 'package:foo/foo.dart';  // LINT
import 'b.dart';
```
- ✅ Do
```dart=1
import 'package:bar/bar.dart';  // OK
import 'package:foo/foo.dart';  // OK

import 'a.dart';
import 'b.dart';
```

> 分隔 export 和其餘全部import
- ❌ Don't
```dart=1
import 'src/error.dart';
export 'src/error.dart'; // LINT
import 'src/string_source.dart';
```
- ✅ Do
```dart=1
import 'src/error.dart';
import 'src/string_source.dart';

export 'src/error.dart'; // OK
```
> 對每個區塊alphabetically sort
- ❌ Don't
```dart=1
import 'package:foo/bar.dart'; // OK
import 'package:bar/bar.dart'; // LINT

import 'a/b.dart'; // OK
import 'a.dart'; // LINT
```
- ✅ Do
```dart=1
import 'package:bar/bar.dart'; // OK
import 'package:foo/bar.dart'; // OK

import 'a.dart'; // OK
import 'a/b.dart'; // OK
```
### 7: prefer_interpolation_to_compose_strings
> 組成字串時，使用 '$' 傳入字串或是數值

- ❌ Don't
```dart=1
'Hello, ' + name + '! You are ' + (year - birth) + ' years old.';
```
- ✅ Do
```dart=1
'Hello, $name! You are ${year - birth} years old.';
```

### 8: prefer_is_empty  &&  prefer_is_not_empty
> ==千萬不要用length 來判斷集合內是否為空==
> 使用length 去確認集合是否為空，會相當的time-consuming
> 使用isEmpty 和isNotEmpty 會更快並更具可讀性

- ❌ Don't
```dart=1
if (lunchBox.length == 0) return 'so hungry...';
if (words.length != 0) return words.join(' ');
```
- ✅ Do
```dart=1
if (lunchBox.isEmpty) return 'so hungry...';
if (words.isNotEmpty) return words.join(' ');
```
### 9: prefer_equal_for_default_values
> 因為Dart 的向後版本支援原因，Dart 允許使用 : 和 = 當作預設值的separator
> 為了一致性，請使用 =

- ❌ Don't
```dart=1
void insert(Object item, {int at: 0}) { ... }
```
- ✅ Do
```dart=1
void insert(Object item, {int at = 0}) { ... }
```
### 10: unnecessary_lambdas
> 當tear-off 可以使用時，不要建立lambda function 

- ❌ Don't
```dart=1
names.forEach((name) {
  print(name);
});
```
- ✅ Do
```dart=1
names.forEach(print);
```