naming-conventions

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Naming Conventions

命名约定

Consistent, role-carrying names make code searchable and self-explaining, and the suffix on a type declares which layer it lives in — so a reviewer, a
grep
, and a banned-import gate can all read the layer off the name alone. This skill is the how; the normative what is Effective Dart. Never invent a house style that contradicts the language's own.
一致且能够承载角色含义的命名可让代码易于搜索和自我解释;类型上的后缀会声明其所属层级——因此评审者、
grep
和导入限制检查门禁都能仅凭名称识别层级。该 skill 讲解“如何做”;规范性的“做什么”参见 Effective Dart。绝不要发明与语言自身规范相冲突的内部风格。

Non-negotiable rules

不可协商的规则

  1. Types are
    UpperCamelCase
    .
    Classes, enums, mixins, extensions, typedefs, type parameters:
    TaskScreen
    ,
    OrderStatus
    ,
    Predicate<T>
    . Consistent shape makes types visually distinct from values.
  2. Members, variables, functions, and parameters are
    lowerCamelCase
    .
    dueDate
    ,
    loadTasks()
    ,
    itemCount
    . It is the language default; deviating costs readers a double-take.
  3. Constants are
    lowerCamelCase
    , never
    SCREAMING_CAPS
    .
    const maxItemsPerPage = 50;
    — not
    const MAX_ITEMS = 50
    . Dart dropped the C convention; the analyzer expects
    constant_identifier_names
    .
  4. Files, folders, libraries, and import prefixes are
    lowercase_with_underscores
    .
    task_detail_screen.dart
    ,
    features/task_detail/
    ,
    import 'package:app_core/app_core.dart';
    . Cross-platform filesystems and pub demand it.
  5. File name = its primary declaration, snake_cased, one primary public type per file.
    TaskNotifier
    lives in
    task_notifier.dart
    . No
    utils.dart
    /
    helpers.dart
    /
    models.dart
    grab-bags and no
    utils/
    /
    common/
    /
    helpers/
    /
    misc/
    junk-drawer folders — a reader who greps a symbol must land in the file that owns it.
    core/
    is the sanctioned pure-foundation layer (value objects,
    Result
    /
    Failure
    , the
    Clock
    seam, pure calculators), not a junk-drawer — see
    project-structure-and-packages
    , which owns the layout.
  6. Acronyms longer than two letters are cased like a word.
    Json
    ,
    Http
    ,
    Url
    ,
    Api
    →
    JsonOrder
    ,
    HttpClient
    ,
    fromJson
    ,
    imageUrl
    — not
    JSONOrder
    ,
    HTTPClient
    . Two-letter caps-in-English acronyms may stay caps as types (
    ID
    ,
    UI
    ). Mixed-case acronyms are unsearchable and inconsistent.
  7. A leading underscore means library-private — use it only when you mean private. Never prefix a public symbol with
    _
    to "namespace" it; that makes it unusable from another file. Public (no
    _
    ) is a documented contract — see
    dartdoc-conventions
    .
  8. No Hungarian / type-encoding in names. Not
    strName
    ,
    iCount
    ,
    lstItems
    ,
    userMap
    ,
    nameString
    ,
    itemsList
    . The type system already knows the type; write
    name
    ,
    usersById
    ,
    items
    .
  9. Full dictionary words; units and semantics live in the name.
    maxItemsPerPage
    ,
    retryDelaySeconds
    ,
    orderTotalMinorUnits
    — never bare
    max
    ,
    delay
    ,
    total
    . Abbreviations (
    opt
    ,
    qty
    ,
    amt
    ) are confined to the inside of one short pure function with a comment mapping them. A name that omits its unit invites a unit bug.
  10. Booleans read as assertions.
    isLoading
    ,
    hasError
    ,
    canSubmit
    ,
    shouldRetry
    — not
    loading
    ,
    error
    ,
    retry
    . Boolean getters and methods start
    is
    /
    has
    /
    can
    /
    should
    so a condition reads like prose.
  11. No
    get
    -prefixed accessors.
    Expose
    dueTasks
    , not
    getDueTasks()
    . Dart has real getters. Functions are verb phrases (
    loadTasks()
    ,
    scheduleReminder()
    ); non-boolean getters are noun phrases (
    itemCount
    ,
    nextDueDate
    ).
  12. Imports grouped and sorted:
    dart:
    first, then
    package:
    , then relative — each group alphabetized,
    export
    s in their own section after imports. Let
    dart format
    plus the
    directives_ordering
    lint enforce it; never hand-fight the formatter.
  1. 类型使用
    UpperCamelCase
    。
    Class、enum、mixin、extension、typedef、类型参数:
    TaskScreen
    、
    OrderStatus
    、
    Predicate<T>
    。统一的形状可以让类型在视觉上与值区分开来。
  2. 成员、变量、函数和参数使用
    lowerCamelCase
    。
    dueDate
    、
    loadTasks()
    、
    itemCount
    。这是语言默认规则;偏离它会让读者额外停顿确认。
  3. 常量使用
    lowerCamelCase
    ,绝不使用
    SCREAMING_CAPS
    。
    const maxItemsPerPage = 50;
    ——不要写成
    const MAX_ITEMS = 50
    。Dart 不再采用 C 语言惯例;analyzer 会报告
    constant_identifier_names
    。
  4. 文件、文件夹、library 和 import prefix 使用
    lowercase_with_underscores
    。
    task_detail_screen.dart
    、
    features/task_detail/
    、
    import 'package:app_core/app_core.dart';
    。这是跨平台文件系统和 pub 的要求。
  5. 文件名等于其主要声明,使用 snake_cased,每个文件仅包含一个主要 public type。
    TaskNotifier
    位于
    task_notifier.dart
    中。不允许使用
    utils.dart
    /
    helpers.dart
    /
    models.dart
    这样的“大杂烩”文件,也不允许使用
    utils/
    /
    common/
    /
    helpers/
    /
    misc/
    这样的杂物抽屉式文件夹——读者 grep 某个符号时,必须能够直接定位到拥有该符号的文件。
    core/
    是经过认可的纯基础层(值对象、
    Result
    /
    Failure
    、
    Clock
    接缝、纯计算器),而不是杂物抽屉——具体布局由
    project-structure-and-packages
    负责。
  6. 超过两个字母的缩写按普通单词处理大小写。
    Json
    、
    Http
    、
    Url
    、
    Api
    →
    JsonOrder
    、
    HttpClient
    、
    fromJson
    、
    imageUrl
    ,而不是
    JSONOrder
    、
    HTTPClient
    。作为类型时,两个字母的英文首字母缩写可以保留大写(
    ID
    、
    UI
    )。混合大小写的缩写难以搜索且缺乏一致性。
  7. 前导下划线表示 library 私有——仅在确实需要私有时使用。 绝不要用
    _
    作为 public 符号的前缀来“划分命名空间”;这会使符号无法从其他文件使用。公开符号(不带
    _
    )本身就是一份有文档的契约——参见
    dartdoc-conventions
    。
  8. 禁止在名称中使用匈牙利式命名或编码类型。 不要使用
    strName
    、
    iCount
    、
    lstItems
    、
    userMap
    、
    nameString
    、
    itemsList
    。类型系统已经知道类型;直接写
    name
    、
    usersById
    、
    items
    。
  9. 使用完整字典单词;名称中应包含单位和语义。 使用
    maxItemsPerPage
    、
    retryDelaySeconds
    、
    orderTotalMinorUnits
    ,绝不要只写
    max
    、
    delay
    、
    total
    。缩写(
    opt
    、
    qty
    、
    amt
    )只能出现在一个简短纯函数内部,并附有说明其含义的注释。名称中省略单位往往会引发单位错误。
  10. 布尔值应读作断言。 使用
    isLoading
    、
    hasError
    、
    canSubmit
    、
    shouldRetry
    ,而不是
    loading
    、
    error
    、
    retry
    。布尔 getter 和方法以
    is
    /
    has
    /
    can
    /
    should
    开头,使条件表达式像自然语言一样清晰。
  11. 禁止使用带
    get
    前缀的访问器。
    应暴露
    dueTasks
    ,而不是
    getDueTasks()
    。Dart 支持真正的 getter。函数使用动词短语(
    loadTasks()
    、
    scheduleReminder()
    );非布尔 getter 使用名词短语(
    itemCount
    、
    nextDueDate
    )。
  12. **导入需分组并排序:**先放
    dart:
    ,然后是
    package:
    ,最后是相对导入;每组按字母顺序排列,
    export
    单独成组并位于导入之后。让
    dart format
    和
    directives_ordering
    lint 负责强制执行;绝不要手工对抗 formatter。

The suffix declares the layer

后缀声明所属层级

A role suffix turns a name into a layer contract: a
grep
or a path-scoped import gate can tell a repository from a view from a platform boundary without opening the file. Use neutral domain nouns (Task, Order, Account, Item) for the entity token.
RoleSuffix / patternLayerFile → symbol
Screen / route target
[Feature]Screen
UI (View)
task_list_screen.dart
→
TaskListScreen
Reusable widget
[Thing]
(+
Widget
only if ambiguous)
UI
task_card.dart
→
TaskCard
ViewModel (Riverpod, default)
[Feature]Notifier
UI (ViewModel)
task_list_notifier.dart
→
TaskListNotifier
ViewModel (Provider appendix only)
[Feature]ViewModel
UI (ViewModel)
task_list_view_model.dart
→
TaskListViewModel
Repository (interface)
[Entity]Repository
data
task_repository.dart
→
TaskRepository
Repository (impl)
Drift[Entity]Repository
/
Remote[Entity]Repository
data
drift_task_repository.dart
Drift DAO
[Entity]Dao
data
tasks_dao.dart
→
TasksDao
Capability interface you define
[Concern]Service
boundary
share_service.dart
→
ShareService
Service impl (per flavor)
[Provider][Concern]Service
app adapter
firebase_analytics_service.dart
→
FirebaseAnalyticsService
Wrapper over a specific plugin/SDK/native channel
[Concern]Gateway
boundary
notification_gateway.dart
→
NotificationGateway
Gateway impl
[Plugin][Concern]Gateway
/
Live[Concern]Gateway
app adapter
fln_notification_gateway.dart
→
FlnNotificationGateway
Pure-Dart domain logic
[Domain]
+ verb suffix (
Calculator
/
Validator
/
Formatter
)
domain
price_calculator.dart
→
PriceCalculator
Immutable modeldomain noun, no suffixany
task.dart
→
Task
Failure type
[Domain]Failure
(sealed)
any
order_failure.dart
→
OrderFailure
  • Notifier
    is the ViewModel role — never
    ViewModel
    or
    ChangeNotifier
    in the type name.
    On Riverpod 3.x the ViewModel is a
    Notifier
    /
    AsyncNotifier
    /
    StreamNotifier
    , one per
    Screen
    , 1:1, named
    [Feature]Notifier
    in
    [feature]_notifier.dart
    (file = primary declaration).
    [Feature]ViewModel
    in
    [feature]_view_model.dart
    is sanctioned ONLY in the Provider/
    ChangeNotifier
    appendix — never on the Riverpod path, and never
    [Feature]Controller
    . See
    state-management-riverpod
    .
  • Service
    vs
    Gateway
    — both name provider-free boundary ports, distinguished by who owns the contract.
    A
    [Concern]Service
    is a capability interface YOU define (
    ShareService
    ,
    AnalyticsService
    ); a
    [Concern]Gateway
    is the thin wrapper over a SPECIFIC external plugin/SDK or native
    MethodChannel
    (
    NotificationGateway
    over
    flutter_local_notifications
    ,
    SecureStorageGateway
    over
    flutter_secure_storage
    ). Domain and UI code names the interface; the concrete impl (
    FirebaseAnalyticsService
    ,
    FlnNotificationGateway
    ) lives only in the composition root. A concrete impl name leaking into shared code is a grep-catchable smell. See
    service-boundary-and-native
    .
  • Pure-Dart types carry a
    Calculator
    /
    Validator
    /
    Formatter
    /
    Parser
    verb suffix and touch no Flutter.
    The suffix advertises that the type is framework-free and unit-testable without a widget.
  • Match the domain's ubiquitous language and keep it consistent everywhere — one word per concept across models, repositories, and UI, so search finds every reference.
角色后缀可将名称转换为层级契约:无需打开文件,
grep
或限定路径的导入门禁就能区分 repository、view 和平台边界。实体部分使用中立的领域名词(Task、Order、Account、Item)。
角色后缀/模式层级文件 → 符号
Screen/路由目标
[Feature]Screen
UI(View)
task_list_screen.dart
→
TaskListScreen
可复用 widget
[Thing]
(仅在有歧义时追加
Widget
)
UI
task_card.dart
→
TaskCard
ViewModel(Riverpod,默认)
[Feature]Notifier
UI(ViewModel)
task_list_notifier.dart
→
TaskListNotifier
ViewModel(仅限 Provider 附录)
[Feature]ViewModel
UI(ViewModel)
task_list_view_model.dart
→
TaskListViewModel
Repository(接口)
[Entity]Repository
data
task_repository.dart
→
TaskRepository
Repository(实现)
Drift[Entity]Repository
/
Remote[Entity]Repository
data
drift_task_repository.dart
Drift DAO
[Entity]Dao
data
tasks_dao.dart
→
TasksDao
由你定义的能力接口
[Concern]Service
boundary
share_service.dart
→
ShareService
Service 实现(按 flavor 划分)
[Provider][Concern]Service
app adapter
firebase_analytics_service.dart
→
FirebaseAnalyticsService
特定 plugin/SDK/native channel 的封装
[Concern]Gateway
boundary
notification_gateway.dart
→
NotificationGateway
Gateway 实现
[Plugin][Concern]Gateway
/
Live[Concern]Gateway
app adapter
fln_notification_gateway.dart
→
FlnNotificationGateway
纯 Dart 领域逻辑
[Domain]
+ 动词后缀(
Calculator
/
Validator
/
Formatter
)
domain
price_calculator.dart
→
PriceCalculator
不可变模型领域名词,无后缀any
task.dart
→
Task
Failure 类型
[Domain]Failure
(sealed)
any
order_failure.dart
→
OrderFailure
  • Notifier
    是 ViewModel 角色——类型名称中绝不要使用
    ViewModel
    或
    ChangeNotifier
    。
    在 Riverpod 3.x 中,ViewModel 是
    Notifier
    /
    AsyncNotifier
    /
    StreamNotifier
    ,每个
    Screen
    对应一个,比例为 1:1,名称为
    [Feature]Notifier
    ,文件为
    [feature]_notifier.dart
    (文件名等于主要声明)。
    [Feature]ViewModel
    和
    [feature]_view_model.dart
    仅允许用于 Provider/
    ChangeNotifier
    附录;在 Riverpod 路径中绝不能使用,也绝不能使用
    [Feature]Controller
    。参见
    state-management-riverpod
    。
  • Service
    与
    Gateway
    ——二者都表示不绑定 provider 的边界端口,区别在于谁拥有契约。
    [Concern]Service
    是由你定义的能力接口(
    ShareService
    、
    AnalyticsService
    );
    [Concern]Gateway
    是对特定外部 plugin/SDK 或 native
    MethodChannel
    的轻量封装(基于
    flutter_local_notifications
    的
    NotificationGateway
    、基于
    flutter_secure_storage
    的
    SecureStorageGateway
    )。领域代码和 UI 代码引用接口;具体实现(
    FirebaseAnalyticsService
    、
    FlnNotificationGateway
    )只能存在于 composition root(组合根)。共享代码中出现具体实现名称,是可以通过 grep 发现的代码异味。参见
    service-boundary-and-native
    。
  • 纯 Dart 类型应使用
    Calculator
    /
    Validator
    /
    Formatter
    /
    Parser
    动词后缀,并且不依赖 Flutter。
    这样的后缀表明该类型不依赖框架,可以在没有 widget 的情况下进行单元测试。
  • 匹配领域的通用语言,并在所有位置保持一致——模型、repository 和 UI 中每个概念只使用一个词,使搜索能够找到全部引用。

Value vs. instant, and other name-carried distinctions

值与瞬时点,以及名称承载的其他区别

Encode a semantic distinction the type system can't in the name. A raw instant (
DateTime.now()
) used where a stable calendar value is expected is a common correctness bug; naming makes the boundary visible.
dart
// A real wall-clock instant is legal only at the Clock boundary and named as one.
final DateTime capturedAt = clock.now();      // instant, from package:clock's Clock (never DateTime.now())

// A stored quantity carries its canonical unit in the name.
final int priceMinorUnits;                    // not `price` — unit is explicit
final int distanceMeters;                     // SI base unit, integer

// Unused callback params are `_` (and `__` for a second).
onChanged: (_) => notifier.refresh(),
See
value-objects-money-and-units
for canonical storage and
service-boundary-and-native
for the
Clock
(from
package:clock
) injected via
clockProvider
— never a bespoke
ClockService
.
在名称中编码类型系统无法表达的语义区别。在需要稳定日历值的位置使用原始瞬时点(
DateTime.now()
)是一种常见正确性错误;通过命名可以让这一边界清晰可见。
dart
// A real wall-clock instant is legal only at the Clock boundary and named as one.
final DateTime capturedAt = clock.now();      // instant, from package:clock's Clock (never DateTime.now())

// A stored quantity carries its canonical unit in the name.
final int priceMinorUnits;                    // not `price` — unit is explicit
final int distanceMeters;                     // SI base unit, integer

// Unused callback params are `_` (and `__` for a second).
onChanged: (_) => notifier.refresh(),
value-objects-money-and-units
负责规范存储;
service-boundary-and-native
负责通过
clockProvider
注入的
Clock
(来自
package:clock
)——绝不要自创
ClockService
。

Worked example

实践示例

dart
// task_list_notifier.dart — file name == primary declaration, snake_cased
import 'dart:async'; // dart: group, alphabetized

import 'package:flutter_riverpod/flutter_riverpod.dart'; // package: group, alphabetized

import 'task.dart'; // relative group, alphabetized

/// Frozen paging bound — unit lives in the name (rule 9).
const int maxItemsPerPage = 50; // lowerCamelCase const, not SCREAMING_CAPS

/// ViewModel for [TaskListScreen]. One Notifier per Screen, 1:1 (role suffix).
class TaskListNotifier extends AsyncNotifier<List<Task>> {
  
  Future<List<Task>> build() => ref.watch(taskRepositoryProvider).loadTasks();

  /// Verb-phrase command; routes through the repository's single write path.
  Future<void> archive(String taskId) async {
    await ref.read(taskRepositoryProvider).archive(taskId);
    ref.invalidateSelf();
  }

  bool get hasTasks => state.valueOrNull?.isNotEmpty ?? false; // boolean assertion
  int get taskCount => state.valueOrNull?.length ?? 0;          // noun getter, no get- prefix
}
dart
// task_list_notifier.dart — file name == primary declaration, snake_cased
import 'dart:async'; // dart: group, alphabetized

import 'package:flutter_riverpod/flutter_riverpod.dart'; // package: group, alphabetized

import 'task.dart'; // relative group, alphabetized

/// Frozen paging bound — unit lives in the name (rule 9).
const int maxItemsPerPage = 50; // lowerCamelCase const, not SCREAMING_CAPS

/// ViewModel for [TaskListScreen]. One Notifier per Screen, 1:1 (role suffix).
class TaskListNotifier extends AsyncNotifier<List<Task>> {
  
  Future<List<Task>> build() => ref.watch(taskRepositoryProvider).loadTasks();

  /// Verb-phrase command; routes through the repository's single write path.
  Future<void> archive(String taskId) async {
    await ref.read(taskRepositoryProvider).archive(taskId);
    ref.invalidateSelf();
  }

  bool get hasTasks => state.valueOrNull?.isNotEmpty ?? false; // boolean assertion
  int get taskCount => state.valueOrNull?.length ?? 0;          // noun getter, no get- prefix
}

Anti-patterns

反模式

  • SCREAMING_CAPS
    constants in new Dart (
    const MAX_ITEMS = 50
    ) — use
    lowerCamelCase
    ; the analyzer flags it.
  • Class name ≠ file name (
    TaskScreen
    living in
    home.dart
    ), or a grab-bag
    utils.dart
    /
    models.dart
    holding unrelated things — breaks grep-to-file.
  • Naming a Flutter-touching type
    …Calculator
    /
    …Validator
    (a pure-Dart suffix), or a Riverpod ViewModel
    …ViewModel
    /
    …VM
    /
    …Controller
    — the suffix then lies about the layer (
    …Notifier
    on the Riverpod path;
    …ViewModel
    only in the Provider appendix).
  • A concrete impl name (
    FlnNotificationGateway
    ,
    FirebaseAnalyticsService
    ) referenced from shared/domain code — name the
    Gateway
    /
    Service
    interface; the impl belongs in the composition root.
  • DateTime.now()
    captured into a field meant to be stable, or an unnamed instant crossing into domain logic — inject a
    Clock
    and name the instant (
    capturedAt
    ).
  • getDueTasks()
    /
    get
    /
    set
    prefixes — Dart has real getters.
  • Type baked into a name:
    userMap
    ,
    nameString
    ,
    itemsList
    ,
    strName
    ,
    iCount
    .
  • Booleans without
    is
    /
    has
    /
    can
    /
    should
    (
    loading
    ,
    valid
    ); unit-silent quantities (
    total
    ,
    delay
    ).
  • Leading
    _
    to "namespace" a public symbol (it makes it private and unreachable);
    l
    /
    O
    /
    I
    single letters or
    data
    /
    temp
    /
    foo
    in committed code.
  • Abbreviations (
    opt
    ,
    qty
    ,
    msg
    ) outside a single short function with a mapping comment.
  • Hand-sorted or mixed import groups — run
    dart format
    ; obey
    directives_ordering
    .
  • 在新的 Dart 代码中使用
    SCREAMING_CAPS
    常量(
    const MAX_ITEMS = 50
    )——应使用
    lowerCamelCase
    ;analyzer 会报告此问题。
  • 类名与文件名不一致(
    TaskScreen
    位于
    home.dart
    中),或者使用
    utils.dart
    /
    models.dart
    这样的“大杂烩”文件存放无关内容——这会破坏从 grep 定位到文件的能力。
  • 为依赖 Flutter 的类型命名为
    …Calculator
    /
    …Validator
    (纯 Dart 后缀),或者为 Riverpod ViewModel 命名为
    …ViewModel
    /
    …VM
    /
    …Controller
    ——此时后缀会错误地声明其所属层级(Riverpod 路径应使用
    …Notifier
    ;
    …ViewModel
    仅限 Provider 附录)。
  • 在共享代码或领域代码中引用具体实现(
    FlnNotificationGateway
    、
    FirebaseAnalyticsService
    )——应引用
    Gateway
    /
    Service
    接口;具体实现应仅存在于 composition root。
  • 将
    DateTime.now()
    捕获到本应保持稳定的字段中,或者让未命名的瞬时点进入领域逻辑——应注入
    Clock
    并为瞬时点命名(
    capturedAt
    )。
  • 使用
    getDueTasks()
    或
    get
    /
    set
    前缀——Dart 支持真正的 getter。
  • 在名称中编码类型:
    userMap
    、
    nameString
    、
    itemsList
    、
    strName
    、
    iCount
    。
  • 布尔值不使用
    is
    /
    has
    /
    can
    /
    should
    (
    loading
    、
    valid
    );数量不标明单位(
    total
    、
    delay
    )。
  • 使用前导
    _
    为 public 符号“划分命名空间”(这会使其私有且无法访问);在已提交代码中使用
    l
    /
    O
    /
    I
    等单字母名称或
    data
    /
    temp
    /
    foo
    。
  • 在单个简短函数及其映射注释之外使用缩写(
    opt
    、
    qty
    、
    msg
    )。
  • 手工排序或混合导入分组——应运行
    dart format
    并遵守
    directives_ordering
    。

Definition of done

完成定义

  • Types
    UpperCamelCase
    ; members/vars/constants
    lowerCamelCase
    ; files/folders/prefixes
    lower_snake_case
    .
  • File name matches its primary declaration; one primary public type per file; no junk-drawer file or folder.
  • Architectural suffix applied and correct for the layer (
    Screen
    /
    Notifier
    /
    Repository
    /
    Dao
    /
    Service
    /
    Gateway
    /
    Failure
    ).
  • Riverpod ViewModels are
    …Notifier
    (not
    …Controller
    /
    …ViewModel
    /
    …VM
    ); pure-Dart types carry a
    Calculator
    /
    Validator
    /
    Formatter
    suffix and no Flutter import;
    Service
    /
    Gateway
    interfaces are provider-free with impls confined to the composition root.
  • Acronyms >2 letters word-cased; full dictionary words; units + semantics in the name; instants named at the
    Clock
    boundary.
  • Booleans read as assertions; functions are verb phrases; getters are noun phrases with no
    get
    prefix.
  • Imports grouped
    dart:
    /
    package:
    /relative and alphabetized;
    dart format
    +
    dart analyze --fatal-infos
    clean.
  • 类型使用
    UpperCamelCase
    ;成员、变量和常量使用
    lowerCamelCase
    ;文件、文件夹和 prefix 使用
    lower_snake_case
    。
  • 文件名与主要声明一致;每个文件仅包含一个主要 public type;不存在“大杂烩”文件或文件夹。
  • 已应用与层级匹配的正确架构后缀(
    Screen
    /
    Notifier
    /
    Repository
    /
    Dao
    /
    Service
    /
    Gateway
    /
    Failure
    )。
  • Riverpod ViewModel 使用
    …Notifier
    (而不是
    …Controller
    /
    …ViewModel
    /
    …VM
    );纯 Dart 类型使用
    Calculator
    /
    Validator
    /
    Formatter
    后缀且不导入 Flutter;
    Service
    /
    Gateway
    接口不绑定 provider,具体实现仅存在于 composition root。
  • 超过两个字母的缩写按单词处理大小写;使用完整字典单词;名称中包含单位和语义;瞬时点在
    Clock
    边界处明确命名。
  • 布尔值读作断言;函数使用动词短语;getter 使用名词短语且不带
    get
    前缀。
  • 导入按
    dart:
    /
    package:
    /相对导入分组并按字母顺序排列;
    dart format
    和
    dart analyze --fatal-infos
    均无问题。

Related skills

相关 skill

  • dart3-idioms-and-coding-standards
    — which construct (sealed/record/enum) each declaration earns, and complexity limits.
  • state-management-riverpod
    — why the ViewModel is a
    Notifier
    , and the single write path.
  • service-boundary-and-native
    — provider-free
    Service
    interfaces and their composition-root impls.
  • value-objects-money-and-units
    — canonical-unit storage behind the unit-in-name rule.
  • naming
    neighbors:
    dartdoc-conventions
    for the
    ///
    contract on public symbols,
    lint-and-style-config
    for the
    directives_ordering
    /
    constant_identifier_names
    enforcement, and
    flutter-architecture
    for the layer DAG the suffixes map to.
  • dart3-idioms-and-coding-standards
    ——每种声明适合采用哪种构造(sealed/record/enum),以及复杂度限制。
  • state-management-riverpod
    ——为什么 ViewModel 是
    Notifier
    ,以及单一写入路径。
  • service-boundary-and-native
    ——不绑定 provider 的
    Service
    接口及其 composition root 实现。
  • value-objects-money-and-units
    ——单位写入名称规则背后的规范单位存储。
  • naming
    的相邻 skill:使用
    dartdoc-conventions
    规范 public 符号的
    ///
    契约;使用
    lint-and-style-config
    强制执行
    directives_ordering
    /
    constant_identifier_names
    ;使用
    flutter-architecture
    管理后缀所映射的层级 DAG。

References

参考