Комментарии 6
Статья называется
как сохранить обратную совместимость с помощью SOLID
Дальше вы пишете
В этой статье разберемся, как вносимые изменения нарушают эти правила и как это исправить.
А потом вы пытаетесь сохранить обратную совместимость нарушением этого самого SOLID. Например:
Установка дефолтного значения не помогает избежать ошибки. Решением является создать отдельный инициализатор / метод.
Первая попавшаяся статья с Хабра гласит, что вы нарушили open-closed принцип тем, что создали дублирующий метод с дополнительными параметрами, которые еще и могут не использоваться:
https://habr.com/ru/amp/publications/811305/
Да, я понимаю, что для обеспечения обратной совместимости без этого не обойтись. Нет, это уже не SOLID. И вы еще почему-то не помечаете лишние методы deprecated
Давайте разбираться. Почему Вы считаете, что принцип нарушен?
Добавление нового свойства и инициализатора не меняет старый контракт – он закрыт для изменения. Но при этом мы в него добавили что-то новое, на что клиенты не обязаны завязываться – мы его расширили. Старых клиентов это не затронуло, новые могут пользоваться расширением. Мы выполнили оба условия принципа. Почему Вы считаете, что не выполнили?
Deprecated как раз поэтому и не используем. Это сломает старый контракт, мы запретим использовать старый метод (closed), которым пользовалась куча клиентов - это спровоцирует их на ненужные изменения и сильно удорожит разработку. Главная цель OCP как раз в том, чтобы минимизировать такие бесполезные изменения. Зачем обязывать клиентов использовать новый контракт, если их и старый устраивает и они получают необходимое им и без нового параметра? Таким образом, мы позволяем старым клиентам работать со старым контрактом, для новых (которым нужен новый параметр и расширенный функционал) мы завели новый. При этом во внутренней реализации наш старый метод будет просто вызывать новый, но с дефолтным значением вновь добавленного параметра. Этим мы избегаем дублирования и повышения стоимости поддержки нашего кода.
вы путаете deprecated и deleted. Deprecated только покажет warning о том, что метод устарел.
Суть принципа OCP:
A class should be open for extension but closed for modification. You should be able to add new features without modifying existing code.
Violation: Modifying existing code instead of extending it for new features.
Correction: Use abstraction, inheritance, and polymorphism to allow for extension.
Где здесь указано, что OCP распространяется только на "контракты"? Или есть какая-то другая интерпретация OCP? В вашем примере вы не только добавляете реализацию нового метода, но и модифицируете старый метод так, чтобы он вызывал новый с лишним параметром.
И почему вы говорите, что избегаете дублирования кода? После изменений у вас методов стало в два раза больше, причем половина из них оставлена для совместимости и просто "перевязывает" новые методы с пустыми параметрами.
В моем понимании OCP (да и SOLID в целом) работает ровно до тех пор пока, вам не нужно менять внутреннее устройство кода. Да, вы не могли предусмотреть эти правки, когда закладывали архитектуру приложения, но это не отменяет того факта, что с этими правками вы в любом случае нарушаете OCP.
Или есть какая-то другая интерпретация OCP?
Попробовал загуглить, не удалось найти Вашу интерпретацию. Но в Википедии интерпретация другая, как раз на интерфейсы (я их назвал контрактами в сообщении выше). Ссылается википедия на первоисточник – на книгу Object-Oriented Software Construction и её автора Б.Мейера. К сожалению, оригинал не читал, но что-то мне подсказывает, что Википедия сильно не исказила смысл.
И почему вы говорите, что избегаете дублирования кода?
В принципе я уже ответил на этот вопрос. Сам код в единственном экземпляре. Есть лишь 2 интерфейса (2 контракта, 2 метода), которые этот код вызывают. Это чистое следование принципу сегрегации интерфейсов, который: а) самим эпплом активно используется (пруф). б) очень помогает принципу OCP, и в связке с ним дает вот такие существенные экономические эффекты.
с этими правками вы в любом случае нарушаете OCP.
Согласен. Если опереться на приведенное из Википедии определение, то по хорошему мы должны были оставить старый класс нетронутым полностью для старых клиентов и завести новый для новых. Новые клиенты должны были пользоваться новым классом.
Тут, видимо, мы машинально применили принципы рефакторинга К.Бека и объединили 2 класса, не нарушив интерфейсы и не спровоцировав ненужные изменения в клиентах. В итоге у нас не 2 класса (один из которых просто добавляет convinience initializer, реализуя тем самым новый интерфейс для удобства новых клиентов), а 1 - объединивший и старый и новый интерфейсы. Тут мы по сути тоже устранили дублирование машинально. Вы правы, стоит этот момент явно осветить в статье. Спасибо за эту тонкую деталь.
на книгу Object-Oriented Software Construction и её автора Б.Мейера. К сожалению, оригинал не читал, но что-то мне подсказывает, что Википедия сильно не исказила смысл.
открыл книгу и прочитал про OCP. Книга какая-то философская - с одной стороны там говорится о неизменности интерфейса, с другой конкретно про данный случай говорится "suddenly, entire parts of the software that were supposed to have been finished and sealed off ages ago get reopened, triggering a new cycle of development, testing, debugging and documentation". Т.е. взаимоисключающие параграфы.
Кстати работаю с google ads - там при значительных изменениях полностью отбрасывают старые модули, вставляют новые. Даже документацию не успевают менять.
самим эпплом активно используется (пруф).
да, но и про OCP там речи тоже не идет
Ну, т.е. OCP можно использовать:
и в узком смысле (стабильность интерфейсов), чтобы не провоцировать лишнюю работу в разработке (изменение клиентов под изменившийся интерфейс)
и в широком (стабильность собранных ранее артефактов), чтобы не провоцировать лишнюю работу по тестированию, дебагингу, документированию старого.
Еще раз спасибо за тонкий, но очень важный момент. Мы пока в более узком смысле OCP рассматривали, но потребность не провоцировать и лишнюю работу по тестированию у нас очень актуальна. Поглядим, как теперь мы могли бы изменить процессы, чтобы и в широком смысле OCP удовлетворять и сколько это будет стоить конкретно в наших условиях. Плюсанул Вам кармочку. Редко такие ценные комментарии на Хабре дают.
Формализация принципа Open/Closed: как сохранить обратную совместимость с помощью SOLID