Czy jest możliwe, aby kod logowania był całkowicie poza logiką biznesową?

12

Za pomocą AOP mogę usunąć kod logowania z logiki biznesowej. Ale myślę, że można go używać tylko do rejestrowania prostych rzeczy (tj. Rejestrowania metody wejścia / wyjścia i wartości parametrów).

A jeśli jednak muszę coś zalogować w logice biznesowej? na przykład

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

}

Powyższa przykładowa metoda może nie być wystarczająco jasna, co chcę tutaj pokazać, że metodę należy traktować jako najmniejszą jednostkę z punktu widzenia domeny. Nie należy go dzielić na mniejsze części.

Czy można wyjść z metody powyżej 3 kodów logowania? Jakie są najlepsze praktyki w takiej sytuacji?

Charlie
źródło
Jestem pewien, że dzienniki „Step1” i „Step2” z twojego przykładu powinny być częścią ścieżki audytu logiki biznesowej, a pierwsza dziennikiem technicznym. Najpierw posortowałbym to ...
tofro

Odpowiedzi:

1

Pewnie!

Ale z mojego doświadczenia wynika, że ​​istnieją dwa ogólne typy przydatnych rejestrowania:

Wszystko loguje: Logi budowane poprzez API profilujące. Dobry do identyfikowania problemów z wydajnością i zgłaszania wyjątków. Bardzo głośny.

Dzienniki zdarzeń biznesowych : dzienniki wywoływane w logice biznesowej. Wszystko, o co może dbać firma. Minimalny hałas. Po prostu godne uwagi, logiczne zdarzenia „biznesowe”. Dobry do kontroli i kluczowych wskaźników wydajności ...

Chciałbym więc bardzo zasugerować dwie rzeczy. Po pierwsze, rób to, co robią inne narzędzia monitorowania, takie jak New Relic, i korzystaj z interfejsu API profilowania .NET 1 . Po drugie, loguj logiczne zdarzenia biznesowe w logice biznesowej . Prowadzenie rejestru niektórych zdarzeń jest logiką biznesową.

I normalnie nie sugerowałbym AOP dla żadnego rodzaju logowania 2 . Z mojego doświadczenia wynika, że ​​albo chcesz wszystkiego , co oznacza, że ​​używasz profilera, albo chcesz zdarzeń logicznych / biznesowych. W drugim przypadku myślę, że łatwiej jest po prostu wywołać program rejestrujący w logice biznesowej.


1. Ale poważnie, zaoszczędź tysiące godzin wysiłku i po prostu użyj istniejącego narzędzia do profilowania ...

2. Oczywiście zakłada to, że podzielasz moją opinię, że aspekt nie jest doskonałym miejscem do ukrywania reguł biznesowych!

svidgen
źródło
Zgadzam się co do „Dzienników zdarzeń biznesowych” i podobnie jak odpowiedzi innych osób, będę przechowywać kod dziennika w logice biznesowej. A w części „Wszystko loguje się” wolę używać rozwiązania AOP, ponieważ będzie ono zgodne z SRP i nie będzie zanieczyszczać mojej logiki biznesowej. W każdym razie najpierw przyjrzę się interfejsowi API profilowania.
Charlie
10

Jasne, możesz do tego łatwo użyć AOP. Po prostu refaktoryzuj części

  • Uzyskaj użytkownika według identyfikatora
  • krok 1
  • krok 2

na osobne metody (tak jak powinieneś to zrobić, aby uczynić kod czystszym). Teraz możesz łatwo skonfigurować środowisko AOP, aby rejestrowało wybrane wywołania metod ( jak pokazano tutaj ). Wyjątek może zostać zarejestrowany bezpośrednio przez osobę dzwoniącą, nie trzeba używać AOP, aby uzyskać to z logiki biznesowej.

Do twojej edycji:

Chcę pokazać tutaj, że metodę należy traktować jako najmniejszą jednostkę z punktu widzenia domeny. Nie należy go dzielić na mniejsze części

Dlaczego by nie miał? Jeśli w „kontekście logiki biznesowej” chcesz zarejestrować „coś”, co jest warte zarejestrowania, i jeśli to „coś” można nadać sensownej nazwie, w większości przypadków sensowne jest przeformułowanie kodu na metodę własny. Jeśli chcesz korzystać z AOP, będzie to wymagało ustrukturyzowania kodu w taki sposób, że prawdopodobnie powinieneś go ustrukturyzować niezależnie od wymogu rejestrowania. Możesz zinterpretować to jako wadę AOP lub zinterpretować to jako korzyść, ponieważ daje ona informację zwrotną, w której można poprawić strukturę kodu.

Doktor Brown
źródło
Szkoda, że ​​mój przykład nie jest wystarczająco jasny. W tym przykładzie chcę pokazać, że metoda jest najmniejszą jednostką z punktu widzenia domeny, której nie należy dzielić na mniejsze części.
Charlie
@Charlie: przykład jest całkowicie jasny. Twoje nieporozumienie tutaj prawdopodobnie oznacza, że ​​dobrym pomysłem byłoby zastosowanie metod większych niż kroki. I to jest złe IMHO, to nie jest dobry pomysł. Posiadanie różnych kroków wartych zarejestrowania jest wyraźnym znakiem, że kroki te powinny mieć własną abstrakcję, a zatem samą metodę.
Doc Brown
@Charlie nic nie powstrzyma cię przed wykonaniem 3 prywatnych metod, które zostaną wywołane przez Twoją jednostkę lub pracę. W ten sposób z zewnątrz pozostało to samo, ale teraz masz wymaganą abstrakcję do logowania.
Rémi
Takie podejście jest odpowiednie, jeśli chcesz sterować strukturą kodu, rejestrując obawy. Czasami jednak chcesz kierować tym czymś innym.
John Wu,
@JohnWu: struktura kodu powinna odzwierciedlać różne obawy / kroki, niezależnie od wymogu rejestrowania. To właśnie tutaj napędza strukturę kodu. Po rozwiązaniu tego problemu rejestrowanie może być wykonane przez AOP, co jest bardziej „efektem ubocznym” nadania kodowi lepszej struktury. Więc myślę, że to nie rejestrowanie kieruje strukturą kodu, bardziej, że wymóg użycia AOP do rejestrowania sprawia, że ​​bardziej przejrzyste jest, że kod brakuje jakiejś struktury, którą powinien mieć.
Doc Brown
3

O ile rejestrowanie danych nie jest częścią wymagań biznesowych, najlepiej, jak mówisz, całkowicie ukryć swój kod.

Oznacza to, że naprawdę nie chcesz rejestrować takich rzeczy, jak „ukończono krok 1”. Chociaż początkowo może być przydatny do debugowania, podczas produkcji po prostu wygeneruje gigabajty śmieci, których nigdy nie obejrzysz.

Jeśli Step1Complete jest jakimś wydarzeniem biznesowym, które wymaga dalszych działań, może zostać ujawnione poprzez dobre, stare wydarzenie bez zmuszania Cię do wstrzyknięcia ILoggera lub podobnego do twojej klasy

Ewan
źródło
To jest to o czym myślałem. Nie mogę znaleźć uzasadnionego powodu do zalogowania się w domenie / modelu biznesowym POCO. Rejestrowanie jest czymś, co naturalnie mieści się poza podstawowymi modelami biznesowymi, IMO.
jleach
2

Za pomocą jakiegoś wspólnego wzorca możesz wyciągnąć kod logowania z logiki biznesowej. Jednak może nie być tego warte

Na przykład, używając listenera (rzemieślniczego lub używając magistrali zdarzeń itp.), Twój kod będzie wyglądał

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(......);

   ...

}

Po zaimplementowaniu rejestrowania w detektorze logika logowania nie jest już używana w logice biznesowej.

Jednak może się okazać, że nie zawsze jest to realistyczne, ponieważ nie zawsze możesz zdefiniować znaczące zdarzenie swojej logiki.

Innym podejściem jest mechanizm taki jak Dtrace w Solarisie, który pozwala ci wstrzykiwać się do uruchomionych procesów (uważam, że można zrobić podobne rzeczy w C #?), Dzięki czemu można zdefiniować rejestrowanie i statystyki w czasie wykonywania. Nadal istnieją inne wady.

Adrian Shum
źródło
Jednym z problemów, które próbuje rozwiązać AOP, jest problem, że kod staje się nieczytelny dla kodu niezwiązanego z działalnością gospodarczą (np. Rejestrowanie połączeń) przeplatanego z „kodem biznesowym”. Zastąpienie „rejestratora” przez „słuchacza” nie rozwiązuje tego, czytelność kodu nie ulega zmianie,
Doc Brown
2

Innym podejściem jest oddzielenie rejestrowania danych biznesowych i rejestrowania technicznego. Następnie możemy nazwać rejestrowanie danych biznesowych „Audytem” i zastosować określony zestaw reguł biznesowych, takich jak warunki przechowywania i reguły przetwarzania, takie jak Monitorowanie aktywności biznesowej.

Z drugiej strony rejestrowanie techniczne lub po prostu „rejestrowanie” jest środkiem ostatecznym do pozostawienia śladu problemów technicznych. Powinien być asynchroniczny, szybki, odporny na nietrwałość komunikatu dziennika. Ponadto komunikaty dziennika powinny przechodzić przez możliwie najmniejszą liczbę serwerów proxy, aby znajdować się blisko źródła problemu.

Logika rejestrowania jest dość zmienna i ściśle związana z implementacją, więc czy naprawdę musisz oddzielić ją od kodu?

Logika audytu powinna być traktowana jako logika domeny i odpowiednio traktowana.

Na przykład w architekturze heksagonalnej może istnieć port audytu wraz z portami klientów, pamięci masowej i MQ (i ewentualnie metryk i kontroli). Byłby to port pomocniczy, tzn. Aktywność na tym porcie jest uruchamiana przez rdzeń biznesowy, a nie przez systemy zewnętrzne.

iTollu
źródło
Bardzo się zgodziłem, że istnieją dwa rodzaje rejestrowania. Ale nie rozumiem Logika logowania jest dość zmienna i jest ściśle powiązana z implementacją , czy chodzi tu o rejestrowanie techniczne? Wydaje mi się, że do rejestrowania technicznego służy on do rejestrowania wartości wejściowych / wyjściowych metod i wartości parametrów, które lepiej jest umieścić poza metodą.
Charlie
@Charlie Tak, przez „The Logging” mam na myśli rejestrowanie techniczne. Rejestrowanie wartości wejściowych / wyjściowych / parametrów jest wystarczające w przypadku funkcji czystych. Następnie możesz oczywiście użyć aspektu lub monady Logger. Ale czyste funkcje są świetne, ponieważ można je przetestować. Tak więc problemy, które rejestrator powinien śledzić, prawdopodobnie zostaną rozwiązane podczas tworzenia / debugowania. Dzięki nieczystym funkcjom, w których rejestrowanie technologii jest najbardziej użyteczne, chcesz rejestrować wszystkie parametry / wyniki wywołań wywołujące skutki uboczne, każdy wyjątek.
iTollu,
1

Sposoby unikania bezpośredniego logowania do klasy lub metody:

  1. Rzuć wyjątek i zaloguj się w bloku catch dalej w górę drzewa połączeń. Jeśli chcesz przechwycić poziom dziennika, możesz zgłosić niestandardowy wyjątek.

  2. Wywoływaj metody, które są już oprzyrządowane do logowania.

Robert Harvey
źródło
1
Czy rejestrowanie jest tam, gdzie okazało się, że stanowi problem, a nawet warte „naprawienia”?
whatsisname
1

Czy naprawdę konieczne jest oddzielenie rejestrowania od logiki biznesowej? Rejestrowanie odbywa się zgodnie z zapisaną logiką biznesową i dlatego ma sens bycie w tej samej klasie / funkcji. Co ważniejsze, pomaga łatwiej odczytać kod.

Jednak jeśli naprawdę chcesz oddzielić rejestrowanie od logiki biznesowej, powinieneś rozważyć wprowadzenie niestandardowych wyjątków i przekazanie tych wyjątków do rejestrowania.

użytkownik88748
źródło
0

Nie, nie w c #

OP, odpowiedź na twoje konkretne pytanie brzmi: nie, nie w c #. Mogą istnieć inne, bardziej rodzime języki AOP, ale wszystkie podejścia do AOP w języku c #, które widziałem, mogą stosować tylko zachowania podejrzane w kontekście punktu łączenia , co oznacza, że ​​musi istnieć przepływ kontroli między jednym blokiem kodu a inne. Aspektowane zachowania nie będą wykonywane w trakcie metody, z wyjątkiem oczywiście wywołania innej metody.

Możesz „apsect-ize” pewne fragmenty logowania

To powiedziawszy, możesz wyciągnąć pewne obawy związane z logowaniem, po prostu nie zapisywać dziennika. Na przykład punkt odcięcia, który jest wykonywany przy wejściu do metody, może skonfigurować kontekst rejestrowania i wyprowadzić wszystkie parametry wejściowe, a przy wyjściu może wychwycić wyjątki lub przekazać dziennik do pamięci trwałej, tego rodzaju rzeczy.

W każdym razie zapisywanie dziennika nie jest aspektem

Dodałbym, że pisanie dziennika nie jest w rzeczywistości przekrojowym problemem. Przynajmniej nie rejestruj debugowania. Dowodem na to jest to, że nie można napisać przekrojowego wymogu, który w pełni wyjaśnia, co zrobiłby ten aspekt - jest specyficzny dla każdego przypadku, ponieważ celem zapisu dziennika jest odzwierciedlenie tego, co się dzieje z logika, a logika w każdej metodzie powinna być w miarę unikalna (patrz OSUSZANIE ).

Innymi słowy, istnieje nierozerwalna logiczna zależność między pisaniem dziennika a tym, co jest pisane. Nie możesz tego uogólnić.

Ale audyt jest

Jeśli masz jakieś funkcjonalne wymaganie dotyczące rejestrowania (np. Rejestrowanie kontroli w celu obsługi wymogu niezaprzeczalności ), to niektórzy twierdzą (i zgodzę się), że jeśli będziesz musiał wykonać te zapisy dziennika w środku metody, nie ustrukturyzowałeś swojego kodu w sposób zgodny z myśleniem aspektowym. Jeśli tak się stanie, należy wyodrębnić kod do osobnych metod, aż do uzyskania wymaganego poziomu szczegółowości.

John Wu
źródło