Можно ли сохранить код регистрации полностью вне бизнес-логики?

12

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

Однако что, если мне нужно что-то записать в моей бизнес-логике? например

public void SomeDomainMethod(string id)
{
   //Get user by Id
   User user = Users.Get(id);
   if (user == null)
   {
      Log.Warn("user is not existed");        //<----------------- Log A
      throw new InvalidOperationException("user is not existed");
   }

   //Step 1 
   while(true)
   {
       //do something
   }
   Log.Info("Step 1 is completed");            //<----------------- Log B

   //Step 2
   while(true)
   {
       //do something
   }
   Log.Info("Step 2 is completed");            //<----------------- Log C

}

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

Можно ли переместиться выше 3-х кодов регистрации из метода? Что лучше всего подходит для такой ситуации?

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

Ответы:

1

Конечно!

Но по моему опыту, есть два основных типа полезных журналов:

Все журналы: журналы построены с помощью профилирования API. Хорошо подходит для выявления проблем с производительностью и отчетности об исключениях. Очень шумный.

Журналы бизнес-событий : журналы, вызываемые в бизнес-логике. Все, что может беспокоить бизнес. Минимальный шум. Просто заметные, логичные, «деловые» события. Хорошо для аудита и KPI ...

Итак, я настоятельно рекомендую две вещи. Во-первых, делайте то, что делают другие инструменты мониторинга, такие как New Relic, и используйте API профилирования .NET 1 . Во-вторых, регистрируйте логические бизнес-события в своей бизнес-логике . Ведение записи определенных событий является бизнес-логикой.

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


1. А если серьезно, сэкономьте тысячи часов усилий и просто используйте существующий инструмент профилирования ...

2. Конечно, это предполагает, что вы разделяете мое мнение о том, что аспект не является отличным местом для сокрытия бизнес-правил!

svidgen
источник
Я полностью согласен с «Журналами бизнес-событий», и, как и ответы других, я буду хранить код журнала в бизнес-логике. Что касается части «Все регистрируется», я предпочитаю использовать решение AOP, так как оно будет следовать SRP и не загрязнять мою бизнес-логику. Во всяком случае, я сначала посмотрю на API профилирования.
Чарли
10

Конечно, вы можете легко использовать АОП для этого. Просто рефакторинг частей

  • Получить пользователя по Id
  • шаг 1
  • шаг 2

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

Для вашего редактирования:

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

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

Док Браун
источник
Это плохо, что мой пример недостаточно ясен. Что я на самом деле хочу показать в этом примере, так это то, что метод является наименьшей единицей с точки зрения предметной области, которую не следует делить на более мелкие части.
Чарли
@Charlie: пример совершенно ясен. Ваше заблуждение здесь, вероятно, состоит в том, что вы думаете, что было бы неплохо иметь более масштабные методы, чем шаги. И это ИМХО неправильно, это не очень хорошая идея. Наличие разных шагов, которые стоит регистрировать, является явным признаком того, что эти шаги должны иметь абстракцию, имя само по себе, следовательно, метод сам по себе.
Док Браун,
@Charlie ничто не мешает вам делать 3 приватных метода, вызываемых вашим подразделением или работой. Таким образом, снаружи он остался прежним, но теперь у вас есть необходимая абстракция для ведения журнала.
Реми
Этот подход хорош, если вы хотите управлять своей структурой кода, регистрируя проблемы. Однако иногда вы хотите управлять этим чем-то другим.
Джон Ву
@JohnWu: структура кода должна отражать различные проблемы / этапы, независимо от требований регистрации. Вот что движет структурой кода здесь. Как только эта проблема решена, протоколирование может быть выполнено AOP, что является скорее «побочным эффектом» придания коду лучшей структуры. Так что я думаю, что это не проблема ведения журналов, которая управляет структурой кода, а то, что требование использования AOP для ведения журнала делает его более прозрачным, так как код пропускает некоторую структуру, которую он должен иметь.
Док Браун
3

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

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

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

Ewan
источник
Вот о чем я думал. Я не могу придумать разумное обоснование для входа в домен / бизнес-модель POCO. Ведение журнала - это то, что естественно укладывается в рамки основных бизнес-моделей, IMO.
jleach
2

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

Например, при использовании слушателя (handcraft one или с использованием шины событий и т. Д.) Ваш код будет выглядеть следующим образом

public void SomeDomainMethod(string id)
{
   //Get user by Id
   User user = Users.Get(id);
   if (user == null)
   {
      listener.OnUserNotFound(userId);
      throw new InvalidOperationException("user is not existed");
   }

   //Step 1 
   while(true)
   {
       //do something
   }
   listener.OnStep1Finished(......);

   ...

}

Внедрив ведение журнала в слушателе, логика ведения журнала больше не входит в вашу бизнес-логику.

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

Другой подход заключается в использовании механизма, подобного Dtrace в Solaris, который позволяет вам внедрять в запущенные процессы (я полагаю, что есть способ сделать подобное в C #?), Чтобы журналы и сбор статистики можно было определять во время выполнения. Тем не менее есть и другие недостатки.

Адриан Шум
источник
Одной из проблем, которую пытается решить AOP, является проблема, связанная с тем, что код становится нечитаемым для некоммерческого кода (например, записи вызовов), переплетенного с «бизнес-кодом». Замена «регистратор» на «слушатель» не решает эту проблему, читаемость кода не изменяется,
Док Браун
2

Другой подход состоит в том, чтобы отделить ведение бизнес-журналов и технических журналов. Затем мы можем назвать ведение бизнес-журнала «Аудит» и применить определенный набор бизнес-правил, таких как срок хранения и правила обработки, такие как Business Activity Monitoring.

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

Логика ведения журнала довольно разнообразна и тесно связана с реализацией, так что вам действительно нужно отделять ее от кода?

Логика аудита должна рассматриваться как логика домена и обрабатываться соответствующим образом.

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

iTollu
источник
Я очень согласен с вами, что есть два вида регистрации. Но я не понимаю, что Logic of The Logging довольно изменчива и тесно связана с реализацией , вы имеете в виду техническую регистрацию здесь? Для технического ведения журнала, я думаю, он используется для регистрации входа / выхода метода и значений параметров, которые лучше оставить вне метода.
Чарли
@Charlie Да, под «ведением журнала» я имею в виду техническое ведение журнала. Регистрация значений входа / выхода / параметров достаточна для чистых функций. Тогда, или, конечно, вы можете использовать аспект или монаду Logger. Но чистые функции хороши тем, что они тестируемы. Таким образом, проблемы, которые должен отслеживать регистратор, вероятно, будут решены во время разработки / отладки. С нечистыми функциями, где техническая регистрация наиболее полезна, вы захотите регистрировать каждый побочный эффект параметров / результатов, каждое исключение.
iTollu
1

Способы избежать регистрации непосредственно в классе или методе:

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

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

Роберт Харви
источник
1
Было ли ведение журнала там, где было показано, что это проблема, и стоит ли ее «исправлять»?
whatsisname
1

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

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

user88748
источник
0

Нет не в с #

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

Вы могли бы "apsect-ize" определенные биты регистрации

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

В любом случае, запись журнала не является аспектом

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

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

Но одитинг это

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

Джон Ву
источник