Статьи

Рефакторинг практического кода, часть 3 — расширяемость

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

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

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

Логическая расширяемость

1. Следуют ли большинство блоков кода нормальному логическому потоку?

Когда вы имеете дело с небольшими логическими проблемами, убедитесь, что вы используете правильные конструкции (если, for, foreach, while и т. Д.). Под «правильными конструкциями» я подразумеваю, что вы должны использовать для работы наиболее логичную и общепринятую языковую функцию. Например, цикл по простым массивам должен выполняться с помощью foreach; это обычный нормальный поток, тогда как использование цикла for для такой простой итерации не является нормальным потоком в языке, подобном PHP. Использование while еще более чуждо для такой простой задачи. У вас могут быть свои причины, и в этом случае отзовитесь от предыдущей части о документировании любой таможенной практики, и вы в порядке.

2. Соответствуют ли сложные решения проблем стандартным шаблонам проектирования?

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

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

Модульная конструкция

1. Следуют ли структуры кода модульному дизайну?

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

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

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

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

2. Является ли зависимость модулей минимальной?

Модули должны быть максимально автономными. Зависимости программных модулей являются естественными и хорошими, например, модуль «Инвентаризация» зависит от модуля «Бухгалтерский учет» для получения однородной системы электронной коммерции, но многие жесткие зависимости являются плохими. Они значительно затрудняют отладку и развертывание.

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

Разделение и инкапсуляция

1. Достаточно ли отделены функции, методы и классы?

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

2. Достаточно ли отделены модули и компоненты?

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

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

Резюме

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

Изображение через Fotolia