Код с запашко́м (код с душко́м, дурно пахнущий код англ. code smell) — термин, обозначающий код с признаками (запахами) проблем в системе. Был введён Кентом Беком[1] и использован Мартином Фаулером в его книге Рефакторинг. Улучшение существующего кода[1].
Запахи кодарефакторинга[2]. Существуют запахи, специфичные как для парадигм программирования, так и для конкретных языков. Основной проблемой, с которой сталкиваются разработчики при борьбе с запахами кода, является то, что критерии своевременности рефакторинга невозможно чётко формализовать без апелляции к эстетике и условному чувству прекрасного. Запахи кода — это не набор чётких правил, а описание мест, на которые нужно обращать внимание при рефакторинге[3]. Они легко обнаруживаются, но при этом не во всех случаях свидетельствуют о проблемах[1].
— это ключевые признаки необходимостиКод с запашком ведёт к распаду кода, разработчики должны стремиться к устранению запашков путём применения однократного или многократного рефакторинга[4]. В процессе рефакторинга происходит избавление от запахов кода, что обеспечивает возможность дальнейшего развития приложения с той же или большей скоростью. Отсутствие регулярного рефакторинга с течением времени способно полностью парализовать проект, поэтому запахи кода необходимо устранять на ранних стадиях[2]. Существуют инструменты поиска и исправления запахов кода[5], однако опыт показывает, что никакие системы показателей не могут соперничать с человеческой интуицией, основанной на информации[6].
Дублирование кода — это использование одинаковых структур кода в нескольких местах. Объединение этих структур позволит улучшить программный код[6].
Примеры дублирования и методы их устранения:
Среди объектных программ дольше всего живут программы с короткими методами. Чем длиннее процедура, тем труднее её понять. Если у метода хорошее название, то не нужно смотреть его тело[3].
Следует придерживаться эвристического правила: если ощущается необходимость что-то прокомментировать, нужно написать метод. Даже одну строку имеет смысл выделить в метод, если она нуждается в разъяснениях[7].
Когда класс реализует слишком обширную функциональность, стоит подумать о вынесении некоторой части кода в подкласс. Это избавит разработчиков от чрезмерного количества имеющихся у класса атрибутов и дублирования кода[7].
В длинных списках параметров трудно разбираться, они становятся противоречивыми и сложными в использовании. Использование объектов позволяет, в случае изменения передаваемых данных, модифицировать только сам объект. Работая с объектами, следует передавать ровно столько, чтобы метод мог получить необходимые ему данные[8].
Проблема возникает, когда при модификации в системе невозможно выделить определённое место, которое нужно изменить. Это является следствием плохой структурированности ПО[8] или программирования методом копирования-вставки.
При выполнении любых модификаций приходится вносить множество мелких изменений в большое число классов. «Стрельба дробью» похожа на «Расходящуюся модификацию», но является её противоположностью. Расходящаяся модификация имеет место, когда есть один класс, в котором производится много различных изменений, а «Стрельба дробью» — это одно изменение, затрагивающее много классов[9].
Метод обращается к данным другого объекта чаще, чем к собственным данным[3].
Фундаментальное практическое правило гласит: то, что изменяется одновременно, надо хранить в одном месте. Данные и функции, использующие эти данные, обычно изменяются вместе, но бывают исключения[10].
Группы данных, встречающихся совместно, нужно превращать в самостоятельный класс[10].
Хорошая проверка: удалить одно из значений данных и проверить, сохранят ли смысл остальные. Если нет, это верный признак того, что данные напрашиваются на объединение их в объект[10].
Проблема связана с использованием элементарных типов вместо маленьких объектов для небольших задач, таких как валюта, диапазоны, специальные строки для телефонных номеров и т. п.
Одним из очевидных признаков объектно-ориентированного кода служит сравнительно редкое использование операторов типа switch (или case). Часто один и тот же блок switch оказывается разбросанным по разным местам программы. При добавлении в переключатель нового варианта приходится искать все эти блоки switch и модифицировать их. Как правило, заметив блок switch, следует подумать о полиморфизме[12].
В коде с таким запашком всякий раз при порождении подкласса одного из классов приходится создавать подкласс другого класса[12].
Класс, затраты на существование которого не окупаются выполняемыми им функциями, должен быть ликвидирован[12].
Этот случай возникает, когда на определённом этапе существования программы обеспечивается набор механизмов, который, возможно, потребуется для некоторой будущей функциональности. В итоге программу становится труднее понимать и сопровождать[13].
Временные поля — это поля, которые нужны объекту только при определённых обстоятельствах. Такое положение вещей трудно для понимания, так как ожидается, что объекту нужны все его поля[14].
Цепочка вызовов появляется тогда, когда клиент запрашивает у одного объекта другой объект, другой объект запрашивает ещё один объект и т. д. Такие последовательности вызовов означают, что клиент связан с навигацией по структуре классов. Любые изменения промежуточных связей означают необходимость модификации клиента[13].
Чрезмерное использование делегирования может привести к появлению классов, у которых большинство методов состоит только из вызова метода другого класса[13].
«Неуместная близость» возникает тогда, когда классы чаще, чем следовало бы, погружены в закрытые части друг друга[15].
Два класса, в которых часть функциональности общая, но методы, реализующие её, имеют разные параметры[16].
Библиотеки через некоторое время перестают удовлетворять требованиям пользователей. Естественное решение — поменять кое-что в библиотеках, но библиотечные классы не изменять. Следует использовать методы рефакторинга, специально предназначенные для этой цели[16].
Классы данных — это классы, которые содержат только поля и методы для доступа к ним, это просто контейнеры для данных, используемые другими классами[16].
Если наследник использует лишь малую часть унаследованных методов и свойств родителя, это является признаком неправильной иерархии.
Часто комментарии играют роль «дезодоранта» кода, который появляется в нём лишь потому, что код плохой. Почувствовав потребность написать комментарий, попробуйте изменить структуру кода так, чтобы любые комментарии стали излишними[17].
Данная страница на сайте WikiSort.ru содержит текст со страницы сайта "Википедия".
Если Вы хотите её отредактировать, то можете сделать это на странице редактирования в Википедии.
Если сделанные Вами правки не будут кем-нибудь удалены, то через несколько дней они появятся на сайте WikiSort.ru .