Поиск по сайту:

Что означает принцип открытости-закрытости для рефакторинга?


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

В своей книге 1988 года Объектно-ориентированное создание программного обеспечения профессор Бертран Мейер определил принцип открытости-закрытости как:

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

«Модуль будет называться закрытым, если он доступен для использования другими модулями. Это предполагает, что модулю дано четко определенное, стабильное описание (интерфейс в смысле сокрытия информации)».

Более лаконично это можно было бы выразить так:

Программные объекты (классы, модули, функции и т. д.) должны быть открыты для расширения, но закрыты для модификации.

Аналогичным образом (и параллельно выводам Мейера) Алистер Кокберн определил паттерн защищенной вариации:

«Определите точки прогнозируемых отклонений и создайте вокруг них стабильный интерфейс».

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

Препятствует ли принцип открытости-закрытости рефакторингу?

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

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

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

Давайте рассмотрим подход к решению этой загадки.

Как защитить клиентов от нежелательных изменений

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

Клиенты должны быть защищены от таких поломок. Единственный способ сделать это — ввести уровень абстракции между клиентами и службой или компонентом. На жаргоне разработки программного обеспечения мы называем этот уровень абстракции «интерфейсом» (или API).

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

Таким образом, вы вернетесь в свой комфортный мир итераций. Теперь вы совершенно свободны в рефакторинге, перекомпоновке кода и продолжении его перестановки в поисках более оптимального решения.

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

Как расширить возможности сервисов

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

Например, если первое приращение службы OrderPayment предлагает лишь базовые возможности (например, возможность обработки общей суммы заказа и расчета налога с продаж), следующее приращение можно безопасно добавить, соблюдая принцип Open -Закрытый принцип. Не нарушая связи между клиентами и сервисом OrderPayment, вы можете реорганизовать реализацию API OrderPayment, добавив новые блоки кода.

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

Статьи по данной тематике: