Как бороться с чудовищными действиями Struts?

Я унаследовал это гигантское устаревшее веб-приложение Java, используя Struts 1.2.4. У меня есть конкретный вопрос относительно действий. Большинство страниц имеют только одно действие, а методы processExecute() — отвратительные монстры (очень длинные и тонны вложенных операторов if, основанных на параметрах запроса).

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

  1. Это правильное направление?
  2. Есть ли промежуточный шаг, который я мог бы сделать, шаблон, который имеет дело с беспорядком внутри монолитных действий? Может быть, другой шаблон команды внутри действия?

person thvo    schedule 16.10.2008    source источник


Ответы (7)


Мой способ справиться с этим:

  • не делайте "все сразу"
  • whenever you change anything, leave it better than you found it
    • replacing conditionals with separate Action implementations is one step.
    • Еще лучше: отделите свои реализации от классов Action, чтобы вы могли использовать их при смене фреймворков.
    • Сохраняйте новую реализацию команды абсолютно без ссылок на Struts, используйте новые действия в качестве оболочки вокруг этих реализаций.
    • Возможно, вам потребуется предоставить интерфейсы для форм действий Struts, чтобы передавать их без копирования всех данных. С другой стороны, вы можете захотеть передать другие объекты, кроме ActionForms, которые обычно представляют собой набор строк (см. ваш другой вопрос о Формы действий Struts 1.2)
  • начать перенос деталей на более новые и лучшие технологии. Struts 1.2 был великолепен, когда он вышел, но это определенно не то, что вы хотите поддерживать в вечности. Сейчас есть несколько поколений лучших фреймворков.

Определенно есть еще - Извините, у меня мало времени...

person Olaf Kock    schedule 16.10.2008

Действия Struts, на мой взгляд, вообще не должны содержать много кода. Они должны просто напрямую взаимодействовать с запросом и ответом — взять некоторые данные из формы или параметра запроса, передать эту информацию на уровень обслуживания, а затем поместить некоторые данные в объект ответа или, возможно, сохранить некоторые данные в сеансе пользователя.

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

Это просто мой личный опыт.

person bpapa    schedule 17.10.2008

Я уже имел дело с подобными вещами. Хороший первый шаг — вставить еще один базовый класс в цепочку наследования между Action и одним из исходных чудовищных классов действий (давайте назовем его ClassA). Особенно, если у вас нет времени сделать все сразу. Затем вы можете начать выделять части функциональности в меньшие параллельные классы действий (ClassB, ClassC). Все, что является общим между исходным ClassA и новыми рефакторинговыми классами, может быть перенесено в новый базовый класс. Таким образом, иерархия теперь выглядит так:

Original Hierarchy:      New Hierarchy:

     Action                   Action
       |                        |
       |                      BaseA
  (old)ClassA                   |
                       +--------+----------+
                       |        |          |
                   ClassB (new)ClassA   ClassC
person Ogre Psalm33    schedule 17.10.2008
comment
Прочтите мой ответ выше, чтобы узнать об иерархии действий. Я думаю, что во многих местах, которые делают это, у них, вероятно, слишком много бизнес-логики в их веб-слое. - person bpapa; 18.10.2008

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

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

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

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

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

person davetron5000    schedule 17.10.2008

Сложная проблема, но типичная для ранней разработки веб-приложений.

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

Вам не нужно идти по пути заводов, интерфейсов и всего такого; обратная реализация гораздо менее полезна... но консолидация бизнес-логики и логики поиска данных в каких-то делегатах... и оставление действий struts для определения потока страниц на основе успеха/неудачи этой логики.

Оттуда вам просто нужно взять несколько недель и отшлифовать его.

person Community    schedule 16.10.2008

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

Вы могли бы по крайней мере преобразовать длинный метод в более мелкие методы с описательными именами.

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

enum Operation {
  ADD, DELETE;
}

...

Operation operation = determineOperation(form);
if (operation == Operation.DELETE) { 
  doDelete(form); 
} else if (operation == Operation.ADD) {
  doAdd(form);
}

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

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

person extraneon    schedule 16.10.2008

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

person Brian Kelly    schedule 16.10.2008
comment
Я собираюсь сказать пшах. Автор утверждает, что методы чудовищно длинные и имеют высокую цикломатическую сложность. Такой код часто является кошмаром для модульного тестирования. - person JonMR; 23.02.2010