Comments 14
Очень крутая статья, но на деле постоянно забываешь что-то абстрагировать и, как итог, вместо итеративной интеграции, куча конфликтов) Это прям надо тренировать в себе, как мне кажется ?
Делаете pull request, он висит несколько дней, после этого вы получаете approve и ... 15 конфликтов
Но ведь это замечательно, теперь вы знаете что код ещё кто-то менял и как именно, и имеете возможность обдуманно слить изменения. Предложенная техника в этом аспекте - способ проигнорировать и выкинуть чужую работу, которой может быть и критичное изменение бизнес-логики. А так-то слишком много слов для "написать независимую реализацию куска кода и заменить ей существующий".
Мне кажется, что здесь вопрос сравнения и компромиссов (как и всё у нас в ИТ). Конфликты, которые разрешаются за пару минуту — это не проблема. Конфликты, которые приводят к переделкам своего решения, траты дней работы, нескольким созвоном с другой командой и т.д. — это уже проблема.
выкинуть чужую работу
Почему выкинуть чужую работу? Чужая работа не выкидывается. Если все очень подробно декомпозируют свою задачу, интегрируют свои изменения часто, то у всех будет актуальная версия. В этом случае тоже могут возникать конфликты, то скорее всего они будут мелкие.
Если все декомпозируют свою задачу, описанной проблемы вообще не возникает. Здесь же решается задача когда нужно влить 2 недели разработки кода, который в этом время значительно менялся другими людьми.
Предложенная техника в этом аспекте - способ проигнорировать и выкинуть чужую работу,
Как раз нет и даже наоборот. Если две недели работать в отрыве от команды а потом сливать 25 изменений, шансы потерять ценное куда выше, чем если эти же изменения вливать ежедневно по одному как предлагает автор
Ну как же, именно работать в отрыве от команды и предлагается, об этом явно написано:
> включить для себя, выключить для всех остальных
> итеративно делать новую реализацию
и в конце
> выключить и удалить старую реализацию
Но старая реализация же активно разрабатывается, иначе откуда взяться конфликтам слияния, которых хотели избежать? Вот вся эта разработка и будет в последнем пункте разом silently потеряна. Так не обязательно было для этого новую технику придумывать, можно было просто влить feature ветку с -s recursive -X theirs
.
Иначе другие разработчики должны были вносить изменения в обе ветки, но это точно не про "выключить для всех остальных", а скорее про "заставить остальных разработчиков коммитить все изменения в две ветки [кода] сразу (при том что одна из них недописана) и обе этих ветки тестировать". Во было бы интересно почитать как это было организовано, как контролировалось, как масштабировалось, и оправдало ли себя.
"Выключить для всех остальных" имеется ввиду, что этот код не может быть "включен" случайно на проде. Все разработчики все равно видят весь код, могут его читать, пожалуйста.
На моей практике не бывает такого, что 2 абстрактные параллельные ветки одновременно активно разрабатываются. Это больше похоже на теоретическую ситуацию. Если оно действительно так, то нужно общаться двум командам и работать в тесной связке.
На практике же чаще встречаешь такое, что ты делаешь новую "абстрактную" ветку и активно её разрабатываешь. Текущую ветку не разрабатывают так активно, но в неё вносят изменения в разных местах. И если месяц копить изменения и вливать все разом, то на практике получается всегда сложнее как ни крути, чем ты это делать маленькими частями постепенно.
Особенность Branch by Abstraction заключается в том, что её сложно измерить саму по себе в вакууме. Чаще можно встретить исследования более общего подхода Trunk-based Development (в котором неотъемлемую часть играет Branch by Abstraction). Есть у Google неплохая вводная про это, и там есть ссылки на исследования DORA. Там говорится о том, что эти техники помогают в целом командам добиваться большей стабильности и скорости поставки в проектах.
Но старая реализация же активно разрабатывается, иначе откуда взяться конфликтам слияния, которых хотели избежать?
Если старая реализация активно разрабатывается, то не пишется новая. Если пишется новая, значит на старой поставили крест (в американской армии есть аббревиатура для таких случаев: fubar = fucked up beyond any repair). Конфликты слияния берутся в соседних компонентах, которые претерпевают неизбежные изменения.
Поддерживаю. Уж лучше я созвонюсь с другой командой, потрачу больше времени, но точно не буду возвращаться к этой задаче, переделывать и трать бОльшее количество времени (поскольку к тому что-то забудется, придётся вспоминать)
Возможно, это будет работать в случае, когда вы полностью переписываете реализацию и выбрасываете старый вариант.
Но если нет полного переписывания, вам нужно будет вливать в новую реализацию чужие изменения ко старой редакции. И пока вы используете слияния git (или другой системы), вы делаете это автоматизированно, сразу получая те 15 конфликтов (а over 9000 бесконфликтных изменений выполняются незаметно). Без гита слияния нужно будет делать вручную, вручную искать конфликты, и так же вручную исправлять. Это неудобно, долго, чревато ошибками.
Тут скорее организационная проблема в том, что pull request'ы висят несколько дней и регулярно дожидаются конфликтов.
Я согласен, что долговисящие Pull Request'ы - это тоже проблема. Но это отдельная.
В этой статье я больше говорил о долгом рефакторинге, если вы, скажем, несколько недель делаете что-то в своей ветке.
а over 9000 бесконфликтных изменений выполняются незаметно
Подход Branch by Abstraction и тесно связанный с ним Trunk-Based Development рекомендует не делать Pull Request на 9000 изменений (только если это не автоматическое переименование файлов). Потому что статистически вы будете получать много сложных конфликтов. В большинстве случаев вместо этого можно сделать интеграции по 200-500 изменений. Они будут давать мало конфликтов и каждый из них будет скорее всего простой.
Это всё направлено на повышение стабильности и предсказуемости работы.
Иногда бывает так, что я сделав примерно 80% работы, понимаю, что это тупиковая ветвь и надо всё делать совсем по другому. При классической схеме с feature branch я просто удаляю свою ветку и начинаю всё заново из свежего мастера. А вот как без геморроя откатить всё то что я успел наколбасить в мастер?
Плюс еще усложняется кодревью. Когда видишь порцию безобидных маленьких пулреквестов размазанных в течении недели, то сложно удержать в голове всю задумку. А когда видишь целиком реализованную фичу, то как-то попроще её ревьюить. Ведь самое сложное на ревью - это заметить косяк в том чего нет в чейнджсете
Не знал, что техника замены одной реализации другой имеет специальное название. Пользуюсь ей при переписывании legacy. ИМХО, есть значительный минус - есть шанс что-то потерять при переносе, когда обновляется старая реализация. Также как и в случае с отдельной ветку нужно мониторить изменения и "подливать" их в новую версию.
Напоминает подход рефакторинга "фикус-удавка".
Как применять Branch by Abstraction в проекте на примере Android-разработки