Site icon AppTractor

50 вопросов о System Design, ответы на которые должен знать каждый Senior iOS-разработчик: часть 5

50 вопросов о System Design, ответы на которые должен знать каждый Senior iOS-разработчик

Первая часть, про архитектуру приложения. Вторая про сетевой слой. Третья — локальное хранилище и Offline-First архитектура. Четвертая — оптимизация производительности.

Часть 5: Swift Concurrency и  многопоточность

Вопрос 21. Как бы вы спроектировали параллельное выполнение запросов к программному интерфейсу?

Почему интервьюеры задают этот вопрос

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

Ответ уровня старшего разработчика

Первый вопрос, который я задаю: зависят ли запросы к программному интерфейсу друг от друга?

Если они независимы, их следует выполнять параллельно.

Например, для дашборда могут потребоваться:

Последовательное выполнение этих запросов без необходимости увеличивает время загрузки.

Вместо этого я запускаю их параллельно и ожидаю, пока будут получены все необходимые данные.

Такой подход повышает отзывчивость приложения и сокращает общее время ожидания.

Пример из производственного приложения

Представим главный экран, которому нужны данные из четырёх независимых запросов.

Последовательное выполнение:

Профиль 
↓ 
Уведомления 
↓ 
Заказы 
↓ 
Акции

Общее время загрузки становится суммой времени выполнения всех четырёх запросов.

Параллельное выполнение:

Профиль
  \ 
Уведомления -----> Интерфейс 
  / 
Заказы 
  \ 
Акции

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

Распространённая ошибка

Запускать все запросы параллельно, не учитывая зависимости между ними.

Некоторым запросам требуется авторизация или данные, полученные из предыдущего ответа.

Понимание зависимостей между задачами так же важно, как и само параллельное выполнение.

Дополнительные вопросы

Вопрос 22. Когда следует использовать async/await?

Почему интервьюеры задают этот вопрос

Большинство современных iOS-проектов постепенно переходят на Swift Concurrency.

Интервьюеры хотят понять, знаете ли вы, в каких случаях async/await повышает читаемость и упрощает поддержку кода.

Ответ уровня старшего разработчика

Я использую async/await, когда операция ожидает результат и при этом не должна блокировать текущий поток.

Например:

По сравнению с вложенными обработчиками завершения async/await позволяет писать код, который проще читать, анализировать и отлаживать.

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

Пример из производственного приложения

Сценарий входа может включать:

  1. Авторизацию пользователя.
  2. Загрузку профиля.
  3. Загрузку настроек приложения.

Такой процесс намного проще воспринимать в виде последовательного асинхронного кода, чем в виде глубоко вложенных колбеков.

Распространённая ошибка

Некоторые разработчики считают, что async/await автоматически ускоряет код.

Это не так.

Он улучшает структуру и читаемость кода.

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

Дополнительные вопросы

Вопрос 23. Когда следует использовать акторы?

Почему интервьюеры задают этот вопрос

Состояния гонки относятся к числу самых сложных для диагностики ошибок.

Интервьюеры хотят понять, умеете ли вы защищать общее изменяемое состояние в современных приложениях на Swift.

Ответ уровня старшего разработчика

Акторы предоставляют безопасный способ управления изменяемым состоянием, к которому могут обращаться несколько параллельно выполняющихся задач.

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

Это значительно снижает вероятность возникновения состояний гонки.

Акторы особенно полезны для:

Пример из производственного приложения

Представим, что несколько экранов одновременно запрашивают маркер доступа.

Без синхронизации могут одновременно запуститься несколько операций его обновления.

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

Распространённая ошибка

Использовать акторы повсюду.

Доступ к актору является асинхронным, поэтому их следует применять только там, где действительно существует общее изменяемое состояние, а не для каждого объекта приложения.

Дополнительные вопросы

Вопрос 24. Как предотвращать состояния гонки?

Почему интервьюеры задают этот вопрос

Состояния гонки часто проявляются только под высокой нагрузкой или при редком совпадении временных условий, поэтому их сложно воспроизводить.

Интервьюеры хотят понять, умеете ли вы проектировать системы, сохраняющие согласованность при параллельном выполнении.

Ответ уровня старшего разработчика

Сначала я определяю общие изменяемые ресурсы.

Например:

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

Конкретное решение зависит от задачи. Иногда подходит актор. В других случаях могут потребоваться последовательное выполнение, неизменяемые структуры данных или тщательно спроектированное владение задачами.

Главное — не допускать неконтролируемой параллельной записи.

Пример из производственного приложения

Допустим, два ответа API одновременно обновляют один и тот же профиль пользователя. Без координации запрос, завершившийся последним, перезапишет изменения другого запроса.

Если все обновления проходят через единую точку синхронизации, данные остаются согласованными.

Распространённая ошибка

Считать, что состояния гонки возникают только в многопоточном коде.

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

Дополнительные вопросы

Вопрос 25. Как сохранить отзывчивость интерфейса во время фоновой работы?

Почему интервьюеры задают этот вопрос

Пользователи оценивают приложение по его отзывчивости.

Интервьюеры хотят понять, умеете ли вы сочетать фоновую обработку с плавной работой интерфейса.

Ответ уровня старшего разработчика

Главный поток должен быть сосредоточен на работе с пользовательским интерфейсом.

Ресурсоёмкие операции, такие как сетевые запросы, декодирование JSON, обработка изображений и запросы к базе данных, следует выполнять в фоне.

На главный поток должно возвращаться только итоговое обновление интерфейса.

Это уменьшает количество пропущенных кадров и помогает сохранять плавность анимаций.

Я также избегаю выполнения лишней работы во время прокрутки и переходов между экранами.

Пример из производственного приложения

Рассмотрим приложение для обработки фотографий.

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

Вместо этого изображение обрабатывается в фоне, а индикатор выполнения сообщает пользователю о ходе операции.

После завершения обработки итоговое изображение сразу отображается на экране.

Всё это время приложение остаётся отзывчивым.

Распространённая ошибка

Переносить в фон вообще всю работу.

Обновления пользовательского интерфейса должны выполняться в главном потоке.

Попытка изменять элементы интерфейса из фонового контекста выполнения приводит к непредсказуемому поведению и предупреждениям в рантайме.

Дополнительные вопросы

Заключение

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

Старшие инженеры понимают не только синтаксис async/await и акторов. Они знают, как координировать асинхронные операции, защищать общее состояние, сохранять отзывчивость интерфейса и принимать обоснованные решения о конкурентном выполнении с учётом требований приложения.

На собеседовании важно объяснять ход своих рассуждений. Расскажите, почему вы выбрали конкретный подход, обсудите компромиссы и по возможности связывайте ответы с реальными производственными сценариями.

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

Источник

Exit mobile version