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

На какой стадии было приложение когда ты пришел?

1.0 Junior🔥 121 комментариев
#Soft Skills и карьера

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

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

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

Контекст проекта и моя роль

Когда я присоединился к проекту, приложение находилось на стадии активной разработки MVP (Minimum Viable Product) с уже запущенным первым публичным релизом в App Store. Команда успешно преодолела начальный барьер выхода на рынок, однако продукт столкнулся с типичными для этой фазы проблемами: накопленный технический долг, отсутствие четкой архитектуры, нестабильная производительность и ограниченная масштабируемость кодовой базы.

Ключевые характеристики состояния проекта:

  1. Архитектурный вакуум: Кодовая база представляла собой вариант Massive View Controller с минимальным разделением ответственности. Бизнес-логика, сетевая логика, работа с базой данных и UI-логика были перемешаны внутри UIViewController, что делало код крайне сложным для тестирования и модификации.

    // Типичный пример кода того времени
    class ProductViewController: UIViewController {
        var products: [Product] = []
        var databaseManager = CoreDataManager()
        var apiClient = APIClient()
    
        override func viewDidLoad() {
            super.viewDidLoad()
            loadFromDatabase()
            fetchFromNetwork()
            setupUI() // 200+ строк кода
            setupGestures()
        }
    
        // Смесь сетевых, БД и UI операций в одном методе
        func fetchFromNetwork() {
            apiClient.getProducts { [weak self] result in
                DispatchQueue.main.async {
                    switch result {
                    case .success(let newProducts):
                        self?.products = newProducts
                        self?.databaseManager.save(newProducts)
                        self?.tableView.reloadData()
                        self?.updateBadgeCount()
                    case .failure(let error):
                        self?.showAlert(error: error)
                    }
                }
            }
        }
    }
    
  2. Отсутствие стандартизации: Не было единых подходов к:

    *   **Навигации:** Использовались "синглтоны-менеджеры" и жесткие переходы по `storyboard` ID.
    *   **Сетевому слою:** Разные части приложения использовали разные библиотеки (`URLSession`, `Alamofire`) без общего `NetworkService`.
    *   **Локальному хранению:** `UserDefaults`, `Core Data` и простые файлы использовались бессистемно.
    *   **DI (Dependency Injection):** Зависимости создавались напрямую внутри классов, что исключало возможность юнит-тестирования.

  1. Производительность и стабильность:
    *   **Утечки памяти:** Частые `retain cycle` из-за неправильного использования `[weak self]` в замыканиях.
    *   **Блокирование UI:** Длительные операции (парсинг JSON, сохранение в БД) выполнялись на главном потоке.
    *   **Высокий `FPS drop`:** Сложные анимации и неоптимизированные `UITableView/UICollectionView` с динамической высотой ячеек вызывали заметные подтормаживания.

  1. Процессы разработки:
    *   **Отсутствие CI/CD:** Сборка и архивация для TestFlight выполнялись вручную, что занимало значительное время и было подвержено человеческим ошибкам.
    *   **Минимальное покрытие тестами:** Юнит-тесты практически отсутствовали, что делало рефакторинг рискованным.
    *   **Прямые коммиты в `main`/`master` ветку:** Не было стратегии ветвления (типа Git Flow), что часто ломало сборку.

Мои первоочередные задачи и внедренные улучшения

  1. Внедрение современной архитектуры: Мы начали постепенный рефакторинг в сторону MVVM-C (Model-View-ViewModel-Coordinator) с реактивным связыванием через Combine (или RxSwift, в зависимости от проекта). Это позволило разделить ответственность, сделать код тестируемым и упростить навигацию.

    // Пример рефакторинга под MVVM
    class ProductViewModel {
        @Published var products: [Product] = []
        private let repository: ProductRepositoryProtocol
    
        init(repository: ProductRepositoryProtocol) {
            self.repository = repository
        }
    
        func loadProducts() {
            repository.fetchProducts()
                .receive(on: DispatchQueue.main)
                .assign(to: &$products)
        }
    }
    
  2. Стандартизация и создание модульного слоя:

    *   Разработан универсальный `NetworkService` с использованием `URLSession` и `Codable`.
    *   Создан `DIContainer` для управления зависимостями (используя `Swinject` или собственное решение).
    *   Внедрен `Coordinator` или `Router` для абстрагирования навигации.

  1. Оптимизация производительности:
    *   Проведен аудит и устранены утечки памяти с помощью Instruments.
    *   Введены `OperationQueue` и приоритетные фоновые очереди для тяжелых задач.
    *   Оптимизированы списки через `diffable data source`, кеширование изображений и предрасчет высот.

  1. Налаживание процессов:
    *   Внедрена стратегия ветвления **Git Flow**.
    *   Настроен **CI/CD (GitHub Actions/Bitrise)** для автоматической сборки, прогона тестов и загрузки в TestFlight.
    *   Написан набор критических юнит- и UI-тестов, повысивших уверенность при рефакторинге.

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