Полезные высказывания из книги "Рефакторинг. Улучшение существующего кода" Фаулера
Рефакторинг (refactoring) - изменение во внутренней структуре программного обеспечения, имеющие целью облегчить понимание его работы и упростить модификацию, не затрагивая наблюдаемого поведения.
Производить рефакторинг (refactor) - изменять структуру программного обеспечения, применяя ряд рефакторингов, не затрагивая его поведения.
Рефакторинг предоставляет технологию приведения кода в порядок, осуществляемую в более эффективном и управляемом стиле.
При каждой возможности проводить тестирование.
Цель рефакторинга - упростить понимание и модификацию ПО.
Оптимизация производительности часто затрудняет понимание кода.
Рефакторинг не меняет видимого поведения ПО.
Рефакторинг улучшает композицию ПО.
Изменение размера образа программы в памяти редко имеет значение.
Удаление дублирующегося кода улучшает композицию.
Рефакторинг облегчает понимание ПО.
Рефакторинг делает код легким для чтения.
Рефакторинг позволяет увидеть в коде больший объем системы.
Рефакторинг помогает найти ошибки.
Рефакторинг ускоряет понимание программ.
Рефакторингом следует заниматься постоянно понемногу.
Сначала необходимость рефакторинга будет неприятна.
Чаще всего рефакторинг начинается с необходимости добавления в ПО новой функции.
Рефакторинг - процесс быстрый и ровный.
Получение сообщения об ошибке - причина провести рефакторинг.
Проводить рефакторинг при разборе кода.
Рефакторинг облегчает модификацию.
Рефакторинг способствует получению более конкретных результатов от разбора кода.
Использовать UML и CRC-карты при разборе дизайна кода.
Рефакторинг разделяет большие объекты на несколько меньших
.
Благодаря помещению отдельного программного слоя между объектной моделью и моделью базы данных можно отделить модификации двух разных моделей друг от друга.
Если изменяемый интерфейс используется недоступным для изменения кодом, то из старого интерфейса вызывать новый, пометив старый как устаревший.
Не нужно предоставлять интерфейсы, которые не требуются.
Не публиковать интерфейсы раньше срока.
Определять родительский класс исключения для пакета в целом.
Представлять себе возможный рефакторинг.
Перед началом рефакторинга код должен выполняться в основном корректно, иначе - переписать код с нуля.
Рефакторинг должен подразумевать его завершение.
Окончание проекта может быть причиной отложения рефакторинга.
Программа весьма отличается от физического механизма.
Рефакторинг может быть полной заменой предварительному проектированию.
При рефакторинге от предварительного проектирования требуется приемлемое решение, а не единственно правильное.
Гибкие решения сложнее обычных.
Даже если точно известно устройство системы, не заниматься гаданием, а провести замеры.
Секрет создания быстрых программ: написать настраиваемую программу, а затем настроить так, чтобы достичь приемлемой скорости.
Подходы написания быстрых программ:
при декомпозиции каждому компоненту выделяется бюджет ресурсов - по времени и памяти; компонент не выходит за рамки бюджета, хотя разрешен обмен ресурсами;
постоянное внимание и попытки программиста сделать систему производительнее.
Если в равной мере оптимизировать весь код, то 90% оптимизации будет произведено впустую.
Большая часть времени расходуется небольшой частью кода.
Запуск в конце разработки профайлера и выявление затратных компонентов.
Рефакторинг выигрывает время для оптимизации.
Рефакториг обеспечивает более высокое разрешение для анализа производительности.
Рефакторинг возник в 80-х.
Одно и то же выражение в двух методах одного класса - необходимо выделение метода.
Одно и то же выражение в подклассах одного уровня - необходимо выделение метода с последующим подъемом поля.
Если код похож, но не совпадает полностью, нужно применить выделение метода для отделения совпадающих фрагментов от различающихся, затем проверить применимость формирования шаблона метода.
Если два метода делают одно и то же с помощью разных алгоритмов, можно выбрать более четкий из алгоритмов и применить замещение алгоритма.
Если дублирующийся код находится в двух разных классах, попробовать применить выделение классов в одном классе, а затем использовать новый компонент в другом.
Следует активнее применять декомпозицию методов.
В 99% случаев, чтобы укоротить метод, требуется лишь выделение метода.
Устранить временные переменные метода заменой временной переменной вызовом метода.
Длинные списки параметров метода сокращать введением граничного объекта, сохранением всего объекта.
Если не удалось удалить все лишние временные переменные и параметры, применить замену метода объектом метода.
Даже одну строку имеет смысл выделитьв метод, если она нуждается в комментарии.
Для условных выражений делать выделение с помощью декомпозиции условных операторов.
Содержащийся в цикле код - отдельный метод.
При большом числе атрибутов класса применять выделение класса.
Одинаковые префиксы или суффиксы подмножества переменных - необходимость создания компонента.
Для создания компонента как подкласса использовать выделение подкласса.
Если класс не использует постоянно все переменные своего экземпляра - применить выделение класса и выделение подкласса несколько раз.
Для класса с чрезмерным объемом кода применить выделение класса или выделение подкласса, а для дальнейшего разделения - применить выделение интерфейса и выявить ещё части.
При необходимости хранения копий некоторых данных в двух местах и обеспечения их согласованности применить дублирование видимых данных.
Класс GUI выделить с его данными и поведением в отдельный объект предметной области.
Работая с объектами, следует передавать методу не все, а столько, чтобы он мог добраться до всех необходимых ему данных.
Для получения данных в одном параметре путем вызова метода применитьзамену параметра вызовом метода объекта, который уже известен.
Чтобы группу данных, полученных от объекта, заменить самим объектом, применить сохранение всего объекта.
Если есть несколько элементов данных без логического объекта, применить введение граничного объекта.
Если не нужно создавать зависимость между вызываемым и крупным объектом, можно передавать все в параметрах.
Если класс часто модифицируется различными способами по разным причинам, необходимо разбиение на классы.
Определить, что изменяется по одной причине в классе, и применить выделение класса.
Когда при выполнении любых модификаций приходится модифицировать множество классов с небольшими изменениями, применить перемещение метода, перемещение поля, чтобы свести все изменения в один класс.
Чтобы поместить связку методов в один класс, использовать встраивание класса.
Если метод больше интересуется не тем классом, в котором он находится применить перемещение метода или выделение метода для части кода этого метода.
Если метод использует функции нескольких классов, то разбить его выделением метода.
То, что изменяется одновременно, надо хранить в одном месте (для исключений - паттерны стратегия и посетитель).
Связки данных, встречающихся совместно, надо превращать в самостоятельный класс: сначала найти эти группы в виде полей, применить к ним выделение метода (в отдельный класс), затем к сигнатурам методов применить введение граничного объекта или сохранение всего объекта.
Элементарные типы убирать применением замены значения данных объектом или замену кода типа классом.
Для условных операторов, зависящих от кода типа, применять замену кода типа подклассами или замену кода типа состоянием, стратегией.
При наличии группы полей, которые должны находиться вместе, применять выделение класса.
Для примитивов в типах параметров применять введение граничного объекта.
Если обнаружена разборка на части массива, применить замену массива объектом.
Для выделения переключателя switch использовать выделение метода, затем перемещение метода, затем пробовать применить замену кода типа подклассами, замену кода типа состоянием или стратегией, замену условного оператора полиморфизмом.
Если есть лишь несколько вариантов переключателя, управляющих одним методом, и не предполагается их изменение, применить замену параметра явными методами.
Если одним из вариантов является null, применить введение объекта Null.
Чтобы заставить экземпляры одной иерархии ссылаться на экземпляры другой, применить перемещение меода и перемещение поля.
При наличии подклассов с недостаточными функциями применить свертывание иерархии, встраивание класса.
Если есть аабстрактные классы, не приносящие большой пользы, применить сворачивание иерархии.
Ненужное делегирование можно устранить с помощью встраивания класса.
К методам с неиспользуемыми параметрами применить удаление параметров.
К методам со странными абстрактными именами применить переименование метода.
Для непонятных переменных применять выделение класса.
Условно выполняемый код удалить, применив введение объекта Null.
Для алгоритма, использующего несколько переменных, применить выделение класса.
Для цепочки сообщений применить сокрытие делегирования (для конечного объекта можно применить выделение метода, перемещение метода и передвинуть использующий его код вниз по цепочке).
Для интерфейса, в котором половина методов делегирует обработку другому классу, применить удаление посредника.
При наличии нескольких методов, не выполняющих большой работы, применить встраивание метода и поместить в вызывающий метод.
Посредника преобразовать в подкласс реального класса можно заменой делегирования наследованием.
С помощью перемещения метода и перемещения поля можно разделить части и уменьшить близость классов, затем применить замену двунаправленной связи однонаправленной, выделением класса, сокрытием делегирования.
При чрезмерном наследовании применить замену наследования делегированием.
Ко всем методам, выполняющим одинаковые действия по различающимся сигнатурам, применить переименование метода, перемещение метода, выделение родительского класса.
Если в библиотечный класс нужно включить 1-2 новых метода, то применить введение внешнего метода.
Если в библиотечный класс нужно включить много новых методов - применить введение локального расширения.
К открытым полям классов применить инкапсуляцию поля.
К открытым полям коллекций применить инкапсуляцию коллекций.
Ко всем полям, значение которых не должно изменяться, применить удаление метода установки значения.
Методы доступа переместить в класс данных, применив перемещение метода, выделение метода.
К методам получения и установки значений полей применить сокрытие метода.
При неправильной иерархии наследования применить спуск метода, спуск поля, создав новый класс на одном уровне с потомком, вытолкнуть в него бездействующие методы.
Можно делать все родительские классы абстрактными.
Для разрушения иерархии при неиспользовании интерфейса родительского класса применить замену наследования делегированием.
Чтобы избавиться от комментариев к блоку, использовать выделение метода, переименование метода, введение утверждения.
Перед рефакторингом должны быть созданы тесты.
В каждом классе должен быть свой метод, с помощью которого он может себя протестировать.
Тестовые данные - test fixture.
Проверять, действительно ли тест проверяет то, что требуется.
Получив сообщение об ошибке, начать с тести модуля, показывающего её.
Тестировать те области, возможность ошибок в которых выше.
Проверять, что ожидаемые ошибки происходят в надлежащем порядке.
Проверять тестами границы.
Для представления денежных величин использовать паттерн количество.
Выделение метода и другие рефакторинги - смотреть по шагам в приложении книги.
Производить рефакторинг (refactor) - изменять структуру программного обеспечения, применяя ряд рефакторингов, не затрагивая его поведения.
Рефакторинг предоставляет технологию приведения кода в порядок, осуществляемую в более эффективном и управляемом стиле.
При каждой возможности проводить тестирование.
Цель рефакторинга - упростить понимание и модификацию ПО.
Оптимизация производительности часто затрудняет понимание кода.
Рефакторинг не меняет видимого поведения ПО.
Рефакторинг улучшает композицию ПО.
Изменение размера образа программы в памяти редко имеет значение.
Удаление дублирующегося кода улучшает композицию.
Рефакторинг облегчает понимание ПО.
Рефакторинг делает код легким для чтения.
Рефакторинг позволяет увидеть в коде больший объем системы.
Рефакторинг помогает найти ошибки.
Рефакторинг ускоряет понимание программ.
Рефакторингом следует заниматься постоянно понемногу.
Сначала необходимость рефакторинга будет неприятна.
Чаще всего рефакторинг начинается с необходимости добавления в ПО новой функции.
Рефакторинг - процесс быстрый и ровный.
Получение сообщения об ошибке - причина провести рефакторинг.
Проводить рефакторинг при разборе кода.
Рефакторинг облегчает модификацию.
Рефакторинг способствует получению более конкретных результатов от разбора кода.
Использовать UML и CRC-карты при разборе дизайна кода.
Рефакторинг разделяет большие объекты на несколько меньших
.
Благодаря помещению отдельного программного слоя между объектной моделью и моделью базы данных можно отделить модификации двух разных моделей друг от друга.
Если изменяемый интерфейс используется недоступным для изменения кодом, то из старого интерфейса вызывать новый, пометив старый как устаревший.
Не нужно предоставлять интерфейсы, которые не требуются.
Не публиковать интерфейсы раньше срока.
Определять родительский класс исключения для пакета в целом.
Представлять себе возможный рефакторинг.
Перед началом рефакторинга код должен выполняться в основном корректно, иначе - переписать код с нуля.
Рефакторинг должен подразумевать его завершение.
Окончание проекта может быть причиной отложения рефакторинга.
Программа весьма отличается от физического механизма.
Рефакторинг может быть полной заменой предварительному проектированию.
При рефакторинге от предварительного проектирования требуется приемлемое решение, а не единственно правильное.
Гибкие решения сложнее обычных.
Даже если точно известно устройство системы, не заниматься гаданием, а провести замеры.
Секрет создания быстрых программ: написать настраиваемую программу, а затем настроить так, чтобы достичь приемлемой скорости.
Подходы написания быстрых программ:
при декомпозиции каждому компоненту выделяется бюджет ресурсов - по времени и памяти; компонент не выходит за рамки бюджета, хотя разрешен обмен ресурсами;
постоянное внимание и попытки программиста сделать систему производительнее.
Если в равной мере оптимизировать весь код, то 90% оптимизации будет произведено впустую.
Большая часть времени расходуется небольшой частью кода.
Запуск в конце разработки профайлера и выявление затратных компонентов.
Рефакторинг выигрывает время для оптимизации.
Рефакториг обеспечивает более высокое разрешение для анализа производительности.
Рефакторинг возник в 80-х.
Одно и то же выражение в двух методах одного класса - необходимо выделение метода.
Одно и то же выражение в подклассах одного уровня - необходимо выделение метода с последующим подъемом поля.
Если код похож, но не совпадает полностью, нужно применить выделение метода для отделения совпадающих фрагментов от различающихся, затем проверить применимость формирования шаблона метода.
Если два метода делают одно и то же с помощью разных алгоритмов, можно выбрать более четкий из алгоритмов и применить замещение алгоритма.
Если дублирующийся код находится в двух разных классах, попробовать применить выделение классов в одном классе, а затем использовать новый компонент в другом.
Следует активнее применять декомпозицию методов.
В 99% случаев, чтобы укоротить метод, требуется лишь выделение метода.
Устранить временные переменные метода заменой временной переменной вызовом метода.
Длинные списки параметров метода сокращать введением граничного объекта, сохранением всего объекта.
Если не удалось удалить все лишние временные переменные и параметры, применить замену метода объектом метода.
Даже одну строку имеет смысл выделитьв метод, если она нуждается в комментарии.
Для условных выражений делать выделение с помощью декомпозиции условных операторов.
Содержащийся в цикле код - отдельный метод.
При большом числе атрибутов класса применять выделение класса.
Одинаковые префиксы или суффиксы подмножества переменных - необходимость создания компонента.
Для создания компонента как подкласса использовать выделение подкласса.
Если класс не использует постоянно все переменные своего экземпляра - применить выделение класса и выделение подкласса несколько раз.
Для класса с чрезмерным объемом кода применить выделение класса или выделение подкласса, а для дальнейшего разделения - применить выделение интерфейса и выявить ещё части.
При необходимости хранения копий некоторых данных в двух местах и обеспечения их согласованности применить дублирование видимых данных.
Класс GUI выделить с его данными и поведением в отдельный объект предметной области.
Работая с объектами, следует передавать методу не все, а столько, чтобы он мог добраться до всех необходимых ему данных.
Для получения данных в одном параметре путем вызова метода применитьзамену параметра вызовом метода объекта, который уже известен.
Чтобы группу данных, полученных от объекта, заменить самим объектом, применить сохранение всего объекта.
Если есть несколько элементов данных без логического объекта, применить введение граничного объекта.
Если не нужно создавать зависимость между вызываемым и крупным объектом, можно передавать все в параметрах.
Если класс часто модифицируется различными способами по разным причинам, необходимо разбиение на классы.
Определить, что изменяется по одной причине в классе, и применить выделение класса.
Когда при выполнении любых модификаций приходится модифицировать множество классов с небольшими изменениями, применить перемещение метода, перемещение поля, чтобы свести все изменения в один класс.
Чтобы поместить связку методов в один класс, использовать встраивание класса.
Если метод больше интересуется не тем классом, в котором он находится применить перемещение метода или выделение метода для части кода этого метода.
Если метод использует функции нескольких классов, то разбить его выделением метода.
То, что изменяется одновременно, надо хранить в одном месте (для исключений - паттерны стратегия и посетитель).
Связки данных, встречающихся совместно, надо превращать в самостоятельный класс: сначала найти эти группы в виде полей, применить к ним выделение метода (в отдельный класс), затем к сигнатурам методов применить введение граничного объекта или сохранение всего объекта.
Элементарные типы убирать применением замены значения данных объектом или замену кода типа классом.
Для условных операторов, зависящих от кода типа, применять замену кода типа подклассами или замену кода типа состоянием, стратегией.
При наличии группы полей, которые должны находиться вместе, применять выделение класса.
Для примитивов в типах параметров применять введение граничного объекта.
Если обнаружена разборка на части массива, применить замену массива объектом.
Для выделения переключателя switch использовать выделение метода, затем перемещение метода, затем пробовать применить замену кода типа подклассами, замену кода типа состоянием или стратегией, замену условного оператора полиморфизмом.
Если есть лишь несколько вариантов переключателя, управляющих одним методом, и не предполагается их изменение, применить замену параметра явными методами.
Если одним из вариантов является null, применить введение объекта Null.
Чтобы заставить экземпляры одной иерархии ссылаться на экземпляры другой, применить перемещение меода и перемещение поля.
При наличии подклассов с недостаточными функциями применить свертывание иерархии, встраивание класса.
Если есть аабстрактные классы, не приносящие большой пользы, применить сворачивание иерархии.
Ненужное делегирование можно устранить с помощью встраивания класса.
К методам с неиспользуемыми параметрами применить удаление параметров.
К методам со странными абстрактными именами применить переименование метода.
Для непонятных переменных применять выделение класса.
Условно выполняемый код удалить, применив введение объекта Null.
Для алгоритма, использующего несколько переменных, применить выделение класса.
Для цепочки сообщений применить сокрытие делегирования (для конечного объекта можно применить выделение метода, перемещение метода и передвинуть использующий его код вниз по цепочке).
Для интерфейса, в котором половина методов делегирует обработку другому классу, применить удаление посредника.
При наличии нескольких методов, не выполняющих большой работы, применить встраивание метода и поместить в вызывающий метод.
Посредника преобразовать в подкласс реального класса можно заменой делегирования наследованием.
С помощью перемещения метода и перемещения поля можно разделить части и уменьшить близость классов, затем применить замену двунаправленной связи однонаправленной, выделением класса, сокрытием делегирования.
При чрезмерном наследовании применить замену наследования делегированием.
Ко всем методам, выполняющим одинаковые действия по различающимся сигнатурам, применить переименование метода, перемещение метода, выделение родительского класса.
Если в библиотечный класс нужно включить 1-2 новых метода, то применить введение внешнего метода.
Если в библиотечный класс нужно включить много новых методов - применить введение локального расширения.
К открытым полям классов применить инкапсуляцию поля.
К открытым полям коллекций применить инкапсуляцию коллекций.
Ко всем полям, значение которых не должно изменяться, применить удаление метода установки значения.
Методы доступа переместить в класс данных, применив перемещение метода, выделение метода.
К методам получения и установки значений полей применить сокрытие метода.
При неправильной иерархии наследования применить спуск метода, спуск поля, создав новый класс на одном уровне с потомком, вытолкнуть в него бездействующие методы.
Можно делать все родительские классы абстрактными.
Для разрушения иерархии при неиспользовании интерфейса родительского класса применить замену наследования делегированием.
Чтобы избавиться от комментариев к блоку, использовать выделение метода, переименование метода, введение утверждения.
Перед рефакторингом должны быть созданы тесты.
В каждом классе должен быть свой метод, с помощью которого он может себя протестировать.
Тестовые данные - test fixture.
Проверять, действительно ли тест проверяет то, что требуется.
Получив сообщение об ошибке, начать с тести модуля, показывающего её.
Тестировать те области, возможность ошибок в которых выше.
Проверять, что ожидаемые ошибки происходят в надлежащем порядке.
Проверять тестами границы.
Для представления денежных величин использовать паттерн количество.
Выделение метода и другие рефакторинги - смотреть по шагам в приложении книги.