Apakah mungkin untuk menjaga kode logging sepenuhnya di luar logika bisnis?

12

Dengan bantuan AOP, saya dapat menghapus kode logging dari logika bisnis saya. Tapi saya pikir itu hanya dapat digunakan untuk mencatat hal-hal sederhana (mis. Metode masuk / keluar dan nilai parameter).

Namun, bagaimana jika saya perlu mencatat sesuatu dalam logika bisnis saya? misalnya

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

}

Metode sampel di atas mungkin tidak cukup jelas, yang ingin saya tunjukkan di sini adalah bahwa metode tersebut harus diperlakukan sebagai unit terkecil dari sudut pandang domain. Seharusnya tidak dibagi menjadi potongan-potongan kecil.

Apakah mungkin memindahkan 3 kode log di atas dari metode ini? Apa praktik terbaik untuk situasi seperti itu?

Charlie
sumber
Saya cukup yakin contoh "Step1" dan "Step2" contoh Anda harus menjadi bagian dari jejak audit logika bisnis dan yang pertama adalah pencatatan teknis. Pertama-tama saya akan menyortir ini ...
tofro

Jawaban:

1

Tentu!

Namun dalam pengalaman saya, ada dua tipe umum logging yang bermanfaat :

Semua log: Log dibuat melalui profil API. Baik untuk mengidentifikasi masalah kinerja dan pengecualian pelaporan. Sangat berisik.

Log peristiwa bisnis : Log dipanggil dalam logika bisnis. Apa pun yang mungkin diperhatikan bisnis. Kebisingan minimal. Peristiwa penting, logis, "bisnis". Baik untuk audit dan KPI ...

Jadi, saya akan sangat menyarankan dua hal. Pertama, lakukan apa yang dilakukan oleh alat pemantauan lain, seperti New Relic, dan gunakan .NET profiling API 1 . Kedua, catat kejadian bisnis logis dalam logika bisnis Anda . Menyimpan catatan peristiwa tertentu adalah logika bisnis.

Dan, saya biasanya tidak menyarankan AOP untuk kedua jenis logging 2 . Dalam pengalaman saya, Anda menginginkan semuanya , yang berarti Anda menggunakan profiler, atau Anda menginginkan acara logis / bisnis. Dan dalam kasus terakhir, saya pikir lebih mudah untuk hanya memanggil logger dalam logika bisnis.


1. Tetapi serius, hemat diri Anda ribuan jam dalam upaya dan hanya menggunakan alat profiler yang ada ...

2. Tentu saja, ini mengasumsikan bahwa Anda berbagi pendapat saya bahwa suatu aspek bukanlah tempat yang bagus untuk menyembunyikan aturan bisnis!

svidgen
sumber
Saya cukup setuju dengan "Log peristiwa bisnis", dan seperti jawaban orang lain, saya akan menyimpan kode log dalam logika bisnis. Dan untuk bagian "Semuanya log", saya lebih suka menggunakan solusi AOP karena akan mengikuti SRP dan tidak mencemari logika bisnis saya. Pokoknya, saya akan melihat API profiling terlebih dahulu.
Charlie
10

Tentu, Anda dapat dengan mudah menggunakan AOP untuk ini. Cukup refactor bagian-bagiannya

  • Dapatkan pengguna dengan Id
  • Langkah 1
  • Langkah 2

menjadi metode terpisah (seperti yang seharusnya Anda lakukan untuk membuat kode Anda lebih bersih). Sekarang Anda dapat dengan mudah mengkonfigurasi kerangka kerja AOP Anda untuk mencatat panggilan metode pilihan Anda ( seperti yang ditunjukkan di sini ). Pengecualian dapat dicatat secara langsung oleh penelepon, tidak perlu menggunakan AOP untuk mengeluarkan ini dari logika bisnis.

Untuk hasil edit Anda:

Yang ingin saya tunjukkan di sini adalah bahwa metode ini harus diperlakukan sebagai unit terkecil dari sudut pandang domain. Seharusnya tidak dibagi menjadi potongan-potongan kecil

Kenapa tidak? Jika, dalam "konteks logika bisnis", Anda ingin mencatat "sesuatu" yang layak dicatat, dan jika "sesuatu" ini dapat diberi nama yang masuk akal, dalam kebanyakan kasus akan masuk akal untuk merefleksikan kode menjadi metode itu sendiri. Jika Anda ingin menggunakan AOP, Anda harus menyusun kode dengan cara yang mungkin harus Anda susun terlepas dari persyaratan logging. Anda dapat menafsirkan ini sebagai kelemahan AOP, atau Anda dapat menafsirkan ini sebagai manfaat, karena memberi Anda umpan balik di mana struktur kode Anda dapat ditingkatkan.

Doc Brown
sumber
Ini buruk saya bahwa contoh saya tidak cukup jelas. Apa yang sebenarnya ingin saya tunjukkan dalam contoh adalah bahwa metode ini adalah unit terkecil dari sudut pandang domain yang tidak boleh dibagi menjadi potongan-potongan kecil.
Charlie
@ Charlie: contohnya sangat jelas. Kesalahpahaman Anda di sini mungkin Anda pikir mungkin ada baiknya menggunakan metode yang lebih besar daripada langkah-langkahnya. Dan itu IMHO salah, itu bukan ide yang baik. Memiliki langkah-langkah berbeda yang layak dicatat adalah tanda yang jelas bahwa langkah-langkah ini harus memiliki abstraksi, nama sendiri, oleh karena itu sebuah metode sendiri.
Doc Brown
@Charlie tidak ada yang menghentikan Anda dari melakukan 3 metode pribadi yang dipanggil oleh unit atau pekerjaan Anda. Dengan cara ini dari luar tetap sama tetapi sekarang Anda memiliki abstraksi yang diperlukan untuk login Anda.
Rémi
Pendekatan ini baik-baik saja jika Anda ingin mengarahkan struktur kode Anda dengan mencatat masalah. Kadang-kadang Anda ingin mengendarainya dengan sesuatu yang lain.
John Wu
@ JohnWu: struktur kode harus mencerminkan keprihatinan / langkah yang berbeda, terlepas dari persyaratan logging. Itulah yang mendorong struktur kode di sini. Setelah masalah ini diselesaikan, logging dapat dilakukan oleh AOP, yang lebih merupakan "efek samping" dari memberikan kode struktur yang lebih baik. Jadi saya pikir bukan masalah logging yang mendorong struktur kode, lebih dari itu persyaratan menggunakan AOP untuk logging membuatnya lebih transparan bahwa kode tersebut melewatkan beberapa struktur yang seharusnya dimiliki.
Doc Brown
3

Kecuali hal-hal Logging adalah bagian dari persyaratan bisnis maka yang terbaik, seperti yang Anda katakan, untuk sepenuhnya keluar dari kode Anda.

Itu berarti Anda benar-benar tidak ingin mencatat hal-hal seperti "langkah 1 selesai". Meskipun awalnya mungkin berguna untuk debugging, dalam produksi itu hanya akan menghasilkan gigabytes sampah yang Anda tidak akan pernah melihatnya.

Jika Step1Complete adalah semacam acara bisnis yang membutuhkan tindakan lebih lanjut maka itu dapat diekspos melalui acara kuno yang bagus tanpa memaksa Anda untuk menyuntikkan ILogger atau yang serupa ke dalam kelas Anda

Ewan
sumber
Itulah yang saya pikirkan. Saya tidak dapat menemukan kasus yang masuk akal untuk masuk dalam domain / model bisnis POCO. Penebangan adalah sesuatu yang cenderung alami di luar model bisnis inti, IMO.
jleach
2

Dengan bantuan beberapa pola umum Anda dapat menarik kode logging dari logika bisnis Anda. Namun Anda mungkin merasa tidak layak melakukannya

Misalnya, dengan menggunakan pendengar (kerajinan tangan atau menggunakan bus acara dll), kode Anda akan terlihat seperti

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

   ...

}

Dengan menerapkan pendataan di pendengar, logika pendataan tidak lagi ada dalam logika bisnis Anda.

Namun Anda mungkin menemukan ini tidak selalu realistis karena Anda mungkin tidak selalu dapat mendefinisikan peristiwa bermakna dari logika Anda.

Pendekatan lain adalah melalui mekanisme seperti Dtrace di Solaris yang memungkinkan Anda untuk menyuntikkan ke proses yang sedang berjalan (saya percaya ada cara untuk melakukan hal serupa di C #?) Sehingga logging dan pengumpulan statistik dapat didefinisikan pada saat runtime. Masih ada kekurangan lainnya.

Adrian Shum
sumber
Satu masalah yang AOP coba selesaikan adalah masalah kode menjadi tidak dapat dibaca dari kode non-bisnis (seperti panggilan logging) yang terjalin dengan "kode bisnis". Mengganti "logger" oleh "pendengar" tidak menyelesaikan ini, keterbacaan kode tidak berubah,
Doc Brown
2

Pendekatan lain adalah memisahkan pembalakan bisnis dan pembalakan teknis. Kemudian kita dapat menyebut pencatatan bisnis "Audit" dan menerapkan seperangkat aturan bisnis tertentu seperti istilah penyimpanan dan aturan pemrosesan seperti Pemantauan Aktivitas Bisnis.

Di sisi lain, penebangan teknis, atau hanya "Logging", adalah cara terakhir untuk meninggalkan jejak masalah teknis. Itu harus async, cepat, toleran terhadap kegagalan untuk mempertahankan pesan log. Juga, pesan log harus melewati paling sedikit jumlah proxy yang mungkin dekat dengan sumber masalah.

Logika Logging cukup variabel dan sangat erat dengan implementasinya, jadi apakah Anda benar-benar perlu memisahkannya dari kode?

Logika Audit harus dianggap sebagai logika domain dan ditangani sesuai itu.

Misalnya, dalam Arsitektur Heksagonal, mungkin ada port Audit bersama dengan port Klien, Storage dan MQ (dan, mungkin, Metrik dan Kontrol). Ini akan menjadi port sekunder, yaitu aktivitas pada port ini dipicu oleh inti bisnis, bukan oleh sistem eksternal.

ITollu
sumber
Saya sangat setuju dengan Anda bahwa ada dua jenis penebangan. Tapi saya tidak mendapatkan Logic of The Logging cukup variabel dan sangat erat dengan implementasinya , maksud Anda teknis logging di sini? Untuk teknis logging, saya pikir ini digunakan untuk mencatat entri / keluar metode dan nilai parameter yang lebih baik untuk duduk di luar metode.
Charlie
@ Charlie Ya, dengan "Penebangan" yang saya maksud adalah teknis logging. Nilai entri / keluar / parameter logging sudah cukup dalam kasus fungsi murni. Kemudian, atau tentu saja, Anda bisa menggunakan aspek atau Logger monad. Tetapi fungsi murni sangat bagus karena dapat diuji. Jadi, masalah, yang seharusnya dilacak oleh logger, kemungkinan akan diselesaikan selama dev / debug. Dengan fungsi yang tidak murni, di mana teknologi logging paling banyak digunakan, Anda ingin mencatat setiap panggilan params / hasil yang efektif, setiap pengecualian.
iTollu
1

Cara untuk menghindari masuk langsung ke kelas atau metode:

  1. Lempar pengecualian, dan lakukan logging di blok tangkapan lebih jauh ke pohon panggilan. Jika Anda perlu menangkap level log, Anda bisa melempar pengecualian khusus.

  2. Melakukan panggilan ke metode yang sudah diinstrumentasi untuk logging.

Robert Harvey
sumber
1
Apakah penebangan berada di tempat itu terbukti menjadi masalah, dan satu bahkan layak "diperbaiki"?
whatsisname
1

Apakah benar-benar diperlukan untuk memisahkan logging Anda dari logika bisnis Anda? Pembalakan yang dilakukan sesuai dengan logika bisnis yang ditulis dan karenanya masuk akal untuk berada di kelas / fungsi yang sama. Lebih penting lagi, ini membantu pembacaan kode yang lebih mudah.

Namun, jika Anda benar-benar ingin memisahkan pencatatan dari logika bisnis Anda, Anda harus mempertimbangkan untuk melempar pengecualian khusus dan menyerahkan pengecualian tersebut untuk pencatatan.

pengguna88748
sumber
0

Tidak, tidak dalam c #

OP, jawaban untuk pertanyaan spesifik Anda adalah tidak, tidak dalam c #. Mungkin ada bahasa AOP lain yang lebih asli di luar sana, tetapi semua pendekatan untuk AOP dalam c # yang saya lihat hanya dapat menerapkan perilaku yang diduga dalam konteks titik bergabung , artinya harus ada aliran kontrol antara satu blok kode dan lain. Perilaku yang diharapkan tidak akan dieksekusi di tengah-tengah suatu metode, kecuali tentu saja dengan memanggil metode lain.

Anda bisa "apsect-ize" bit logging tertentu

Yang sedang berkata, Anda bisa mengekstrak kekhawatiran tertentu yang terlibat dalam penebangan, hanya saja tidak menulis log. Misalnya, cutpoint yang dieksekusi saat masuk ke metode dapat mengatur konteks logging dan output semua parameter input, dan saat keluar bisa menangkap pengecualian atau melakukan log ke penyimpanan permanen, hal semacam itu.

Menulis log bukan merupakan aspek

Saya akan menambahkan bahwa menulis log sebenarnya bukan masalah lintas sektoral. Setidaknya tidak debug logging. Bukti saya untuk ini adalah bahwa Anda tidak dapat menulis persyaratan lintas sektoral yang sepenuhnya menjelaskan apa yang akan dilakukan aspek ini - spesifik untuk setiap kasus, karena tujuan penulisan log adalah untuk mencerminkan apa yang terjadi dengan logika, dan logika dalam setiap metode harus cukup unik (lihat KERING ).

Dengan kata lain, ada ketergantungan logis yang tidak dapat dipisahkan antara penulisan log dan hal-hal yang sedang ditulis. Anda tidak dapat menggeneralisasikannya.

Tapi audit itu

Jika Anda memiliki semacam persyaratan logging fungsional (mis. Audit logging untuk mendukung persyaratan non-repudiation ) maka beberapa orang akan berdebat (dan saya akan setuju) bahwa jika Anda menemukan diri Anda perlu menjalankan penulisan log ini di tengah-tengah suatu metode, Anda belum menyusun kode dengan cara yang konsisten dengan pemikiran berorientasi aspek. Jika ini terjadi, Anda harus mengekstrak kode menjadi metode terpisah hingga Anda mendapatkan tingkat rincian yang Anda butuhkan.

John Wu
sumber