Flutter 自体の Style Guide から学ぶ

**[Style-guide-for-Flutter-repo](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo)** の話。

ふと [CONTRIBUTING.md](https://github.com/flutter/flutter/blob/master/CONTRIBUTING.md) を読んでたら見つけたのでメモ。
全部書くと長いので、_個人的に厳選したものだけ_を_簡潔に意訳_してます。[^1]

## Flutter リポジトリの Style Guide

### [Getters feel faster than methods](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#getters-feel-faster-than-methods)
プロパティのゲッターは効率的であるべき という話。
例えば、キャッシュしたり、オーダーに気を遣ったりしよう。

単純な処理じゃない場合はメソッドにしよう。
Web の話で言えば、`document.forms` より `document.getForms()` と書かれていてほしい。

### [Avoid complecting (braiding multiple concepts together)](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#avoid-complecting-braiding-multiple-concepts-together)
各 API はそれぞれで完結しているべき という話。

だから、例えば Widget の child の型を見てどうこうするのは良くないよね。

### [Avoid APIs that encourage bad practices](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#avoid-apis-that-encourage-bad-practices)

良くない習慣を助長する API はやめよう という話。

コストの高い処理をするのであれば、それが API で表されているのがあるべき姿。
例えば Future や Stream を返そう。

### [Avoid exposing API oceans](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#avoid-exposing-api-oceans)
大雑把に API を公開しちゃダメだよ という話。

例えば、 `dart:ui` が `Path.fromSVG()` を公開しないのは、Dart で直接実行するのと速度的には差がほぼないから。
そういうのを不用意に公開しないことで、保守,ドキュメント,テストなどの負担を減らせる。

### [Writing prompts for good documentation](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#writing-prompts-for-good-documentation)

良いドキュメントを残す時の観点はこういうのがあるよね という話。

[例1]
プロパティや引数の型について、議論すべき正常範囲外のケースがないかを検討しよう。 ex) null, 無限, NaN, 空

[例2]
クラスのメンバーについて、相互の影響について考えよう。例えば、他のある値が null の時だけ〇〇になる みたいなことはないか。

[例3]
ライフサイクルに気をつけよう。例えば、誰かが所有しているオブジェクトがあったとして、その `dispose()` は誰が責任を持って呼ぶのか。

### [Provide sample code](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#provide-sample-code)
サンプルコードあると嬉しいよね という話。

適切なフォーマットでサンプルを書く。

```dart
/// {@tool sample}
/// An infinite list of children:
///
/// ```dart
/// ListView.builder(
///   padding: EdgeInsets.all(8.0),
///   itemExtent: 20.0,
///   itemBuilder: (BuildContext context, int index) {
///     return Text('entry $index');
///   },
/// )
/// ```
/// {@end-tool}
class ListView { // ...
```


### [Use `///` for public-quality private documentation](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#use--for-public-quality-private-documentation)
public な API のコメントは必ず `///` だよね という話。
品質が十分でない private な API にだけ `//` を使おう。

### [Dartdoc-specific requirements](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#dartdoc-specific-requirements)
[Dartdoc](https://github.com/dart-lang/dartdoc) に従ってドキュメント書こう という話。

```dart
/// Creates a foobar, which allows a baz to quux the bar.
///
/// The [bar] argument must not be null.
///
/// The `baz` argument must be greater than zero.
Foo({ this.bar, int baz }) : assert(bar != null), assert(baz > 0);
```

### [Use asserts liberally to enforce contracts and invariants](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#use-asserts-liberally-to-enforce-contracts-and-invariants)

`assert()` はデバッグモードでだけ有効なんだから、必要と感じたらどんどん入れていこう という話。

### [Prefer specialized functions, methods and constructors](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#prefer-specialized-functions-methods-and-constructors)

読み手に意味を直接的に伝えられるメソッドを使おう という話。[^2]

```dart
// BAD:
const EdgeInsets.TRBL(0.0, 8.0, 0.0, 8.0);

// GOOD:
const EdgeInsets.symmetric(horizontal: 8.0);
```

### [Have good hygiene when using temporary directories](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#have-good-hygiene-when-using-temporary-directories)

一時ディレクトリはちゃんと管理しよう という話。

`flutter_` で始まり、ピリオドで終わる一意の名前を付けよう(その後に自動生成されたランダムな文字列を続ける)。

あと、不要になったディレクトリはちゃんと綺麗に片付けること!
テストでは `tryToDelete` を使おう。[^3]

### [Perform dirty checks in setters](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#perform-dirty-checks-in-setters)

セッターで Dirty チェックをしよう という話。

Dirty チェックというのは、変更された値がアプリの他の箇所と同期されているかをチェックすること。
例えば、セットのタイミングで Dirty であることをマーキングしておくにはこんな感じで書く。

```dart
TheType get theProperty => _theProperty;
TheType _theProperty;
void set theProperty(TheType value) {
  assert(value != null);
  if (_theProperty == value)
    return;
  _theProperty = value;
  markNeedsWhatever(); // the method to mark the object dirty
}
```

### [Common boilerplates for `operator ==` and `hashCode`](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#common-boilerplates-for-operator--and-hashcode)

`operator ==` と `hashCode` をオーバーライドする時はこう書こう という話。

```dart
@override
bool operator ==(Object other) {
  if (other.runtimeType != runtimeType)
    return false;
  final Foo typedOther = other;
  return typedOther.bar == bar
      && typedOther.baz == baz
      && typedOther.quux == quux;
}

@override
int get hashCode => hashValues(bar, baz, quux);
```

オブジェクトがたくさんプロパティを持つなら、`operator ==` を頭に置くことも検討しよう。

### [Override toString](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#override-tostring)

`toString` をオーバーライドしてデバッグに使うよりも、`Diagnosticable` を使おう という話。
[devtools](https://pub.dartlang.org/packages/devtools) や IDEでの調査も捗る。

### [Prefer naming the argument to a setter `value`](https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#prefer-naming-the-argument-to-a-setter-value)

特に理由がない限りセッターの引数は `value` にしよう という話。

## おわりに
driver test まわりの挙動に色々疑問があってソース追いかけていたのに、いつの間にか Style Guilde 読んでた...


[^1]: 中には `analysis_options.yaml` に書いておけばいいだけのものもあるので設定大事。
[^2]: それっぽいメソッドが生えてないかドキュメントを逐次確認するのが大切ってことですね。
[^3]: 例えばこんな感じにね! [flutter_tools/test/integration/flutter_run_test.dart#L29](https://github.com/flutter/flutter/blob/d51c6b5094d23678bd9a2bf5ee4e523f3b0c5783/packages/flutter_tools/test/integration/flutter_run_test.dart#L29)