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

Расскажи о неудачном опыте

2.2 Middle🔥 161 комментариев
#UIKit и верстка

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

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

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

Об одном неудачном проекте и его уроках

Один из самых ярких неудачных проектов в моей практике связан с разработкой сложного многомодульного финансового приложения в середине 2010-х годов. Задача казалась классической: создать приложение для управления личными финансами с прогнозированием, синхронизацией данных между устройствами и интеграцией с несколькими банковскими API (честно говоря, тогда это было модно и казалось перспективным).

Корень проблем: архитектура и процесс

Основная ошибка была совершена на самом старте проекта — в выборе архитектуры и организации процесса разработки.

  • Чрезмерная сложность архитектуры. Мы решили использовать тогда еще новую и не до конца освоенную парадигму VIPER (View-Interactor-Presenter-Entity-Router), при этом не имея глубокого опыта с ней в команде. Мотивация была «правильной»: разделить ответственность, обеспечить тестируемость. Но на практике это вылилось в:
    // Пример того, как это усложняло даже простые операции
    class BudgetInteractor {
        weak var presenter: BudgetPresenter?
        var entity: BudgetEntity?
        func fetchData() {
            // Запрос к сервису -> преобразование в Entity -> передача Presenter
            // Все это для одной модели
        }
    }
    // Один модуль (скажем, экран бюджета) мог включать 8-10 файлов.
    
    Каждый модуль превращался в лабиринт классов. **Сложность поддержки** росла экспоненциально.

  • Отсутствие единого состояния (State Management). Мы не использовали централизованный подход к управлению состоянием (типа Redux или даже простого собственного Store). Данные «жили» в разных Interactor и Entity, синхронизация между модулями стала адом. Баги, где данные на одном экране не соответствовали данным на другом, были постоянными.

  • Плохая коммуникация и отсутствие прототипа. Дизайнеры и менеджеры продукта работали с нами удаленно. Мы начали писать код без полноценного, отработанного и согласованного UI/UX прототипа. Это привело к постоянным изменениям требований на этапе, когда модули уже были «закодированы» по изначальному ТЗ. Рефакторинг сложной VIPER-архитектуры под новые требования был крайне трудоемким.

Технические последствия

  • Низкая скорость разработки. Добавление новой функциональности занимало недели вместо дней.
  • Проблемы с тестированием. Хотя VIPER задумывался для тестируемости, из-за сильной связности некоторых модулей и сложной сети зависимостей unit-тесты писать было тяжело, а многие стали бесполезными после рефакторинга.
  • Ужасная синхронизация данных. Реализация offline-режима и синхронизации между устройствами (честный CoreData + CloudKit) стала кошмаром из-за разрозненной архитектуры данных.

Критическая точка и решение

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

Решение, которое, хоть и было болезненным, спасило проект:

  1. Полный архитектурный рефакторинг. Мы остановили разработку новых функций на месяц. Провели анализ, выбрали более простую и знакомую команде архитектуру — MVVM с координаторами (Coordinators) для навигации и централизованным State Container (простой собственный класс-хранилище на основе наблюдаемых свойств).

    // Новый подход был значительно чище
    class BudgetViewModel {
        var budget: Observable<Budget>
        func updateBudget() {
            // Прямое обращение к сервису и обновление центрального State Container
            appState.budget = newBudget
        }
    }
    
  2. Строгий процесс и прототип. Мы установили правило: никакой серьезной разработки без утвержденного и статического прототипа в Figma (тогда использовали Sketch). Все изменения требований проходили через этап обновления прототипа перед любыми изменениями в коде.

  3. Приоритет на данные. Первым делом после рефакторинга мы построили надежный, единый Data Layer с четким Repository pattern и Unified Model, который использовался всем приложением.

Выученные уроки

  • Архитектура должна служить команде, а не принципам. Не выбирайте сложную архитектуру ради ее «красоты» или моды, если она не соответствует опыту команды и реальным требованиям проекта. MVVM, MVC или даже хорошо структурированный UIKit могут быть лучше чрезмерно декомпозированного VIPER для многих проектов.
  • Единое состояние — основа сложных приложений. Для приложений с множеством данных и экранов централизованное управление состоянием (будь то Redux, SwiftUI’s State, или собственный Store) — это не опция, это необходимость.
  • Прототип — это часть технической спецификации. Без финализированного дизайна и UX нельзя начинать писать сложную логику. Это гарантия бесконечных изменений и рефакторингов.
  • Рефакторинг — это инструмент, а не признак неудачи. Иногда нужно остановиться, признать, что текущий путь ведет в тупик, и провести коренной рефакторинг. Это дорого в краткосроке, но спасает проект в долгосроке.

Этот опыт, хотя и был тяжелым, стал одним из самых ценных в моей карьере. Он научил меня оценивать не только «как сделать», но и «стоит ли делать именно так», учитывая человеческие и процессные факторы, а не только чисто технические.