Проблемы с рефакторингом

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

ЗАМЕДЛЕНИЕ НОВЫХ ФУНКЦИЙ

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

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

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

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

КОД СОБСТВЕННОСТИ

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

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

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

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

ВЕТВИ

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

С CI каждый член команды интегрируется с основной линией не реже одного раза в день. Это предотвращает слишком большое отклонение ветвей друг от друга и, таким образом, значительно снижает сложность слияний. CI не предоставляется бесплатно: это означает, что вы используете методы для обеспечения работоспособности основной ветки, учитесь разбивать большие функции на более мелкие части и использовать переключатели функций (также известные как флаги функций), чтобы отключить любые внутрипроцессные функции, которые не могут быть разбитым.

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

ТЕСТИРОВАНИЕ

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

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

КОД НАСЛЕДИЯ

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

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

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

БАЗЫ ДАННЫХ

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

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

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

Конец части II, переходите к части III.

Вернуться назад к индексу