[Перевод] Программируй меньше, думай больше… инкрементально

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

Фагнер Брек считает, что такое происходит потому, что эти проекты не реализовывали принципы непрерывной интеграции. В своей заметке, перевод которой перед вами, он пишет, что в известном ему случае кое-что нужно делать по-другому с самого начала:

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


Но как это сделать? Это фундаментальный вопрос, с которым каждому приходится столкнуть в программном проекте: всё изменится.

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

1gb009hvd526asy-zyjfiwfln8y.jpeg

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


Вместо того, чтобы спрашивать «как построить большой проект?», вы должны спросить: «как разделить большой проект таким образом, чтобы я мог построить самый маленький полезный кусок?»

От переводчика: оригинальная статья посвящена идее Incremental Delivery, которую далее мы будем называть итеративной разработкой, самым тривиальным образом опираясь на википедию, поскольку это не противоречит высказанным в статье идеям. Если же вам больше нравится «инкрементная поставка», то совершить мысленную замену будет нетрудно.


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

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

Но кое-что в этом комиксе не совсем очевидно.

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

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

В итоге, пользователь просто доволен.

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

Возможна и другая интерпретация: в первом случае, клиент получает именно то, что он думал, что он хочет. А во втором — он выяснил, что ему нравится ветер, гуляющий в волосах, пока ездил на велосипеде. Без промежуточной итерации он бы этого не узнал.


Теперь он счастливее.

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


Есть еще один неочевидный момент.

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

На самом деле итеративная разработка не делает вас действительно «быстрее». Если определить «скорость», как количество кода, написанное за определенное время, итеративная разработка может занять даже больше времени, чтобы закончить весь проект.

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

То, что люди хотят, изменится, и первоначальный запрос устареет. Или, как я и говорил раньше — всё изменится.

Единственное, что можно сделать, это принять этот факт с самого начала и строит планы соответственно.

Не пытайтесь изменить мир, плывите в потоке.

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


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

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

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

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


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

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

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

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

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

Уйдет уйма времени, чтобы сделать что-то работающее.

Или вы можете написать небольшую функцию, которая вернет прибыль от операции покупки/продажи и которую можно запустить в Chrome DevTools.

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

Еще можно добавить пару операторов console.log в качестве замены «тестовой платформы». Этого должно быть достаточно, чтобы убедиться, что функция работает. Вы даже можете построить её с помощью TDD!

function profitFrom({ sell, buy }) {
    const profit = sell - buy;
    return (100 * profit / buy) + '%';
}
console.log(`${profitFrom({ buy: 50, sell: 50 }) === '0%' && 'PASSED' || 'FAILED'}: No profit or loss for break even`);
console.log(`${profitFrom({ buy: 50, sell: 100 }) === '100%' && 'PASSED' || 'FAILED'}: Profit`);
console.log(`${profitFrom({ buy: 100, sell: 50 }) === '-50%' && 'PASSED' || 'FAILED'}: Loss`);


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

Если действительно нужно, то запустите статический сервер и просто скопируйте HTML.

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


В эссе «Собор и Базар» рассказывается об использовании итеративной разработки в OpenSource сообществе. Вот выдержка:

Лайнус относился к своим пользователям, как к со-разработчикам, с максимальной эффективностью:

7. Выпускай продукт раньше. Выпускай часто. И слушай своих клиентов.


Этот принцип в конечном итоге нашел свое место в Agile-манифесте в такой форме: «Наивысшим приоритетом является удовлетворение потребностей заказчика, благодаря регулярной и ранней поставке ценного программного обеспечения».

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

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

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

А это означает, что надо меньше программировать и думать более инкрементально.

Убедитесь, что вы не начинаете с не того колеса… или упустите свой шанс.

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

© Habrahabr.ru