fresh digitable

めんどくさかったなってことを振り返ったり振り返らなかったりするための記録

effective dartを一言ぐらいでまとめていく(Document編)

続きです:akihito104.hatenablog.com

Document

dart.dev

  • そのコードを書いている間はコードの意図が明白であったとしても、そのコードを初めて見る人や、将来の自分でさえも、その時の文脈を知らないかもしれない。
  • コメントを書くのには数秒程度しかかからないが、それによってたくさんの人の時間を節約できる。
  • コメントは自分たちが思っている以上にもっと書いた方がいい。

comment

  • コメントは文章のように書く。大文字で始めて、ピリオドで終わる。
  • コメントにはブロックコメントを使わない。ブロックコメントはコードの一時的なコメントアウトの時だけにする。

doc comments

/// で書き始めるとdartdocにできていい感じの見た目のページを作れる。

  • メンバや型のドキュメントには///を使う。歴史的経緯でJavadoc風の /* ... /も使えるけど、///の方が*を箇条書きのマークとして使えるのでおすすめ。
  • publicなAPIにはドキュメントを書くのが望ましい。
  • ライブラリレベルのdoc commentを検討する。クラスがプログラムの唯一の構成単位であるJavaとは違い、Dartにおけるライブラリは、ユーザーがそれを直接使い、importし、それについて考える実態である。libraryディレクティブは、ライブラリのコンセプトや提供する機能を説明するのによい場所である。ドキュメントはファイルの先頭にあるlibraryディレクティブのすぐ上に書く。libraryディレクティブがない時は追加しよう。次のようなことを書くとよい
    • ライブラリが何をするためのものなのか、1行で表す。
    • ライブラリ全体を通して使う用語を説明する
    • APIをくまなく使うようないくつかのコードサンプル
    • 最も重要な、または共通的なクラスや関数へのリンク
    • このライブラリで取り扱う領域に関する外部への参照
  • private APIにもドキュメントを書くよう考える。
  • ドキュメントは1行の要約から始める。ただの断片的な文だけで十分な場合もあるが、読み手がこの先も読むに値するか判断できるようなものが望ましい。
  • 最初の文章とdoc commentとの間に空行を入れて分ける。
  • 周囲の文脈を冗長に書かない。doc commentを読む人はそのクラスや、そのメンバのシグネチャなら簡単に把握できるので、そういったことをわざわざ特定のメンバのdoc commentに書く必要はない。
  • 関数やメソッドのコメントは三人称の動詞で書き始めるのが望ましい。
  • 変数やgetter, setterのコメントは名詞で書き始めるのが望ましい。何が得られるのかを強調するべき。もしプロパティにgetterとsetterが両方ともある時、dartdocはそれらを1つのプロパティとみなすので片方にだけドキュメントを書けばよい。両方に書いてある場合は、setterの方が無視される。
  • ライブラリや型のコメントは名詞で書き始めるのが望ましい。クラスのドキュメントがしばしば最も重要になる。型の不変性を記載したり、使う用語を確立したり、クラスのメンバに対するコンテキストを提供することにもなる。少しでいいのでクラスのドキュメント作成を頑張ると、ほかのドキュメンテーションをシンプルにできることもある。
  • サンプルコードを付けるのを考慮する。
  • 大かっこをつかってスコープ内識別子を参照する。クラス内のメンバや名前付きコンストラクタを参照するときはドットでつなげればよい。
  • パラメータや戻り値、例外の説明は文章の中で行う。特別なシンタックスを使うなどして個別に詳細に書く言語もあるが、Dartはではパラメータなどを大かっこで括って本文内に統合する。
  • doc commentはメタデータアノテーションの上に書く。

markdown

  • 過度に使いすぎるのを避ける。
  • フォーマットにHTMLを使うのを避ける。
  • コードブロックにはバックティックフェンス (```) を使うのが望ましい。

writing

  • 簡潔に書く。
  • 略語や頭字語は使わない。
  • メンバのインスタンスに対して言及するときは、theではなくthisを使うのが好ましい。

effective dartを一言ぐらいでまとめていく(Style編)

JavaではEffective Javaを、KotlinではKotlin in actionを読んだので、同じようなことをDartでもやっておこうと思って探したら公式のページに書いてあった。

dart.dev

書き始めて3か月ぐらい経つのでちょっと遅いかもしれないが読んでいくことにする。全訳するのはだるいので、項目ごとに短めにまとめていく。タイトルをほぼ直訳するだけになるかもしれない。また、自分の解釈を多分に含むので、Dartを勉強しようとして間違えてこのページに来てしまった人は公式のページも合わせて読んでほしい。

本題

一貫性があり、ロバストで速いDartのコードを書くための2つの包括的なテーマを紹介する:

  • 一貫性があること:二つのコードを見比べたとき、両者の異なる部分にこそ有用なことが存在する。そうであるべき。
  • 簡潔であること:Dartは他のいろんな言語を改善するような形で簡潔に記述できるように作られた。ただし、コードゴルフみたいに詰め込んだコードを書くよりも、経済的なコードを書くべき。

DartアナライザーにはLinterの機能があって、一貫性のあるいいコードを書く助けになる。

ガイドラインは4つの部分に分けられる。 - スタイル - ドキュメンテーション - 使い方 - デザイン

スタイル

識別子

  • class, enum, typedef, 型パラメータはパスカルケースにする。引数なしのアノテーションクラスは小文字で始めてもよい。
  • extensionsの名前はパスカルケースにする。
  • ライブラリ、ファイル名、ディレクトリ名、パッケージ名はスネークケースにする。
  • importプレフィクスはスネークケースにする。
  • メンバ、トップレベル定義、変数、引数、名前付き引数はキャメルケースにする。
  • これから書くコードでは、定数やEnumのメンバはキャメルケースにする。
    • 昔はSCREAMING_CAPSを使ってたけどやめた。その時のものが多少残っている。
  • 2文字より多い頭字語や略語は大文字にする。ただし、IO(Input/Output)、Id(Identification)は例外とする。
  • 使わないコールバック変数は_, __にするのが好ましい。ただし、匿名とかローカルのものだけで、トップレベル関数は逆に省略してはならない。
  • privateでない識別子にリーディングアンダースコアを使わない。
  • プレフィックス文字を使わない。

順序

  • インポートの順序
    • dart:
    • package:
    • 相対インポート
    • export
  • それぞれのセクションごとに空白で区切る
  • セクションごとにアルファベットでソートする

フォーマット

  • dart formatを使え
  • フォーマットしても読みにくいコード(識別子が長すぎたり、ネストがめっちゃ深かったり、いろんなオペレータを複雑に組み合わせてたり)になったら意味がないので、変数名を短くしたり、別の変数に移し替えたりできないか考えてみてほしい。
  • 1行が80文字より長くならないようにする。ただし、URLやファイルパス、コメント、長い文字列(Stringの変数に格納するものなど)はこの限りではない。
  • すべての制御文で波カッコ(中カッコ)を使う。ただし、一行で書けるif文についてはこの限りではない。

BackdropFilterを使わずに画像にblurをかける

"flutter Image blur"で検索してもBackdropFilterの記事しか出ないのでカッとなって書いた。画像にボケと透明度を同時に適用したいとか、BackdropFilterだとボケの感じが思ってたのとなんか違うなという時にどうぞ。

ImageFiltered(
  imageFilter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
  child: Image.network('...',  // dst
    color: Colors.white.withOpacity(0.5),  // src
    colorBlendMode: BlendMode.lighten, // 重ねる色に合わせていい感じになるやつを選んでください
  ),
)

私の場合は、

  • 画像にボケをかけたい -> BackdropFilterを使いたまえ
  • Widgetのグループを半透明にしたい -> Opacityで包みたまえ

の合わせ技で、リストに入っているというのも効いたのか、ボケと半透明が適用された画像が表示されないことがあった。

ここでの問題点は、BackdropFilter自体が結構重い処理*1なのに加えて、さらにOpacityもまたそれなりに重い*2ということで、これを解決したければ、Opacityのページにも書いてあるようにImageのプロパティを使って透過度を適用するのが軽くてよいらしい。私はPorter-DuffのBlendModeをつかって適用+ImageFilteredblurで解決したが、もっと簡単な方法もあるかもしれない。

*1: https://api.flutter.dev/flutter/widgets/BackdropFilter-class.html のサンプルコードの下あたりを参照。

*2: https://api.flutter.dev/flutter/widgets/Opacity-class.html のサンプルコードの下あたりを参照。offscreen bufferを使うことになって重いし、画面の再描画処理も走るので古いGPUの端末では遅くなりそうみたいなことが書いてある。