Проектирование по вытягивающему принципу

Feb 16, 2011 01:23

В тексте некоторые фразы представляют собой гиперссылки на предыдущие мои статьи, которые раскрывают контекст. Видите ссылку? Вокруг нее текст, смысл которого ускользает? Или может быть, вы с ним несогласны? Или же, вам просто любопытно? Тыкайте в ссылку.

Сегодня в беседе с коллегой рассказал про то, как работает архитектор, и осознал, что ни разу ни где об этом не писал.

Кто читал старые книги по программированию помнит термины "программирование сверху вниз", "программирование снизу вверх", и, самое невероятное - "от центра к краям". Удивительная особенность этих терминов в том, что они просты и понятны, но ни один нормальный человек, примеряя объяснения на себя, понимает, что так работать не может. Это модели понятные, но к реальности никак не относящиеся. Так же, как и «легенда агилистов о ватерфоле».

Что имеет место в реальности - это две стратегии при работе над архитектурой. Вы их сразу узнаете при объяснении. Назовем их "push" и "pull".



Push.

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

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

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

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

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

Pull.

Это у нас гордые и способные программисты. Они, бывает, называют программистов, описанных выше "архитектурными астронавтами". Почему? Да потому, что они ерундой какой-то занимаются, когда надо просто взять и написать код. И они умеют колбасить этот код тоннами, и делать это быстро. И этот код - работает.

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

Либо, когда они пытаются работать в группах, их гонят оттуда коллеги ссаными тряпками то у них не складывается. Ибо, для того, чтобы продуктивно писать код группой, надо хоть как-то договорится о том, каковы общие принципы устройства этого кода, а это - "архитектурная астронавтика".

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

***

Думаю, теперь вы легко узнаете в описанных утрированно-полярных типажах "программирование сверху вниз" и "программирование снизу вверх". Или же - "вотрефол" и "agile", тут уж все зависит от вида разводимых тараканов.

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

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

Если же человек полагается не на крепкую веру, а на логику, и если он психически здоров - то он может находится в точке равновесия, будучи равно заинтересованным в обоих исходах дела, и - поэтому может позволить себе думать, а это уже не мало. И начинает понимать много чего интересного. Я объясню, и станет понятно, почему я назвал это pull и push.

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

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

Как же правильно делать этот фреймворк? И, главное, как писать приложение - ведь разработка фреймворка не может являться целью, так как у него отсутствует ценность для пользователя. Я скажу как. В разработке разумно применять вытягивающий принцип (pull), в сочетании с предварительным проектированием (push). И объясню, что означает эта фраза. После чего, рассмотрим это на интереснейшем примере, которого все избегают - как работает архитектор в случае живого продукта с длинной историей и тоннами легаси кода.

***

Начнем с того - что такое «вытягивающий принцип». Можно засорять мозг Канбаном и Тойотой, а можно просто объяснить суть, не так-ли? И в результате, понять, что Канбан в его «традиционном» приложении к разработке не имеет к этой сути отношения. Слушайте.

Суть вытягивающего принципа проста - это поставка под заказ.

У нас есть отдел снабжения, который закупает товар. Склад, куда товар поступает. И отдел продаж, который товар забирает.

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

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

Пусть у нас начало - склад пустой. На складе всего сто мест. И у нас неизвестна средняя задержка на поставку товара. Мы выдаем в снабжение 100 карточек - по количеству мест на складе.

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

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

Вопрос. Какой будет остаток товара на складе через месяц?
1-я неделя: 5*5 = 25 карточек. Склад - 75. Отправлен заказ.
Вторая неделя: 25 карточек пришло, и 25 карточек вернулось.
Далее так же.

То есть, уже на вторую неделю остаток на складе остановится на 75 штуках.

Глядя на это, мы можем принять решение:
1) Увеличить количество карточек, чтобы с какой-то дури забить склад до 100%. Либо...
2) Принять разумное решение уменьшить количество карточек до минимума, держа остаток на складе, ну, скажем, хотя бы максимум на недельный объем продаж. То есть - на складе должно остаться 25 штук. Что означает что? Что отделу продаж достаточно изъять из оборота 50 карт. И снять вчетверо меньший склад, аренда которого обойдется дешевле. Все. As easy as that.

Чтобы оценить, насколько это клево, надо знать, какова "классическая" альтернатива. Предполагается решить оптимизационную задачу на поиск экстремума. (Пытливые умы - читаем. http://www.eup.ru/Download/2002-05-15/workcap.pdf Мотаем до "Определение наиболее экономичного размера заказа". Никакого хардкора - школьной математики достаточно).

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

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

Но почему именно она помогает?

1) Она позволяет точно регулировать объем товара на складе, держа его на уровне необходимого минимума. Ибо товар на складе - это замороженные деньги, вынутые из оборота. Большое количество товара на складе ухудшает экономику.
2) Она позволяет легко и непринужденно оптимизировать объем складских помещений, затраты на аренду (или покупку-строительство) которых вообще не зависят от объема хранящегося на них товара.
3) Она позволяет делать перечисленное автоматически, посредством элементарной арифметики, и без участия "отдела планирования". При этом - реакция на изменения ситуации будет также автоматическая.

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

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

Следуя же Канбану, центр не выдает подразделениям «наряды» - подразделения взаимодействуют горизонтально.

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

Теперь вернемся к софтостроению. Многие думают, что раз они ограничивают по размеру очередь задач у своих «гибких» программистов - то они занимаются Канбаном, и должны получить все его бенефиты. Должен вас разочаровать - нет. На деле - вы, подобно меланезийским аборигенам, занимаетесь культом Карго.

Почему? Разберем контрольные вопросы, на понимание материала. :)

1) Запись в трекере - это "замороженные деньги"? Вы что-то кому-то платите при внесении задачи в трекер?
2) Большая ли статья расходов - затраты на хранилище-склад записей-задач в трекере, т.е. жесткий диск сервера, на котором работает трекер?
3) Мы что, ЭТО собрались оптимизировать?

Вы ведь используете трекер? Тикеты-issue-tasks-defects-other-shit в нем и есть те самые канбанные карточки. В случае одной ступени «конвейера» и неограниченным складом тикетов, за площадь которого вы ничего не платите, проблемы, решаемые «вытягивающим принципом» в нашем случае просто-напросто отсутствуют.

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

***

Ну что, пытливые умы? Догадались ли вы, что когда вы занимаетесь предварительным проектированием (к которому относится и разработка фреймворка) - у вас появляется та самая недостающая «ступень конвейера»?

Подождите читать дальше. Остановитесь.

Подумайте немного - обо всем, что я написал выше. Постарайтесь осмыслить. При этом - выкиньте в жопу эти Канбановские «карточки» - они не имеют никакого значения, суть в другом. Если я все правильно рассчитал - пытливые умы сейчас должны словить просветление. А если не словили - то не все потеряно. Я помогу.

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

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

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

- А потом - можно мне писать фреймворк?

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

- Могу я наконец заняться разработкой фреймворка?

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

Это и есть «вытягивающий принцип» - вы проектируете по показаниям, а не впрок на всякий случай. Решая проблемы, а не потому, что красиво и стройно. Pull, а не push.

Заканчивается написание фреймворка разработкой работающих прототипов proof-of-the concept. Не надо отлаживать эти примеры до промышленного качества, вылавливая 99 процентов ошибок! Не надо никому сдавать их в эксплуатацию! Их цель - служить примером использования фреймворка для программистов, а также - тестом для испытания его ключевых характеристик. Ключевых, а не каких попало, понимаете? Это именно то, что называется в ГОСТ-ах «эскизным проектом».

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

***

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

Представьте, что вы работаете в компании, у которой есть большой по объему кода и функциональности продукт. И он старый, с реликтовыми пластами. Ему лет, скажем, 10. Или 15. Вы бывали в такой ситуации? Нет? Значит, не повезло. Ибо продукты делятся на две категории. Коммерчески успешные продукты, востребованные пользователями, и активно развивающиеся, либо - продукты, никогда не доживающие до описанной стадии.

В такой компании поддержка совмещена с развитием. Приходится исправлять дефекты, и инкрементально докручивать мелкие и крупные фичи. Это, строго говоря, не проектная деятельность, ибо нет ни начала, ни конца. Но это и не производство. Фичи разные, а не одинаковые, как автомобили Тойота. Ой, как не любят авторы методологий связываться с этой ситуацией! :) Может быть, потому, что разработчики успешных продуктов в гробу видали авторов методологий, пытающихся за деньги учить их жизни? Кто знает? :)

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

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

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

Мы группируем их в пачку, и стартуем проект, который выполняется в три фазы.
1) Проектирование, во время которого мы выбираем подход к реализации. В течении этого срока, основное время тратится на чтение кода и reverse engineering. Система большая, постоянно меняется, и ни один человек не может понимать ее целиком. Поэтому, для начала надо разобраться, как же она сейчас работает, и в процессе этого разбирательства понять, как ее годным образом поменять. Поэтому, архитектор обязан уметь читать код.
2) Рефакторинг, при котором исправляется часть дефектов, и система готовится к безболезненному наложению пакета новой функциональности. Это выделять необходимо, потому, что не меняя функциональности, можно относительно дешево провести регрессионное тестирование, сравнивания работу старого и нового кода в тестовом режиме. Требования в десятилетней системе давно утеряны и «уплыли» от оригинала, так что при таком тестировании вы можете узнать много нового.
3) Накатывание новых фич. Это - почти классический проект, ибо мы привели ситуацию к норме.

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

Кроме того, эти пачки могут быть (и бывают) довольно мелкими, чтобы выполнить действительно качественное общее проектирование, и поменять архитектуру в стратегически правильном направлении. Чтобы при поступлении следующей пачки нам не пришлось все опять переделывать. Что делать?

Непрерывно работать над видением «эталонной архитектуры», как если бы вы писали продукт с нуля, с учетом вашего опыта его поддержки. Зная типичные дефекты, и геморрой по внесению изменений - что бы вы сделали не так? К этой архитектуре должен стремится продукт посредством серии описанных итераций. Ее не надо реализовывать впрок - систему большого объема разом не переделать.

Но именно на нее надо ориентироваться, когда возникает «вытягивание». Имея четкое видение «эталона», вы удивитесь - к нему легко приближаться фрагментами. Зная общие принципы, вы будете выпонять этап (1) так, что снизите вероятность переделки в будущем.

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

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

В таких компаниях разорвана фундаментальная обратная связь, составляющую саму суть инженерии. Штат таких компаний пухнет, пухнет вместе с объемом производимого говнокода (если лишние программисты не будут писать кода, их уволят), написание которого планируется по PMBoK-у, а стоимость поддержки и внесения в него изменений растет, растет, и цикл повторяется, повторяется…

Вы слышали, что случилось с Нокией? Полюбопытствуйте. И заодно подивитесь, что над Симбианом работает 5000 разработчиков. Для справки, насколько я помню - ядро Windows 2000 делало около 900-ста.

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

Это очень важно. Это действительно имеет значение. А agile, waterfall, и карточки канбана - выбросьте в топку это негодное Г.

agile, проектирование, дизайн, и ваще все, архитектура, канбан, управление проектами

Previous post Next post
Up