2010-06-03 1 views
0

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

Упрощенный пример:

class ABInterface { 

    static methodA(); 
    static methodB(); 
    ... 
    static methodZ(); 
}; 

Интерфейс используется компонента А, так что различные методы могут использовать ABInterface :: Methoda() для того, чтобы подготовить некоторые входные данные, а затем вызвать соответствующие функции в пределах компонента В.

Сейчас мы пытаемся перестроить этот интерфейс по различным причинам:

  • Расширение нашего тестового покрытия блока - мы должны решить этот д необходимо предусмотреть соответствие между компонентами и заглушками/ложными данными

  • Интерфейс между этими компонентами отличается от оригинальной конструкции (т.е. перед этим классом интерфейса создается множество новых функций, используемых для межкомпонентного i/f).

  • Код старый, сильно изменился с течением времени и нуждается в рефакторинге.

Это изменение не должно быть разрушительным для остальной части системы. Мы пытаемся ограничить оставление многих требуемых артефактов в производственном коде. Производительность очень важна и не должна быть (или очень минимальной) деградации после редизайна. Код - OO в C++.

Я ищу некоторые идеи, какой подход принять. Любые предложения о том, как это сделать эффективно?

+0

Для рекомендаций по рефакторингу интерфейс одного класса не очень полезен. Нам бы скорее нужна какая-то «легкая» диаграмма uml. Для правильного рефакторинга это поток информации, который нам нужен. –

+0

Только один класс интерфейса и его статические методы используются в компоненте A для правильных вызовов в компонент B. Оба компонента - это не только 2 класса, но и библиотеки. Поток информации - метод из компонента A, использующий статический метод из класса интерфейса, вызывает метод в B. В B выполняются некоторые вычисления, один или несколько входных параметров заполняются, и соответствующий код возврата возвращается обратно вызывающая функция в A. Я надеюсь, что это объясняет лучший поток (у меня нет готового uml). – ratkok

ответ

1

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

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

Похоже, что кто-то важный в вашем проекте - это старый программист на языке C, который давно слышал какой-то громкий голос, который говорит что-то вроде «единственный способ заставить C++ работать быстро, это использовать статические методы». Проблема в том, что он все еще верит в это. 20 лет назад громкий шум, возможно, был прав, но компиляторы и оптимизаторы значительно улучшились за эти два десятилетия. Так что дайте вашим изменениям попробовать.

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

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

  • Примечание: Я также являюсь старым программистом на языке C, который также использовал такие глупые вещи, как 20 лет назад. Разница в том, что я узнал, что некоторые оптимизации гораздо более критичны, чем другие, и что новые компиляторы удивительно хороши в том, что они сами выбирают большинство вещей. Мои попытки «оптимизировать» вещи преждевременно обычно заканчивались дорогостоящим кодом, который обычно не превосходит настройки компилятора.
+0

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

0

Если методы A-Z были нестационарными и виртуальными, вы могли бы сделать это легко, правильно? Таким образом, если статический метод A-Z должен был вызвать нестатический виртуальный метод A-Z, вы могли бы переопределить поведение. Зная это, вам нужен способ изменить экземпляр, содержащий нестатические версии для тестирования.

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

Вот и все мои идеи, не глядя на настоящую проблему.

+0

Да, если методы были нестационарными - это было бы легко. Предлагаете ли вы добавить новый набор виртуальных функций (для этого существующего класса), которые вызываются из статических, и чем вывести из этого класса новый класс, который предоставляет differnet implementaiton и может быть создан и использован при тестировании? Я не уверен, что понимаю альтернативу. Возможно, я не был в моих оригинальных вопросах - компоненты - это не только 2 класса, но и библиотеки/модули. – ratkok

0

Спасибо за ответы и комментарии.

После просмотра «зависимостей Ломать Techniques» главы из Working Effectively with Legacy Code книги, сочетания следующих двух методов на самом деле, как представляется, решение нашей проблемы:

  • Instance доверитель - обернуть/заменить статические методы из класса утилиты с новыми виртуальными методами.
  • Статический сеттер - для создания экземпляра другого класса утилиты (производственного кода или кода-заглушки).

Объединение этих двух элементов позволит нам отделить тестируемый компонент от остальной части кода продукта.

Нашей единственной проблемой является поражение производительности (из-за использования виртуальных функций).