Работа с богами
Я работаю в команде среднего размера и регулярно сталкиваюсь с этими мучительно большими файлами классов. Моя первая тенденция - обращаться к ним с ножом, но обычно это только усугубляет ситуацию и приводит меня в плохое состояние души.
Например, представьте, что вы только что получили службу Windows для работы. Теперь в этой службе есть ошибка, и вам нужно выяснить, что делает служба, прежде чем вы сможете надеяться на ее исправление. Вы открываете сервис и видите, что кто-то решил использовать один файл для всего. Здесь есть метод Start, метод Stop, таймеры, вся обработка и функциональность. Я говорю тысячи строк кода. Методы под сто строк кода встречаются редко.
Теперь предположим, что вы не можете переписать весь класс, и эти классы богов будут продолжать появляться, как лучше всего справиться с ними? С чего начать? Что вы пытаетесь сделать в первую очередь? Как ты справляешься с такими вещами, а не просто хочешь получить все, что нужно?
Если у вас есть какая-то стратегия, чтобы просто держать себя в руках, это тоже приветствуется.
Советы пока что:
- Установить тестовое покрытие
- Сворачивание кода
- Реорганизовать существующие методы
- Поведение документа как обнаружено
- Цель для постепенного улучшения
Редактировать:
Чарльз Конвей рекомендует подкаст, который оказался очень полезным. ссылка на сайт
Майкл Фезерс (парень в подкасте) начинает с предпосылки, что слишком боялись просто вывести проект из-под контроля исходного кода и просто поиграть с ним напрямую, а затем выбросить изменения. Я могу сказать, что я виноват в этом.
По сути, он сказал, чтобы взять предмет, о котором вы хотите узнать больше, и просто начать его разбирать. Откройте для себя его зависимости, а затем разбейте их. Следуйте за этим всюду, куда бы он ни шел.
Отличный совет Возьмите большой класс, который используется в другом месте, и пусть он реализует интерфейс emtpy. Затем возьмите код, используя класс, и пусть он создает экземпляр интерфейса. Это даст вам полный список всех зависимостей этого большого класса в вашем коде.
7 ответов
Ой! Похоже, место, которое я использую для работы.
Посмотрите на Эффективную работу с устаревшим кодом. В нем есть несколько жемчужин о том, как бороться с ужасным кодом.
DotNetRocks недавно провел шоу по работе с устаревшим кодом. Нет волшебной таблетки, которая заставит его работать.
Лучший совет, который я услышал, - начинайте постепенно оборачивать код в тестах.
Это напоминает мне о моей нынешней работе и когда я впервые присоединился. Они не позволили мне переписать что-либо, потому что у меня был один и тот же аргумент: "Эти классы такие большие и плохо написаны! Никто не мог понять их, не говоря уже о том, чтобы добавить им новую функциональность".
Поэтому первое, что я хотел бы сделать, это убедиться, что за областями, которые вы хотите изменить, необходимо провести комплексное тестирование. И, по крайней мере, тогда у вас будет шанс изменить код и не иметь (слишком много) аргументов (надеюсь). Под тестами я подразумеваю функциональное тестирование компонентов с помощью интеграционных или приемочных тестов и обеспечение их полного охвата. Если тесты хороши, то вы сможете уверенно изменить код, разделив большой класс на более мелкий, избавившись от дублирования и т. Д. И т. Д.
Даже если вы не можете реорганизовать файл, попробуйте реорганизовать его. Переместите методы / функции так, чтобы они по крайней мере были логически организованы в файле. Затем добавьте множество комментариев, объясняющих каждый раздел. Нет, вы не переписали программу, но, по крайней мере, теперь вы можете прочитать ее правильно, и в следующий раз, когда вам придется работать с файлом, у вас будет много написанных вами комментариев (что, надеюсь, означает, что вы будете быть в состоянии понять их), что поможет вам разобраться с программой.
Свертывание кода может помочь. Если вы можете перемещать вещи внутри гигантского класса и организовывать это несколько логичным способом, то вы можете складывать разные блоки вокруг.
Скройте все, и вы вернетесь к парадигме Си, за исключением складок, а не отдельных файлов.
Я чувствую твою боль. Однажды я решил что-то подобное для хобби-проекта, связанного с обработкой данных цифрового телевидения на моем компьютере. Сотрудник на форуме по аппаратному обеспечению написал замечательный инструмент для записи шоу, просмотра всего, что было, и многого другого. Кроме того, он проделал невероятно важную работу по устранению ошибок в реальных вещательных сигналах, которые нарушали стандарт. Он проделал потрясающую работу с планированием потоков, чтобы быть уверенным, что несмотря ни на что, вы не потеряете эти пакеты в реальном времени: на старом Pentium он мог записывать четыре потока одновременно, одновременно играя в Doom, и никогда не терял пакет. Короче говоря, этот код включает в себя тонну великих знаний. Я надеялся взять некоторые фрагменты и включить их в свой собственный проект.
Я получил исходный код. Один файл, 22 000 строк C, без абстракций. Я часами читал это; была вся эта замечательная работа, но все было сделано плохо. Я не смог повторно использовать ни одну строку или даже одну идею.
Я не уверен, какова мораль этой истории, но если бы я был вынужден использовать этот материал на работе, я бы попросил разрешения отрывать от него по одному кусочку за раз, создавать юнит-тесты для каждого куска и, в конечном итоге, вырастить новую, разумную вещь из кусочков. Этот подход немного отличается от попытки реорганизовать и поддерживать большой кирпичик на месте, но я бы предпочел оставить прежний код без изменений и попытаться запустить новую систему параллельно.
Я тоже сталкивался с этой ситуацией.
Лично я сначала печатаю (да, это может быть много страниц) код. Затем я рисую рамку вокруг разделов кода, которые не являются частью какого-либо "основного цикла" или являются просто вспомогательными функциями, и сначала я понимаю, что понимаю эти вещи. Причина в том, что они, вероятно, упоминаются много раз в основной части класса, и хорошо знать, что они делают
Во-вторых, я идентифицирую основные алгоритмы и разлагаю их на части, используя систему нумерации, которая чередует цифры и буквы (это некрасиво, но хорошо работает для меня). Например, вы можете посмотреть на часть алгоритма на 4 "уровня" глубиной, и нумерация будет 1.b.3.e или какая-то другая ужасная вещь. Обратите внимание, что когда я говорю "уровни", я не имею в виду непосредственно обязательные блоки управления или область действия, но там, где я определил шаги и подэтапы алгоритма.
Тогда нужно просто прочитать и перечитать алгоритм. Когда вы начинаете, это звучит как много времени, но я обнаружил, что выполнение этого развивает естественную способность постигать большое количество логики одновременно. Кроме того, если вы обнаружите ошибку, приписываемую этому коду, то, предварительно визуально разбив ее на бумаге, вы сможете "перемещаться" по коду позже, поскольку у вас уже есть какая-то карта в голове.
Если ваши начальники не думают, что вы что-то понимаете, пока у вас нет какой-либо формы UML, описывающей это, вам может помочь диаграмма последовательности UML, если вы притворяетесь, что подэтапные уровни представляют собой разные "классы", представленные горизонтально, и от начала до конца представлен вертикально сверху вниз.
Первое, что я хотел бы сделать, это написать несколько модульных тестов, чтобы упаковать текущее поведение, предполагая, что их уже нет. Затем я бы начал с той области, где мне нужно внести изменения, и попытался бы очистить этот метод - то есть переделать рабочий код перед внесением изменений. Используйте общие методы рефакторинга для извлечения и повторного использования методов из существующих длинных методов, чтобы сделать их более понятными. Когда вы извлекаете метод, ищите другие места в коде, где существует подобный код, блокируйте эту область и повторно используйте только что извлеченный метод.
Ищите группы методов, которые "держатся вместе" и могут быть разбиты на их собственные классы. Напишите несколько тестов о том, как эти классы должны работать, при необходимости создайте классы, используя существующий код в качестве шаблона, затем замените новые классы на существующий код, удалив методы, которые они заменяют. Опять же, используйте свои тесты, чтобы убедиться, что вы ничего не нарушаете.
Внесите достаточные улучшения в существующий код, чтобы вы чувствовали, что можете реализовать свою новую функцию / исправление чистым способом. Затем напишите тесты для новой функции / исправления и внедрите их для прохождения тестов. Не думайте, что вам нужно все исправить с первого раза. Стремитесь к постепенному улучшению, но всегда оставляйте код лучше, чем вы его нашли.