Работа с богами

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

Например, представьте, что вы только что получили службу Windows для работы. Теперь в этом сервисе есть ошибка, и вам нужно выяснить, что делает сервис, прежде чем вы сможете надеяться исправить его. Вы открываете сервис и видите, что кто-то решил использовать один файл для всего. Здесь есть метод Start, метод Stop, таймеры, вся обработка и функциональность. Я говорю тысячи строк кода. Методы под сто строк кода встречаются редко.

Теперь предположим, что вы не можете переписать весь класс, и эти классы богов будут продолжать появляться, как лучше всего справиться с ними? С чего начать? Что вы пытаетесь сделать в первую очередь? Как ты справляешься с такими вещами, а не просто хочешь получить все, что нужно?

Если у вас есть какая-то стратегия, чтобы просто держать себя в руках, это тоже приветствуется.

Советы пока что:

  1. Установить тестовое покрытие
  2. Сворачивание кода
  3. Реорганизовать существующие методы
  4. Поведение документа как обнаружено
  5. Цель для постепенного улучшения

Редактировать:

Чарльз Конвей рекомендует подкаст, который оказался очень полезным. ссылка на сайт

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

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

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

12.12.2008 04:10:47
Беги, и не переставай смотреть за спиной !!!
JoshBerke 12.12.2008 04:29:57
Если бы я только мог, Джош ... Если бы я только мог ...
Ty. 12.12.2008 04:32:00
Хех, я слышал, да, мне когда-то приходилось пересматривать это многопоточное приложение COM +, 20 000 строк кода, его циклическая сложность была выше, чем я когда-либо видел. Ооо, и это было только как 5 методов. Я рвал и смеялся над Mgmt за предложение, что мы "повторно" используем этот сервис.
JoshBerke 12.12.2008 04:42:10
И я бы хотел получить лучший совет, но ... Я знаю боль ...
JoshBerke 12.12.2008 04:43:53
Да, язык не зависит от Бога. Иронический?
Marcelo MD 12.12.2008 15:43:55
7 ОТВЕТОВ
РЕШЕНИЕ

Ой! Похоже, место, которое я использую для работы.

Посмотрите на Эффективную работу с устаревшим кодом . В нем есть несколько жемчужин о том, как бороться с ужасным кодом.

DotNetRocks недавно провел шоу по работе с устаревшим кодом. Нет волшебной таблетки, которая заставит его работать.

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

9
12.12.2008 04:21:42
В этом подкасте было несколько действительно хороших советов. Спасибо за пост.
Ty. 12.12.2008 06:02:12
Надеюсь, вы сможете найти работающую стратегию в любое время. Если вы найдете какой-либо конкретный метод, который поможет вам опубликовать его? Я хотел бы услышать об этом.
Chuck Conway 12.12.2008 06:37:18

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

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

4
12.12.2008 04:18:09

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

Скройте все, и вы вернетесь к парадигме Си, за исключением складок, а не отдельных файлов.

3
12.12.2008 04:18:59
Большая часть кода является довольно процедурной, так что поиск решений этой проблемы, которые были обработаны в C, также может быть хорошим местом. Спасибо!
Ty. 12.12.2008 04:27:26
Звучит так, как будто «намазываю помаду на свинью» - я бы кусал пулю и пытался постепенно улучшить дизайн.
tvanfosson 12.12.2008 04:29:08
Я думаю, что это мой самый большой умственный блок. Как только я начинаю идти по пути того, что «должен» делать, я нахожусь в психическом состоянии, где единственное решение, которое я вижу, это почти полное переписывание.
Ty. 12.12.2008 04:30:35
Следуйте мантре TDD, хотя и в несколько ином контексте. Сделайте самое простое, что может сработать. Занимает дисциплину, но оно того стоит.
tvanfosson 12.12.2008 04:33:40
cbo - я согласен, но, по крайней мере, свинья больше не выглядит так неугодно. Ty - Правильное решение, вероятно, полностью переписано, но очень часто это не то решение, для которого у нас есть ресурсы.
Chris Cudmore 12.12.2008 13:43:21

Даже если вы не можете реорганизовать файл, попробуйте реорганизовать его. Переместите методы / функции так, чтобы они по крайней мере были логически организованы в файле. Затем добавьте множество комментариев, объясняющих каждый раздел. Нет, вы не переписали программу, но, по крайней мере, теперь вы можете прочитать ее правильно, и в следующий раз, когда вам придется работать с файлом, у вас будет много комментариев, написанных вами (что, надеюсь, означает, что вы будете быть в состоянии понять их), которая поможет вам разобраться с программой.

4
12.12.2008 04:19:34
Если код написан так плохо, что требует «много комментариев», то его, безусловно, необходимо реорганизовать. Код должен объясняться только минимальными комментариями.
tvanfosson 12.12.2008 04:31:54
Код может быть «хорошо написан», но поскольку он делает что-то сложное, для того, кто его никогда не видел, ему нужно много комментариев. Не бесполезные (например, перебирая все объекты в списке), но полезные (например, необходимо сбросить foo (), чтобы bar () не потерпела неудачу позже).
Elie 12.12.2008 13:43:14
Это более полезно, чем может показаться пуристам: я написал код, который должен был выполнять ужасные процедурные вращения, потому что это то, что он должен был делать (это было чтение и выборочная маршрутизация электронной почты). Лучшее, что я мог оставить следующему программисту, было много комментариев.
staticsan 19.12.2008 06:03:48

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

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

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

2
12.12.2008 04:19:55

Я тоже сталкивался с этой ситуацией.

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

Во-вторых, я идентифицирую основные алгоритмы и разлагаю их на части, используя систему нумерации, которая чередует цифры и буквы (это уродливо, но хорошо работает для меня). Например, вы можете посмотреть на часть алгоритма на 4 «уровня» глубиной, и нумерация будет 1.b.3.e или какая-то другая ужасная вещь. Обратите внимание, что когда я говорю «уровни», я не обязательно обращаюсь непосредственно к блокам управления или области видимости, но где я определил шаги и подэтапы алгоритма.

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

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

3
12.12.2008 04:38:30
Оооо! Это много усилий, но это должен быть идеальный способ сделать это. Престижность.
Jonathan C Dickinson 12.12.2008 08:01:12

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

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

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

3
12.12.2008 05:48:39
Иногда модульные тесты могут быть хорошим диагностическим инструментом, чтобы выяснить, что на самом деле делает этот метод под названием «Method1» :).
Jonathan C Dickinson 12.12.2008 08:02:32