Цитаты и примечания

Эффективная работа с устаревшим кодом

Майкл Фезерс

Что мне понравилось в этой книге: большое внимание уделяется тому, как применить тестовую систему к унаследованному коду (так что у вас есть подстраховка, чтобы начать вносить в него изменения). Он предлагает некоторые конкретные подходы к поиску «частей унаследованного кода, которые могут окупить усилия по его тестированию», но также есть предупреждение о компромиссах: если унаследованный код не поддается тестированию, усилия, необходимые для существующее покрытие может добавить некоторый риск и потребовать много времени.

Изменение программного обеспечения

Причины смены ПО

  • Добавление функции
  • Исправление ошибки
  • Улучшение дизайна
  • Оптимизация использования ресурсов

Улучшение дизайна

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

Изменение риска

  • Мы не знаем, насколько поведение подвергается риску, когда мы вносим изменения
  • Как проверить правильность наших изменений? / не нарушает какое-либо существующее поведение? Введите автоматическое тестирование
  • Консервативный подход (меньше изменений) порождает страх перед будущими изменениями.

Работа с обратной связью

Покрытие тестами как подстраховка

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

  • Модульные тесты дают обратную связь по мере разработки, поэтому вы можете проводить рефакторинг с гораздо большей безопасностью.
  • Разрывая зависимости, мы можем делать более глубокие изменения.

Устаревший алгоритм изменения кода

Зачем ломать зависимости?

Распознавание и разделение

  • Распознавание: когда нам нужно получить доступ к вычисляемому значению для проверки.
  • Разделение. Если мы не можем поместить код в тестовую систему, здесь мы можем использовать фальшивые соавторы (фальшивые объекты, фиктивные объекты, заглушки и т. д.)

Модель шва

  • Это просто точка в коде, где вы можете изменить поведение.
  • Вы сами решаете, какое поведение использовать (точка включения соединения)

О рефакторинге

Помните, код — это ваш дом, и вы должны в нем жить.

Класс/метод Sprout: это просто класс или метод, который вы можете использовать вместо исходного класса/метода, когда хотите обновить или добавить функцию.

Обернуть класс/метод: переименовать класс или метод, чтобы можно было обновить или добавить функцию.

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

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

  • TDD: полезно сосредоточиться на одной вещи за раз.
  • Программирование на основе различий: наследование классов для исправления/изменения поведения. Может помочь в некоторых случаях, но нарушает принцип подстановки Лисков.

Проблемы при попытке использовать Test Harness для класса

  • Объекты класса непросто создать
  • Зависимости усложняют создание Test Harness (глобальные зависимости делают его еще хуже).
  • Конструктор (для класса для тестирования) имеет побочные эффекты и/или страдает от «строительного блоба» (много сложных параметров).
  • Необходимо проверить влияние изменения в тестируемом классе. Введите Эскизы эффектов: аналогично диаграммам взаимодействия компонентов, но с использованием методов (внутри того же класса). Таким образом, вы можете четко видеть, как изменение метода влияет на другие методы.

  • Глобальные или статические данные также могут усложнить тестирование.
  • Точка перехвата: место в коде, где вы можете обнаружить последствия определенного изменения. Полезно при написании тестов.

Тесты документируют фактическое текущее поведение системы.

Рассказывание историй для объяснения архитектуры

  • Грубая идея состоит в том, чтобы объяснить 2 или 3 основные идеи архитектуры в качестве первого подхода.
  • Вы объясняете, что такое элементы дизайна и как они взаимодействуют
  • Ваш первый подход будет намеренно расплывчатым, вы не будете лгать, вы просто будете скрывать некоторую сложность, чтобы иметь возможность объяснить более высокий уровень
  • Затем вы можете «детализировать», подробно объясняя концепции.

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

История дает нам ориентир.

Проблемы с большими классами

  • Проблемы планирования задач: чем больше обязанностей у класса, тем больше вам может понадобиться изменить его.
  • Низкое сцепление и высокая сплоченность всегда имеют значение, особенно для большого класса.

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

Устранение повторяющегося кода

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

  • Удаление дублированного кода требует покрытия тестами
  • Это также способ перегонки дизайна.
  • Принцип открытости/закрытости: код должен быть открыт для расширения, но закрыт для модификации.

Некоторые другие полезные практики

  • Заменить функцию указателем функции

Таким образом вы можете отделить реализацию, упростив ее тестирование/расширение/замену

  • Оттолкнуть зависимость

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

  • Подкласс и метод переопределения

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

  • Функция подтягивания

Сделав это, вы можете сосредоточиться на конкретной подтянутой функции (опять же, чтобы протестировать ее или изменить/расширить).