Какой дизайн (с использованием ООП) лучше?Внешняя или внутренняя регистрация? - PullRequest
0 голосов
/ 02 мая 2019

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

Внешнее ведение журнала

Должен ли я сохранять сообщения журнала (для любых ошибок) вместе с результатом и вести регистрацию после шага бизнес-логики

Преимущества:

  1. Это дает мне информацию журнала, которую я могу использовать для проверки отрицательных случаев во время модульного тестирования, вместо анализа файла журнала.
  2. Отделить ведение журнала от бизнес-логики.
  3. Я могу реализовать ведение журнала как отдельную функцию, где я могу войти в различные форматы в зависимости от реализации (HTML, JSON и т. Д.)

Недостатки

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

Внутренняя регистрация

Должен ли я вести протоколирование одновременно с выполнением бизнес-логики

Преимущества

  1. Не хранить никакой информации, упростить решение и эффективно передать контекст родительских объектов дочернему объекту,
  2. Ведение журнала при возникновении исключения.

Недостатки

  1. Но не в состоянии отделить ведение журнала / отчетность от бизнес-логики.
  2. Я не получу информацию журнала для проверки отрицательных случаев для юнит-тестов. Поэтому мне нужно будет проанализировать файл журнала для проверки.

Больше контекста ниже:

Я создаю этот инструмент для сравнения свойств в двух ресурсах, которые могут иметь тип - JSON, свойства, виртуальные машины, REST API и т. Д. В Python.

Инструмент читает метаданные json, имеющие следующую структуру:

{
  "run-name": "Run Tests"
  "tests": [
    {
      "name": "Test 1",
      "checks":[
         {
          "name": "Dynamic Multiple",
          "type": "COMPARE",
          "dynamic": [
            {
              "file": "source.json",
              "type": "JSON",
              "property": "topology.wlsClusters.[].clusterName"
            }
          ],
          "source": {
            "file": "source.json",
            "type": "JSON",
            "property": "topology.wlsClusters.[clusterName == ${1}].Xms"
          },
          "target": {
            "file": "target.properties",
            "type": "PROPERTY",
            "property": "fusion.FADomain.${1}.default.minmaxmemory.main",
            "format": "-Xms{}?"
          }
        },
      ]
    }
  ]
}

JSON выше говорит моему инструменту:

  1. Извлекает 'clusterName' из каждого объекта wlsCluster в topology.wlsClusters. Это дает список «clusterNames».
  2. Из «source.json» извлекайте значения Xms из каждого объекта wlsCluster, где «clusterName» принадлежит приведенному выше списку.
  3. Аналогичным образом извлеките все значения Xms из файла target.properties, используя приведенный выше список.
  4. Сравните каждое значение из исходного списка Xms с целевым списком Xmx.
  5. Если все совпадают, то УСПЕХ, иначе, НЕИСПРАВНОСТЬ.

Интуитивно понятно, что JSON может быть сопоставлен с соответствующими объектами следующим образом:

  • Test
  • Проверка
  • Ресурс

Теперь, в идеале, я знаю, что должен сделать следующие шаги:

  • Запустите все тесты и все проверки в каждом тесте.
  • Для каждого теста, если тип сравнивается
    • Чтение и вычисление «динамических» значений
    • Считайте 'source' и замените динамические значения в поле свойства и извлеките соответствующие свойства
    • Аналогичным образом прочитайте 'target' и извлеките соответствующие свойства
    • Сравнить и вернуть 'PASSED' или 'FAILED'

Итак, в общем, у меня есть следующие шаги:

  1. ПОЛУЧИТЬ И ХРАНИТЬ ЗНАЧЕНИЯ.
  2. СРАВНИТЬ ЗНАЧЕНИЯ

Я также хочу распечатать журналы в следующем формате.

[<TIMESTAMP> <RUN-NAME> <TEST-NAME> <CHECK-NAME> <ERROR-LEVEL> <MESSAGE-TYPE> <RESOURCE-NAME>] custom-msg

где

ERROR-TYPE: INFO DEBUG etc
MESSAGE-TYPE: COMPARE, SYNATAX-ERROR, MISSING-PROPERTY etc

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

  • передать эту информацию дочерним объектам,
  • или попросите родителя прочитать информацию о дочернем объекте.

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

Но здесь мое решение усложняется.

  • Мне нужно хранить результаты выборки в каждом объекте, которые могут быть найденным значением или «Нет», если значение не найдено.Теперь мне нужно сохранить тип ошибки и сообщение об ошибке, а также когда значение не найдено.Позволяет назвать этот класс Value.
  • Каждое свойство может иметь список такого значения.
  • Каждый ресурс может создавать список такого свойства.
  • Каждый чек может создаватьсписок таких ресурсов.

ПРИМЕЧАНИЕ: это разработано в Python.(Если это важно для вас.)

1 Ответ

0 голосов
/ 02 мая 2019

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

Код наподобие if (test.check.resource.AProperty == aValue) является четким признаком того, что ваши спагетти начали готовить.

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

Имея это в виду, не позволяйте классам регистрироваться вообще, а только сообщайте о том, что они тестировали / проверяли, и о результате этого.

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

Вот некоторый код на c # для иллюстрации (я не знаю достаточно хорошо Python):

interface VerifierContext
{
  void AddSuccess(string checkName, string resourceName, string message);
  void AddFailure(string checkName, string resourceName, SomeEnum failureType, string message);
}
public class SomeChecker
{
    public void Validate(VerifierContext context)
    {
        context.AddFailure("CompanyNameLength", "cluster.Company", SomeEnum.LengthRestriction, "Company name was 30chars, can only be 10");
    }
}

Это даст вам полный список проверок,Если вы хотите получить вложенность, вы можете добавить методы Enter / Exit:

public class SomeChecker
{
    public void Validate(VerifierContext context)
    {
        context.Enter("CompanyValidations");

        foreach (var validator in _childValidators)
            validator.Validate(context);

        context.Exit("CompanyValidations");
    }
}

Конечно, вы можете создать его разными способами.Мое главное - чтобы каждый класс в вашем чеке / парсере принимал решение о том, все ли прошло нормально или нет.Он не должен решать, как все должно быть зарегистрировано.

Класс, который запускает работу, может затем просмотреть все результаты и выбрать уровень журнала в зависимости от errorType и т. Д.

Все классы также легко тестируются.поскольку они зависят только от контекста.

...