Язык программирования Swift 6: улучшенная многопоточная безопасность, типовая надёжность и производительность

Swift 6 — крупнейшее обновление языка от Apple со времён Swift 5.5, в котором появился async/await. Главное здесь — защита от гонок данных, обеспечиваемая компилятором: ошибки многопоточности, которые раньше всплывали в два часа ночи на устройстве пользователя, теперь выявляются как ошибки сборки на этапе swift build. Всё остальное — новый фреймворк Swift Testing, доработки any Sendable, типизированные ошибки, region-based isolation, кроссплатформенный Foundation — работает на этот единственный сдвиг в том, как Swift обращается с многопоточностью.

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

Ключевые выводы

Swift 6 превращает гонки данных в ошибки компиляции. Полная проверка многопоточности (strict concurrency checking) ловит баги с разделяемым изменяемым состоянием на этапе сборки, а не в момент сбоя. Миграция — это реальный объём работы, но выигрыш в продакшене больше, чем у любого обновления Swift со времён ARC.

Region-based isolation сводит лишние церемонии к минимуму. Не нужно помечать каждый тип как Sendable. Компилятор отслеживает, какие значения пересекают границы акторов, и ругается только тогда, когда возможна настоящая гонка.

Swift Testing меняет рефлексы «по умолчанию XCTest». Макросы @Test, #expect, параметризованные тесты и теги дают эргономику лучше, чем XCTest, и при этом фреймворк работает бок о бок с XCTest на время миграции.

Типизированные ошибки и noncopyable-типы закрывают крайние случаи. Типизация ошибок делает границы библиотек явными; ~Copyable поддерживает ресурсы в стиле RAII (файловые дескрипторы, мьютексы, токены) без ссылочной семантики.

Кроссплатформенный Swift наконец заслуживает доверия. Swift-реализация Foundation объединяет macOS, iOS, Linux и Windows. Вместе со Swift on Android (рабочая группа 2025 года) Swift становится разумным выбором для общей бизнес-логики на всех ключевых платформах.

Почему именно Фора Софт пишет этот разбор Swift 6

Фора Софт делает iOS-продукты на Swift для клиентов из EdTech, e-health, медиа и корпоративного видео. В 2024–2025 годах мы перевели свои собственные продакшен-кодовые базы на Swift 6 — в том числе iOS-клиент обучающей платформы BrainCert, iOS-приложение для видеоэффектов в реальном времени SuperPower FX и мобильные инструменты для корпоративной видеоплатформы VALT. Каждая миграция упиралась в свою разновидность многопоточных ловушек, поэтому компромиссы ниже — проверенные, а не теоретические.

Мы используем Agent Engineering (старшие инженеры курируют Cursor, Claude, Copilot), чтобы миграции на Swift 6 не выходили из бюджета: более строгая диагностика компилятора неожиданно хорошо сочетается с правками, которые предлагает ИИ — каждое предложенное исправление обязано пройти более строгую проверку типов и многопоточности, прежде чем попасть в код. В результате наши оценки на миграцию обычно оказываются на 20–40% ниже стандартных ставок агентств.

Планируете миграцию продакшен-приложения на Swift 6?

Расскажите, на какой версии Swift вы сейчас, какой стиль многопоточности и каков масштаб приложения. В ответ пришлём конкретный план миграции, список рисков и компактную оценку — обычно ощутимо ниже, чем расчёт «всё переписать заново».

Позвоните нам → Напишите нам →

Сжатая хронология — от Swift 5.1 до Swift 6

Swift 6 — кульминация пятилетней дуги развития. Каждый релиз серии 5.x добавлял очередной кусочек модели многопоточности; Swift 6 перевернул умолчания и закрепил всю модель в системе типов.

Версия Релиз Главная фича Почему это было важно
Swift 5.1 Сен 2019 Непрозрачные возвращаемые типы, стабильность модулей Открыли путь SwiftUI и бинарной дистрибуции
Swift 5.5 Сен 2021 async/await, акторы, Sendable Нативная многопоточность вместо колбэков GCD
Swift 5.7 Сен 2022 Экзистенциальный any, обобщённый some Разница между обобщениями и экзистенциалами стала явной
Swift 5.9 Сен 2023 Макросы, noncopyable-типы (превью) Кодогенерация на этапе компиляции, паттерны RAII
Swift 5.10 Мар 2024 Полная изоляция данных (по согласию) Финальная репетиция перед умолчаниями Swift 6
Swift 6.0 Сен 2024 Строгая многопоточность по умолчанию, Swift Testing Защита от гонок данных на этапе компиляции

Строгая проверка многопоточности по умолчанию

Главное изменение Swift 6 в том, что полная проверка многопоточности теперь включена по умолчанию в режиме языка -swift-version 6. Компилятор отвергает любые пути выполнения, в которых возможно разделение изменяемого состояния между доменами изоляции. Там, где Swift 5.x ограничивался предупреждением, Swift 6 выдаёт ошибку сборки.

На практике это значит: классы, не соответствующие Sendable, не могут быть захвачены замыканиями @Sendable; значения, пересекающие границу актора, должны быть передаваемыми; глобальное изменяемое состояние без изоляции — это ошибка компиляции. Реальная стоимость миграции — доказать, какие куски кода действительно безопасны, и починить те, что нет.

// Swift 5: compiles with a warning
class CounterUnsafe {
  var value = 0
}
let c = CounterUnsafe()
Task.detached { c.value += 1 }  // data race, warning only

// Swift 6: compile error unless `Counter` is an actor
// or Sendable-safe
actor Counter {
  private(set) var value = 0
  func bump() { value += 1 }
}
let counter = Counter()
Task { await counter.bump() }   // compiler is happy

Включайте строгую многопоточность, когда: вы уже на Swift 5.10 с включённой полной проверкой, CI зелёный, а команда уверенно работает с акторами и async/await. Если хотя бы одно из трёх не выполнено — сначала приведите проект к этому состоянию, а потом переключайте режим языка.

Region-based isolation (SE-0414) — меньше аннотаций Sendable

Фича, благодаря которой строгая многопоточность становится терпимой, — region-based isolation. Вместо требования помечать каждый тип как Sendable, компилятор отслеживает, какие значения пересекают границы изоляции, и возражает только тогда, когда настоящая гонка действительно возможна.

В типичной миграции приложения region-based isolation сокращает число добавляемых аннотаций Sendable на 50–70%. Не-Sendable значение, созданное на MainActor и переданное в Task на том же акторе, — в порядке; компилятор недоволен лишь тогда, когда видит, что это значение уходит в другой домен изоляции.

Практический эффект: меньше диффов на ревью, меньше механических обходных extension Foo: @unchecked Sendable {}, гниющих в кодовой базе, и меньше церемоний на пути к защите от гонок данных.

Параметры и значения sending (SE-0430)

Ключевое слово sending помечает значения, которые компилятору разрешено перенести через границу изоляции — обычно потому, что вызывающая сторона после вызова к ним больше не обращается. Это убирает целый класс дилемм «сделать Sendable или клонировать» и заменяет их точной локальной аннотацией.

actor Uploader {
  func send(_ payload: sending Payload) async throws {
    // The compiler verifies the caller released the Payload.
    // We can safely mutate it across the actor boundary.
  }
}

В коде обработки видео и стриминга, где мы постоянно гоняем буферы по конвейерам, именно sending сделал строгую многопоточность жизнеспособной в SuperPower FX. Буферы — короткоживущие; пометить их как sending ближе к правде, чем делать их Sendable.

Используйте sending, когда: вызывающая сторона передаёт не-Sendable значение через async-границу и не сохраняет и не использует его дальше. Типичные случаи: буферы, промежуточные результаты, разовая полезная нагрузка запроса.

Типизированные ошибки (SE-0413) — явные контракты на ошибки

В Swift 6 появились типизированные ошибки: функция теперь может объявить, какой конкретный тип ошибки она бросает, а не просто throws как открытое множество.

enum UploadError: Error { case network, serialization, size }

func upload(_ file: URL) throws(UploadError) -> UploadID {
  // Only UploadError cases compile.
}

Применяйте типизированные ошибки на границах библиотек (входные точки SDK, сетевой слой, файловый I/O), где множество возможных сбоев небольшое и исчерпывающее. Во внутреннем коде оставайтесь на нетипизированном throws — жёсткая типизация ошибок слишком глубоко приводит к болезненным рефакторингам, когда появляется новый режим сбоя.

Берите типизированные ошибки, когда: вы проектируете границу SDK или фреймворка, набор ошибок стабилен и невелик, а вызывающие стороны выигрывают от исчерпывающего switch. Не на каждой внутренней функции.

Застряли на предупреждениях Sendable или дедлоках на акторах?

Мы распутывали многопоточность Swift 6 в реальных продакшен-приложениях — от видеоконвейеров и сетевых SDK до приложений на SwiftUI. Пришлите путь к файлу или текст ошибки — рассчитаем точечный спринт исправлений.

Позвоните нам → Напишите нам →

Noncopyable-типы (SE-0390 / SE-0437) — RAII на значимых типах

Swift 6 переводит noncopyable-типы (~Copyable) из превью в стабильное состояние, с более широкой поддержкой в стандартной библиотеке. Используйте их для значений, представляющих уникальный ресурс: файловый дескриптор, токен мьютекса, хэндл GPU-буфера, текущую сетевую транзакцию. Компилятор не даст случайно дублировать такое значение — вы не сможете дважды закрыть один файл или потерять блокировку.

struct FileHandle: ~Copyable {
  private let fd: CInt
  init(_ path: String) throws { /* open fd */ }
  consuming func close() { /* close fd */ }
  deinit { /* close if not consumed */ }
}

func write(to file: borrowing FileHandle) { /* ... */ }

Это ответ Swift на move-семантику C++ и владение в Rust без полного налога borrow-checker. Для мобильного видеокода, работающего с GPU-буферами, аппаратными кодировщиками и сессиями захвата, такой подход исключает целый класс трудноуловимых утечек.

Берите ~Copyable, когда: значение представляет уникальный хэндл или токен владения — файловый дескриптор, мьютекс, GPU-буфер, аппаратную сессию — и случайное дублирование является багом, а не удобством.

Swift Testing — замена XCTest, которая едет в комплекте с Xcode

Swift Testing — новый фреймворк на макросах, поставляемый вместе со Swift 6. Он заменяет цепочки XCTAssert единственным #expect и приносит из коробки параметризованные тесты, теги, трейты и сьюты.

import Testing

@Suite("Uploader")
struct UploaderTests {
  @Test(arguments: [1024, 5 * 1024 * 1024, 100 * 1024 * 1024])
  func respectsSizeLimit(size: Int) async throws {
    let result = try await upload(size: size)
    #expect(result.status != .rejected)
  }
}

Swift Testing сосуществует с XCTest, поэтому миграцию можно вести фичу за фичей: пишите новые тесты в Swift Testing, существующие сьюты XCTest не трогайте, пока сами не редактируете этот файл по другому поводу. К тому моменту, когда вы пройдёте по самым активно меняющимся участкам, большая часть проверок уже окажется переписана — без массового рефакторинга в один заход.

Swift Testing мы сочетаем с инструментами ИИ-QA, которые описаны в нашей статье о процессах тестирования: Swift Testing — для юнит-тестов и быстрых интеграционных проверок, Reflect Mobile / Zentester — для end-to-end UI-сценариев. Именно эта связка позволяет нам держать ритм релизов предсказуемым на сложных видеоприложениях.

Foundation на Swift — macOS, iOS, Linux, Windows, Android

Swift 6 завершает переписывание Foundation на Swift. Поведение Date, URL, JSONEncoder, String и соседних типов теперь одинаковое на платформах Apple и не-Apple, при этом производительность на устройствах Apple остаётся близкой к Objective-C-версии или превосходит её.

Вместе с рабочей группой Swift on Android 2025 года Swift впервые со времён Objective-C превращается в реалистичный язык для общей логики между iOS, Android, macOS, Linux и Windows. Один язык может пройти через все таргеты полностековой системы и нести в себе доменную модель целиком — более широкий контекст по Swift on Android описан в нашем дайджесте лета 2025 года.

Макросы повзрослели — практические паттерны

Макросы появились в Swift 5.9 и созрели к 6.0: лучше диагностика, стабильнее инструментарий, всё больше штатных макросов (@Observable, @Suite, @Test). Четыре места, где макросы оправдывают себя в наших приложениях:

1. Наблюдение. @Observable заменяет шаблонный код ObservableObject/@Published одним атрибутом и чисто работает со строгой многопоточностью.

2. Кодогенерация для сериализации. Собственные макросы вида @CodedAt / @Freestanding убирают рутину с Codable-ключами на доменных типах.

3. Эргономика тестов. @Test, #expect и #require сворачивают три строки XCTest в одну.

4. Константы времени сборки. Заводят API-ключи или схемы remote-config в систему типов на этапе компиляции, а не как строки во время выполнения.

Поэтапный план миграции, переживающий настоящие релизы

Попытка переключить продакшен-приложение на Swift 6 в один спринт — верный способ испортить выходные. Мы делим миграцию на четыре фазы, каждая из которых уезжает на том же релизном поезде, что и обычные изменения.

Фаза 1 — зафиксировать кодовую базу на Swift 5.10 с полной проверкой. Включите SWIFT_STRICT_CONCURRENCY=complete. Выпускайте релизы с предупреждениями. Ведите в CI график выгорания предупреждений — так регрессии будут видны сразу.

Фаза 2 — заменить глобальное изменяемое состояние акторами или синглтонами с @MainActor. Большая часть предупреждений приходит именно отсюда. Удержитесь от соблазна выйти через @unchecked Sendable — компилятор почти всегда прав.

Фаза 3 — доработать границы библиотек. Добавьте Sendable, sending и типизированные ошибки на поверхностях SDK. Внутренний код может подождать.

Фаза 4 — переключиться на -swift-version 6. Когда предупреждений ноль, смена режима проходит как обычный день. Праздновать стоит молча — работа была в фазах 2 и 3.

Сколько это стоит — миграция на Swift 6 в инженеро-неделях

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

1. Небольшое iOS-приложение (<50 тыс. строк, в основном async/await). 2–4 инженеро-недели — в основном расстановка Sendable и точечные правки нескольких глобальных болевых точек.

2. Среднее приложение (50–200 тыс. строк, смесь GCD и async). 6–10 инженеро-недель. Главный объём — переподключить очереди GCD на акторы и распутать синглтоны с разделяемым состоянием.

3. Крупное приложение (200 тыс.+ строк, много моста с Objective-C). 12–20 инженеро-недель, разбитых на два-три релиза.

4. SDK с публичным API. Прибавьте сверху 2–3 недели на аккуратно версионированные аннотации Sendable/sending/типизированных ошибок — чтобы зависимые приложения могли мигрировать в своём темпе.

По нашему опыту, Agent Engineering сокращает каждый бакет на 20–40%: более строгий компилятор неожиданно хорошо сочетается с правками от ИИ — каждое предложение обязано собираться в новом режиме, поэтому ложные срабатывания ИИ отсеиваются мгновенно. Чтобы получить защитимую оценку под вашу кодовую базу, свяжитесь с нами по телефону или почте ниже.

Мини-кейс — Swift 6 в приложении с видео в реальном времени

Ситуация. Продакшен-приложение для iOS с захватом видео в реальном времени, on-device ML-инференсом и сетевым стеком эпохи GCD. Полная проверка Swift 5.10 выдавала 400+ предупреждений. Цель: перейти на Swift 6, не уронив ритм релизов (раз в две недели) и KPI по проседаниям кадров.

12-недельный план. Недели 1–3: выгорание предупреждений по глобальным синглтонам через изолированный @MainActor-актор AppState и перенос трёх очередей GCD в актор пайплайна захвата. Недели 4–7: разметить поверхности видеокодека и сетевого SDK sending и Sendable, ввести сьюты Swift Testing в двух самых активно меняющихся модулях. Недели 8–10: закрыть последние 50 предупреждений мелкими рефакторингами, плюс одно сознательное @unchecked Sendable на специально разделяемом кэше — с задокументированным обоснованием. Недели 11–12: переключить -swift-version 6, выкатить под фичефлагом, раскатать на всю аудиторию.

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

Решающий фреймворк — внедрять ли Swift 6 в этом квартале?

1. Кодовая база уже на async/await? Если нет, сначала переезжайте на async/await; выигрыши Swift 6 на async-native коде мультипликативны.

2. Включена ли полная проверка в Swift 5.10? Если да, тяжёлая часть уже позади; переключайте режим в ближайшем релизе. Если нет, это и есть фаза 1.

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

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

5. Какая доля сбоев приходится на многопоточность? Если в топ-5 крашей заметная часть связана с многопоточностью, миграция окупит себя уже в первом релизе после переключения. Если нет — планируйте её вокруг продуктовых задач и выкатывайте по возможности.

Чего стоит избегать

1. Слишком быстро тянуться к @unchecked Sendable. Каждый такой обходной путь — технический долг. Если он действительно нужен, задокументируйте причину; если нет — правьте дизайн.

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

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

4. Откладывать Swift Testing до конца. Первый @Test в начале миграции многому учит команду по поводу новых макросов до того, как они понадобятся в дедлайне.

5. Недооценивать мост с Objective-C. Бриджированные Obj-C API дают самый шумный поток Sendable-замечаний. Закладывайте запас на любое приложение с заметным Obj-C-ядром.

KPI — что мерить после перехода на Swift 6

KPI качества. Сбои многопоточного класса на 10 тыс. сессий (цель — уходить к нулю), предупреждения компиляции в CI (цель — ноль) и доля нестабильных юнит-тестов (ожидаемо снижается, когда Swift Testing вытесняет неудобные async-паттерны XCTest).

Бизнес-KPI. Время до выкатки хотфикса по многопоточному инциденту (до и после), время вхождения новых инженеров в кодовую базу (новички должны быстрее осваиваться, поскольку компилятор сам учит их модели многопоточности) и стабильность ритма релизов.

KPI надёжности. Заморозки главного потока (теперь вы явно владеете областями @MainActor), эквиваленты ANR-зависаний и время холодного старта (обычно улучшается, иногда умеренно проседает, в любом случае стоит отслеживать).

Когда мигрировать пока не стоит

Не каждому приложению надо прыгать на Swift 6 в этом квартале. Подождите, если команда сейчас в середине миграции на SwiftUI или async/await (миграции делайте по одной), если приложение всё ещё опирается на заметный объём Objective-C-кода, который вы не готовы перевести на мост, или если релизный коридор уже сжат внешними событиями (запреты на сабмиты в App Store, окно крупного релиза ОС).

Swift 6 никуда не денется к следующему кварталу. А сломанный релиз, в котором миграция столкнулась с продуктовым пушем, аукнется надолго.

Нужен план миграции на Swift 6, которому можно доверять?

Наша iOS-команда мигрировала продакшен-приложения с видео в реальном времени, ML и мостами на Objective-C на Swift 6. Пришлите ссылку на репозиторий или короткое описание — вернёмся с поэтапным планом и компактной оценкой.

Позвоните нам → Напишите нам →

FAQ

Можно ли использовать фичи Swift 6, не переключая режим языка?

Да. Большая часть фич Swift 6 (region-based isolation, sending, типизированные ошибки, noncopyable-типы, Swift Testing) доступна начиная со Swift 5.10 по опциональным флагам. Многие команды включают их инкрементно за один-два релиза до того, как переключить -swift-version 6.

Сломает ли Swift 6 мою существующую кодовую базу?

Только если вы включите режим языка 6. Компиляторы Swift 6 по-прежнему собирают код на Swift 5 — более строгое поведение включается опционально, помодульно. Используйте это, чтобы мигрировать модуль за модулем.

Стоит ли немедленно переключаться с XCTest на Swift Testing?

Спешить не нужно. Swift Testing сосуществует с XCTest. Пишите новые тесты в Swift Testing, а существующие сьюты переписывайте по случаю, когда уже редактируете соответствующий файл. Принудительный массовый рефакторинг ничего не даст по сравнению с инкрементным подходом.

Как Swift 6 взаимодействует с приложениями на SwiftUI?

SwiftUI помечен @MainActor и хорошо стыкуется со строгой многопоточностью. Заложите дополнительные работы, если у вас неизолированные синглтоны вью-моделей или вы передаёте не-Sendable замыкания в actions SwiftUI — компилятор теперь подсвечивает такие паттерны, которые раньше проскакивали.

Какое правило большого пальца по типизированным ошибкам?

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

Можно ли использовать Swift 6 для бэкенда на Linux или Windows?

Да. Swift 6 со Swift-реализацией Foundation — реальный вариант для бэкенда на Linux и Windows. В связке с Vapor или Hummingbird он закрывает HTTP API. Команды, уже сидящие на Swift на клиенте, выигрывают от единого языка через всю архитектуру.

Как Swift 6 влияет на планы по Swift на Android?

Рабочая группа Swift on Android 2025 года опирается на тулчейн Swift 6. Общая бизнес-логика на Swift 6 со строгой многопоточностью — самая аккуратная стартовая точка для новых кроссплатформенных модулей. SwiftUI по-прежнему остаётся только iOS-овым; нативный UI под каждую платформу — всё ещё рекомендуемый подход.

Во сколько обычно обходится миграция на Swift 6?

Небольшое приложение — как правило, 2–4 инженеро-недели; среднее — 6–10; крупное — 12–20 в несколько релизов. С Agent Engineering мы регулярно выходим на 20–40% ниже этих диапазонов. Каждая оценка зависит от конкретной кодовой базы, поэтому числа выше — ориентиры, а не контракты.

Углублённый разбор

Swift 6 в iOS-разработке

Как строить видеочаты нового поколения на Swift 6 — продакшен-компаньон к этому обзору фич.

SwiftUI

SwiftUI для видеоконференций против UIKit

Где SwiftUI выигрывает, где UIKit ещё себя оправдывает и как Swift 6 меняет эти компромиссы.

SPM

Swift Package Manager для видеоприложений

Границы модулей и аннотации Sendable между пакетами — практический спутник миграции на Swift 6.

Контекст

Технологический дайджест лета 2025

iOS 26, Swift on Android, GPT-5 — более широкий ландшафт релизов вокруг Swift 6.

QA

Наш процесс тестирования

Как Swift Testing встраивается в общий QA-плейбук Фора Софт.

Готовы сделать Swift 6 безопасным для своего продакшен-приложения?

Swift 6 — серьёзный шаг вперёд: защита от гонок данных на этапе компиляции, лучшая эргономика тестов, noncopyable-ресурсы, типизированные ошибки на границах библиотек и кроссплатформенный Foundation, который наконец делает один язык реальным выбором сразу для iOS, Android, macOS, Linux и Windows. Миграция — это работа, но каждое продакшен-приложение, которое мы перевозили, выходило измеримо безопаснее и проще для размышлений.

Размазывайте миграцию по релизам, опирайтесь на region-based isolation и sending, чтобы держать число Sendable-аннотаций низким, и заводите Swift Testing там, где уже пишете тесты. Когда понадобятся инженеры, которые проделывали это на работающих приложениях, мы на расстоянии короткого звонка.

Выпускайте Swift 6 уверенно

Расскажите про версию Swift, размер приложения и сроки. Мы вернёмся с поэтапным планом миграции, защитимой оценкой и двумя ставками по многопоточности, которые стоит сделать первыми.

Позвоните нам → Напишите нам →

  • Разработка