| Kind | Convention | Example |
|---|---|---|
| Files | snake_case |
user_repository.dart |
| Classes / Enums / Typedefs | PascalCase |
UserRepository |
| Variables / Parameters / Methods | camelCase |
currentUser, getUserById() |
| Constants | camelCase |
defaultTimeout |
| Private members | _camelCase |
_httpClient |
Each construct has a required suffix that signals its role at a glance:
| Construct | Suffix | Example |
|---|---|---|
| Domain entity | (none) | User, Order |
| Domain error | Error |
UserError, OrderError |
| Repository interface | I prefix + Repository |
IUserRepository |
| Repository implementation | Repository |
UserRepository |
| Use case | UseCase |
SignInUseCase, GetOrdersUseCase |
| DTO | Dto |
UserDto, OrderDto |
| Data source interface | I prefix + Api / Service / DataSource |
IUserApi, IAnalyticsService |
| Data source implementation | Protocol prefix + base name | UserApiRest, UserApiGraphQL |
| Bloc | Bloc |
LoginBloc |
| Bloc event base | Event |
LoginEvent |
| Bloc state base | State |
LoginState |
| Page widget | Page |
LoginPage |
| View widget | View |
LoginView |
| Body widget | Body |
LoginBody |
| Field validator | Field |
EmailField, PasswordField |
| Validation failure | ValidationFailure |
EmailValidationFailure |
| Params object | Params |
ContractDetailParams |
| Status enum (single-class Bloc) | Status |
LoginStatus |
File names must match the primary class they contain, converted to snake_case:
UserRepository → user_repository.dart
IUserRepository → i_user_repository.dart
SignInUseCase → sign_in_use_case.dart
LoginBloc → login_bloc.dart
LoginEvent → login_event.dart
LoginState → login_state.dart
UserDto → user_dto.dart
Domain enums are named in singular PascalCase with no Enum suffix:
// ✅
enum UserStatus { active, inactive, unknown }
// ❌
enum UserStatusEnum { active, inactive, unknown }DTO-level enums that mirror a domain enum add a Dto suffix to distinguish them:
enum UserStatusDto { active, inactive, unknown }The I prefix makes it explicit whether a type is a contract or a concrete implementation:
// Domain — interface
abstract interface class IUserRepository { ... }
// Infrastructure — implementation
class UserRepository implements IUserRepository { ... }Use case names must begin with an action verb that describes what the use case does:
// ✅
class SignInUseCase { ... }
class GetOrdersUseCase { ... }
class UpdateUserProfileUseCase { ... }
// ❌
class LoginUseCase { ... } // vague
class UserUseCase { ... } // no verbDart supports static access shorthands (dot shorthands) when the context type can be inferred. Prefer dot shorthands over fully qualified names whenever the type is unambiguous.
// ✅ Preferred
UserStatus get defaultStatus => .active;
void setStatus(UserStatus status) { ... }
setStatus(.active);
final UserStatus status = switch (currentStatus) {
.active => .inactive,
.inactive => .active,
.unknown => .unknown,
};
// ❌ Verbose when type is clear
UserStatus get defaultStatus => UserStatus.active;
setStatus(UserStatus.active);Dot shorthands work with:
- Enum values
- Static methods / constructors when the return type matches the context type
They do not work when the type cannot be inferred (e.g., var x = .active).