software-architecture
January 9, 2023

Гарри Поттер и грехи копипаста

Бивис и Баттхед.. эм в смысле Generalist & Abrassador

Слышали наверное такую мантру «не порождай сущности без крайней на то необходимости»?

Оно же:

Don't repeat yourself" (DRY)

https://en.wikipedia.org/wiki/Don%27t_repeat_yourself

А как красиво это раскрывается:

«Каждая часть знания должна иметь единственное, непротиворечивое и авторитетное представление в рамках системы»

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

Даже прям жалко стало ломать весь этот манямирок своими пролетарскими кирзачами с легким налетом навоза.

Но тем не менее.

Рабочий процесс печати на яблоках

Два стула

Представьте что у вас есть программа, которая умеет печатать на яблоках и грушах слово Х#Й.

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

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

В какой-то момент появляется большой новый клиент и просит.. ну это самое:

интимную стрижку доработку за много $$ лично под него.

Хочет этот новый клиент конечно же очевидного:

Необходимо обеспечить возможность печати слов Х#Й (входит в базовый функционал) а также П#ЗДА и ДЖИГУРДА. Помимо яблок и груш (входит в базовый функционал) необходимо обеспечить печать еще на дынях и арбузах.

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

Одним словом вас развели совратили соблазнили на создание второго продукта с перекрывающимся функционалом.

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

Нет, это не МЖМ
Я им про EBITDA они мне про DRY, затем про мам и родню, потом мордобой. Дальше не помню. Очнулся — гипс. (ц)

Да, у меня богатый опыт в таких переговорах :)

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

Для психики разработчиков разумеется, вы то — каменный. Вон даже глаз не дергается, пока.

И варианта тут — как стульев в том старом анекдоте, ровно два:

  1. Форк (копирование) всей кодовой базы и отдельная ветка разработки;
  2. Основная кодовая база и большая отключаемая фича.

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

Но со вторым тоже все не так просто.

Абрассадор высоких стандартов разработки ссыт в уши указывает простым смертным как жить.

Другие варианты

А как же «отключаемые плагины», «персональные модули интеграции», «кастомизация скриптами под заказчика» и все прочее?

А никак.

Вернее оно все конечно есть, но не для вас: без разделения минимум 70/30 это не сработает.

Где-то 70% реализации вашего чудо-продукта должно быть в виде отделяемой программируемой логики и лишь 30% — сама платформа.

А у вас конечно все 100%, т.е. все решение это сам продукт и есть. Ну может иконка в настройках настраивается, ок.

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

Естественно все отделенное от платформы, где другой жизненный цикл.

Но вернемся в подвал к нашим баранам героям, где программист Василий принимает ключевое для вашего чудо-продукта решение:

Форк или фича?

Поможем Василию разобраться с вариантами.

Программист Василий принимает решение

Форк всей кодовой базы

Тут на самом деле все просто:

была одна программа, стало две.

Скопировал-вставил, повторил. Примерно как хомячки размножаются.

И вообщем-то на этом сказку можно было бы и закончить:

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

А потом пришла война синхронизация изменений.

Основная версия поехала вперед, туда начали добавлять новый функционал, не актуальный для большого клиента и его персональной версии.

Плюс исправления багов, плюс обновления библиотек.

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

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

Свести обратно уже практически невозможно — нецелесообразно экономически. Перенос даже исправлений багов — затруднен.

Плюс отдельная версия начинает медленно устаревать, поскольку обновлять ее клиент не считает нужным — у него-то все работает.

На все это уходит время и силы команды разработки, а штат увеличивать в два раза конечно никто не спешит.

Страшно стало?

А на самом деле это лучший вариант, тк за все эти ужасы, боль и страдания вам стабильно платят. И рисков для компании и продукта особых нет.

Разве что в «клуб приличных разработчиков» не пустят, чтож поделать.

Вот теперь поговорим про настоящий мрак и ужас.

Бабушка-программист вспоминает свои мертвые проекты.

Большая отключаемая фича

По-сути это часть Feature-driven development (FDD)

https://en.wikipedia.org/wiki/Feature-driven_development

Cмысл в том что вы реализуете абсолютно все хотелки большого клиента в виде набора отключаемых фич, которые соответственно отключены у всех остальных клиентов.

На первый взгляд тут одни сплошные плюсы:

  • кодовая база остается единой — чек
  • релиз-цикл остается без изменений — чек
  • все исправления и обновления идут в одной кодовой базе — чек

Ну что ура? Победа? Можно начинать праздновать?

Конечно же нет.

Это только первая высадка в джунгли Вьетнама, до первых вьетконговцев. А дальше начинается ад. 

И сейчас я на правах местного жителя, устрою вам по нему экскурсию.

Внутри разработки крупного проекта

Круг первый: умножение затрат на тестирование

Допустим вы реализовали три отключаемые фичи (какие молодцы!)

Как думаете сколько комбинаций режимов работы программы вам теперь нужно проверить для полного тестирования?

Восемь (8) !

Ох#ели и не верите?

Ну давайте считать:

  • работа без включенных фич вообще;
  • фича №1 включена, №2 и №3 выключены;
  • ... (таких будет 2х3 = 6 разных вариантов)..
  • работа со всеми включенными фичами;

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

Конечно же на практике этого никто не делает, даже из крупных вендоров, из-за чудовищного объема работы. Поэтому просто смиритесь и вы:

как только появляются отключаемые опции — возможность 100% тестирования пропадает.

Если вам станет легче, то например весь этот ад с опциями был (и наверное есть до сих пор) в кодовой базе Oracle RDBMS.

Поэтому типичный разработчик, допущенный до исходников тратил 99% времени на разбор результатов провалившихся тестов, а не на саму разработку.

Один неверный чих и 2000+ автотестов загораются красным. (ц)

Круг второй: усложнение разработки

Очевидно что проверку на включение/отключение каждой конкретной фичи необходимо расставить по коду, временами даже в скриптах сборки или миграции данных.

И таких мест чаще всего будет много:

void ZNUMA::pd_initialize() {
_enabled = UseNUMA; 
}
uint32_t ZNUMA::count() { 
if (!_enabled) { 
// NUMA support not enabled 
return 1; 
} 
return os::Linux::numa_max_node() + 1; 
} 
uint32_t ZNUMA::id() { 
if (!_enabled) { 
// NUMA support not enabled 
return 0; 
} 
return os::Linux::get_node_by_cpu(ZCPU::id()); 
}

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

Вообщем в случае какой-то действительно большой фичи, такие проверки будут вообще везде: в интерфейсе, в логике, в базе, в скриптах сборки.

Очень быстро вместо привычного «работает/не работает» у вас в проекте появится новая терминология:

частично работает , не работает без включенной опции Y, сборка ломается с опцией Х — в таком стиле.

Представляете в какой ад и с какой скоростью скатится ваш проект?

Круг третий: актуализация

Вам кто-то сказал что функционал не устаревает и, будучи однажды реализованным, всегда будет дальше использоваться?

Нет, вам соврали ввели в заблуждение.

Неактуальные фичи вам придется вырезать с мясом убирать и затем долго и упорно тестировать систему.

Снова и снова.

Но и это еще не все ваши проблемы. Как у вас с документацией в вашем чудо-проекте?

Есть но нет?

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

Да еще:

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

Вполне очевидно, что затраты на разработку с такими реалиями как минимум удвоятся, это если еще разработчиков не сильно бить мотивировать.

Но и это еще не все.

Самое страшное

Теперь представим такое событие как отказ от проекта.

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

Причины тут не важны, сроки реального использования персональной версии тоже.

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

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

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

Кое-где даже динозавры до сих пор бегают. С единорогами.

Поэтому если вы что-то сделали для Гугла, то применимо это будет только для Гугла, даже если это банальный бухгалтерский отчет.

Надеюсь вы не успели переключить всю команду на создание этой персональной версии, забыв про обычных клиентов и их нужды?

Потому что в этом случае проще пристрелить откатиться на момент начала работ над персональной версией, чем пытаться поддерживать проект где 70-80% кода лежит мертвым грузом.

Вот где самый ужос.

Печальный итог

Вообщем, принципы это конечно хорошо.

Но лучше все же сладко кушать и крепко спать, а принципы оставьте для палаты английских лордов — у них их как раз нехватает.