Я расскажу, как внести функциональные изменения в плохо спроектированный код в разумные сроки и при этом ничего не сломать — о возможных проблемах, ошибках в процессе и о том, как с ними справляться.
В частности, покажу, как в этом помогают тесты и почему они важны как система раннего обнаружения ошибок. Расскажу о зависимостях, их классификации и о том, какое влияние разные типы зависимостей оказывают на наше понимание работы программы и возможности её протестировать.
Большую часть этого доклада я посвятил простым практическим приёмам рефакторинга и модификации кода — для упрощения понимания системы и более лёгкого внесения функциональных изменений.
1 of 52
Download to read offline
More Related Content
Виктор Брыкcин — Как всё починить и ничего не сломать: работа со сложным кодом при помощи тестов
1. Как всё починить и
ничего не сломать
Работа со сложным кодом при помощи тестов
10. 1. Уменьшают время проверки соответствия требованиям
⌘+U вместо цикла проверки командой QA
2. Фиксируют функциональность
Нет в тестах = не реализовано
Модульные тесты
10
13. Явная зависимость — зависимость, определенная в
публичном интерфейсе класса.
Неявная зависимость определяется и используется
только в реализации.
Явная и неявная зависимость
13
14. Внешняя зависимость — зависимость, которая
передается в модуль вызывающим кодом.
Внутренние зависимости создаются или извлекаются
самим модулем.
Внешняя и внутренняя зависимость
14
15. Гибкая зависимость — зависимость, позволяющая
изменить реализацию без изменения кода модуля.
Жесткие зависимости требуют модификации кода
модуля для изменения поведения.
Гибкая и жесткая зависимость
15
17. protocol NetworkRequestFactory {
func request() -> NetworkRequest
}
class NetworkRequestFactoryImpl : NetworkRequestFactory {
// ...
}
class NetworkManager {
public var requestFactory: NetworkRequestFactory =
NetworkRequestFactoryImpl()
}
Явная внутренняя гибкая зависимость
17
18. protocol ServiceLocator {
func resolve<T>() -> T
}
protocol NetworkRequestFactory {
func request() -> NetworkRequest
}
class NetworkManager {
private let _networkRequestFactory: NetworkRequestFactory
public init(withServices serviceLocator: ServiceLocator) {
_networkRequestFactory = serviceLocator.resolve()
}
}
Неявная внешняя гибкая зависимость
Другие варианты: передача в качестве зависимости Any/id 18
19. protocol NetworkRequestFactory {
func request() -> NetworkRequest
}
class NetworkRequestFactoryImpl : NetworkRequestFactory {
// ...
}
class NetworkManager {
public let requestFactory: NetworkRequestFactory =
NetworkRequestFactoryImpl()
}
Явная внутренняя жесткая зависимость
Другие варианты: наследование 19
20. class NetworkRequestFactory {
public static var sharedFactory = NetworkRequestFactory()
func request() -> NetworkRequest {
// ...
}
}
class NetworkManager {
private let _requestFactory: NetworkRequestFactory
public init() {
_requestFactory = NetworkRequestFactory.sharedFactory
}
}
Неявная внутренняя жесткая зависимость
Другие варианты: вызовы функций 20
21. 1. Модуль тестируется со всеми жесткими зависимостями
2. Гибкие зависимости заменяются на mock-объекты
3. Проверяется выполнение заявленных контрактов модуля
Тестирование
21
45. Процесс — цепочка преобразований с одним входом и одним
выходом.
Вход и выход процесса — часть внутреннего состояния объекта.
Выделение процессов
45
46. Процесс
46
class ViewController : UIViewController {
private var _account: Account
private var _articles: [ Articles ]
private var _drafts: [ Drafts ]
}
// Процесс работает только с articles и account
class UpdateArticlesProcess {
public func updateArticles(for account: Account) -> [ Articles ] {
}
}
47. 1. Выделяется процесс в виде внутренней зависимости
2. Процесс покрывается тестами
3. Процесс выносится во внешнюю зависимость
4. Меняются тесты у основного объекта
Итерационное выделение процессов
47
48. 1. Принцип бойскаута
2. Не переделывать все сразу
3. Искать понятные абстракции
Best practices
48
50. 1. Тесты помогают вносить изменения
2. Нетестируемый код можно преобразовать в трестируемый
3. С небольшими объектам работать проще, чем с громоздкими
Заключение
50