Плохой стиль в коде В рамках данной темы рассмотрим некоторые наиболее часто встречающиеся «проблемные» места в программном коде. Здесь под проблемностью понимается не наличие синтаксических либо логических ошибок, но потенциальная опасность для участка кода при изменении, масштабировании системы либо ее наследовании другими разработчиками. Повторяющийся код Это – своебразный лидер среди плохих приемов при кодировании. Если вы видите однотипный код в нескольких местах программы, вы можете быть уверены на 100%, что код программы может и должен быть улучшен. Простейший пример проблемы с повторяющимся кодом – наличие одного и того же выражения в двух методах одного и того же класса. Слишком длинный метод Программы, написанные на объекктно-ориентированном языке, живут дольше и лучше, если они состоят из коротких методов. Поначалу начинающим программистам в таких языках кажется, что программа состоит из последовательности вызовов разных методов, однако позже они начинают ценить каждый из таких коротких методов. Чем более длинной является метод, тем сложнее понять, в чем заключается его назначение и как он работает. Одной из техник, которая позволяет определить необходимость разбиения метода на составляющие, является следующая (предложенная Фаулером): если вы хотите прокомментировать фрагмент кода в методе, лучше организуйте новый метод и дайте ему хорошо понятное наименование. Порой это можно делать даже для одной строчки кода, и даже в тех случаях, когда вызов нового метода будет длиннее исходней строчки кода. Также хорошими кандидатами для вынесения в новые методы являются условия и циклы. Слишком большой класс Сюда относятся классы, для которых в коде программы создается слишком много объектов (экземпляров), а также классы, которые включают слишком много кода. В первом случае класс может быть уменьшен путем извлечения подкласса либо интерфейса. Во втором – могут быть подвергнуты декомпозиции слишком длинные методы внутри большого класса. Если же слишком большой класс относится к пользовательскому интерфейсу, полезным может быть вынесение данных и описания поведения в отдельные объекты. Слишком длинный список параметров При объектно-ориентированном программировании нет необходимости передавать в методы все данные, которые требуются для метода. Метод может взять данные у своего экземпляра класса, либо же обратиться к атрибутам другого класса. Сокращение списков параметров методов приводит к улучшению понимания программного кода. Из данного правила существует исключение, когда разработчик явно не хочет создавать зависимость от вызываемого объекта путем обращения из метода к его атрибутам. В этом случае обоснованным является передача требуемых значений в виде параметров метода. Расходящиеся изменения Под расходящимися изменениями понимается необходимость изменения класса различными способами в различных ситуациях. К примеру, если в классе регулярно возникает необходимость изменения нескольких методов при переходе на новую базу данных, а также смена нескольких других методов при смене локализации – вероятно, необходимо разделить класс на два. В результате, каждый из полученных классов будет изменяться лишь при однотипных изменениях во внешней системе. Извлечение дроби Эта ситуация обратна предыдущей. При изменении во внешней системе становится необходимым внести множество мелких изменений в различные методы нескольких классов. В итоге становится тяжело отследить все эти изменения, высока вероятность пропустить важное изменение на фоне множества мелких. Для двух последних проблемных ситуаций общим выходом является установление соответствия 1:1 между возможными изменениями во внешней системе и классами кода. Зависть к чужим данным Эта ситуация возникает, когда метод одного класса требует для своей работы значительных объемов данных (числа переменных) из другого класса или нескольких классов. Наиболее простым решением может быть перенос метода в тот класс, к данным которого он испытывает наибольшую зависть; существуют также и другие методы для более сложных случаев, основанные на применении различных шаблонов проектирования. Заросли данных Часто бывает, что различные переменные постоянно оказываются вместе в различных вызовах методов, полях классов и т.д. Напрашивается идея о вынесении их в отдельный класс и упрощении кода таким образом. Критерием для проверки такой возможности может быть такой: если удалить одну из переменных, будут ли оставшиеся иметь смысл сами по себе? Использование выражений switch (case) Для обїектно-ориентированного кода характерным является редкое использование данных операторов. Проблема с оператором switch как правило связана с повторяющимся кодом – часто одинаковый или схожий оператор встречается в различных метсах в коде. Если же нужно добавить еще одно условие в оператор – его необходимо добавить во всех случаях, где он встречается. В объектно-ориентированном программировании подобные проблемы решаются при помощи использования полиморфизма. Параллельные иерархии наследования Это частный случай извлечения дроби. Ситуация, в которой при наследовании от какогото класса необходимо также провести аналогичное наследование от другого класса. Ленивый класс Каждый из создаваемых классов является дорогим в смысле его разработки, тестирования и поддержки. Необходимо избегать классов, которые не стоят затраченных на них усилий. Например, класс, ставший ненужным в результате рефакторинга, либо класс, связанный с запланированными изменениями, от кторых в итоге пришлось отказаться. Сомнительная универсализация Довольно часто при разработке ПО встречается ситуация, когда в начале проекта принимается решение заложить в систему средства для реализации функций, которые явно не требуются, но могут появиться в результате обобщения востребованных в данный момент функций. Порой это приводит к серьезным усложнениям кода. Если же в итоге окажется, что все эти ухищрения окажутся бесполезными, от них стоит отказаться в определенный момент. Данная проблема может быть выявлена так: если единственными пользователями какоголибо класса являются тестовые примеры (test cases). В этом случае можно удалить и класс, и тестовые примеры. Однако если класс лишь поддерживает выполнение какого-либо тестового примера, который, в свою очередь, проверяет важную функциональность, удалять такой класс не надо. Временное поле Иногда в классе часть полей не определены, поскольку их значение присваивается лишь в некоторых случаях, например, в определенных ветвях сложного алгоритма. Смысл таких классов довольно трудно понять, и сложным также является их последующее использование. Цепочки сообщений Такая ситуация возникает, когда объект спрашивает другой объект о некотором значении; тот, в свою очередь образается к третьему объекту, тот – к четвертому, и т.д. Например, это может выглядеть как последовательность вызовов getThis. Промежуточное звено Примером является ситуация, когда вы спрашиваете у начальника, свободен ли он в определенное время, а начальник обращается для ответа на вопрос к своему ежедневнику. Фактически, начальник делегирует свой «метод» «классу» еженедельника. При этом вам все равно, есть ли у начальника еженедельник или нет, вы об этом ничего не знаете. Со временем может оказаться, что большая часть методов класса ничего не делает, а лишь делегирует свои функции другому классу. В этом случае целесообразно удалить это промежуточное звено и обращаться напрямую к носителю необходимых данных. Неестественная близость Иногда классы оказываются связаны между собой слишком тесно. Например, при наследовании подклассы стремятся узнать слишком много о своих родителях. Альтернативные классы с разными интерфейсами Часто методы имеют разные сигнатуры, но делают одно и то же. Классы данных Это классы, которые имеют поля, методы get, set для них, и ничего более. Такие классы являются тупыми хранителями данных и практически наверняка они обрабатываются из других классов со слишком большими недостатками в коде. Следует добавить в такие классы некоторую функциональность, которая позволяла бы им нести больше ответственности за хранимые данные. Отказ в наследстве Часто подклассы не нуждаются в огромном количестве методов, которые они могут унаследовать, а используютлишь малую их часть. Такая ситуация может вынудить пересмотреть всю иерархию. Комментарии Сами по себе комментарии, конечно же, не являются плохим стилем. Однако часто обильные комментарии в коде подчеркивают то, что код вокруг них плохо, т.е. непонятно написан. Часто после внесения улучшений в код отпадает необходимость в соответствующих комментариях, и их можно удалить.