Приветствую Вас ГостьВторник, 14.05.2024, 02:49

Каталог статей


Стив Макконнелл "Совершенный код". Рефакторинг

Важнейшей стратегией достижения цели Главного Правила Эволюции ПО является рефакторинг, который Мартин Фаулер определяет как «изменение внутренней структуры ПО без изменения его наблюдаемого поведения, призванное облегчить его понимание и удешевить модификацию»

Разумные причины выполнения рефакторинга

Код повторяется Повторение кода почти всегда говорит о неполной факторизации системы на этапе проектирования. Повторение кода заставляет параллельно изменять сразу несколько фрагментов программы и нарушает правило: «Копирование и вставка кода — следствие ошибки проектирования» 

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

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

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

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

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

Отдельные части класса изменяются независимо от других частей Иногда класс имеет две (или более) разных области ответственности. Если это так, вы заметите, что вы изменяете или одну часть класса, или другую, и лишь немногие изменения затрагивают обе части класса. Это признак того, что класс следует разделить на несколько классов в соответствии с отдельными областями ответственности.

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

Вам приходится параллельно изменять несколько иерархий наследования Если при создании каждого нового подкласса одного класса вам приходится создавать подкласс другого класса, вы имеете дело с особым видом параллельного изменения.

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

Родственные элементы данных, используемые вместе, не организованы в классы Если вы неоднократно используете один и тот же набор элементов данных, рассмотрите целесообразность объединения этих данных и выполняемых над ними операций в отдельный класс.

Метод использует больше элементов другого класса, чем своего собственного Это значит, что метод нужно переместить в другой класс и вызывать из старого класса.

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

По цепи методов передаются бродячие данные Данные, передаваемые в метод лишь затем, чтобы он передал их другому методу, называются «бродячими». Это не всегда плохо, но в любом случае спросите себя, согласуется ли передача конкретных данных с абстракцией, формируемой интерфейсом каждого из методов.

Объект-посредник ничего не делает Если роль класса сводится к перенаправлению вызовов методов в другие классы, подумайте, не устранить ли его и вызывать другие классы непосредственно.

Метод имеет неудачное имя Если методу присвоено плохое имя, измените определение метода, исправьте все его вызовы и перекомпилируйте программу.

Сложный код объясняется при помощи комментариев В важности комментариев трудно усомниться, но их не следует использовать для объяснения плохого кода. Старая мудрость гласит: «Не документируйте плохой код — перепишите его»

Программа содержит код, который может когда-нибудь понадобиться Программисты очень плохо угадывают, какая функциональность может потребоваться позднее. «Проектирование впрок» связано со многими предсказуемыми проблемами. Мнение экспертов по этому поводу однозначно: если вы хотите наилучшим образом подготовиться к будущим требованиям, не пишите  гипотетически нужный код, а уделите повышенное внимание ясности и понятности кода, который нужен прямо сейчас.

Отдельные виды рефакторинга

Замена магического числа на именованную константу Если вы используете численный или строковый литерал, скажем, 3.14, замените его именованной константой, такой как PI.

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

Встраивание выражения в код Замените промежуточную переменную, которой присваивается результат вычисления выражения, на само выражение.

Замена выражения на вызов метода Этот вид рефакторинга обычно служит для устранения из кода повторяющихся выражений.

Введение промежуточной переменной Присвойте результат вычисления выражения промежуточной переменной, имя которой резюмирует суть выражения.

Преобразование многоцелевой переменной в несколько одноцелевых переменных Если переменная используется более чем с одной целью (к частым подозреваемым относятся такие переменные, как i, j, temp и x), создайте для каждой из целей отдельную переменную, выбрав для нее более определенное имя.

Использование локальной переменной вместо параметра Если исключительно входной параметр метода служит в качестве локальной переменной, подумайте, не лучше ли создать для этого настоящую локальную переменную.

Преобразование элементарного типа данных в класс

Преобразование набора кодов в класс или перечисление

Преобразование массива в класс Если элементами массива являются разные типы, создайте класс, включающий поля для каждого элемента массива.

Инкапсуляция набора Если класс возвращает набор, наличие нескольких экземпляров набора может привести к проблемам с синхронизацией. Сделайте так, чтобы класс возвращал набор, допускающий только чтение, и создайте методы для добавления элементов в набор и их удаления.

Замена традиционной записи на класс данных Создайте класс, содержащий члены записи (record). Это позволит централизовать проверку ошибок, слежение за персистентностью и выполнение других операций, касающихся записи.

Рефакторинг на уровне отдельных операторов

Декомпозиция логического выражения Упростите логическое выражение, введя грамотно названные промежуточные переменные, документирующие суть выражения.

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

Консолидация фрагментов, повторяющихся в разных частях условного оператора Если в конце блока else содержится такой же фрагмент кода, что и в конце блока if, вынесите этот фрагмент за пределы оператора if-then-else.

Использование оператора break или return вместо управляющей переменной цикла Если для управления циклом используется такая переменная, как done, удалите ее и выполняйте выход из цикла при помощи оператора break или return.

Возврат из метода сразу после получения ответа вместо установки возвращаемого значения внутри вложенных операторов if-then-else Выход из метода сразу же после нахождения возвращаемого значения часто помогает облегчить чтение кода и снизить вероятность ошибок. Альтернативный вариант — установка возвращаемого значения и следование к выходу из метода через заторы операторов — может оказаться более сложным.

Замена условных операторов (особенно многочисленных блоков case) на вызов полиморфного метода Значительную часть логики, обычно включаемой при структурном программировании в блоки case, можно реализовать с помощью наследования в виде полиморфных методов.

Рефакторинг на уровне отдельных методов

Извлечение метода из другого метода Превратите фрагмент метода в отдельный метод.

Преобразование объемного метода в класс Если метод слишком велик, попробуйте превратить его в класс и разбить на несколько методов. Иногда это повышает удобочитаемость кода.

Замена сложного алгоритма на простой Этот вид рефакторинга пояснений не требует.

Добавление параметра Если метод должен получать из вызывающего кода больше информации, передавайте ее в форме дополнительного параметра.

Удаление параметра Если метод не нуждается в каком-то параметре, удалите его.

Отделение операций запроса данных от операций изменения данных Как правило, операции запроса данных не должны изменять состояние объекта. Если операция вроде GetTotals() (получение итоговой суммы) изменяет состояние объекта, разделите функциональность запроса и функциональность изменения состояния объекта, создав два отдельных метода.

Объединение похожих методов путем их параметризации Два похожих метода могут различаться только используемой в них константой. Объедините их в один метод и передавайте в него нужное значение как параметр.

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

Передача в метод целого объекта вместо отдельных полей Если вы передаете в метод несколько значений одного объекта, подумайте о таком изменении интерфейса метода, чтобы он принимал сразу весь объект.

Передача в метод отдельных полей вместо целого объекта Если вы создаете объект только затем, чтобы передать его в метод, подумайте о таком изменении метода, чтобы он принимал отдельные поля, а не весь объект.

Безопасный рефакторинг

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

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

Стремитесь ограничить объем отдельных видов рефакторинга Некоторые виды рефакторинга масштабнее других, к тому же не всегда можно точно сказать, что именно составляет «один вид рефакторинга». Чтобы четко представлять все следствия вносимых изменений, не раздувайте виды рефакторинга.

Выполняйте отдельные виды рефакторинга по одному за раз Некоторые виды рефакторинга сложнее других. За исключением самых простых случаев выполняйте все виды рефакторинга по одному за раз, компилируя и тестируя программу перед следующим видом рефакторинга.

Составьте список действий, которые вы собираетесь предпринять Естественным расширением Процесса Программирования с Псевдокодом является составление списка видов рефакторинга, которые приведут вас из точки А в точку Б. Составление такого списка поможет поддерживать каждое изменение в соответствующем контексте.

Составьте и поддерживайте список видов рефакторинга, которые следует выполнить позже Выполняя один вид рефакторинга, вы можете счесть необходимым еще один вид. Взявшись за него, вы можете обнаружить в коде недостатки, призывающие к третьему виду. Если изменение не требуется сию минуту, включите его в список изменений, которые следовало бы внести в программу когда-то, но не обязательно вносить прямо сейчас.

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

Выполняйте обзоры изменений Если обзоры важны при первоначальном написании кода, то при последующих изменениях их важность лишь повышается.

Плохие причины выполнения рефакторинга

Не рассматривайте рефакторинг как оправдание написания плохого кода с намерением исправить его позднее Рефакторинг — это изменение работоспособного кода, не влияющее на поведение программы. Программисты, которые возятся с плохим кодом, не выполняют рефакторинг — они занимаются хакерством.

Не рассматривайте рефакторинг как способ, позволяющий избежать переписывания кода Иногда код невозможно улучшить небольшими изменениями — его нужно выбросить и переписать с нуля.

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

Выполняйте рефакторинг при создании новых методов Создавая метод, проверьте, хорошо ли организованы связанные с ним методы. При необходимости выполните их рефакторинг.

Выполняйте рефакторинг при создании новых классов Создание нового класса часто подчеркивает недостатки имеющегося кода. Используйте эту возможность для рефакторинга других классов, тесно взаимодействующих с новым классом.

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

Выполняйте рефакторинг модулей, подверженных ошибкам Некоторые модули более подвержены ошибкам, чем другие. Есть ли в коде фрагмент, внушающий страх вам и всем остальным членам вашей группы, его стоит рассматривать их как мишени рефакторинга.

Выполняйте рефакторинг сложных модулей Другим подходом к рефакторингу является концентрация на модулях, имеющих максимальные оценки сложности

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

 

 

 

 

Категория: Стив Макконнелл "Совершенный код" | Добавил: leshic (16.11.2021)
Просмотров: 282 | Рейтинг: 0.0/0
Всего комментариев: 0
Имя *:
Email *:
Код *:
Вход на сайт
Поиск
Категории раздела
Стив Макконнелл "Совершенный код" [20]
Стив Макконнелл "Совершенный код"
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0