Я изменил одну сигнатуру метода, и теперь у меня более 25 000 ошибок. Что теперь?


166

Я недавно начал новую работу, где я работаю над очень большим приложением (15M loc). В моей предыдущей работе у нас было такое же большое приложение, но (к лучшему или к худшему) мы использовали OSGi, что означало, что приложение было разбито на множество микросервисов, которые можно было независимо изменять, компилировать и развертывать. Новое приложение представляет собой всего лишь одну большую кодовую базу, возможно, с парой .dll.

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

Я никогда не сталкивался с такой проблемой на моей последней работе. Что я делаю?


7
Вам нужно будет дать нам больше информации о видах ошибок и о том, что такое «этот класс», мы не против читателей.
whatsisname

137
«более 25000 ошибок», такие цифры, показанные в VS, часто неверны. Есть несколько ошибок, но с поврежденной сборкой часто используемой dll другие сборки тоже терпят неудачу, что приводит к увеличению числа астрономических ошибок. Я всегда начинаю исправление с первого сообщения об ошибке, найденного в выходных данных сборки, а не в списке ошибок.
Бернхард Хиллер

13
Я хотел бы видеть подписи до и после метода, который вы изменили. КСТАТИ - 25k ошибок на самом деле не слишком много, чтобы иметь дело с ними. Утомительно, да, пугающе, да, неуправляемо, нет.
Jmoreno

46
Публичный интерфейс - это контракт. Не нарушайте такие контракты - создавайте новые.
Мэтью Прочитал

6
25000 ошибок !? Хьюстон, у нас проблема. Обязательно отмените изменения и поговорите с вашим менеджером, объясните ему, что вам, возможно, придется создать новый интерфейс вообще.
Код Whisperer

Ответы:


349

25000 ошибок в основном означает «не трогай это». Поменяй это обратно. Создайте новый класс с желаемым интерфейсом и медленно перемещайте потребителей этого класса в новый. В зависимости от языка, вы можете пометить старый класс как устаревший, что может вызвать всевозможные предупреждения компилятора, но фактически не нарушит вашу сборку.

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


79
Это не обязательно должен быть новый класс . В зависимости от языка и обстоятельств это может быть функция, интерфейс, черта и т. Д.
Ян Худек

33
Это также помогает, если старый интерфейс может быть заменен оболочкой совместимости вокруг нового.
Ян Худек

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

13
@theDmi: Я согласен, 1 изменение и 25 000 ошибок, скорее всего, означают максимум 2,5 000 изменений, и я не удивлюсь, обнаружив, что это было около 250. Много работы в любом случае, но выполнимо.
Jmoreno

33
Эти 25000 ошибок могут быть исправлены одним изменением. Если я нарушу базовый класс огромной иерархии, каждый из производных классов будет извергать ошибки о недопустимой базе, каждое использование этих классов будет извергать ошибки о несуществующем классе и т. Д. Представьте, что это был «getName», и я добавил Аргумент. Переопределение в классе реализации «HasAName» теперь не работает (ошибка), и все , что унаследовано от него, теперь генерирует ошибки (все 1000 классов), а также каждый раз, когда я создаю экземпляр любого из них (24 раза на класс в средний). Исправление ... одна строка.
Якк

80

Разделяй и властвуй с помощью рефакторингов

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

Делить

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

Покорять

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

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

пример

Например, в C # можно использовать Resharper для изменения сигнатуры метода. Если изменение достаточно простое, например, добавление нового параметра, вы можете указать, какое значение следует использовать на сайтах вызовов, которые в противном случае имели бы ошибку компиляции.

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

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

Иногда это не работает

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

К сожалению, это не будет работать, если изменение подписи слишком сложно и не может быть разбито на более мелкие изменения. Но это редко; разделив эту проблему на более мелкие проблемы , как правило , показывает , что это возможно.


12
Этот. Рефакторинг, если вы можете (безопасно), в противном случае вам нужна правильная миграция.
слеске

3
И ради любви ко всему, пожалуйста, используйте встроенные в IDE инструменты рефакторинга, а не просто изменяйте (например) сигнатуру метода локально и затем исправляйте ошибки.
KlaymenDK

36

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

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

Удачи.


15
Это первый шаг, который я сделаю: «Я младший, и мой босс сказал мне сделать что-то, и теперь я получаю действительно большое сообщение об ошибке, но мой босс не сказал мне об этом». Шаг 1: «Эй, босс, я это сделал, но сейчас я получаю 25 тыс.
Ошибок

28

Не трогай это. Не совершай ничего.

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

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

И, возможно, начальник сказал вашим старшим коллегам внести то же самое изменение, и они сказали «нет». Потому что они знали, что произойдет. Вот почему вам дали работу.


2
Это, безусловно, важная вещь, чтобы иметь в виду. Если новый сотрудник действительно амбициозен в значительной степени, он может быть достаточно трудолюбивым (легковерным), чтобы выполнить действительно большую задачу, которая в конечном итоге получит преимущество в 5-байтовой памяти, или будет немного более логичным для перекодирования и поддержки позже.
Великая утка

@TheGreatDuck: Скажите мне, что вы никогда не видели интерфейс, используемый везде и неправильно везде. Я уверен, что есть.
Джошуа

@ Джошуа, это даже не имеет отношения к тому, что я только что сказал. Были времена, когда исправлялась небольшая ошибка, не всегда самая разумная идея - переписать более 10000 строк кода. К сожалению, новый сотрудник может быть достаточно легковерным, чтобы вытащить 10 бездельников вне работы, переписать этот код, чтобы произвести впечатление на своего босса и выполнить его. Конечно, это здорово, но иногда достаточно. Вы просто должны принять существование ошибки.
Великая утка

1
@Joshua btw, я только присоединился к этому сообществу, потому что этот вопрос вошел в мою популярную ленту вопросов. У меня нет опыта такого масштабного дизайна. Я просто согласился с мнением этого человека.
Великая утка

22

Укоренившиеся API нельзя просто изменить. Если вам действительно нужно их изменить, аноатируйте и / или документируйте их как устаревшие (какими бы средствами ни позволял язык) и документируйте, какой API следует использовать вместо этого. Затем старый API можно постепенно свернуть ... возможно, очень медленно, в зависимости от вашего временного бюджета на рефакторинг.


10

оценивать

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

Вперед

Если изменение необходимо; тогда необходим план миграции.

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

Это точка фиксации: убедитесь, что все тесты пройдены, зафиксированы, отправлены.

мигрировать

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

Так что давай; не стесняйтесь использовать инструменты, чтобы помочь ( sedбудучи самым основным, есть другие).

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

Это точка фиксации (или, возможно, несколько точек фиксации): убедитесь, что все тесты пройдены, зафиксированы, отправлены.

Удалить

Через некоторое время (может быть, всего за день) просто удалите старый метод.


4
sedвероятно, плохая идея ... Что-то, что на самом деле «понимает» язык и не будет вносить непреднамеренные радикальные изменения, тем лучше.
wizzwizz4

1
@ wizzwizz4: К сожалению, я нашел очень мало инструментов, которые достаточно хорошо понимают язык для C ++; большинство инструментов, кажется, обслуживают переименование и все. Конечно, впечатляет переименование только точных вызовов методов (и не каких-либо перегрузок или несвязанных, но с одинаковыми именами вызовов методов), но этого недостаточно для чего-то более сложного. По крайней мере, вам понадобятся способности (1) перемешать аргументы, (2) применить преобразование к данному аргументу ( .c_str()например, вызов ) и ввести новые аргументы. sedвроде работает, компилятор ловит свои проблемы потом.
Матье М.

1
sed(или ed) может быть достаточно для такого рода вещей - при условии, что вы должным образом просматриваете различия перед тем, как совершить коммит.
Тоби Спейт

Это TCRR HTML, да? :)
Даниэль Спрингер

8

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

Я предполагаю, что вы просто отредактировали код вручную, что привело ко всем ошибкам. Я также предполагаю, что вы знакомы с Java (видя вашу ссылку на OSGi), поэтому, например, в Eclipse (я не знаю, какую среду программирования вы используете, но в других средах есть аналогичные инструменты рефакторинга) вы можете использовать «Refactoring -> Rename» обновить все ссылки на метод, который должен оставить вас без ошибок.

Если вы вносите другие изменения в сигнатуру метода, а не просто переименовываете (изменяете число или типы параметров), вы можете использовать «Рефакторинг -> Изменить сигнатуру метода». Однако, скорее всего, вам придется быть более осторожным, как предполагают другие ответы. Кроме того, независимо от типа изменения, это все еще может быть довольно сложной задачей, фиксируя все эти изменения в загруженной кодовой базе.


2
ОП специально сказал, что OSGi был на своей предыдущей работе, так что это не очень актуально здесь.
CVn

3
@ MichaelKjörling Если OP был программистом на Java в своей предыдущей работе, есть большая вероятность, что они тоже будут программистом на Java в этой работе.
Богатое

@ MichaelKjörling Я хотел дать конкретную рекомендацию, используя Eclipse для рефакторинга, потому что OP знаком с Java. Полагаю, что в действительности OP использует Java для текущего проекта, это не так важно, но я должен уточнить свой ответ. Благодарю.
MikkelRJ

6

Здесь мой вклад.

Недавно я начал новую работу, где я работаю над очень большим приложением (15 миллионов строк кода).

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

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

Как отметил @Greg, вы должны иметь возможность протестировать существующий код, чтобы иметь действительную ссылку для сравнения (регрессионные тесты). Ваше решение должно быть в состоянии генерировать те же результаты, что и существующее. На данном этапе вас не волнует, верны ли результаты . Первая цель - это рефакторинг, а не исправление ошибок. Если в существующем решении написано «2 + 2 = 42», то и в вашем решении тоже должно быть. Если он не выбрасывает исключения, ваш тоже не должен. Если он возвращает нули, ваш тоже должен возвращать нули. И так далее. В противном случае вы будете подвергать риску 25 тыс. Строк кода.

Это ради ретро-совместимости.

Почему? Потому что сейчас это ваша уникальная гарантия успешного рефакторинга.

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

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

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

После того, как вы разработали и внедрили новый «контракт», замените старый. Устаревай или убирай.

Я предложил оставить ошибки в одиночку, потому что рефакторинг и исправление ошибок - это разные задачи. Если вы попытаетесь взять их вместе, вы можете потерпеть неудачу в обоих случаях. Вы можете подумать, что нашли ошибки, однако они могут быть «функциями». Так что оставь их в покое (на минуту).

Мне кажется, что 25 тысяч строк кода достаточно для того, чтобы сосредоточиться только на одной задаче.

Как только ваша первая задача выполнена. Покажите эти ошибки / функции своему боссу.

Наконец, как сказал @Stephen:

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


5

Проверь это.

Все остальные рекомендуют, как провести рефакторинг, чтобы не было никакого влияния. Но с таким количеством ошибок, даже если вы преуспели в рефакторинге всего с 10 строками кода (вы, вероятно, можете), вы оказали влияние на 25 000 потоков кода , даже если вам не нужно было их переписывать.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.