Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Правильное именование Boolean свойств
Именование Boolean свойств — это важная часть код-стиля. Правильные имена делают код более читаемым и понятным. Рассмотрю лучшие практики.
1. Основное правило: глагол в утвердительной форме
Хорошо
bool isLoading = true;
bool isVisible = false;
bool isEnabled = true;
bool hasError = true;
bool canDelete = false;
bool isLoggedIn = true;
Плохо
bool loading = true; // неясно, что это bool
bool visible = false; // как читать: "видимый" или состояние?
bool enabled = true; // неоднозначно
bool error = true; // не очевидно, что это бул
bool delete = false; // глагол, а не состояние
2. Префиксы для Boolean свойств
is- (самый распространенный)
class User {
final String name;
final bool isActive;
final bool isAdmin;
final bool isEmailVerified;
final bool isBlocked;
final bool isOnline;
}
// Использование
if (user.isActive) {
// пользователь активен
}
has- (наличие чего-либо)
class Document {
final String title;
final bool hasComments;
final bool hasAttachments;
final bool hasRevisions;
final bool hasEncryption;
}
// Использование
if (document.hasAttachments) {
// показываем иконку с attachment
}
can- (возможность выполнить действие)
class Article {
final String content;
final bool canEdit;
final bool canDelete;
final bool canShare;
final bool canPublish;
final bool canArchive;
}
// Использование
if (article.canEdit) {
// показываем кнопку Edit
}
should- (рекомендация)
class AppSettings {
final bool shouldAutoSave;
final bool shouldNotify;
final bool shouldRefresh;
final bool shouldValidateOnChange;
}
// Использование
if (settings.shouldAutoSave) {
// автосохранять документ
}
will- (будущее действие)
class Event {
final String name;
final bool willStart;
final bool willBeRecorded;
final bool willHaveBreaks;
}
3. Практические примеры в Flutter
Model класс
@immutable
class Post {
final String id;
final String title;
final String content;
final bool isPublished;
final bool isPinned;
final bool isFeatured;
final bool hasComments;
final bool hasLikes;
final bool canEdit;
final bool canDelete;
final bool shouldNotifyAuthor;
const Post({
required this.id,
required this.title,
required this.content,
this.isPublished = false,
this.isPinned = false,
this.isFeatured = false,
this.hasComments = false,
this.hasLikes = false,
this.canEdit = false,
this.canDelete = false,
this.shouldNotifyAuthor = true,
});
}
State класс
class _PostPageState extends State<PostPage> {
bool isLoadingPost = false;
bool isLoadingComments = false;
bool isEditingPost = false;
bool hasErrorLoadingPost = false;
bool shouldShowDeleteConfirmation = false;
bool canLoadMore = true;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Post'),
actions: [
if (canEdit)
IconButton(
icon: Icon(Icons.edit),
onPressed: _editPost,
),
],
),
body: isLoadingPost
? Center(child: CircularProgressIndicator())
: hasErrorLoadingPost
? ErrorWidget(onRetry: _loadPost)
: PostContent(post: widget.post),
);
}
Future<void> _loadPost() async {
setState(() => isLoadingPost = true);
try {
// загружаем пост
} catch (e) {
setState(() => hasErrorLoadingPost = true);
} finally {
setState(() => isLoadingPost = false);
}
}
}
ViewModel класс
class PostViewModel extends ChangeNotifier {
// Loading states
bool _isLoadingPost = false;
bool _isLoadingComments = false;
bool _isSubmitting = false;
// Error states
bool _hasErrorLoadingPost = false;
bool _hasErrorLoadingComments = false;
// UI states
bool _isEditingPost = false;
bool _shouldShowDeleteConfirmation = false;
bool _shouldExpandComments = false;
// Permission states
bool _canEdit = false;
bool _canDelete = false;
bool _canComment = false;
// Computed properties
bool get isLoading => _isLoadingPost || _isLoadingComments;
bool get hasError => _hasErrorLoadingPost || _hasErrorLoadingComments;
bool get canPerformActions => _canEdit || _canDelete || _canComment;
Post? _post;
Post? get post => _post;
Future<void> loadPost(String postId) async {
_isLoadingPost = true;
notifyListeners();
try {
_post = await _repository.getPost(postId);
_hasErrorLoadingPost = false;
_canEdit = _post!.canEdit;
_canDelete = _post!.canDelete;
} catch (e) {
_hasErrorLoadingPost = true;
} finally {
_isLoadingPost = false;
notifyListeners();
}
}
Future<void> deletePost() async {
_isSubmitting = true;
notifyListeners();
try {
await _repository.deletePost(_post!.id);
_shouldShowDeleteConfirmation = false;
} finally {
_isSubmitting = false;
notifyListeners();
}
}
}
4. Bool в контроллерах и блоках
StateNotifier (Riverpod)
class AuthState {
final bool isLoading;
final bool isLoggedIn;
final bool hasError;
final String? errorMessage;
final bool shouldShowBiometric;
final bool canRetry;
const AuthState({
this.isLoading = false,
this.isLoggedIn = false,
this.hasError = false,
this.errorMessage,
this.shouldShowBiometric = false,
this.canRetry = true,
});
AuthState copyWith({
bool? isLoading,
bool? isLoggedIn,
bool? hasError,
String? errorMessage,
bool? shouldShowBiometric,
bool? canRetry,
}) => AuthState(
isLoading: isLoading ?? this.isLoading,
isLoggedIn: isLoggedIn ?? this.isLoggedIn,
hasError: hasError ?? this.hasError,
errorMessage: errorMessage ?? this.errorMessage,
shouldShowBiometric: shouldShowBiometric ?? this.shouldShowBiometric,
canRetry: canRetry ?? this.canRetry,
);
}
BLoC State
abstract class LoginState {}
class LoginInitial extends LoginState {}
class LoginLoading extends LoginState {}
class LoginFailure extends LoginState {
final String message;
final bool canRetry;
final bool shouldShowPasswordReset;
LoginFailure({
required this.message,
this.canRetry = true,
this.shouldShowPasswordReset = false,
});
}
class LoginSuccess extends LoginState {
final User user;
final bool shouldNavigateToHome;
final bool shouldShowWelcome;
LoginSuccess({
required this.user,
this.shouldNavigateToHome = true,
this.shouldShowWelcome = true,
});
}
5. Bool в виджетах
class ProductCard extends StatelessWidget {
final Product product;
final bool isFavorite;
final bool isSelected;
final bool isOutOfStock;
final bool canAddToCart;
final bool showDiscount;
const ProductCard({
required this.product,
this.isFavorite = false,
this.isSelected = false,
this.isOutOfStock = false,
this.canAddToCart = true,
this.showDiscount = false,
});
@override
Widget build(BuildContext context) {
return Card(
child: Stack(
children: [
// Main content
Column(
children: [
// Image with favorite button
Stack(
children: [
ProductImage(product: product),
if (showDiscount)
DiscountBadge(discount: product.discount),
Positioned(
right: 0,
top: 0,
child: FavoriteButton(
isFavorite: isFavorite,
),
),
],
),
// Product info
ProductInfo(product: product),
// Price and stock status
if (isOutOfStock)
Text('Out of Stock')
else
PriceWidget(price: product.price),
// Add to cart button
if (canAddToCart)
AddToCartButton(product: product),
],
),
// Selection indicator
if (isSelected)
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.blue, width: 2),
),
),
],
),
);
}
}
6. Анти-паттерны
Плохо: отрицание в имени
// ❌ Плохо — двойное отрицание сложно читать
bool isNotEmpty = true;
if (!isNotEmpty) { // if not not empty?
// что-то делаем
}
// ✅ Хорошо
bool isEmpty = false;
if (isEmpty) {
// что-то делаем
}
Плохо: глаголы в прошедшем времени
// ❌ Плохо
bool loaded = true;
bool clicked = false;
bool submitted = true;
// ✅ Хорошо
bool isLoaded = true;
bool isClicked = false;
bool isSubmitted = true;
Плохо: неоднозначные имена
// ❌ Плохо — неясно, что это bool
bool valid = true;
bool active = false;
bool ready = true;
// ✅ Хорошо
bool isFormValid = true;
bool isUserActive = false;
bool isDataReady = true;
7. Стайл гайд для проекта
// style_guide.md для Flutter проекта
## Boolean Naming Convention
1. Используй всегда префиксы:
- is* (состояние): isLoading, isVisible, isEnabled
- has* (наличие): hasError, hasComments
- can* (возможность): canEdit, canDelete
- should* (рекомендация): shouldNotify, shouldRefresh
- will* (будущее): willStartSoon
2. Избегай отрицания в имени:
- ❌ isNotEmpty
- ✅ isEmpty
3. Будь специфичен:
- ❌ loading
- ✅ isLoadingUserProfile
4. Используй camelCase:
- ✅ isUserLoggedIn
- ❌ is_user_logged_in
- ❌ IsUserLoggedIn
5. Примеры:
```dart
// Loading
bool isLoadingPage;
bool isLoadingComments;
// Visibility
bool isVisible;
bool isExpanded;
bool isCollapsed;
// States
bool isActive;
bool isEnabled;
bool isSelected;
bool isLoggedIn;
// Has/Has not
bool hasData;
bool hasError;
bool hasAttachments;
// Can do
bool canEdit;
bool canDelete;
bool canPublish;
// Should/Should not
bool shouldNotify;
bool shouldRefresh;
bool shouldAutoSave;
### Итого
**Правила именования Boolean свойств:**
- **Используй префиксы:** is*, has*, can*, should*, will*
- **Избегай отрицания:** изпользуй isEmpty вместо isNotEmpty
- **Будь специфичен:** isLoading вместо loading
- **Используй camelCase:** isUserLoggedIn, не IsUserLoggedIn
- **Выбери префикс:**
- is* для состояний (isLoading, isVisible)
- has* для наличия (hasError, hasAttachments)
- can* для возможностей (canEdit, canDelete)
- should* для рекомендаций (shouldNotify)
Правильные имена делают код более читаемым и предотвращают ошибки типа "if (!isNotEmpty)" — двойное отрицание, которое сложно читать.