Статьи

Выявление запахов кода в Java

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

Индикация поверхности, которая обычно соответствует более глубокой проблеме в системе

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

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

В этом уроке мы рассмотрим некоторые из них.

1. Комментарии:

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

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

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

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

2. Дубликат кода:

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

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

Давайте попробуем придерживаться принципа СУХОЙ (не повторять себя) везде, где это возможно. Согласно принципу СУХОЙ , мы не должны переписывать функцию или функцию, которая уже написана.

3. Длинный метод:

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

Всякий раз, когда я вижу, что нарушаю это правило, я спрашиваю себя: «Этот метод делает только одну вещь (принцип SRP)?» , Если нет, то я пытаюсь логически разделить мой метод на что-то, что имеет больше смысла.

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

4. Большой класс:

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

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

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

5. Длинный список параметров:

Еще один похожий запах кода — длинные списки параметров. Метод с длинным списком параметров может быть сложным в использовании и увеличивает вероятность неправильных отображений из-за недосмотра:

1
2
3
4
public void doSomething(String name, int id, String deptCode, String regNumber) {
  
    ...
}

Решение здесь состоит в том, чтобы ввести объекты параметров, которые захватывают контекст. Итак, мы можем уточнить вышеуказанный метод как:

1
2
3
public void doSomething(Student student) {
    ...
}

Здесь мы достигли правильной инкапсуляции.

6. Класс данных:

Класс данных — это класс, который содержит только элементы данных вместе с их получателями и установщиками:

1
2
3
4
5
6
7
8
public class Student {
  
    private int id;
    private String name;
  
    //constructor, getters and setters
  
}

Это обычно указывает на то, что это не может быть хорошей абстракцией.

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

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

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

7. Дивергентный класс:

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

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

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

8. Цепочки сообщений:

Цепочка сообщений — это запах кода, когда мы вызываем метод для объекта, а затем вызываем другой метод для этого возвращаемого объекта и так далее:

1
int id = obj.getDept().getSubDept().getHOD().getId();

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

Обычно это также нарушает закон Деметры , который определяет, какие методы могут быть вызваны для хорошего объектно-ориентированного проектирования.

9. Дробовик Хирургия:

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

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

Мы можем устранить запах кода операции дробовика, перемещая методы вокруг. Если изменение требует от нас изменения методов в нескольких классах, мы должны спросить себя: «Должны ли эти методы объединяться в один или два класса?» а затем пусть наш инстинкт разработчика направит нас.

10. Особенность зависти:

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

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

11. Неуместная близость:

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

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

12. Примитивная одержимость:

Как следует из названия, мы иногда слишком полагаемся на примитивные типы. Хотя нам нужны примитивы в нашем коде, они должны существовать на самых низких уровнях кода.

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

13. Спекулятивная общность:

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

Agile Development способствует дизайну Just In Time. Наши проекты должны оставаться простыми и их должно быть достаточно для поддержки текущих функций. Требования пользователей часто быстро меняются, поэтому мы должны вводить обобщения только тогда, когда это необходимо. В противном случае мы можем в конечном итоге тратить наше время на проекты, которые в конечном итоге никогда не используются.

14. Отклоненный запрос:

Запах кода отклоненного запроса возникает, когда подкласс наследует что-то, но не нуждается в этом.

Если подклассы наследуют вещи, которые они не используют, они могут не быть подходящим подклассом для суперкласса:

01
02
03
04
05
06
07
08
09
10
11
12
13
public class Bird {
  
    void fly() {
        System.out.println("Flying!!");
    }
}
  
public class Ostrich extends Bird {
  
    void fly() {
        throw new IllegalStateException("An ostrich can't fly");  
    }
}

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

  • Либо не определяйте нежелательное поведение в суперклассе, либо
  • Создайте их как отдельные автономные классы

Вывод:

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

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

Опубликовано на Java Code Geeks с разрешения Шубхры Шриваставы, партнера нашей программы JCG . Смотрите оригинальную статью здесь: Идентификация запахов кода в Java

Мнения, высказанные участниками Java Code Geeks, являются их собственными.