Подтвердить что ты не робот

Нужны идеи рефакторинга для Anti-Pattern Arrow

Я унаследовал монстра.

Это маскировка, поскольку приложение .NET 1.1 обрабатывает текстовые файлы, соответствующие стандартам оплаты по требованию Healthcare (ANSI 835), но это монстр. Обработанная информация относится к заявкам на здравоохранение, EOB и возмещениям. Эти файлы состоят из записей, которые имеют идентификатор в первых нескольких позициях и полях данных, отформатированных в соответствии со спецификациями для этого типа записи. Некоторые идентификаторы записей являются идентификаторами контрольного сегмента, которые ограничивают группы записей, относящихся к определенному типу транзакции.

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

Этот вложенный, если длина 715 строк. Да, это правильно. Семьсот-и-Fif-подросток. Я не эксперт по анализу кода, поэтому я загрузил несколько бесплатных инструментов анализа и придумал рейтинг McCabe Cyclomatic Complexity 49. Они говорят мне, что довольно большое число. Высокий, как в подсчете пыльцы в районе Атланты, где 100 является стандартом для высоких, и в новостях говорится: "Сегодня количество пыльцы составляет 1,523". Это один из лучших примеров Anti-Pattern Arrow, который я когда-либо посещал. При его наивысшем отступении глубиной 15 табов.

Мой вопрос в том, какие методы вы бы предложили реорганизовать или реструктурировать такую ​​вещь?

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

Возможно, есть шаблон дизайна, который может быть полезен. Может ли Цепочка Командования быть способ приблизиться к этому? Имейте в виду, что он должен оставаться в .NET 1.1.

Спасибо за любые идеи.

4b9b3361

Ответ 1

На этой неделе у меня только что был унаследованный код, который был похож (хотя и не такой ужасный), как то, что вы описываете.

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

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

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

Теперь Refactor!

Несколько вещей, которые я сделал, которые я нашел полезными:

Преобразование if операторов

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

if (someCondition)
{
  100+ lines of code
  {
    ...
  }
}
else
{
  simple statement here
}

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

Метод извлечения

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

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

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

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

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

Ответ 2

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

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

Разберите свои состояния, что вызывает переход. Фактический код для обработки записи должен быть факторизован и вызываться при выполнении состояния (если это требует его конкретное состояние).

Таким образом, операция State1 вызывает "чтение записи", а затем на основе этой записи переходит в другое состояние.

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

Ответ 3

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

Ответ 4

Я бы начал с беспрепятственного использования метода извлечения. Если у вас его нет в текущей среде Visual Studio IDE, вы можете либо получить стороннее дополнение, либо загрузить проект в более новом VS. (Он попытается обновить ваш проект, но вы будете внимательно игнорировать эти изменения, а не проверять их.)

Вы сказали, что у вас код с отступом 15 уровней. Начните примерно с 1/2 выхода и извлечения метода. Если вы можете придумать хорошее имя, используйте его, но если вы не можете, извлеките его в любом случае. Сплит пополам. Здесь вы не идете идеальной структуры; вы пытаетесь разбить код на куски, которые будут вписываться в ваш мозг. Мой мозг не очень большой, поэтому я буду продолжать ломать и ломаться, пока он больше не повредит.

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

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

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

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

Партнер по сопряжению будет полезен здесь.

Ответ 5

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

Ответ 7

Иногда я совмещаю шаблон состояния со стеком.

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

Он отлично работает для обработки XML с помощью анализатора SAX (обработчик содержимого просто подталкивает и выскакивает состояния, чтобы изменить свое поведение по мере ввода и выхода элементов). EDI также должен поддаваться этому подходу.