Разработка
Ошибка на 12 миллиардов долларов: почему Apple отказалась от сторибордов (и почему большинство команд до сих пор их используют)
Следуя этим шагам, команды iOS-разработчиков смогут методично отказаться от сторибордов, минимизируя сбои и обеспечивая максимальную поддержку. Результатом станет не просто удаление XML-файла — это фундаментальный сдвиг в сторону более гибкой, ориентированной на код инженерной культуры.
Сториборды (Storyboards) были неудачным экспериментом Apple, обошедшимся в миллиарды долларов времени разработчикам, но Apple никогда этого не признавала. После десяти лет работы с командами iOS-разработки я скажу прямо: сториборды в Xcode — это худший источник проблем. В одном запоминающемся случае конфликт слияния в нашем файле Main.storyboard проскользнул незамеченным и сломал навигацию приложения в продакшене. Наш конвейер CI остановился, потому что Xcode отказался компилировать поврежденный файл. Новые сотрудники смотрели на огромный холст запутанных контроллеров представлений, не зная, с чего начать. Мы потеряли целый рабочий день, распутывая неудачное слияние — время, которое можно было бы потратить на разработку новых функций.
Если вам это знакомо — ночные конфликты слияния, загадочные сбои Interface Builder, кошмары в онбординге — вы не одиноки. Apple тихо признала эти проблемы и уже много лет отговаривает разработчиков от использования сторибордов (Вы когда-нибудь замечали, как в недавних примерах кода WWDC используется SwiftUI или программный пользовательский интерфейс, без файла .storyboard? В стандартном шаблоне приложения SwiftUI даже нет файла сториборда). В этом подробном обзоре мы рассмотрим реальные затраты на использование сторибордов с помощью реальных цифр, сравним код до и после и изучим современные альтернативы, такие как SwiftUI, которые спасают команды от проблем с конфликтами слияния в Xcode. В конце вы получите конкретные шаги по модернизации вашей iOS-архитектуры — и, возможно, пару историй из практики, которыми сможете поделиться.
Реальная стоимость сторибордов
Сколько времени разработчиков теряется из-за борьбы со сторибордами? Давайте посмотрим на это в перспективе. Сториборды печально известны тем, что вызывают конфликты слияния — эти непрозрачные XML-войны, когда два разработчика изменяют один и тот же файл. В команде из нескольких разработчиков это не редкое неудобство — это постоянная нагрузка. В одном из опросов разработчиков 2019 года «конфликты слияния с Git» были названы главным недостатком сторибордов. Каждый конфликт может легко отнять 1–2 часа времени Senior-разработчиков (сравнение XML, ручное редактирование, надежда, что Xcode откроет файл). В команде из 10 человек даже один конфликт в неделю означает потерю примерно 10 часов. Умножьте это на среднюю полную ставку разработчика (~100 долларов в час), и вы потратите 1000 долларов в неделю на проблемы со слиянием. Это примерно 50,000 долларов в год для команды среднего размера — только на разрешение конфликтов со сторибордами! Теперь представьте, что у Apple 34 миллиона зарегистрированных разработчиков. Даже если лишь небольшая часть из них использует сториборды ежедневно, совокупные затраты легко могут исчисляться миллиардами долларов за десятилетие. Без шуток — это та самая «ошибка на 12 миллиардов долларов», в которой мы все живем.
И конфликты слияния — это лишь часть этих затрат. Большие сториборды также негативно влияют на конвейеры CI и стабильность приложения. Неправильно смердженый сториборд — это не просто головная боль для человека; он ломает сборку. Xcode наотрез откажется компилировать некорректный XML-файл, вызывая срабатывание тревожных сигналов в CI, пока кто-нибудь не исправит это вручную. Я видел, как ночные сборки завершались с ошибкой, потому что Interface Builder автоматически обновлял некоторые ограничения представления на другой машине, что приводило к ошибке «Внутреннее несоответствие», которая останавливала тестирование. Сториборды могут даже вызывать сбои во время выполнения, если аутлеты или переходы неправильно подключаются во время разрешения конфликтов — представьте себе сбой при запуске из-за того, что элемент пользовательского интерфейса не был найден из-за неудачного мерджа.
Затраты на онбординг и обучение — ещё один скрытый убийца. Вручить новому члену команды огромный сториборд — всё равно что бросить его в лабиринт. Он тратит дни, просматривая переходы между приложениями, пытаясь составить схему работы. Один разработчик рассказал, что по мере роста его приложения сториборд «стал головной болью… прокрутка огромного экрана для исправления мелочи стала настоящей проблемой». В отличие от этого, навигация по коду (с помощью поиска, ссылок и точек останова) для большинства разработчиков происходит быстрее. Эти дополнительные дни или недели задержки онбординга имеют реальные финансовые последствия — замедление разработки фич и разочарование нового сотрудника.
Наконец, следует учитывать упущенные возможности и технический долг. Каждый час, потраченный на отладку того, почему Interface Builder ведёт себя странно, — это час, не потраченный на совершенствование архитектуры или написание модульных тестов. Сториборды поощряют мышление в стиле «магия Interface Builder», которая может скрывать сложность до тех пор, пока она не проявится позже. Команды, использующие сториборды, часто откладывают рефакторинг, потому что «сейчас слишком рискованно трогать сториборд» — что приводит к накоплению проектного долга, исправление которого в будущем обходится дорого.
В итоге: сториборды несут в себе скрытые издержки, связанные с разрешением конфликтов слияния, сбоями в работе инструментов и снижением производительности команды. Средние и крупные команды платят за это в виде задержек релизов, выгорания разработчиков и, да, реальных денег. Это налог на каждый коммит и каждое обновление, что в сумме составляет колоссальные потери в масштабах всей отрасли. Неудивительно, что многие опытные разработчики теперь считают сториборды скорее обузой, чем удобством.
Почему это произошло?
Если сториборды настолько неудобны, зачем Apple вообще их ввела? Чтобы понять это, нужно вспомнить первоначальную цель Apple. Еще в 2011 году (во времена iOS 5) сториборды позиционировались как способ демократизации создания пользовательских интерфейсов. Apple хотела позволить разработчикам (и дизайнерам) визуально размещать экраны и потоки без написания кода. «Создавайте полноценный пользовательский интерфейс, не написав ни строчки кода. Перетаскивайте и создавайте работающий интерфейс», — хвастались ранние документы. Сториборды обещали ускорить прототипирование и помочь разработчикам «визуализировать весь поток приложения» с первого взгляда. В теории это должно было сэкономить время и уменьшить количество шаблонного кода для пользовательского интерфейса и навигации.
Какое-то время это работало — особенно для разработчиков-одиночек или небольших приложений. На раннем этапе многие из нас «надеялись, что создание пользовательского интерфейса станет более приятным и менее трудоемким». Признаюсь, мое первое знакомство со сторибордами было похоже на волшебство: я мог видеть все свои экраны в одном месте, нажать кнопку для создания перехода, и вуаля — мгновенный поток приложения. Apple удалось снизить порог входа для новичков и сделать разработку простых приложений быстрой. Так что же пошло не так?
Появился Git. Видение Apple не в полной мере учитывало реалии системы контроля версий и командной работы. Сториборды — это, по сути, большие XML-файлы. Когда один человек редактирует сториборд, Xcode генерирует машинный XML-код. Когда его редактируют два человека… все рушится. XML недружелюбен к Git: построчная система контроля версий не может интеллектуально объединить два изменения в элементе. Результатом являются печально известные конфликты слияния, о которых мы говорили — «сториборды — это машинный XML, конфликты трудно диагностировать и разрешать». В отличие от кода, где конфликты слияния часто невелики и понятны человеку, конфликт в сториборде может охватывать 500 строк непонятного XML. Как отметил разработчик Эндрю Раух, даже «незначительный конфликт слияния в огромном файле … может привести к потере или повреждению огромного объема работы». Именно то, что делало сториборды привлекательными (абстрагирование пользовательского интерфейса в файл визуального дизайна), превращает их в кошмар для распределенной разработки.
Монолитный дизайн — еще одна проблема. Сториборды поощряли размещение множества экранов в одном файле (например, Main.storyboardс десятками сцен). Такой централизованный подход становится единой точкой отказа. Один большой сториборд означает один файл, к которому в конечном итоге прикасаются все. Это как иметь гигантскую глобальную переменную для вашего пользовательского интерфейса — конечно, будут возникать конфликты. Некоторые команды пытались смягчить это, разбив сториборды на несколько отдельных файлов (по одному на модуль или функцию). Это немного помогает, но вы все равно сталкиваетесь со слиянием XML-файлов в каждом отдельном случае и должны вручную управлять навигацией между сторибордами. А если каждый сториборд по-прежнему редактируется 2–3 людьми, конфликты только множатся.
Негибкие зависимости еще больше усугубили ситуацию. Сториборды и Interface Builder привязывают вас к работе в «стиле Xcode». Нужна пользовательская инициализация для контроллера представления? Вы используете аннотацию prepareForSegue или @IBOutlets и надеетесь, что они будут связаны. Хотите повторно использовать макет представления в двух местах? Вам придётся дублировать его или возиться со ссылками на сториборды. Со временем в больших проектах накапливается много «магии Interface Builder» — скрытые переходы, неопределённые атрибуты рантайма, условный пользовательский интерфейс, который не очевиден в коде. Это становится хрупким. Инженеры часто обнаруживают, что для реализации сложной функции (например, многошаговой динамической формы или настраиваемого во время выполнения пользовательского интерфейса) бороться со сторибордом сложнее, чем просто писать код. Как было сказано в одном блоге: «со сторибордами, чтобы получить ссылку на один контроллер представления, вы в итоге пишете неоправданно длинный код». Сториборды абстрагировали простые аспекты пользовательского интерфейса, но сделали сложные сценарии более запутанными.
Тем временем Apple развивала свои фреймворки. Auto Layout стал более удобным для работы с кодом благодаря привязкам, а SwiftUI предложил полностью декларативный подход, основанный на коде. Первоначальные преимущества сторибордов — быстрая компоновка и WYSIWYG-дизайн — начали угасать по мере того, как Xcode получил улучшенный предварительный просмотр кода пользовательского интерфейса, а команды стали уделять приоритетное внимание удобству сопровождения. Apple никогда не заявляла прямо, что «сториборды устарели», но их действия говорят сами за себя. Рассмотрим примеры и шаблоны WWDC последних лет: Apple «определенно направляет вас» к SwiftUI — Xcode буквально просит вас выбрать SwiftUI или Storyboard при создании нового проекта, и выбор SwiftUI вообще не создает сториборд. Многие демонстрационные проекты WWDC за последние несколько лет незаметно перешли на SwiftUI для демонстрации пользовательского интерфейса или программный UIKit, полностью избегая сторибордов. Даже Launch Screen Storyboard (когда-то обязательный) теперь может быть заменен простыми графическими ресурсами, начиная с iOS 14 — небольшой намек на то, что сториборды больше не являются предпочтительным вариантом.
Если коротко, storyboard’ы появились с благими намерениями, но реальность (контроль версий, большие приложения, сложные UI-сценарии) внесла свои коррективы. Фреймворки Apple переросли парадигму сторибордов, а сообщество столкнулось с слишком большим количеством боли при их использовании. В итоге Apple «мягко убила» сториборды — не удалив их напрямую, а предложив более удобные и гибкие альтернативы, из-за чего они стали восприниматься как устаревший подход. Проблема в том, что многие команды до сих пор продолжают использовать их по инерции или из привычки, зачастую даже не осознавая, что технологическая почва под ними уже изменилась.
Улучшенная архитектура
Итак, если не сториборды, то каков путь? Хорошая новость в том, что у нас есть два современных подхода, которые могут освободить вашу команду: программный пользовательский интерфейс (UIKit в коде) и SwiftUI. Оба позволяют избежать проблем с XML-слияниями и возвращают вам контроль над версиями. Давайте шаг за шагом рассмотрим, как перейти от проекта, основанного на сторибордах, к более поддерживаемой архитектуре.
Шаг 1: Начните с малого — по одному представлению за раз. Вам не нужно удалять все сториборды за одну ночь. Определите проблемный пользовательский интерфейс (возможно, экран настроек, который постоянно вызывает конфликты слияния, или новая функция, которая еще не реализована). Используйте это в качестве пилотного проекта. Для существующего экрана вы можете удалить его из сториборда и перестроить его в коде или SwiftUI. Для нового экрана просто не добавляйте его в сториборд. Этот поэтапный подход сопряжен с риском — ваше приложение может постепенно перейти на новый уровень без огромного запроса на слияние типа «удаление сториборда на 5000 строк», который напугает вашего технического директора.
Шаг 2: Выберите свой вариант — код UIKit или SwiftUI. Если ваша целевая платформа развертывания — iOS 13+, и ваша команда готова изучать SwiftUI, то этот фреймворк — перспективный выбор. Преимущества SwiftUI для команд включают декларативный синтаксис, предварительный просмотр в реальном времени и более простое повторное использование компонентов. Если SwiftUI не является подходящим вариантом в данный момент (возможно, вы все еще поддерживаете iOS 12, или команде нужно время, чтобы освоиться), вы можете использовать программный UIKit. Это означает разработку интерфейсов в коде Swift с использованием UIView и Auto Layout (якорей или фреймворков, таких как SnapKit). Это может показаться утомительным, но многие команды сообщают, что пользовательский интерфейс на основе кода, хотя и многословен, гораздо более предсказуем и удобен для слияния, чем Interface Builder. В любом случае, вы будете хранить пользовательский интерфейс в текстовых файлах (код Swift), которые можно проверять, сравнивать и объединять без проблем.
Шаг 3: Организуйте свой проект для модульного пользовательского интерфейса. В сторибордах один файл часто содержал множество экранов. В коде же следует разделять файлы по функциям. Распространенная структура — это создание отдельной папки для каждого значимого потока пользовательского интерфейса или модуля. Например:
MyApp/ ├─ Scenes/ │ ├─ Login/ │ │ ├─ LoginViewController.swift // if using UIKit │ │ └─ LoginView.swift // if using SwiftUI (maybe alongside a UIViewController wrapper for navigation) │ ├─ Dashboard/ │ │ ├─ DashboardViewController.swift │ │ └─ DashboardView.swift │ └─ Settings/ │ ├─ SettingsViewController.swift │ └─ SettingsView.swift ├─ AppDelegate.swift └─ SceneDelegate.swift (or SwiftUI App struct)
Для каждого экрана или компонента создается свой собственный Swift-файл (или пара файлов для представления и ViewModel и т.д., в зависимости от необходимости). Это означает, что два разработчика могут работать над разными экранами, не затрагивая один и тот же файл, что исключает конфликты. Это противоположность монолитному сториборду. Кроме того, код поощряет создание небольших, сфокусированных классов и структур — вместо одного огромного графа у вас будет множество небольших модулей.
Шаг 4: Воссоздайте пользовательский интерфейс в коде. Давайте проиллюстрируем простой пример. Предположим, у нас есть сцена сториборда для формы входа с двумя текстовыми полями и кнопкой. В контроллере на основе сториборда код может выглядеть так:
// Before: Storyboard-based ViewController
class LoginViewController: UIViewController {
@IBOutlet weak var usernameField: UITextField! // hooked up in Interface Builder
@IBOutlet weak var passwordField: UITextField!
@IBOutlet weak var loginButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Additional setup if any
loginButton.addTarget(self, action: #selector(onLoginTapped), for: .touchUpInside)
}
@objc func onLoginTapped() {
// handle login action
authenticate(usernameField.text, passwordField.text)
}
}
Здесь все элементы пользовательского интерфейса (usernameField, passwordField и т.д.) были созданы в сториборде и связаны через аутлеты. Макет определяется в XML-файле, и там же задаются любые атрибуты текста или цвета. Теперь, после перехода на SwiftUI, эквивалентный пользовательский интерфейс можно создать в одной структуре:
// After: SwiftUI View (Composable UI)
import SwiftUI
struct LoginView: View {
@State private var username = ""
@State private var password = ""
var onLogin: (String, String) -> Void // callback to handle login
var body: some View {
VStack(spacing: 16) {
Text("Welcome Back").font(.headline)
TextField("Username", text: $username)
.textFieldStyle(.roundedBorder)
SecureField("Password", text: $password)
.textFieldStyle(.roundedBorder)
Button("Log In") {
onLogin(username, password)
}
.buttonStyle(.borderedProminent)
}
.padding()
}
}
Обратите внимание, как в SwiftUI вся иерархия и поведение пользовательского интерфейса видны в одном месте (и это всего лишь код). Если двум разработчикам нужно изменить пользовательский интерфейс, Git объединит их текстовые изменения, как и любой другой код Swift (без странных конфликтов XML). SwiftUI также предоставляет холст предварительного просмотра в реальном времени, поэтому вы по-прежнему получаете визуальную справку, но она генерируется из кода. Для команд одним из недооцененных преимуществ является возможность проверки кода — гораздо проще проверить запрос на слияние с изменениями в LoginView.swift (вы можете запустить его и увидеть разницу), чем проверить изменения в файле .storyboard (которые практически невозможно интерпретировать визуально).
Даже если вы останетесь с UIKit, вы можете добиться аналогичной ясности. Вы можете написать:
// After: Programmatic UIKit ViewController
class LoginViewController: UIViewController {
private let usernameField = UITextField()
private let passwordField = UITextField()
private let loginButton = UIButton(type: .system)
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
// Configure subviews
usernameField.placeholder = "Username"
passwordField.placeholder = "Password"
passwordField.isSecureTextEntry = true
loginButton.setTitle("Log In", for: .normal)
// Layout using Auto Layout
[usernameField, passwordField, loginButton].forEach { subview in
subview.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(subview)
}
NSLayoutConstraint.activate([
usernameField.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 100),
usernameField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
usernameField.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.8),
passwordField.topAnchor.constraint(equalTo: usernameField.bottomAnchor, constant: 16),
passwordField.centerXAnchor.constraint(equalTo: view.centerXAnchor),
passwordField.widthAnchor.constraint(equalTo: usernameField.widthAnchor),
loginButton.topAnchor.constraint(equalTo: passwordField.bottomAnchor, constant: 24),
loginButton.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])
// Hook up button action
loginButton.addTarget(self, action: #selector(onLoginTapped), for: .touchUpInside)
}
@objc private func onLoginTapped() {
authenticate(usernameField.text, passwordField.text)
}
}
Да, здесь больше строк кода, чем в примере со SwiftUI — UIKit многословен — но каждая строка понятна. Мы выделяем представления, устанавливаем свойства, добавляем дочерние представления, устанавливаем констраинты. Никакой скрытой магии. И что особенно важно, этот файл может редактироваться несколькими разработчиками без сбоев в Xcode. Если два разработчика добавят ограничение в одну и ту же функцию, Git покажет простой конфликт, который они смогут разрешить в коде. Сравните это с двумя разработчиками, добавляющими представления в сториборд: Xcode смешает их изменения в XML и, скорее всего, создаст поврежденный файл, который ни один из них не сможет расшифровать.
Шаг 5: Сравните результаты — разница колоссальная. Давайте подведем итоги сравнения Storyboard и Code/SwiftUI по ключевым аспектам командной разработки:
| Критерий | Storyboard | UI в коде (UIKit/SwiftUI) |
|---|---|---|
| Conflicts | Частые и сложные для разрешения (merge «бинарного» XML). | Редкие и понятные (обычные текстовые merge-конфликты в коде). |
| Team Collaboration | Один большой файл → частые коллизии; сложно работать параллельно нескольким разработчикам. | Каждый экран изолирован в коде; несколько разработчиков могут комфортно работать одновременно. |
| Code Reviews & Blame | Почти невозможно нормально ревьюить XML-диффы или понять, кто что изменил. | Полная прозрачность — изменения в коде, можно ревьюить построчно. |
| Maintenance & Refactoring | Рискованно — даже небольшие изменения в IB могут вызвать побочные эффекты; сложно делать find & replace. | Безопасно — работают стандартные инструменты рефакторинга (rename class и т.д.). |
| Performance (Dev UX) | Xcode тормозит с большими storyboard’ами, долго открывает и рендерит. | Код компилируется как обычно; превью SwiftUI — опциональны. |
| Reusability & Modularity | Слабая — сложно переиспользовать UI-компоненты между storyboard’ами (часто возникает дублирование). | Отличная — легко выносить переиспользуемые view или кастомные UI-классы. |
| Onboarding Clarity | Высокий порог входа: нужно ментально разбирать большой граф с неявной логикой. | Новый разработчик читает логичный код, может искать использования и ставить breakpoints. |
| Advanced UI Customization | Ограничено возможностями Interface Builder; сложные сценарии всё равно требуют кода-обходов. | Без ограничений — любую UI-логику можно реализовать в коде; SwiftUI даёт высокую гибкость. |
Очевидно, что для всего, что выходит за рамки крошечного приложения, основанные на коде пользовательские интерфейсы предлагают огромное преимущество в плане удобства сопровождения и скорости работы команды. Как прямо выразился один разработчик: большие сториборды становятся «хаотичными» и «похожими на веб-сайты», в то время как код остается организованным. Представьте себе SwiftUI или программный UIKit как альтернативу Storyboard, которая действительно масштабируется: никаких загадочных различий «внутренней автоматической компоновки», никаких кошмаров конфликтов слияния в Xcode и структура, которая лучше поддерживает современные архитектуры приложений (MVC, MVVM, Redux и т.д. — все это проще реализовать в коде).
Распространенные ошибки при миграции
Переход от сторибордов — это не так просто, как кажется, и есть подводные камни, которых следует избегать. Помогая мигрировать несколько приложений, я могу рассказать о распространенных ошибках и способах их избежать:
- Запрос на слияние на 5000 строк кода: заманчиво преобразовать все сразу — не делайте этого. Массивные запросы на слияние, в которых вы удаляете все сториборды (буквально тысячи строк XML исчезают) и добавляете сотни строк нового кода, будут пугать ваших рецензентов и повышать риск появления новых ошибок. Вместо этого разбейте процесс на более мелкие запросы на слияние по функциям или экранам. Например, мигрируйте по одной вкладке приложения за раз. Таким образом, если что-то пойдет не так, вы будете точно знать, где искать проблему. Это также делает проверку кода более реалистичной — ваши коллеги смогут запустить ветку и проверить функциональность по одной части за раз.
- Оверинжиниринг на замену: некоторые команды впадают в противоположную крайность — вводят ненужные абстракции во имя «чистого кода», когда отказываются от сторибордов. Остерегайтесь паралича анализа: для простого приложения вам может не понадобиться полноценный паттерн VIPER или Coordinator. Переход к программному пользовательскому интерфейсу — это уже большое изменение; добавление совершенно новой архитектуры одновременно может перегрузить команду. Мой совет: начните с простого. Если вы используете UIKit, распространенный паттерн — создание легковесных классов
ViewBuilderилиViewCreator(как это сделала KISS Digital) для инкапсуляции кода компоновки. Или просто оставьте код пользовательского интерфейса в контроллере представления, но убедитесь, что он не слишком большой, вынеся вспомогательные методы. Если вы используете SwiftUI, у вас может возникнуть соблазн чрезмерно использовать обобщения или сложные методы управления состоянием — сопротивляйтесь этому на раннем этапе. Сначала сделайте так, чтобы это работало понятно и просто. Вы можете переработать код в сложные паттерны, когда базовая структура будет прочной. - Не обновляйте базу знаний команды: сториборды могли быть частью культуры вашей команды в течение многих лет. Возможно, в вашем README написано «откройте
Main.storyboard, чтобы увидеть поток приложения», или в документации по онбордингу новых разработчиков объясняется, как добавлять новый пользовательский интерфейс в Interface Builder. При миграции обновите документацию и правила работы. Убедитесь, что все знают новые соглашения: например, «Новые экраны следует создавать в Scenes/как SwiftUI View и, при необходимости, как хостирующийUIViewController». Проведите внутренний семинар, чтобы показать команде, как выполнять распространенные задачи новым способом (например, навигация без переходов, использованиеUIHostingControllerдля интеграции SwiftUI и т. д.). Также подумайте о ваших дизайнерах или специалистах по продукту — если они привыкли быстро просматривать раскадровки для оценки пользовательского интерфейса, предоставьте им альтернативные артефакты (например, дизайны Figma или работающий прототип), чтобы они не чувствовали себя в неведении. - Недоработанные гибриды: во время миграции вы можете находиться в гибридном состоянии (часть пользовательского интерфейса в сториборде, часть в SwiftUI/коде). Это нормально — просто имейте план интеграции. Одна из распространенных ошибок — нечеткое разграничение подходов к новой работе. Если один разработчик тихо добавляет новые экраны в сториборд, в то время как другие разрабатывают на SwiftUI, в итоге получится непоследовательный проект-франкенштейн. Избегайте этого, установив границу: например, «После версии 5.0 новые контроллеры представлений в
Main.storyboardне допускаются. Все новые пользовательские интерфейсы создаются на SwiftUI». При необходимости подкрепите это проверками CI или ответственными за код. Последовательность убережет вас от путаницы в будущем. - Игнорирование тестирования во время миграции: при переписывании кода пользовательского интерфейса убедитесь, что вы запускаете свои UI-тесты (если они у вас есть) или проводите тщательное ручное тестирование затронутых экранов. Миграция из сторибордов в код может привести к незначительным различиям (макет может быть не совсем идентичен на пиксель, или может потребоваться перенастройка меток доступности). Легко сосредоточиться на коде и забыть о контроле качества. Используйте снепшот-тесты или просто попросите вашу команду контроля качества сравнить старые и новые экраны. Такая дополнительная осмотрительность предотвратит ситуацию, когда вы радуетесь удалению сторибордов, а затем обнаруживаете, что в процессе сломали множество элементов пользовательского интерфейса.
Короче говоря, осуществляйте миграцию обдуманно и обучайте свою команду. Отказ от сторибордов окупается, но только если все согласны, и вы не заменяете старые проблемы новыми, созданными вами самими.
Когда НЕ следует отказываться от сторибордов
Стоит ли вообще использовать сториборды? Да — в определенных случаях. Хотя в этой статье убедительно доказывалось нецелесообразность использования сторибордов в командных проектах, требующих постоянной поддержки, существуют сценарии, когда их сохранение имеет смысл:
- Разработчик-одиночка или небольшая команда, быстро создающая MVP: если вы работаете в одиночку или пара начинающих разработчиков, создающих прототип или MVP, сториборды действительно могут ускорить разработку. Недостаток, связанный с сотрудничеством, не имеет значения, если файл обрабатывает только один человек. Вы можете перетаскивать элементы пользовательского интерфейса быстрее, чем кодировать все, и получаете быстрый визуальный результат. Для одноразового приложения или прототипа затраты на создание всей программной архитектуры пользовательского интерфейса могут быть неоправданными.
- Очень недолговечное или простое приложение: как советовал Набиль Кази, учитывайте срок службы и размер приложения. Если это небольшая утилита или внутренний инструмент, который, как ожидается, будет иметь одну версию или минимальное количество обновлений, то долгосрочные проблемы с поддержкой, связанные с сторибордами, уменьшаются. Вполне возможно, что для приложения с тремя экранами, которое поддерживает один разработчик, вполне достаточно сториборда. Сложность приложения, вероятно, никогда не достигнет критической точки, когда он начнет мешать.(хотя даже в этом случае небольшие приложения можно хорошо реализовать на SwiftUI с минимальными усилиями — но скорость может оказаться важнее всего, если вы уже хорошо знакомы со сторибордами).
- Команды с недостаточным опытом кодирования пользовательского интерфейса: некоторые команды (особенно старые или кросс-функциональные, где не все являются экспертами по Swift) на данный момент могут просто быть более продуктивными, используя Interface Builder. Если дизайнеры или менее опытные разработчики напрямую вносят свой вклад в пользовательский интерфейс, сториборды становятся более доступными. Существует кривая обучения автоматической компоновке в коде или подходу SwiftUI. В таких случаях может быть разумно постепенно обучать команду, а не вырывать сториборды за одну ночь. Вы же не хотите резко снизить скорость работы из-за того, что половина команды пытается понять, почему их представление SwiftUI не отображается. Временно использование нескольких небольших сторибордов (по одной на каждую функцию) может облегчить некоторые проблемы, сохраняя при этом привычный рабочий процесс.
- Причины, связанные с устаревшим кодом, и зависимости от Interface Builder: иногда у вас может быть устаревший код, который зависит от функций, специфичных для сторибордов (например, устаревшие компоненты UIKit, которыми проще управлять в IB), или сториборды для таких вещей, как лаунч-скрины и т.д. Пока они не будут отрефакторены, вы можете сохранить сториборд.
Подумайте об этом так: сториборды — это инструмент. Если ваш проект достаточно прост или ситуация в вашей команде такова, что преимущества перевешивают недостатки, используйте их. Ключевое значение имеет честная оценка компромиссов. Если вы работаете в одиночку, проблема конфликтов слияния исчезает (конфликтовать не с кем!). Если вам нужны быстрые итерации пользовательского интерфейса для демонстрации завтра, создайте сториборд и работайте над ним — вы всегда можете удалить его позже, если это потребуется. Используйте сториборды, когда они действительно экономят время, и будьте готовы отказаться от них, когда дело доходит до масштабирования и сотрудничества. Как было отмечено в одной статье: используйте сториборды для краткосрочных проектов с небольшим количеством разработчиков; в противном случае помните, что они «несовместимы с Git» для больших команд.
Следующие шаги для команд iOS-разработчиков
Убеждены, что сториборды могут тормозить развитие вашей команды? Вот прагматичный план действий для дальнейшего продвижения:
1. Проведите аудит использования сторибордов в вашем проекте. Проведите инвентаризацию: сколько сторибордов в вашем приложении? Каков их размер (откройте XML-файл и посмотрите количество строк)? Есть ли «основной сториборд», к которому приходится прикасаться большинству членов команды? Также посмотрите историю изменений в Git — были ли файлы сторибордов частыми источниками конфликтов слияния или загадочных ошибок? Количественная оценка этого поможет обосновать заинтересованным сторонам необходимость изменений. Если вы обнаружите, что файл Main.storyboard изменяется в 70% веток разработки и часто вызывает проблемы со слиянием, это явный признак необходимости действовать.
2. Выявите наиболее проблемные файлы. Не все сториборды одинаковы. Возможно, ваш файл Settings.storyboard небольшой и редко используется — его можно оставить как есть на данный момент. Сосредоточьтесь на тех частях пользовательского интерфейса, которые доставляют больше всего проблем: процесс онбординга? Интерфейс главной вкладки? Возможно, сториборд с основными экранами вашего интернет-магазина? Это отличные кандидаты. Вам нужно выбрать сценарий, в котором преимущества миграции (меньше конфликтов, проще вносить улучшения) команда почувствует немедленно.
3. Поэкспериментируйте с небольшой миграцией. Выберите небольшую функцию или экран и перепишите его на SwiftUI (или UIKit). Например, начните с экрана «О нас» или простого экрана переключения настроек — что-нибудь с низким риском. Это ваш пилотный проект, чтобы выявить и устранить недостатки. Как вы будете интегрировать его с остальной частью приложения? (Вероятно, через UIHostingController для SwiftUI или просто заменив старый ViewController новым.) Используйте это как возможность установить шаблоны для более масштабной миграции: структура проекта, соглашения об именовании, подход к навигации. После этого проведите ретроспективу: посчитала ли команда новый подход улучшением? Как прошли проверка кода и тестирование? Устраните любые проблемы в небольших масштабах.
4. Получите поддержку команды и начните работу. Представьте результаты пилотного проекта всей команде. Подчеркните различия: например, «Обратите внимание, что новый экран SwiftUI был создан вдвое быстрее, и у нас не было конфликтов слияния в этой ветке». Разработчикам часто нужно увидеть улучшенный DX (опыт разработчика), чтобы поверить в это. Предоставьте обучающие ресурсы: если SwiftUI — это правильный путь, возможно, стоит объединить менее опытных людей с теми, кто участвовал в пилотном проекте, или поделиться учебными пособиями Apple. Поощряйте вопросы и делитесь историями успеха (возможно, кто-то обнаружил, что добавление новой кнопки в SwiftUI намного быстрее, чем работа в Interface Builder — отметьте это!).
5. Постепенно перерабатывайте ценные процессы. Уверенность, полученная в ходе пилотного проекта, и согласованность действий команды, начинают постепенно перерабатывать сложные сториборды, выявленные на шаге 2. Возможно, в каждом спринте вы будете переписывать один экран или один процесс. Всегда обеспечивайте паритет — новый пользовательский интерфейс должен идеально воспроизводить старую функциональность (если только вы не воспользуетесь возможностью улучшить его). Удаляйте сцены из сторибордов по мере работы (чтобы избежать путаницы). Каждый раз зависимость проекта от сторибордов уменьшается, и преимущества накапливаются: меньше конфликтов, проще слияние кода, быстрее сборки (сториборды могут немного замедлить время сборки, особенно обработка раскадровок запуска).
6. Установите сроки отказа от устаревших функций. Полезно иметь цель, например: «К 4 кварталу наша цель — полностью удалить Main.storyboard» или «К версии 2.0 — ни одного сториборда, кроме LaunchScreen». Это создает срочность и общее видение. Отслеживайте прогресс на командных встречах. Отмечайте этапы удаления (может быть странно приятно удалить файл сториборда и увидеть свое имя под огромным diff-файлом!).
7. Отслеживайте и корректируйте. Следите за такими показателями, как стабильность сборки и удовлетворенность команды. Если что-то не работает — например, команда испытывает трудности с ошибками SwiftUI — устраните это (возможно, нужна последняя версия Xcode от Apple или дополнительное обучение). Цель — постоянное повышение производительности разработчиков. По мере погашения технического долга вы заметите ускорение слияний и упрощение разработки новых функций.
Следуя этим шагам, команды iOS-разработчиков смогут методично отказаться от сторибордов, минимизируя сбои и обеспечивая максимальную поддержку. Результатом станет не просто удаление XML-файла — это фундаментальный сдвиг в сторону более гибкой, ориентированной на код инженерной культуры. Ваша команда будет вам благодарна, и вы удивитесь, как вы вообще могли так долго терпеть эти споры о сторибордах.
Заключение
После многих лет борьбы с визуальным дизайнером Xcode стали очевидны три горькие истины:
- Сториборды не масштабируются. То, что работает для прототипа или небольшого приложения, становится недостатком для приложений с десятками экранов и разработчиками. Конфликты слияния, неработающие сборки и проблемы с поддержкой — это реальные проблемы, которые можно измерить потерянным временем и деньгами.
- Apple перешла на новые технологии (и нам тоже следует это сделать). Хотя Apple никогда не выпускала пресс-релиз, в котором говорилось бы: «Чториборды мертвы», их акцент на SwiftUI и программных примерах — это явный признак перемен. Индустрия переходит к пользовательским интерфейсам, управляемым кодом, которые проще тестировать и поддерживать. Придерживаться сторибордов — это как цепляться за сборщик мусора Objective-C — вы можете это делать, но вы плывете против течения.
- Перемены даются тяжело, но стагнация еще тяжелее. Многие команды сопротивляются отказу от сторибордов, потому что «так было всегда» или боятся потратить время на освоение нового. Тем не менее, эти же команды продолжают ежедневно сталкиваться с трудностями. Вложение небольшого количества времени в улучшение архитектуры окупается каждый день, обеспечивая более плавную разработку. Кратковременный дискомфорт от освоения нового подхода гораздо менее болезненный, чем долгосрочная рутина, связанная с проблемами сторибордов.
Лично я когда-то был поклонником сторибордов. Мне нравилось, как быстро я мог создавать пользовательские интерфейсы и видеть, как приложение оживает. Но по мере роста моих проектов я почувствовал эту тяжесть — загадочные ошибки слияния, невозможность быстро рефакторить код, страх открыть файл сториборда размером 15 МБ и наблюдать за «пляжным мячом» Xcode. Переход к программной разработке пользовательских интерфейсов (а теперь и SwiftUI) напомнил мне, почему мне нравится iOS-разработка: я могу сосредоточиться на создании функций, а не на борьбе с инструментами. Наша задача как разработчиков — приносить пользу, и это намного проще, когда ваши инструменты и процессы не работают против вас.
Ничего страшного, если ваша команда еще не готова полностью отказаться от сторибордов. Но начните разговор. Признайте проблемы и сделайте один маленький шаг. Импульс нарастет. Через несколько месяцев у вас появятся реальные данные, демонстрирующие более быструю сборку, меньше проблем с Git и более довольных инженеров. Это то подтверждение, которое вам нужно, чтобы полностью отказаться от устаревших инструментов.
Вот мой вызов: попробуйте заменить один экран сториборда на SwiftUI или чистый код в следующем спринте. Сравните опыт проверки кода, процесс слияния и отзывы команды. Готов поспорить, вы не захотите возвращаться к старым методам. Было время и для сторибордов, но современные iOS-команды процветают и без них.
Команды, обладающие широкими полномочиями, создают лучшие приложения. Не позволяйте устаревшему инструменту сковывать вашу скорость разработки. Шаг за шагом вы сможете вернуть все потерянные часы (и деньги), потраченные на работу со сторибордами, и инвестировать их в то, что действительно важно — отличные функции и чистый код.
-
Вовлечение пользователей4 недели назад
Большинство приложений терпят неудачу не из-за плохой «идеи»
-
Новости4 недели назад
Видео и подкасты о мобильной разработке 2026.4
-
Видео и подкасты для разработчиков4 недели назад
Изоляционно-плагинная архитектура в Dart-приложениях, переносимость на Flutter
-
Видео и подкасты для разработчиков2 недели назад
Видео droidcon London 2025


