CTO Vetmanager, PHP Developer, Ironman 70.3

SRP или DRY?

На днях пост “Вывернутый Солид” поднял нехилую бурю в воронежском комьюнити и в моем рабочем чате. Сергей Предводителев в воронежском чате предложил отличное объяснение принципа SRP, но таким образом соблюдая SRP можно нарушить DRY. Этих принципов как собак нерезанных, что же делать, что соблюдать?

Разберем пример Сергея:

Да тут можно прямую связь ставить: код не должен ломаться в неожиданных местах → SRP.

Пример, есть 3 класса:

А → B ← C

Вася пользует класс А для своих нужд, а петя класс С для своих. Сегодня расчёты выполняемые классом B удовлетворяют обоим пользователям. Завтра Вася пришёл и попросил изменить что-то в расчётах. Программист залез, поменял класс B, у Васи всё работает как он и хотел. А вот у Пети беда - у него почему-то ВДРУГ НЕОЖИДАННО стали показываться другие цифры.

Примени программист изначально SRP, он бы сделал:

A → B1 , B2 ← C

И проблемы не случилось бы. При этом если бы класс A и С использовал один Вася, то проблемы не было бы, так как Вася изначально бы знал, что изменив расчёты в B, это повлияет и на С.

Лайк за такой простой пример. Все верно. Нужно отделить код для Васи, от кода для Пети. Кто-то из них врач, а кто-то маркетолог. У них разные задачи и требования к софту. Если в начале может показаться, что функционал для обоих почти не отличается, то со временем они будут к тебе ходить и просить изменений. У каждого будут свои изменения и класс B может усложняться подстраиваясь под классы A и C и под новые требования Васи и Пети.

Допустим, Вася и Петя к нам уже принесли много тикетов, мы осознали свою ошибку и пришло время разделить класс B на калассы B1 и B2. Лучше поздно, чем никогда. Мы смотрим на класс B и холодный код течет по спине. Мы видим код, который нужен и Васи и Пете. Нам нужно дублировать код в классах B1 и B2. Мы нарушаем DRY. Что нам соблюдать DRY или SRP?

Возможно, у вас получится общий функционал для класса B1 и B2 вынести в класс D. Тогда получим такую схему:

А → B1 ← D

C → B2 ← D

Нам удалось избежать вредной копипасты в коде. Что если не все можно вынести в общий класс D? Что соблюдать DRY или SRP? Простой ответ - соблюдать нужно SRP. В большинстве подобных случаев задублировав лишний десяток строк кода мы получим более простой и поддерживаемый код.

Я могу, чисто теоретически, себе представить варианты, когда Вася и Петя в 99% тикетов просят изменений в том коде, который пришлось задублировать для классов B1 и B2, при этом только 1% тикетов в коде, который нам дублировать не пришлось. Тогда мы почувствуем боль от нарушения DRY. Если это проявится, то может Вася и Петя - это не разные виды пользователей и зря мы тут применили SRP?