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

Какими правилами руководствуешься при написании кода?

2.0 Middle🔥 241 комментариев
#Soft Skills и карьера#Архитектура и паттерны

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

При написании кода я руководствуюсь совокупностью принципов, паттернов и практик, которые можно разделить на несколько ключевых категорий. Эти правила направлены на создание масштабируемого, поддерживаемого, надежного и тестируемого кода, что особенно критично в мобильной разработке, где требования и контекст исполнения часто меняются.

1. Основополагающие архитектурные принципы (SOLID & Co.)

Это основа основ, которая позволяет создавать гибкие модули.

  • Single Responsibility (SRP): Каждый класс (или структура) должен иметь одну и только одну причину для изменения. Например, NetworkService занимается только сетью, а DataPersistor — только сохранением.
    // ПЛОХО: Класс делает слишком много
    class UserManager {
        func fetchUser() { /* сетевой запрос */ }
        func saveToDatabase() { /* работа с БД */ }
        func validateEmail() { /* валидация */ }
    }
    
    // ХОРОШО: Ответственности разделены
    class NetworkService { func fetchUser() {} }
    class DatabaseService { func saveUser() {} }
    struct EmailValidator { func validate(_ email: String) -> Bool {} }
    
  • Open/Closed (OCP): Код должен быть открыт для расширения, но закрыт для модификации. Достигается через протоколы и инъекцию зависимостей.
    protocol Logger {
        func log(_ message: String)
    }
    
    class AnalyticsManager {
        private let logger: Logger
        init(logger: Logger) { self.logger = logger } // Зависимость внедрена
        func trackEvent() { logger.log("Event tracked") }
    }
    // Теперь мы можем подставить ConsoleLogger, FileLogger или FirebaseLogger, не меняя AnalyticsManager.
    
  • Dependency Inversion (DIP): Модули верхнего уровня не должны зависеть от модулей нижнего уровня. Оба должны зависеть от абстракций (протоколов). Это краеугольный камень для тестируемости, так как позволяет легко подменять реальные сервисы мок-объектами.

2. Практические паттерны для iOS-разработки

Эти паттерны решают типичные задачи платформы.

  • Использование MVVM (или MVVM-C): Это мой основной выбор для разделения ответственности между слоями. ViewModel преобразует данные Model для отображения во View (ViewController/UIView), содержа только логику представления. Это делает ViewController "тупым" и облегчает тестирование бизнес-логики.
  • Координаторы (Coordinators) / Router-ы: Для управления потоком навигации. Это полностью выносит логику переходов (present, push) из ViewController, делая его переиспользуемым и еще более простым. Координатор знает о зависимостях и может их инжектировать.
  • Реактивное программирование (Combine / RxSwift): Для обработки асинхронных событий (пользовательский ввод, сетевые ответы, таймеры) в декларативном, связанном стиле. Это устраняет "ад колбэков" и создает предсказуемые потоки данных.
    // Пример с Combine: связываем поле ввода и кнопку
    @Published var searchText: String = ""
    @Published var isButtonEnabled: Bool = false
    
    cancellables = $searchText
        .map { !$0.isEmpty }
        .assign(to: \.isButtonEnabled, on: self)
    

3. Принципы написания чистого кода (Clean Code)

Правила "на каждый день" для читаемости.

  • Значимые имена: userProfileViewController вместо upvc, fetchLatestArticles вместо getData.
  • Маленькие функции: Функция должна делать одно действие. Если функция описывается союзом "и" (получает данные и парсит и сохраняет) — ее нужно разбить.
  • Избегание магических чисел и строк: Использую enum или константы.
    // ПЛОХО
    if statusCode == 404 { ... }
    
    // ХОРОШО
    enum HTTPStatusCode {
        static let notFound = 404
    }
    if statusCode == HTTPStatusCode.notFound { ... }
    
  • Принцип наименьшего знания (Закон Деметры): Объект должен иметь как можно меньше знаний о структуре других объектов. Не создаем "цепочки вызовов" вида user.account.lastPayment.amount.

4. Обеспечение качества и безопасности

  • Юнит-тестирование: Обязательно пишу тесты для ViewModel, сервисов, утилит. Стремлюсь к высокому покрытию критической бизнес-логики. Использую моки и стабы благодаря DIP.
  • Обработка ошибок: Никаких try! или force unwrap в продакшн-коде. Использую do-catch, Result или throws, предоставляя пользователю понятные сообщения.
  • Потокобезопасность: Все операции с изменяемым состоянием, доступным из разных потоков, защищаю с помощью DispatchQueue, Actors (в Swift 5.5+) или других механизмов синхронизации.
  • Оптимизация памяти: Внимательно отношусь к циклам сильных ссылок (strong reference cycles) в замыканиях и при использовании делегатов. Применяю [weak self], [unowned self] где это уместно.
  • Локализация и доступность (Accessibility): Заложиваю поддержку с самого начала, используя NSLocalizedString и устанавливая accessibilityIdentifier для UI-элементов.

5. Практики работы в команде

  • Стиль кода (Code Style): Строго следую принятому в команде SwiftLint конфигурации. Единообразие важнее личных предпочтений.
  • Code Review: Подхожу к ревью как к возможности улучшить код и поделиться знаниями. Всегда оставляю конструктивные комментарии, объясняя "почему". И ожидаю того же в ответ.
  • Документация: Пишу документацию для публичного API (публичных методов и свойств) с помощью DocC или обычных комментариев. В сложных алгоритмах оставляю пояснения о намерении, а не о том, что делает каждая строка.

Эти правила — не догма, а инструментарий. Их применение всегда взвешиваю в контексте задачи, сроков и сложности проекта. Однако базовые принципы SOLID, инкапсуляции и тестируемости остаются незыблемыми в любом сценарии, так как они напрямую влияют на долгосрочную жизнеспособность кодовой базы.

Какими правилами руководствуешься при написании кода? | PrepBro