- PVSM.RU - https://www.pvsm.ru -
Каждую неделю на профильных блогах мы читаем как нужно использовать методологию X и фреймворк Y, чтобы написать хорошо спроектированный и легко поддерживаемый софт. Нам постоянно говорят, что, мол, говнокод — это плохо, рефакторинг — наше все, дают те или иные очень важные сферические советы в вакууме. В большинстве этих статей можно встретить абстрактные философские нравоучения, например, вот это я распечатаю и повешу при входе в офис:
А что, если я скажу, что не все проекты одинаковые, и некоторые из них не то что можно, а даже нужно тщательно выращивать из прототипа? Об этом я рассказывал на конференции Unite'12 [1], а сейчас расскажу вам.
Идея написать этот текст у меня пылилась в голове уже очень давно. Но реальным катализатором вдруг стала вчерашняя статья под заголовком «Почему нельзя превращать прототип в итоговую программу [2]». Оказывается, мне вдруг нельзя делать то, что я успешно делаю уже два года и горжусь этим.
Пока недовольный читатель не начал быстро скролить вниз, чтобы первым написать комментарий и поведать мне как же я неправ, хочу указать на один факт, который (почему-то) многие игнорируют — все проекты разные! Если вы делаете enterprise приложения, это не значит, что никто не пишет embedded системы, аппы для смартфонов или одноразовые презентации.
Отсюда и проявления яростного холивора в комментариях ко всякому подобному посту. Так что, позвольте сперва рассказать о специфике проектов, которыми я обычно занимаюсь.
Я работаю в компании Interactive Lab [3]. В основном, мы делаем оффлайн интерактивные инсталляции, создание софта для которых сильно отличается от обычного software development:
Значит, сижу я в офисе, никого не трогаю, читаю Хабр, там, персик ем… И тут подходит ко мне босс и задает вопрос, который в общих чертах сводится к следующему: «Валентин Владимирович, а сколько у Вас займет сделать вот такую штуку, которую мы никогда не делали и смутно вообще представляем как можно сделать?.. Ммм, недели две, да?». Ну, и выясняется потом, что какое-то мероприятие через три недели, клиент «что именно хочет не знает, но хочет очень круто чтоб было все», никаких ассетов нет, идей тоже как-то не особо…
Принцип итеративной разработки уже совсем не нов, и ему посвящены сотни статей, в том числе и на Хабре. Как там, евангелисты Agile говорят? Берем, значит, фичелист, смотрим, что сможем сделать за итерацию, скажем, в две недели. Делаем. Смотрим опять…
Так, стоп! Фичелист? У нас нет ни ТЗ, ни четкого представления что это вообще должно быть. Итерация в две недели? У нас времени всего 15 рабочих дней, какие две недели, вы что!?
Вот так мы пришли к следующему алгоритму:
Как Вы видите, итерациями по 1-2 дня прототип растет в финальное приложение. И это отлично работает.
Пройдя глазами по алгоритму, проследовав по циклу пару раз и выйдя из него, можно сразу представить себе очевидные его плюсы:
Почему-то в большинстве статей о прототипах говорят как о чем-то временном, мерзком, липком и неприятном. Мол, на небрежный прототип недобросовестные разработчики накручивают все новые и новые фичи, превращая его в монстра Франкенштейна. А главный вывод — нужно все обязательно переписать, и наступит счастье!

Мне иногда задают укоризненный вопрос: «А Вам не стыдно за код своего приложения, который получился постепенным апгрейдом прототипа?». Мне, честно говоря, стыдно за весь свой код, который я писал больше месяца назад. Почему? Потому что за прошедший месяц, в том числе и пока писался этот код, лично я вырос как разработчик. И сегодняшний Я написал бы все уже совсем по-другому. Ну а завтрашнему Я очень бы хотелось все это переписать к чертям! Поэтому, я каждый раз грязно улыбаюсь, когда слышу предложения взять и переписать все заново.
Давайте будем думать о прототипе, как о дереве, которое к определенному сроку должно распуститься и дать плоды. Только от нас зависит зацветет оно розами и на нем вырастут сахарные персики, или оно внезапно покроется цветами-убийцами, а нас, как виновников всего этого безобразия, поставят мечом их рубить. При этом, как в сказке, на месте срубленного одного вырастает два новых. Думаю, уже все поняли метафору.
Вообще, сходимость написанного кода к говнокоду при количестве строк n > N сильно зависит от конкретного человека. Если ваш программист лепит к дереву-прототипу щупальца, не особо заботясь о его будущем, почему вы думаете, что заново все переписав, он в конце асимптотически не сойдется опять к подобному результату?

Делать, просто, нужно все правильно. Хорошо себе представлять, что это не прототип на выброс, а живой организм, который от ваших действий на этапе ростка сильно изменится, выросши в финальную свою форму. И форма эта может СИЛЬНО отличаться от того, что вы закладывали в его генотип при старте.
И как ваша бабушка на своем небольшом огородике за городом выдергивает траву вокруг ростков, подрезает их, прививает одни сорта на другие, — так же и вы должны аккуратно следить за своим прототипом по мере его роста. Этим и отличается хороший программист от плохого. Хороший программист видит куда растет его код, что нужно сделать уже сейчас, чтобы потом не пришлось рубить мертвые ветки; понимает как аккуратно избавиться от жуков, терроризирующих дерево; знает когда нужно его огородить так, чтобы оно росло в нужном направлении.
Если бы мне давали 10 рублей за каждую статью, в которой упоминаются KISS [4] или DRY [5], я бы давно купил BMW 3, о которой мечтаю. Эти баззворды уже заткнули за пояс страшное OOP, на котором сидят The Gang of Four [6] и хлестают его паттернами проектирования (та еще картина, конечно).
Все, что имеет значение — может ли человек вырастить из прототипа здоровое дерево.
Конкретно в наших реалиях всё, к тому же, нужно сделать ещё и очень быстро. Итерации-то день-два, не больше. Вот и начинаешь бороться с самовольными интерпретациями KISS, DRY и всякими OOP головного . Что, честно признаюсь, не всегда получается.
Это как, простите, с РПЦ [8]. Опытные священники, теологи и историки религии, поди, знают почему вот этот конкретный обряд именно такой, хотя со стороны выглядит весьма странно. Но спроси любого из 97% остальных верующих — получишь ответ, мол, делай как сказали и будет тебе спасение. И хорошо, если не побьют.
И KISS, и DRY, OOP… что там еще? Проектирование всякое. Все это хорошие концепции, но дрожь берет, когда видишь, как они в жизни применяются. И понимаешь, что такое применение с выращиванием прототипа совместимо чуть менее, чем никак. Отсюда и страшные хромые деревья с цветками-людоедами.
Особенно, когда человека бросает на экстремальные ситуации. Если OOP, то обязательно 100500 абстрактных классов и по интерфейсу на каждого, да еще, чтобы что-то конкретное создать нужно делать это через специальную фабрику фабрик билдеров. Зато полнейший DRY. Все мегаабстрактно и никакой код не повторяется. И никого не смущает, что, чтобы всего этого добиться, потребовалось написать в 20 раз больше кода. А ведь еще и IoC с DI надо вфигачить, чтоб совсем никто не мог понять где эта программа начинается вообще.
А программисты же люди такие, им дай только все усложнить. Думаешь вырастить прототип кипятильника, а через неделю ловишь себя на мысли, что сидишь ядерный реактор пишешь. И как, блин, с кипятильника на реактор мысль перескочила, уже не понятно.
А KISS, в основном, сваливается в противоположный экстремум. Где в середине разработки понимаешь, что все настолько Simple, что ветка, вообще говоря, у дерева может быть только одна, и ничего с этим уже не поделаешь. Выкидываем прототип, говорим, что прототипирование отстой и начинаем заново.
Как это обычно в фильмах говорят. «Забудь все, что ты знаешь!», «Чтобы поймать кошку, тебе нужно стать кошкой!» и тд. Но это не про нас. Не нужно ничего забывать. Наоборот, хорошо было бы помнить примеры экстремумов применения всяких методик, чтобы в минутку мимолетной рефлексии вовремя осознать, что сносит вас куда-то не туда.
Но, какое-то время
Итак, что нужно делать, чтобы дерево-прототип не завяло? Несколько на первый взгляд простых принципов:
Очень короткие итерации и фидбэк
От специфики проекта нужно выбрать минимальное время на итерацию и обязательно запускать приложение в конце каждой итерации на целевом устройстве / у целевой аудитории. Если вы делаете интерфейс для большого мультитач-стола, не поленитесь, подойдите к нему и потыкайте в нарисованные кнопочки. До них легко дотянуться? По ним легко толстым пальцем попасть? Конечно, мышой-то все могут на мелком экране. Садись переделывай!
Целостность
В наше время принято, что над одним проектом работают сразу несколько программистов. Каждый делает какой-то свой модуль. Так вот, важные модули должны разрабатываться параллельно, синхронизация разработчиков проходить как можно чаще. В идеале, раз в итерацию. Цель — как можно раньше собрать все работающие модули вместе и посмотреть что получилось.
Не важно на какой стадии разработки сейчас модуль. А если (как обычно бывает) подошло время интеграции, а код в таком состоянии, что ничего из прошлого УЖЕ не работает, а из нового ЕЩЕ не работает, возможно, вас это шокирует, но неработающие места МОЖНО ЗАКОММЕНТИРОВАТЬ!
Решение текущих проблем
Допустим, есть простая задача на час-два. Но, программисты же люди такие, как у шахматиста, в голове сразу же разворачивается партия на 64 хода вперед. Становится понятно, что потом придется сделать одно, а чтобы была расширяемость, второе. К тому же, ходу на 32м уже сейчас видно, что для пущей фотореалистичности балансировки нагрузки просчета физики нужно начинать делать третье прямо сейчас. Да и вообще, напишем-ка фреймворк!
ЛИНЕЙКОЙ ПО РУКАМ!!! А потом ногами-ногами! Сейчас решаем только текущие проблемы. Самым быстрым способом. Как показывает практика, у таких размашистых фичей есть большая вероятность сильно измениться или вообще отпасть полностью.
Аккуратно следить за экстремумами
Хорошо, все делаем быстро и тупо… НЕТ! Ну что ж вы опять! Очень старайтесь не впадать в крайности и делать все прямо совсем тупо. Вы же видите куда вас все это дело приведет — оставьте себе моменты для маневра: аккуратное OOP без излишеств, впилите в компоненты state machines, сделайте чуть больше настроек, чем нужно сейчас, отрефакторите немного разросшийся класс. Делать все просто и только то, что нужно, не значит обязательно плодить говнокод. Просто, у некоторых по-другому не получается.
Максимальная приближенность ассетов к финальным
Все ассеты с самого начала по основным параметрам нужно подгонять максимально близко к ожидаемым. Пусть в первом прототипе вместо картинок будут lolcats [9] из личного архива разработчика, а вместо планируемых FullHD видео скачанныйкупленный Iron Man 2 в BluRay качестве.
Если вы планируете показывать 100 картинок, нагенерите их ровно 100 (а лучше 150 для надежности), вместо того, чтобы всю жизнь прототипа проверять его на плавно скролящихся трех картинках. А потом с удивлением обнаружить, что 100 картинок лагают, виснут и в память не влазят.
Есть еще некоторое количество мелких договоренностей, которые не настолько важны, чтобы навязывать их использование. Все равно каждая команда, которая решает жить и работать по подобным принципам, скоро приходит к своим специфическим негласным правилам.
А я лишь надеюсь, что из этой статьи каждый возьмет что-то полезное для себя. И что деревья-прототипы будут расти, а само слово «прототип» потеряет свой негативный оттенок.
Автор: valyard
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/17464
Ссылки в тексте:
[1] рассказывал на конференции Unite'12: http://video.unity3d.com/video/6952739/unite-2012-creating
[2] «Почему нельзя превращать прототип в итоговую программу: http://habrahabr.ru/post/155019/
[3] Interactive Lab: http://www.interactivelab.ru/
[4] KISS: http://en.wikipedia.org/wiki/KISS_principle
[5] DRY: http://en.wikipedia.org/wiki/Don't_repeat_yourself
[6] The Gang of Four: http://en.wikipedia.org/wiki/Design_Patterns
[7] мозга: http://www.braintools.ru
[8] РПЦ: http://ru.wikipedia.org/wiki/%D0%A0%D1%83%D1%81%D1%81%D0%BA%D0%B0%D1%8F_%D0%BF%D1%80%D0%B0%D0%B2%D0%BE%D1%81%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%86%D0%B5%D1%80%D0%BA%D0%BE%D0%B2%D1%8C
[9] lolcats: https://www.google.ru/search?q=lolcat&tbm=isch
Нажмите здесь для печати.