← Назад к вопросам

Как правильно именовать Bool свойство?

2.0 Middle🔥 131 комментариев
#Dart

Комментарии (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)" — двойное отрицание, которое сложно читать.