Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions МанатовИА/МанатовИА.md
Original file line number Diff line number Diff line change
@@ -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