เป็นไปได้หรือไม่ที่จะเก็บรหัสการบันทึกไว้อย่างสมบูรณ์นอกตรรกะทางธุรกิจ


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 อันออกจากวิธีการ? วิธีปฏิบัติที่ดีที่สุดสำหรับสถานการณ์เช่นนี้คืออะไร?


ฉันค่อนข้างมั่นใจว่าตัวอย่าง "บันทึกขั้นตอนที่ 1" และ "ขั้นตอนที่ 2" ของคุณควรเป็นส่วนหนึ่งของหลักฐานการตรวจสอบตรรกะทางธุรกิจและบันทึกแรกทางเทคนิค ฉันจะจัดเรียงสิ่งนี้ก่อน ...
อังคารที่

คำตอบ:


1

แน่นอน!

แต่จากประสบการณ์ของฉันมีการบันทึกที่มีประโยชน์ทั่วไปสองประเภท:

บันทึกทุกอย่าง :บันทึกที่สร้างขึ้นผ่าน API การทำโปรไฟล์ เหมาะสำหรับระบุปัญหาด้านประสิทธิภาพและการรายงานข้อยกเว้น เสียงดัง.

บันทึกเหตุการณ์ธุรกิจ :บันทึกการเรียกใช้ในตรรกะทางธุรกิจ ทุกสิ่งที่ธุรกิจอาจสนใจ เสียงรบกวนน้อยที่สุด เหตุการณ์ "ธุรกิจ" ที่โดดเด่นและสมเหตุสมผล ดีสำหรับการตรวจสอบและ KPI ของ ...

ดังนั้นฉันขอแนะนำสองสิ่ง ประการแรกทำในสิ่งที่ตรวจสอบเครื่องมืออื่น ๆ ทำเช่นที่ระลึกใหม่และใช้ .NET โปรไฟล์ API 1 ประการที่สองเข้าสู่ระบบงานธุรกิจเชิงตรรกะในตรรกะทางธุรกิจของคุณ การเก็บบันทึกเหตุการณ์บางอย่างเป็นตรรกะทางธุรกิจ

และผมจะไม่ปกติแนะนำ AOP การเรียงลำดับของการเข้าสู่ระบบทั้ง2 จากประสบการณ์ของฉันคุณต้องการทุกอย่างซึ่งหมายความว่าคุณกำลังใช้ตัวสร้างโปรไฟล์หรือคุณต้องการกิจกรรมเชิงตรรกะ / ธุรกิจ และในกรณีหลังนี้ฉันคิดว่ามันตรงไปตรงมามากกว่าที่จะเรียกใช้ตัวบันทึกในตรรกะทางธุรกิจ


1. แต่จริงจังช่วยตัวคุณเองหลายพันชั่วโมงในความพยายามและใช้เครื่องมือตัวสร้างโปรไฟล์ที่มีอยู่ ...

2. แน่นอนนี่ถือว่าคุณแบ่งปันความคิดเห็นของฉันว่าแง่มุมไม่ใช่สถานที่ที่ดีในการซ่อนกฎเกณฑ์ทางธุรกิจ!


ฉันค่อนข้างเห็นด้วยกับ "บันทึกเหตุการณ์ทางธุรกิจ" และเช่นเดียวกับคำตอบของผู้อื่นฉันจะเก็บรหัสบันทึกไว้ในตรรกะทางธุรกิจ และสำหรับส่วน "บันทึกทุกอย่าง" ฉันชอบใช้โซลูชัน AOP เพราะจะเป็นไปตาม SRP และไม่ทำให้เกิดความเสียหายต่อตรรกะทางธุรกิจของฉัน อย่างไรก็ตามฉันจะดูที่ API การทำโปรไฟล์ก่อน
Charlie

10

แน่นอนว่าคุณสามารถใช้ AOP ได้อย่างง่ายดาย เพียงแค่ refactor ชิ้นส่วน

  • รับรหัสผู้ใช้
  • ขั้นตอนที่ 1
  • ขั้นตอนที่ 2

เป็นวิธีการแยกต่างหาก (อย่างที่คุณควรทำเพื่อทำให้โค้ดของคุณสะอาดขึ้น) ตอนนี้คุณสามารถกำหนดค่ากรอบ AOP ของคุณได้อย่างง่ายดายเพื่อบันทึกการเรียกใช้เมธอดที่คุณเลือก ( เช่นที่แสดงที่นี่ ) ข้อยกเว้นสามารถบันทึกได้โดยตรงจากผู้โทรไม่จำเป็นต้องใช้ AOP ในการลบตรรกะทางธุรกิจ

หากต้องการแก้ไขของคุณ:

ฉันต้องการแสดงที่นี่คือวิธีการที่ควรได้รับการปฏิบัติในฐานะหน่วยที่เล็กที่สุดจากมุมมองของโดเมน ไม่ควรแบ่งเป็นชิ้นเล็ก ๆ

ทำไมถึงไม่ควร? หากใน "ตรรกะทางธุรกิจ" คุณต้องการเข้าสู่ระบบ "บางสิ่ง" ซึ่งมีค่าการบันทึกและหาก "บางอย่าง" นี้สามารถให้ชื่อที่สมเหตุสมผลในกรณีส่วนใหญ่มันจะทำให้รู้สึกถึงการ refactor รหัสเป็นวิธีการใน มันเอง หากคุณต้องการใช้ AOP คุณจะต้องจัดโครงสร้างโค้ดของคุณในแบบที่คุณควรจะจัดโครงสร้างไว้โดยไม่คำนึงถึงข้อกำหนดการบันทึก คุณสามารถตีความสิ่งนี้ว่าเป็นข้อเสียของ AOP หรือคุณสามารถตีความสิ่งนี้ว่าเป็นประโยชน์เนื่องจากมันจะให้ความคิดเห็นกับคุณในการปรับปรุงโครงสร้างรหัสของคุณ


มันไม่ดีของฉันที่ตัวอย่างของฉันไม่ชัดเจนพอ สิ่งที่ฉันต้องการแสดงในตัวอย่างคือวิธีนี้เป็นหน่วยที่เล็กที่สุดจากมุมมองของโดเมนซึ่งไม่ควรแบ่งออกเป็นชิ้นเล็ก ๆ
Charlie

@ Charlie: ตัวอย่างชัดเจนสมบูรณ์ ความเข้าใจผิดของคุณที่นี่อาจเป็นไปได้ว่าคุณคิดว่ามันเป็นความคิดที่ดีที่จะมีวิธีการที่ใหญ่กว่าขั้นตอน และนั่นเป็นความผิดที่ IMHO ไม่ใช่ความคิดที่ดี การมีขั้นตอนต่าง ๆ ที่คุ้มค่าในการบันทึกคือสัญญาณที่ชัดเจนขั้นตอนเหล่านี้ควรมีนามธรรมซึ่งเป็นชื่อของตัวเองดังนั้นจึงเป็นวิธีการที่เป็นของตัวเอง
Doc Brown

@ Charlie ไม่มีอะไรหยุดยั้งคุณไม่ให้ทำ 3 วิธีส่วนตัวที่ถูกเรียกโดยหน่วยงานหรือที่ทำงานของคุณ วิธีนี้จากข้างนอกมันยังคงเหมือนเดิม แต่ตอนนี้คุณมีสิ่งที่เป็นนามธรรมที่จำเป็นสำหรับการเข้าสู่ระบบของคุณ
Rémi

วิธีนี้ใช้ได้ถ้าคุณต้องการผลักดันโครงสร้างรหัสของคุณโดยบันทึกข้อกังวล บางครั้งคุณต้องการขับอย่างอื่น
John Wu

@JohnWu: โครงสร้างรหัสควรสะท้อนถึงข้อกังวล / ขั้นตอนต่าง ๆ โดยไม่คำนึงถึงข้อกำหนดการบันทึก นั่นคือสิ่งที่ขับเคลื่อนโครงสร้างรหัสที่นี่ เมื่อแก้ไขปัญหานี้แล้วการบันทึกสามารถทำได้โดย AOP นั่นคือ "ผลข้างเคียง" ของการทำให้โค้ดมีโครงสร้างที่ดีขึ้น ดังนั้นฉันคิดว่ามันไม่ใช่ความกังวลเกี่ยวกับการบันทึกที่ทำให้โครงสร้างรหัสเป็นเรื่องที่มากกว่าความต้องการของการใช้ AOP สำหรับการบันทึกทำให้มันโปร่งใสมากขึ้นว่ารหัสนั้นขาดโครงสร้างบางอย่างที่ควรมี
Doc Brown

3

เว้นแต่ว่าการบันทึกข้อมูลเป็นส่วนหนึ่งของข้อกำหนดทางธุรกิจดังนั้นจึงเป็นการดีที่สุดที่คุณควรเก็บเอาไว้ในโค้ดของคุณอย่างสมบูรณ์

นั่นหมายความว่าคุณไม่ต้องการบันทึกสิ่งต่าง ๆ เช่น "ขั้นตอนที่ 1 เสร็จสมบูรณ์" แม้ว่าในตอนแรกมันอาจจะมีประโยชน์สำหรับการดีบั๊ก แต่ในการผลิตมันจะสร้างขยะกิกะไบต์ที่คุณจะไม่มีวันได้เห็น

หาก Step1Complete เป็นกิจกรรมทางธุรกิจบางประเภทที่ต้องการการดำเนินการเพิ่มเติมคุณสามารถสัมผัสกับเหตุการณ์แบบเก่าที่ดีโดยไม่บังคับให้คุณฉีด ILogger หรือสิ่งที่คล้ายกันในชั้นเรียนของคุณ


นั่นคือสิ่งที่ฉันคิด ฉันไม่สามารถใช้กรณีที่สมเหตุสมผลในการเข้าสู่ระบบภายในรูปแบบโดเมน / ธุรกิจ POCO การบันทึกเป็นสิ่งที่มีแนวโน้มที่จะเข้ากับโมเดลธุรกิจหลักนอก IMO
jleach

2

ด้วยความช่วยเหลือของรูปแบบทั่วไปบางอย่างคุณสามารถดึงรหัสการบันทึกจากตรรกะทางธุรกิจของคุณ อย่างไรก็ตามคุณอาจไม่พบว่ามันคุ้มค่าที่จะทำเช่นนั้น

ตัวอย่างเช่นโดยการใช้ฟัง (งานฝีมืออย่างใดอย่างหนึ่งหรือใช้ event bus ฯลฯ ) รหัสของคุณจะมีลักษณะ

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 พยายามแก้ไขคือปัญหาของรหัสที่อ่านไม่ได้ของรหัสที่ไม่ใช่ธุรกิจ (เช่นการโทรเข้าสู่ระบบ) ผสมผสานกับ "รหัสธุรกิจ" แทนที่ "คนตัดไม้" โดย "ฟัง" ไม่แก้ปัญหานี้ความสามารถในการอ่านของรหัสจะไม่เปลี่ยนแปลง
Doc Brown

2

อีกวิธีหนึ่งคือการแยกบันทึกธุรกิจและบันทึกทางเทคนิคออกจากกัน จากนั้นเราสามารถเรียกการบันทึกทางธุรกิจ "การตรวจสอบ" และใช้กฎธุรกิจเฉพาะเช่นข้อกำหนดการจัดเก็บและกฎการประมวลผลเช่นการตรวจสอบกิจกรรมทางธุรกิจ

ในทางกลับกันการบันทึกทางเทคนิคหรือเพียงแค่ "การบันทึก" เป็นวิธีการสุดท้ายที่จะทิ้งร่องรอยของปัญหาทางเทคนิค มันควรจะเป็น async รวดเร็วทนต่อความล้มเหลวในการคงข้อความบันทึกไว้ นอกจากนี้ข้อความบันทึกควรผ่านจำนวนพร็อกซีที่น้อยที่สุดที่เป็นไปได้เพื่อให้ใกล้กับแหล่งที่มาของปัญหา

ลอจิกของการบันทึกเป็นตัวแปรค่อนข้างและควบคู่ไปกับการใช้งานอย่างแน่นหนาดังนั้นคุณต้องแยกมันออกจากรหัสหรือไม่?

ตรรกะของการตรวจสอบควรถูกพิจารณาว่าเป็นตรรกะของโดเมนและจัดการตามนั้น

ตัวอย่างเช่นในสถาปัตยกรรมหกเหลี่ยมอาจมีพอร์ตการตรวจสอบพร้อมกับไคลเอนต์ที่เก็บข้อมูลและพอร์ต MQ (และอาจเป็นไปได้ว่าพอร์ตการวัดและการควบคุม) มันจะเป็นพอร์ตรองนั่นคือกิจกรรมในพอร์ตนี้ถูกเรียกใช้โดยแกนธุรกิจแทนที่จะเป็นระบบภายนอก


ฉันเห็นด้วยอย่างมากกับคุณว่ามีการบันทึกสองแบบ แต่ฉันไม่ได้รับเหตุผลของการบันทึกเป็นตัวแปรค่อนข้างและควบคู่ไปกับการดำเนินการอย่างแน่นหนาคุณหมายถึงการบันทึกทางเทคนิคที่นี่? สำหรับการบันทึกทางเทคนิคฉันคิดว่ามันใช้เพื่อบันทึกการเข้า / ออกและค่าพารามิเตอร์ซึ่งดีกว่าที่จะนั่งนอกเมธอด
Charlie

@ Charlie ใช่โดย "The Logging" ฉันหมายถึงการบันทึกทางเทคนิค การบันทึกค่า entry / exit / พารามิเตอร์เพียงพอในกรณีของฟังก์ชันบริสุทธิ์ จากนั้นหรือแน่นอนคุณสามารถใช้มุมมองหรือ Logger monad แต่ฟังก์ชั่นที่บริสุทธิ์นั้นยอดเยี่ยมในการทดสอบ ดังนั้นปัญหาตัวบันทึกควรจะติดตามมีแนวโน้มที่จะได้รับการแก้ไขในระหว่าง dev / debug ด้วยฟังก์ชั่นไม่บริสุทธิ์ที่ใช้การบันทึกเทคโนโลยีเป็นส่วนใหญ่คุณต้องการบันทึกทุกการโทร / พารามิเตอร์การโทรที่มีประสิทธิภาพทุกข้อยกเว้น
iTollu

1

วิธีหลีกเลี่ยงการบันทึกโดยตรงในชั้นเรียนหรือวิธีการ:

  1. โยนข้อยกเว้นและทำการบันทึกของคุณในบล็อกการดักที่ไกลกว่าสายการโทร หากคุณต้องการบันทึกระดับการบันทึกคุณสามารถโยนข้อยกเว้นที่กำหนดเองได้

  2. โทรไปยังวิธีการที่ได้รับการบันทึกไว้แล้ว


1
มีการบันทึกว่ามันอยู่ที่ไหนที่จะมีปัญหาและหนึ่งก็คุ้มค่า "แก้ไข"?
whatsisname

1

จำเป็นหรือไม่ที่ต้องแยกการบันทึกของคุณออกจากตรรกะทางธุรกิจของคุณ? การบันทึกข้อมูลเสร็จสิ้นนั้นสอดคล้องกับตรรกะทางธุรกิจที่เขียนขึ้นดังนั้นจึงเหมาะสมที่จะอยู่ในคลาส / ฟังก์ชันเดียวกัน ที่สำคัญมันช่วยให้อ่านรหัสได้ง่ายขึ้น

อย่างไรก็ตามในกรณีที่คุณต้องการแยกการบันทึกจากตรรกะทางธุรกิจของคุณจริงๆคุณควรพิจารณาโยนข้อยกเว้นที่กำหนดเองและส่งข้อยกเว้นเหล่านั้นเพื่อการบันทึก


0

ไม่ไม่ได้อยู่ใน c #

OP คำตอบสำหรับคำถามเฉพาะของคุณคือไม่ใช่ไม่ใช่ใน c # อาจมีภาษาอื่น ๆ ที่มี AOP มากกว่าเดิม แต่วิธีการทั้งหมดของ AOP ใน c # ที่ฉันเห็นสามารถใช้พฤติกรรมที่ถูกมองในบริบทของจุดเชื่อมต่อเท่านั้นซึ่งหมายความว่าจะต้องมีการควบคุมระหว่างบล็อกโค้ดหนึ่งและ อื่น พฤติกรรมที่ตรวจพบจะไม่ถูกดำเนินการในระหว่างวิธีการยกเว้นโดยการเรียกวิธีอื่น

คุณสามารถ "apsect-ize" บิตการบันทึกบางอย่าง

ดังที่ได้กล่าวไปแล้วคุณสามารถแยกข้อกังวลบางอย่างที่เกี่ยวข้องกับการบันทึกไม่ใช่เพียงการเขียนบันทึก ตัวอย่างเช่นจุดตัดที่ดำเนินการกับการเข้าสู่วิธีการสามารถตั้งค่าบริบทการบันทึกและส่งออกพารามิเตอร์อินพุตทั้งหมดและเมื่อออกสามารถจับข้อยกเว้นหรือส่งบันทึกไปยังที่จัดเก็บถาวรซึ่งเป็นประเภทของสิ่งนั้น

การเขียนบันทึกไม่ได้เป็นเรื่องต่อไป

ฉันจะเพิ่มว่าการเขียนบันทึกไม่ได้เป็นความกังวลข้ามตัดจริงๆ อย่างน้อยก็ไม่ได้ดีบักการบันทึก หลักฐานของฉันสำหรับเรื่องนี้คือคุณไม่สามารถเขียนข้อกำหนดตัดขวางที่อธิบายอย่างเต็มที่ว่าสิ่งนี้จะทำอะไร - มันมีความเฉพาะสำหรับแต่ละกรณีเพราะวัตถุประสงค์ของการเขียนบันทึกคือเพื่อสะท้อนสิ่งที่เกิดขึ้นกับ ตรรกะและตรรกะในแต่ละวิธีควรจะมีความเป็นเอกลักษณ์ที่สมเหตุสมผล (ดูDRY )

กล่าวอีกนัยหนึ่งมีการพึ่งพาตรรกะที่แยกไม่ออกระหว่างการเขียนบันทึกและสิ่งที่เขียนเกี่ยวกับ คุณไม่สามารถพูดคุยได้

แต่การตรวจสอบคือ

หากคุณมีข้อกำหนดการบันทึกการทำงานบางประเภท (เช่นการบันทึกการตรวจสอบเพื่อสนับสนุนข้อกำหนดการปฏิเสธไม่ได้ ) บางคนอาจโต้แย้ง (และฉันยอมรับด้วย) ว่าถ้าคุณพบว่าตัวเองจำเป็นต้องดำเนินการบันทึกการเขียนเหล่านี้ คุณยังไม่ได้จัดโครงสร้างโค้ดของคุณในลักษณะที่สอดคล้องกับการคิดเชิงกว้าง หากสิ่งนี้เกิดขึ้นคุณควรแยกรหัสออกเป็นวิธีการแยกต่างหากจนกว่าคุณจะได้ระดับของเมล็ดที่คุณต้องการ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.