Немного о рефакторинге

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

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

1. Избавление от временных переменных.

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

До:

После:

2. Замещение алгоритма

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

До:

После:

3. Передача объекта вместо его атрибутов

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

До:

После:

4. Введение поясняющих переменных в условиях

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

До:

После:

5. Извлечение метода

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

До:

После:

 6. Самостоятельная инкапсуляция атрибутов класса

Если в классе существует множество атрибутов открытых для прямого чтения и записи, то лучше изменить порядок доступа к ним через set и get методы. Плюсы: мы всегда знаем где и в каких местах происходит изменение (инициализация) атрибутов, возможность переопределения логики в дочерних классах.

До:

После:

7. Замена литералов и магических чисел константами

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

До:

После:

8. Разделение метода получения и изменения данных на отдельные методы

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

До:

После:

9. Параметризация метода

Бывают такие ситуации, когда несколько методов выполняют одни и те же действия, но с разными значениями внутри. Например, один метод увеличивает значение стоимости товара на 10, а другой – на 30 процентов. И тут конечно лучше было бы создать просто один метод, но для разных значений, который принимал бы параметр, сколько прибавлять процентов к стоимости – 10 или 30, а может и 50 и т.д. Отсюда и название приема – параметризация метода. Пример в данном случае будет лишним, из описания все и так понятно.

10. Перемещение методов и полей вверх по иерархии классов.

Предположим имеем иерархию классов: ZCL_MAN (человек) — абстрактный класс. Унаследованный от него класс ZCL_POST_MAN (почтальон) в котором есть открытый атрибут имени (gv_name), не унаследованный, а объявленный непосредственно в самом классе. Очевидно что каждый человек, несмотря на его должность имеет имя, благодаря встроенному в редактор классов рефакторинг ассистенту мы можем с легкостью переместить данный атрибут выше по иерархии в абстрактный класс. Для начала необходимо открыть класс ZCL_POST_MAN на изменение и перейти на вкладку атрибутов, далее нажать F7 (вызов ассистента).

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

11. Встраивание метода

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

12. Замена внутренней переменной вызовом метода

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

До:

После:

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

6 комментариев

  1. Интересно.

    На заметку… Видел что SAP иногда объявляет группы констант, через операторы begin of/end of. Правда жалко не хватает иногда групповых операций, типа IN.

      1. Именно… ну как пример, есть несколько типов заказов которые надо обработать в программе.

        CONSTANTS: BEGIN OF lc_OrderType,
        DirectSalse TYPE RSORDERTYPE VALUE ‘ZDR’, «Прямые продажи
        InDirectSales TYPE RSORDERTYPE VALUE ‘ZIDR’ «Простые непрямые продажи
        ShemeA TYPE RSORDERTYPE VALUE ‘ZSHA’, » бла бла бла

        ShemeZ TYPE RSORDERTYPE VALUE ‘ZSHZ’,
        END OF lc_OrderType.

        В коде соответственно

        IF -type = lc_OrderType-InDirectSales.

  2. Ну почему же странный? У каждого действия есть свои причины, возможно тут:
    — проще чистить переменные. (CLEAR: lc_OrderType.)
    — интереснее хранить все константы в группе, что бы не искать потом по коду объявленные переменные
    — при включенной подстановке в редакторе, автоматом выходят все вариант
    — что то другое..
    Ну а для использования IN, можно например так попробовать:

    DATA: lv_x TYPE lfart VALUE ‘ZDR’,
    lc_ordertype TYPE RANGE OF likp-lfart.

    lc_ordertype = ‘IEQ’.
    lc_ordertype-low = ‘ZDR’. «Прямые продажи
    APPEND lc_ordertype.

    lc_ordertype = ‘IEQ’.
    lc_ordertype-low = ‘ZIDR’. «Простые непрямые продажи
    APPEND lc_ordertype.

    IF lv_x IN lc_ordertype.
    WRITE ‘Ok’.
    ENDIF.

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

    1. Ну константы редко меняются исходя из названия. Чаще хранятся в пулах типов, либо как атрибуты интерфейсов если об ООП речь.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *