Search
Write a publication
Pull to refresh
0
0
Евгений Терехов @nergal-perm

Программист

Send message

Хм, так какие результаты это все принесло бизнесу? Как благодаря этому выросла выручка и/или операционная прибыль? И выросла ли?

Мы в этой ветке обсуждений уже много тем затронули. Попробую подытожить:

  1. За термином "рефакторинг" уже прочно закрепилось значение вроде "за неделю провести масштабную чистку кода" - то есть приложить значительное усилие и значительно изменить структуру.

  2. Мне, наверное, стоит (вслед за уже упомянутым Кентом Беком) перестать использовать слово "рефакторинг" для обозначения мелких структурных правок, вносимых в код на постоянной основе и требующих очень небольших затрат времени. Кент Бек начал называть это "уборкой" (tidying up).

  3. "Уборка" в целом нужна только для упрощения внесения требуемого бизнес-изменения, поэтому ее нужно проводить перед такими изменениями (и то не всегда, есть нюансы).

  4. Рефакторинг (с выделением времени, заведением тикетов и прочей бюрократией), похоже, нужен там, где на "уборку" забивают.

Я попробую переформулировать то, что пытаюсь донести.

Рефакторинг имеет смысл ТОЛЬКО перед лицом изменений. Если код не нужно изменять, то и рефакторить его нечего, это экономически невыгодно и никому не нужно. И если уж рефакторинг так связан с изменениями, то и проводить его нужно ПЕРЕД изменением, чтобы было проще внести это самое изменение (тут есть оговорка "проще != легче", "проще" - это про правильные уровни абстракции и количество элементов и связей, а "легче" - это про копипаст, грубо говоря). С этой позиции можно не чистить 499 экземпляров "плохого кода", если они не мешают внести требуемое бизнесом изменение.

у вас бы эта работа заняла пару лет, звучит не очень эффективно

Может, и все пять лет, кто знает? Если копипасты просочились туда, где ничего уже не меняется, пусть живут.

неделю чистил код

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

В общем, вопрос в цели этого процесса. Если цель - вычистить ВСЕ копипасты, ну ОК, идем чистить ВСЕ копипасты. А если цель - превратить время в деньги, тогда чистим только то, что мешает превращению.

комит то в конечном итоге у вас будет один, или 100 комитов на сто копипаст

Если предположить, что я целенаправленно (есть тикет, выделено время, вот это все) работаю над устранением копипасты, то в "моей" ветке будет по коммиту на каждую копипасту. По умолчанию минимум раз в день я буду сквошить эти коммиты и мержить их в main, чтобы остальные участники команды могли работать со свежим кусочком отрефакторенного кода. Ну и в любой момент времени (изменились приоритеты, прилетел критичный баг или нужно фичу для демо допилить) я точно так же засквошу новые коммиты в main и спокойно переключусь на другую задачу.

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

Справедливости ради скажу, что за последние 4 года работы на двух проектах отдельные задачи на рефакторинг не заводились ни разу - все происходило внутри реализации фич. Прямо по заветам Кента Бека - first make the change easy, then make an easy change.

хм, я тоже с компилируемым языком работаю (Java), и тоже многократно подобные штуки исполнял, и компилятором при этом всегда пользовался, без этого никак.

Подход в целом был таким (представим, что копипаста с нюансами):

  1. Определяем самый критичный нюанс/вид копипасты и пишем НОВЫЙ (это важно!!!) класс/метод, который в конце будет использоваться вместо этого вида копипасты. Метод ниоткуда не вызывается пока что, но уже обложен тестами, чтобы все было красиво.

  2. Призываем на помощь компилятор, чтобы отловить все места использования критичного вида копипасты. Удаляем или переименовываем класс/метод (главное, не через инструменты рефакторинга, а руками), который используется в критичной копипасте, чтобы компилятор ругнулся на все случаи такого использования. К сожалению, это не всегда возможно, точнее, результаты не всегда однозначны, могут быть и ложноположительные срабатывания, когда удаленный/переименованный метод/класс еще и вне копипасты используется.

  3. По одному месту за раз заменяем копипасту на вызов/использование нового метода/класса, каждый раз после этого прогоняем тесты.

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

Ну и понятно, что без тестов такие изменения - это уже не рефакторинг, а реХАКторинг.

PS. А если есть способ автоматически внести эти однотипные изменения - прекрасно. Но безопаснее все же руками с прогоном тестов - так скоуп изменений всегда очень ограничен и прерваться в любой момент можно.

Один рефакторинг - убрать копипасту из одного места :)

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

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

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

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

Я вот никак не могу понять, почему на рефакторинг нужно специально выделять время, тикеты заводить, с заказчиком согласовывать... Помните, в книжке у Мартина приемы рефакторинга какие были? Переименовать переменную, выделить метод, заменить коды типами. Все быстро и не сложно, чего тут согласовывать, на что тут время выделять? Код при проведении даже довольно длинной цепочки таких рефакторингов находится в нерабочем состоянии час-два максимум, а значит, практически в любой момент рефакторинг можно прервать и вернуться к реализации фич.

Или тут под рефакторингом понимается масштабное архитектурное перепроектирование?

Расскажите, пожалуйста, подробнее, а в чем польза от Гильдии Архитекторов для продуктов / проектов компании в целом? Ну, кроме нетворкинга и обмена опытом, я имею в виду. Помогаете ли вы новым командам и продуктам определить / выбрать оптимальную архитектуру? Помогаете ли существующим продуктам мигрировать на более эффективные архитектуры? Есть ли какие-нибудь гайдлайны, чеклисты и тому подобные артефакты, облегчающие разработку и сопровождение в части архитектуры?

А то ведь и книг по архитектуре полно, и статей на профильных ресурсах, и докладов на Youtube, и Телеграм-каналов (с тысячами подписчисков, кстати). Толку-то от еще одного контент-ресурса?

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

Будем красиво выглядеть в глазах аудиториии и, возможно, придем к имеющему практический смысл соглашению :)

Конечные автоматы это концепция из прошлого века, если не сказать из прошлого тысячилетия.

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

сколько же у вас состояний? больше чем атомов во вселенной?

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

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

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

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

По моему опыту оказалось удобно сабтаски использовать для управления конкретными работами. Одна выполненная сабтаска может быть условно "бесполезной", т.е. ее нельзя никуда задеплоить или можно, но это ни на что вообще не повлияет. А вот история (состоящая из одной или нескольких подзадач) - это видимая для пользователя функциональность или законченный рефакторинг. Законченную историю можно задеплоить, протестировать и даже иногда использовать.

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

Хм, а если я декомпозирую функциональность из примера ("Разработка добавления комментирования к постам в социальной сети") вот так:

  1. Реализовать возможность просмотра комментария в виде простого текста без форматирования. То есть, на фронте это компонент отображения текста комментария, в БД - структура для хранения комментария, в API - метод получения комментария. Пока что к одному посту возможен один комментарий, для тестирования будем создавать его в БД вручную.

  2. Реализовать возможность просмотра всех комментариев (и там возможная пагинация, подгрузка еще что-то в этом роде).

  3. Реализовать возможность добавить комментарий по нажатию на кнопку в UI. На фронте - кнопка и условия ее доступности, в API - метод создания комментария, который пока что будет создавать захардкоженный текст. При проверке будем нажимать на кнопку и видеть, что список комментариев пополняется.

  4. Реализовать возможность удалить комментарий по нажатию на кнопку.

  5. Реализовать возможность ввести произвольный текст в качестве комментария.

  6. Реализовать возможность форматирования текста в комментарии.

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

Расскажите, пожалуйста, как происходит процесс изменения схемы GraphQL. Вот, к примеру, есть система "на бою", у нее сотни клиентских приложений, у каждого клиентского приложения тысячи юзеров. И в какой-то момент какое-то поле в схеме GraphQL (скажем, идентификатор клиентского приложения, оно во всех запросах присутствует) вдруг должно быть изменено. Скажем, раньше это был простой строковый идентификатор, а теперь нужно передавать объект из двух полей: GUID и строковый идентификатор. Как это изменение должно выкатиться на прод, не задев все клиентские приложения?

Как Вы в своих реальных рабочих проектах с этим справляетесь?

А в чем преимущество «колеса» в наглядности перед, скажем, простым списком видов тестирования? Вы пишете, что это «полезный способ визуализации», а в чем конкретно заключается польза? Что именно иллюстрирует это колесо? Почему какие-то типы тестирования справа, а какие-то слева? Почему тип тестов А соседствует с типами B и C? Имеют ли значения цвета?

Information

Rating
Does not participate
Location
Пермь, Пермский край, Россия
Date of birth
Registered
Activity