diff --git "a/\320\234\320\260\320\275\320\260\321\202\320\276\320\262\320\230\320\220/\320\234\320\260\320\275\320\260\321\202\320\276\320\262\320\230\320\220.md" "b/\320\234\320\260\320\275\320\260\321\202\320\276\320\262\320\230\320\220/\320\234\320\260\320\275\320\260\321\202\320\276\320\262\320\230\320\220.md" new file mode 100644 index 0000000..c69ae2a --- /dev/null +++ "b/\320\234\320\260\320\275\320\260\321\202\320\276\320\262\320\230\320\220/\320\234\320\260\320\275\320\260\321\202\320\276\320\262\320\230\320\220.md" @@ -0,0 +1,45 @@ +## Отчёт по рефакторингу + +### Выбранный проект + +**Rumble** — open-source iOS-приложение для обхода блокировок на базе VPN-туннеля. + +- **Репозиторий:** https://github.com/RumbleOrg/Rumble +- **Описание:** Приложение создаёт локальный VPN-туннель, который пропускает трафик через утилиту `ciadpi` с настраиваемыми параметрами манипуляции пакетами. Позволяет обходить DPI-фильтрацию (Deep Packet Inspection), используемую интернет-провайдерами для блокировки сайтов и сервисов. +- **Стек технологий:** + - Язык: Objective-C + - UI-фреймворк: UIKit (программный, без Storyboard) + - Системные фреймворки: NetworkExtension (`NETunnelProviderManager`, `NETunnelProviderProtocol`), Foundation + - Сборочная система: Theos (сборка unsigned IPA) + - CI: GitHub Actions + +--- + +### Принципы рефакторинга + +- **Инициализация в конструкторе** — состояние объекта приводится в корректное, полностью инициализированное состояние уже в `init`, а не откладывается до момента загрузки представления. Это устраняет зависимость от порядка обхода вкладок пользователем. +- **Устранение порядковой связанности** — логика не должна зависеть от того, в каком порядке пользователь посетил экраны приложения. +- **Единственный источник истины** — конфигурация по умолчанию определена ровно в одном месте (в `initWithStyle:` класса `RMSettingsViewController`), а не дублируется в нескольких местах. +- **Корректный порядок инициализации зависимостей** — связанные свойства объекта устанавливаются до передачи объекта в другой контейнер. + +--- + +### Описание выполненного рефакторинга + +#### Проблема 1: краш при запуске VPN без посещения вкладки Settings + +**Обнаруженная проблема.** Значения по умолчанию для ключей `Args`, `DNSServer` и `IPv6` регистрировались в `NSUserDefaults` только внутри `RMSettingsViewController.viewDidLoad` — метода, который вызывается лишь тогда, когда пользователь открывает вкладку Settings. При первом запуске приложения, если пользователь сразу нажимал кнопку VPN, не заходя в настройки, `NSUserDefaults` возвращал `nil` для `Args` и `DNSServer`. VPN-расширение (`PacketTunnelProvider`) проверяет типы переданных параметров и при получении `nil` завершало соединение с ошибкой `NEVPNErrorConfigurationInvalid`. + +**Решение.** Инициализация массива `settings` и регистрация значений по умолчанию перенесены из `viewDidLoad` в `initWithStyle:`. Этот метод вызывается в `RMAppDelegate.didFinishLaunchingWithOptions:` при создании экземпляра контроллера — до того, как пользователь может взаимодействовать с интерфейсом. Логика и данные остались в одном файле (`RMSettingsViewController.m`), дублирования не возникло. + +#### Проблема 2: кнопка VPN оставалась неактивной + +**Обнаруженная проблема.** При первичной инициализации VPN-менеджера свойства `providerBundleIdentifier` и `serverAddress` устанавливались на объекте `prot` *после* того, как он был присвоен `mgr.protocolConfiguration`. Из-за этого менеджер получал объект протокола без обязательных полей, не мог корректно сконфигурировать туннель и оставался в неактивном состоянии — кнопка включения VPN не реагировала на нажатие. + +**Решение.** Строки установки `providerBundleIdentifier` и `serverAddress` перемещены выше строки `mgr.protocolConfiguration = prot`, чтобы объект протокола передавался в менеджер уже полностью сконфигурированным. + +--- + +### Pull Request + +https://github.com/RumbleOrg/Rumble/pull/1