Clean Code на Swift: принципы и примеры для iOS/macOS

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Clean Code на Swift: зачем это нужно iOS-разработчику

Каждый разработчик сталкивался с ситуацией, когда старый код через месяц превращается в "спагетти". В мире Swift, где проекты растут быстро, поддержка чистоты кода становится критичной. Clean Code — это не просто эстетика, а инструмент, который экономит часы дебага и упрощает добавление новых фич. В этой статье мы разберем ключевые принципы Clean Code применительно к Swift, с реальными примерами для iOS и macOS.

1. Именование: читаемость прежде всего

Правильное именование — основа чистого кода. В Swift, где API часто самодокументируемы, плохие имена — главный источник путаницы.

Плохой пример:

class DataManager {
    func getData() -> [String: Any] {
        // ...
    }
}

Хороший пример:

class UserProfileFetcher {
    func fetchUserProfile(for userID: String) -> Result<UserProfile, NetworkError> {
        // ...
    }
}
  • Используйте глаголы для методов (fetch, update, delete).
  • Избегайте сокращений — vc, btn, str — это прошлый век.
  • Булевы переменные должны читаться как утверждения: isLoggedIn, hasNetworkConnection.

2. Функции: маленькие и с одной целью

В Swift, где замыкания и функциональное программирование популярны, легко увлечься и написать монолитную функцию. Принцип единой ответственности (Single Responsibility) здесь работает на 100%.

Плохой пример:

func processUserData(user: User) {
    // Валидация
    if user.email.isEmpty { return }
    // Сохранение в CoreData
    CoreDataStack.shared.save(user)
    // Отправка на сервер
    APIClient.shared.send(user)
    // Обновление UI
    DispatchQueue.main.async {
        self.tableView.reloadData()
    }
}

Хороший пример (разделение на маленькие функции):

func processUserData(user: User) {
    guard validateUser(user) else { return }
    saveUserLocally(user)
    sendUserToServer(user)
    updateUI()
}

private func validateUser(_ user: User) -> Bool {
    return !user.email.isEmpty
}

private func saveUserLocally(_ user: User) {
    CoreDataStack.shared.save(user)
}

private func sendUserToServer(_ user: User) {
    APIClient.shared.send(user)
}

private func updateUI() {
    DispatchQueue.main.async {
        self.tableView.reloadData()
    }
}

Правило 20 строк: если функция не помещается на экран — разбивайте. Каждая функция должна делать только одно действие.

3. SOLID в Swift: практические примеры

Принципы SOLID — это не абстракция, а рабочие инструменты. Разберем два ключевых для iOS.

Принцип открытости/закрытости (Open/Closed)

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

protocol PaymentProcessor {
    func process(amount: Double, currency: String) -> Bool
}

class ApplePayProcessor: PaymentProcessor {
    func process(amount: Double, currency: String) -> Bool {
        // Логика Apple Pay
        return true
    }
}

class StripeProcessor: PaymentProcessor {
    func process(amount: Double, currency: String) -> Bool {
        // Логика Stripe
        return true
    }
}

// Теперь добавить новый способ оплаты — просто создать новый класс, не трогая старые.

Принцип подстановки Лисков (Liskov Substitution)

Подклассы не должны ломать логику родителя. Типичная ошибка — переопределение метода с изменением контракта.

class Vehicle {
    func startEngine() {
        print("Engine started")
    }
}

class ElectricCar: Vehicle {
    override func startEngine() {
        // Нарушение: электромобиль не заводит двигатель
        fatalError("No engine to start")
    }
}

// Правильно: использовать протоколы для разных типов
protocol Vehicle {
    func move()
}

struct GasCar: Vehicle {
    func move() {
        startEngine()
        drive()
    }
}

struct ElectricCar: Vehicle {
    func move() {
        activateBattery()
        drive()
    }
}

4. Обработка ошибок и опциональные типы

Swift предлагает мощные инструменты для работы с ошибками. Clean Code требует явной обработки, а не игнорирования.

Плохой пример (force unwrap):

let user = users.first!
let name = user.name!

Хороший пример (guard + Result):

func fetchUser(by id: String) -> Result<User, AppError> {
    guard let user = database.findUser(by: id) else {
        return .failure(.userNotFound)
    }
    return .success(user)
}

// Использование
switch fetchUser(by: "123") {
case .success(let user):
    print("User: \(user.name)")
case .failure(let error):
    print("Error: \(error.localizedDescription)")
}
  • Избегайте force unwrap (!) — используйте guard let или if let.
  • Создавайте кастомные ошибки с enum, наследующим от Error.
  • Не глотайте ошибки в пустом catch — логируйте или пробрасывайте.

5. Комментарии: меньше — лучше

Хороший код сам себя документирует. Комментарии нужны только для объяснения "почему", а не "что".

Избыточный комментарий:

// Увеличиваем счетчик на 1
counter += 1

Полезный комментарий:

// Используем асинхронную очередь, чтобы не блокировать UI
DispatchQueue.global().async {
    performHeavyCalculation()
}

Если вы пишете комментарий к функции — подумайте, не говорит ли имя функции само за себя. func calculateTotalPrice() — комментарий не нужен.

Заключение

Clean Code на Swift — это не магия, а набор дисциплин, которые превращают код в понятный текст. Начните с малого: переименуйте плохие переменные, разбейте большую функцию, добавьте обработку ошибок. Со временем это войдет в привычку, и ваш код станет не только рабочим, но и красивым.

Помните: чистый код пишется для людей, а не для компилятора. Чем проще ваш код читается, тем легче его поддерживать и развивать. А в мире iOS/macOS,

Блоги

Рекомендаций по книгам