จะเรียกว่า "ความกังวลข้ามตัด" เป็นข้อแก้ตัวที่ถูกต้องในการทำลาย SOLID / DI / IoC?


43

เพื่อนร่วมงานของฉันชอบพูดว่า "การบันทึก / การแคช / ฯลฯ เป็นข้อกังวลข้าม" จากนั้นดำเนินการใช้ซิงเกิลที่เกี่ยวข้องทุกที่ พวกเขารัก IoC และ DI

มันเป็นข้อแก้ตัวที่ถูกต้องหรือไม่ที่จะทำลายหลักการของ SOLI D ?


27
ฉันพบว่าหลักการ SOLID ส่วนใหญ่มีประโยชน์สำหรับผู้ที่มีประสบการณ์ที่จำเป็นในการติดตามโดยไม่รู้ตัวอยู่แล้ว
svidgen

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

4
@svidgen หลักการ SOLID นั้นมีประโยชน์เช่นกันเมื่อผู้ที่ไม่รู้จักพวกเขาตรวจสอบโค้ดของคุณและถามคุณว่าทำไมคุณถึงทำแบบนั้น เป็นเรื่องดีที่สามารถชี้ไปที่หลักการและพูดว่า "นั่นเป็นสาเหตุ"
candied_orange

1
คุณมีตัวอย่างใด ๆ หรือไม่ว่าทำไมคุณคิดว่าการบันทึกเป็นกรณีพิเศษ เป็นช่องทางที่ค่อนข้างง่ายในการเปลี่ยนเส้นทางข้อมูลไปยังซึ่งมักเป็นส่วนหนึ่งของกรอบ X ที่คุณใช้
ksiimson

คำตอบ:


42

เลขที่

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

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

และจากนั้นคุณจะได้รับข้อโต้แย้งว่าคนตัดไม้ตัวเองจะจัดการการเปลี่ยนแปลง "โอ้ถ้าเป้าหมาย / การกรอง / การจัดรูปแบบ / การเปลี่ยนแปลงกลยุทธ์แล้วเราจะเปลี่ยนการตั้งค่า!" นั่นคือขยะ ตอนนี้ไม่เพียง แต่คุณมี God Object ที่จัดการสิ่งเหล่านี้ทั้งหมดคุณกำลังเขียนโค้ดของคุณใน XML (หรือคล้ายกัน) ที่คุณไม่ได้รับการวิเคราะห์แบบคงที่คุณไม่ได้รับข้อผิดพลาดในการรวบรวมเวลาและคุณไม่ต้อง ไม่ได้รับการทดสอบหน่วยที่มีประสิทธิภาพจริงๆ

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

แต่การบันทึกและการแคช (และปัญหาการตัดขวางที่แพร่หลายอื่น ๆ ) ไม่ใช่กรณีเหล่านั้น พวกเขามักจะเป็นตัวอย่างที่ดีของปัญหาการมีเพศสัมพันธ์และการออกแบบที่คุณได้รับเมื่อคุณละเลยแนวทาง


22
คุณมีทางเลือกอื่นในตอนนั้น? ฉีด ILogger ลงในทุกชั้นที่คุณเขียนหรือไม่ เขียนมัณฑนากรสำหรับทุกคลาสที่ต้องการคนตัดไม้?
Robert Harvey

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


20
ปัญหาที่แท้จริงที่ฉันมีกับ ImC ดันทุรังก็คือรหัสที่ทันสมัยทั้งหมดขึ้นอยู่กับสิ่งที่ไม่ถูกฉีดหรือแยกออกไป ถ้าคุณเขียน C # ตัวอย่างเช่นคุณไม่ได้มักจะเป็นนามธรรมStringหรือInt32หรือแม้กระทั่งListออกจากโมดูลของคุณ มีเพียงขอบเขตที่สมเหตุสมผลและมีสติในการวางแผนการเปลี่ยนแปลง และนอกเหนือจากประเภท "แกนกลาง" ที่เห็นได้ชัดส่วนใหญ่การแยกแยะสิ่งที่คุณอาจเปลี่ยนไปนั้นเป็นเพียงประสบการณ์และการตัดสินอย่างแท้จริง
svidgen

6
@svidgen - ฉันหวังว่าคุณจะไม่ได้อ่านคำตอบของฉันในฐานะผู้สนับสนุน IoC ที่ไร้เหตุผล และเพียงเพราะเราไม่แยกประเภทแกนหลักเหล่านี้ (และสิ่งอื่น ๆ ที่รอบคอบ) ไม่ได้หมายความว่าการมีลิสต์ทั่วโลก / String / Int / etc
Telastyn

38

ใช่

นี่คือประเด็นทั้งหมดของคำว่า "ความกังวลเกี่ยวกับการตัดขวาง" - หมายถึงบางสิ่งที่ไม่เหมาะสมอย่างเป็นระเบียบในหลักการของโซลิด

นี่คือที่ที่อุดมการณ์พบกับความเป็นจริง

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


9
คำตอบที่สมเหตุสมผลและเป็นจริง
user1936

11
คุณช่วยเล่าให้เราฟังหน่อยได้ไหมว่าทำไมหลักการทั้งห้าข้อของโซลิดจึงถูกทำลายโดยข้อกังวลข้าม ฉันมีปัญหาที่จะเข้าใจว่า
Doc Brown

4
ใช่. ฉันอาจคิดว่ามีเหตุผลที่ดีที่จะ "ทำลาย" หลักการแต่ละข้อ แต่ไม่ใช่เหตุผลเดียวที่จะทำลายทั้ง 5!
svidgen

1
มันจะเหมาะสำหรับฉันที่จะไม่ต้องหัวของฉันกับกำแพงทุกครั้งที่ฉันต้องจำลองคนตัดไม้ / แคชเดียวสำหรับการทดสอบหน่วย ลองนึกภาพว่ามันจะเป็นอย่างไรในการทดสอบหน่วยโปรแกรมประยุกต์บนเว็บโดยไม่ต้องมีHttpContextBase(ซึ่งถูกนำมาใช้ด้วยเหตุผลนี้) ฉันรู้แน่นอนว่าความจริงของฉันจะเปรี้ยวจริงๆถ้าไม่มีคลาสนี้
devnull

2
@devnull บางทีที่ปัญหาแล้วมากกว่าความกังวลที่ตัดข้ามตัวเอง ...
บอริสไปเดอร์

25

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

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

ฉันคิดว่าการแคชเป็นสถานการณ์ที่แตกต่างอย่างสิ้นเชิงอย่างไรก็ตาม


3
ตอนนี้ฉันได้เพิ่มความสนใจในการใช้ฟังก์ชั่น (อาจเป็น monadic) เพื่อฝังสิ่งต่าง ๆ เช่นการบันทึกการจัดการข้อผิดพลาด ฯลฯ ในกรณีที่คุณใช้โดยไม่ต้องใส่มันลงในตรรกะทางธุรกิจหลัก ( ดูfsharpforfunandprofit.com/rop )
sara

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

12
@RubberDuck - บอกฉันว่า "การบันทึกไม่ควรแพร่กระจาย" เมื่อฉันได้รับรายงานข้อผิดพลาดจากฟิลด์และความสามารถในการดีบักเพียงอย่างเดียวที่ฉันต้องรู้ว่าเกิดอะไรขึ้นนั่นคือล็อกไฟล์ที่ฉันไม่ต้องการแพร่กระจาย บทเรียนที่เรียนรู้การเข้าสู่ระบบควร "แพร่หลาย" อย่างแพร่หลาย
Dunk

15
@RubberDuck: ด้วยซอฟต์แวร์เซิร์ฟเวอร์การบันทึกเป็นวิธีเดียวที่จะอยู่รอด เป็นวิธีเดียวที่จะหาจุดบกพร่องที่เกิดขึ้นเมื่อ 12 ชั่วโมงก่อนแทนที่จะเป็นตอนนี้บนแล็ปท็อปของคุณเอง ไม่ต้องกังวลเรื่องเสียงรบกวน การใช้ซอฟต์แวร์การจัดการเข้าสู่ระบบเพื่อให้คุณสามารถค้นหาบันทึกของคุณ (นึกคิดคุณควรตั้งค่าการเตือนภัยที่จะส่งอีเมลถึงคุณในบันทึกข้อผิดพลาด)
slebetman

6
เจ้าหน้าที่ฝ่ายสนับสนุนของเราโทรหาฉันและบอกฉันว่า "ลูกค้าคลิกหน้าเว็บบางหน้าและเกิดข้อผิดพลาดขึ้น" ฉันถามพวกเขาว่าข้อผิดพลาดพูดอะไรพวกเขาไม่รู้ ฉันถามสิ่งที่ลูกค้าคลิกโดยเฉพาะพวกเขาไม่รู้ ฉันถามว่าพวกเขาสามารถทำซ้ำพวกเขาไม่สามารถ ฉันยอมรับว่าการบันทึกสามารถทำได้ด้วยตัวบันทึกที่ใช้งานได้ดีในจุดบานพับที่สำคัญไม่กี่แห่ง แต่ข้อความแปลก ๆ เล็กน้อยที่นี่และมีคุณค่าเช่นกัน ความกลัวในการบันทึกจะทำให้ซอฟต์แวร์มีคุณภาพลดลง หากคุณมีข้อมูลมากเกินไปให้ตัดกลับ อย่าปรับให้เหมาะสมก่อนเวลาอันควร
Pace

12

2 เซ็นต์ของฉัน ...

ใช่และไม่.

คุณไม่ควรจริงๆละเมิดหลักการที่คุณนำมาใช้; แต่หลักการของคุณควรจะเหมาะสมและนำมาใช้ในการบริการเพื่อเป้าหมายที่สูงขึ้น ดังนั้นด้วยความเข้าใจที่ถูกต้องปรับอากาศบางชัดเจนละเมิดอาจจะไม่เกิดขึ้นจริงการละเมิดของ "จิตวิญญาณ" หรือ "ร่างของหลักการโดยรวม."

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

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

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

ดังนั้นฉันขอเสนอข้อแม้ใหญ่สองข้อของฉัน :

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

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

หากคุณรู้สึกผิดเกี่ยวกับข้อผิดพลาดของคุณในการตัดสินโปรดไปที่คำสารภาพและดำเนินการต่อ ...

ประการที่สอง: การกลับการควบคุมไม่เท่ากับการพึ่งพาการฉีด

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

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

และถ้าคุณกำลังเขียนโค้ดกับอแด็ปเตอร์ไม่ว่าLoggerจะถูกส่งไปยังอแด็ปเตอร์นั้นหรือถูกค้นพบโดยอแด็ปเตอร์นั้นค่อนข้างไม่สำคัญกับเป้าหมายการบำรุงรักษาโดยรวม และที่สำคัญกว่านั้นคือถ้าคุณมีอะแดปเตอร์ระดับโมดูลก็อาจจะเป็นเรื่องเหลวไหลที่จะฉีดเข้าไปในอะไรก็ได้ มันเขียนสำหรับโมดูล

tl; dr - หยุดยุ่งเกี่ยวกับหลักการโดยไม่คำนึงถึงสาเหตุที่คุณใช้หลักการ และในทางปฏิบัติมากขึ้นเพียงสร้างAdapterสำหรับแต่ละโมดูล ใช้วิจารณญาณของคุณเมื่อตัดสินใจว่าคุณจะวาดขอบเขตที่ "โมดูล" Adapterจากภายในแต่ละโมดูลไปข้างหน้าและการอ้างอิงโดยตรงกับ และแน่นอนว่าให้ฉีดlogger ที่แท้จริงลงในAdapter- แต่ไม่ใช่ทุก ๆ สิ่งที่อาจจำเป็นต้องใช้


4
ผู้ชาย ... ฉันจะได้คำตอบที่สั้นกว่านี้ แต่ฉันไม่มีเวลา
svidgen

2
+1 สำหรับการใช้อะแดปเตอร์ คุณต้องแยกการพึ่งพาส่วนประกอบของบุคคลที่สามเพื่อให้สามารถแทนที่พวกเขาได้ทุกที่ที่เป็นไปได้ การบันทึกเป็นเป้าหมายที่ง่ายสำหรับเรื่องนี้ - มีการใช้งานการบันทึกจำนวนมากและส่วนใหญ่มี API ที่คล้ายกันดังนั้นการใช้งานอะแดปเตอร์อย่างง่ายสามารถช่วยให้คุณเปลี่ยนได้อย่างง่ายดาย และสำหรับคนที่บอกว่าคุณจะไม่เปลี่ยนผู้ให้บริการบันทึกของคุณ: ฉันต้องทำสิ่งนี้และมันทำให้เกิดความเจ็บปวดอย่างแท้จริงเพราะฉันไม่ได้ใช้อะแดปเตอร์
จูลส์

"หลักการของ SOLID โดยเฉพาะนอกเหนือจากความต้องการที่แตกต่างกันมากนั้นท้ายที่สุดก็คือเป้าหมายของ" การส่งมอบซอฟต์แวร์ที่ทำงานได้และบำรุงรักษาได้ "" - นี่เป็นหนึ่งในแถลงการณ์ที่ดีที่สุดที่ฉันเคยเห็น ในฐานะที่เป็นนักเขียนรหัสแบบ OCD อย่างอ่อนโยนฉันมีส่วนร่วมในการต่อสู้กับอุดมคติและการเพิ่มผลผลิต
DVK

ทุกครั้งที่ฉันเห็น +1 หรือความคิดเห็นเกี่ยวกับคำตอบเก่าฉันอ่านคำตอบของฉันอีกครั้งและค้นพบอีกครั้งว่าฉันเป็นนักเขียนที่ไม่เป็นระเบียบและไม่ชัดเจน ... ฉันขอขอบคุณความคิดเห็นที่ @DVK
svidgen

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

8

แนวคิดที่ว่าการบันทึกควรจะถูกนำมาใช้เป็นซิงเกิลเป็นหนึ่งในการโกหกที่ได้รับการบอกกล่าวบ่อยครั้งที่มันได้รับแรงฉุด

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

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


2
ทางออกที่คุณเสนอคืออะไร? เป็นการฉีด ILogger ลงในทุกชั้นที่คุณเขียนหรือไม่ สิ่งที่เกี่ยวกับการใช้รูปแบบมัณฑนากร?
Robert Harvey

4
ตอนนี้ไม่ตอบคำถามของฉันใช่ไหม? ฉันระบุรูปแบบเป็นเพียงตัวอย่าง ... มันไม่จำเป็นต้องเป็นแบบนั้นถ้าคุณมีสิ่งที่ดีกว่าในใจ
Robert Harvey

8
ฉันไม่เข้าใจคำตอบนี้จริงๆในแง่ของข้อเสนอที่เป็นรูปธรรม
Brian Agnew

3
@ RobbieDee - ดังนั้นคุณกำลังบอกว่าการบันทึกควรจะดำเนินการในทางที่ซับซ้อนและไม่สะดวกโดย "ปิดโอกาส" ที่เราอาจต้องการเข้าสู่ระบบหลายแห่ง? แม้ว่าการเปลี่ยนแปลงเช่นนั้นเกิดขึ้นจริง ๆ คุณคิดว่าการเพิ่มฟังก์ชันการทำงานให้กับอินสแตนซ์ของ Logger ที่มีอยู่จะทำงานได้มากกว่าความพยายามทั้งหมดในการส่งผ่าน Logger นั้นระหว่างคลาสและอินเทอร์เฟซที่เปลี่ยนแปลงเมื่อคุณตัดสินใจว่าคุณต้องการ Logger หรือไม่ หลายสิบโครงการที่การบันทึกหลายสถานที่จะไม่เกิดขึ้น?
Dunk

2
Re: "คุณอาจต้องการเข้าสู่ระบบหลาย ๆ ที่ขึ้นอยู่กับลักษณะของผลลัพธ์": แน่นอน แต่วิธีที่ดีที่สุดในการจัดการที่อยู่ในกรอบการทำบันทึกแทนที่จะพยายามฉีดหลาย ๆ การพึ่งพาการบันทึกแยกต่างหาก (เฟรมเวิร์กการบันทึกทั่วไปสนับสนุนสิ่งนี้อยู่แล้ว)
ruakh

4

การบันทึกอย่างแท้จริงเป็นกรณีพิเศษ

@Telastyn เขียน:

คุณจะไม่เปลี่ยนไลบรารีการบันทึกหรือเป้าหมายหรือการกรองหรือการจัดรูปแบบหรือ ... หรือไม่?

หากคุณคาดหวังว่าคุณอาจต้องเปลี่ยนไลบรารีการบันทึกของคุณคุณควรใช้ส่วนหน้า เช่น SLF4J หากคุณอยู่ในโลก Java

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

ในระยะสั้นปัญหาเหล่านี้ได้รับการแก้ไข ... สำหรับการบันทึก ... และด้วยเหตุนี้จึงไม่จำเป็นต้องใช้การฉีดพึ่งพาเพื่อแก้ปัญหาเหล่านั้น

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

@Telastyn เขียน:

จากนั้นคุณจะได้รับข้อโต้แย้งว่าคนตัดไม้จะจัดการกับการเปลี่ยนแปลง "โอ้ถ้าเป้าหมาย / การกรอง / การจัดรูปแบบ / การเปลี่ยนแปลงกลยุทธ์แล้วเราจะเปลี่ยนการตั้งค่า!" นั่นคือขยะ ตอนนี้ไม่เพียง แต่คุณมี God Object ที่จัดการสิ่งเหล่านี้ทั้งหมดคุณกำลังเขียนโค้ดของคุณใน XML (หรือคล้ายกัน) ที่คุณไม่ได้รับการวิเคราะห์แบบคงที่คุณไม่ได้รับข้อผิดพลาดในการรวบรวมเวลาและคุณไม่ต้อง ไม่ได้รับการทดสอบหน่วยที่มีประสิทธิภาพจริงๆ

ฉันกลัวว่ามันเป็นทฤษฎีที่น่าเชื่อถือมาก ในทางปฏิบัติผู้พัฒนาระบบและผู้รวมระบบส่วนใหญ่ชอบข้อเท็จจริงที่ว่าคุณสามารถกำหนดค่าการบันทึกผ่านไฟล์กำหนดค่า และพวกเขาชอบความจริงที่ว่าพวกเขาไม่ได้คาดหวังให้ทดสอบการบันทึกของโมดูล

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


3

ใช่ และ ไม่ !

ใช่: ฉันคิดว่ามันมีเหตุผลที่ระบบย่อยต่าง ๆ (หรือ semantic layer หรือ library หรือพัฒนาการอื่น ๆ ของ modular bundling) แต่ละคนยอมรับ (เหมือนกันหรือ) logger ที่แตกต่างกันในระหว่างการเริ่มต้นแทนที่จะเป็นระบบย่อยทั้งหมดที่อาศัย singletonมากกว่าระบบย่อยทั้งหมดอาศัยเดี่ยวทั่วไปเดียวกันที่ใช้ร่วมกัน

อย่างไรก็ตาม

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


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


3

ก่อนอื่นมันเริ่มต้นด้วย singleton cache ที่แข็งแกร่งสิ่งต่อไปที่คุณเห็นคือ singletons ที่แข็งแกร่งสำหรับเลเยอร์ฐานข้อมูลที่แนะนำสถานะโกลบอล API ที่ไม่ใช่คำอธิบายของ class es และรหัสที่ไม่สามารถพิสูจน์ได้

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

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

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


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

@amon: นาฬิกาเป็นเหมือนการเข้าสู่ระบบที่มีกลไกอื่นที่ให้บริการเพื่อวัตถุประสงค์เดียวกับ DI คือ Joda-Time และพอร์ตจำนวนมาก (ไม่ว่ามีอะไรผิดปกติอะไรกับการใช้ DI แทน;. แต่มันเป็นเรื่องง่ายในการใช้ Joda เวลาโดยตรงมากกว่าที่จะพยายามที่จะเขียนอะแดปเตอร์ injectible ที่กำหนดเองและผมไม่เคยเห็นใครเสียใจทำเช่นนั้น)
ruakh

@ มอน "ฉันเคยมีประสบการณ์คล้ายกับนาฬิกาที่คุณไม่เคยต้องการอะไรเลยนอกจากเรียลไทม์ใช่มั้ยยกเว้นเมื่อทดสอบเขตเวลา / กรณีขอบ DST แน่นอน ... " - หรือเมื่อคุณรู้ว่ามีข้อบกพร่อง ฐานข้อมูลของคุณเสียหายและมีความหวังเดียวที่จะนำมันกลับมาใช้คือการแยกวิเคราะห์บันทึกเหตุการณ์ของคุณและเล่นซ้ำโดยเริ่มจากการสำรองข้อมูลครั้งล่าสุด ... แต่ทันใดนั้นคุณต้องใช้รหัสทั้งหมดของคุณเพื่อทำงานตามบันทึกเวลาของรายการบันทึกปัจจุบัน เวลา.
จูลส์

3

ใช่และไม่ใช่ แต่ส่วนใหญ่ไม่ใช่

ฉันคิดว่าบทสนทนาส่วนใหญ่จะอิงจากอินสแตนซ์แบบคงที่เทียบกับการฉีด ไม่มีใครเสนอว่าการบันทึกทำลาย SRP ที่ฉันคิดเอาไว้? ส่วนใหญ่เรากำลังพูดถึง "หลักการการพึ่งพาการพึ่งพาอาศัยกัน" Tbh ฉันส่วนใหญ่เห็นด้วยกับไม่มีคำตอบของ Telastyn

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

ใช้: Convert.ToInt32("1")

ฉันชอบสิ่งนี้:

private readonly IConverter _converter;

public MyClass(IConverter converter)
{
   Guard.NotNull(converter)
   _converter = conveter
}

.... 
var foo = _converter.ToInt32("1");

ทำไม? ฉันยอมรับว่าฉันจะต้อง refactor รหัสถ้าฉันต้องการความยืดหยุ่นในการแลกเปลี่ยนรหัสการแปลง ฉันยอมรับว่าฉันจะไม่สามารถเยาะเย้ยเรื่องนี้ได้ ฉันเชื่อว่าความเรียบง่ายและความทนทานนั้นคุ้มค่ากับการค้าขายนี้

เมื่อมองไปที่ปลายอีกด้านของสเปกตรัมถ้าIConverterเป็นSqlConnectionผมจะต้องตกใจเมื่อเห็นว่าเป็นการโทรคงที่ สาเหตุที่เห็นได้ชัดคือ faily ฉันจะชี้ให้เห็นว่าSQLConnectionสามารถ "cross-cutting" ในการปรบมือดังนั้นฉันจะไม่ใช้คำที่แน่นอนเหล่านั้น

คือการเข้าสู่ระบบมากขึ้นเช่นSQLConnectionหรือConvert.ToInt32? ฉันจะพูดมากขึ้นเช่น 'SQLConnection`

คุณควรจะเยาะเย้ยเข้าสู่ระบบ มันพูดกับโลกภายนอก เมื่อเขียนวิธีการใช้Convert.ToIn32ฉันใช้มันเป็นเครื่องมือในการคำนวณผลลัพธ์อื่น ๆ ที่ทดสอบได้แยกต่างหากของชั้นเรียน ฉันไม่ต้องการตรวจสอบConvertถูกเรียกอย่างถูกต้องเมื่อตรวจสอบว่า "1" + "2" == "3" การบันทึกแตกต่างกันมันเป็นเอาต์พุตแบบอิสระทั้งหมดของคลาส ฉันถือว่าเป็นผลผลิตที่มีคุณค่าต่อคุณทีมสนับสนุนและธุรกิจ ชั้นเรียนของคุณไม่ทำงานหากการบันทึกไม่ถูกต้องดังนั้นการทดสอบหน่วยไม่ควรผ่าน คุณควรทดสอบสิ่งที่ชั้นเรียนของคุณบันทึก ฉันคิดว่านี่เป็นอาร์กิวเมนต์นักฆ่าฉันหยุดที่นี่ได้จริงๆ

ฉันก็คิดว่ามันเป็นสิ่งที่ค่อนข้างจะเปลี่ยนแปลง การบันทึกที่ดีไม่เพียง แต่พิมพ์สตริง แต่เป็นสิ่งที่แอปพลิเคชันของคุณกำลังทำอยู่ (ฉันเป็นแฟนตัวยงของการบันทึกตามเหตุการณ์) ฉันเห็นการบันทึกพื้นฐานกลายเป็นการรายงาน UIs ที่ค่อนข้างซับซ้อน เห็นได้ชัดว่ามันง่ายมากที่จะมุ่งหน้าไปในทิศทางนี้ถ้าการบันทึกของคุณมีลักษณะ_logger.Log(new ApplicationStartingEvent())และไม่เหมือนLogger.Log("Application has started")กัน อาจมีคนแย้งว่านี่คือการสร้างสินค้าคงคลังสำหรับอนาคตที่อาจไม่เคยเกิดขึ้นนี่คือการตัดสินและฉันคิดว่ามันคุ้มค่า

ในความเป็นจริงในโครงการส่วนตัวของฉันฉันสร้าง UI ที่ไม่ได้เข้าสู่ระบบโดยใช้_loggerเพื่อหาว่าแอปพลิเคชันทำอะไร นี่หมายความว่าฉันไม่จำเป็นต้องเขียนโค้ดเพื่อค้นหาว่าแอปพลิเคชันทำอะไรและฉันก็จบลงด้วยการบันทึกที่มั่นคง ฉันรู้สึกเหมือนว่าทัศนคติต่อการบันทึกของฉันนั้นง่ายและไม่เปลี่ยนแปลงความคิดนั้นจะไม่เกิดขึ้นกับฉัน

ดังนั้นฉันเห็นด้วยกับ Telastyn สำหรับกรณีการบันทึก


นี่คือวิธีที่ฉันเข้าสู่ระบบ Incidently ฉันต้องการลิงก์ไปยังบทความหรืออะไร แต่ฉันหาไม่เจอ ถ้าคุณอยู่ในโลก .NET Semantic Logging Application Blockและมองขึ้นไปบันทึกเหตุการณ์คุณจะพบ อย่าใช้มันเช่นเดียวกับรหัสส่วนใหญ่ที่สร้างขึ้นโดยทีม "ลวดลายและการปฏิบัติ" ของ MS โดยประชดประชันมันเป็นปฏิปักษ์
นาธานคูเปอร์

3

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

การรักษาวัตถุอย่างเดียวไม่ได้เกี่ยวข้องกับ SOLID นั่นคือวัฏจักรชีวิตของคุณว่าคุณต้องการให้วัตถุอยู่ในความทรงจำนานแค่ไหน

คลาสที่ต้องการการพึ่งพาเพื่อเตรียมใช้งานไม่ควรทราบว่าอินสแตนซ์ของคลาสที่ให้มานั้นเป็นแบบซิงเกิลหรือแบบชั่วคราว แต่ tldr; ถ้าคุณกำลังเขียน Logger.Instance.Log () ในทุก ๆ เมธอดหรือคลาสมันเป็นโค้ดที่มีปัญหา (code ดมกลิ่น / คลัปแข็ง) เป็นระเบียบมาก นี่คือช่วงเวลาที่คนเริ่มเหยียดหยามโซลิด และผู้พัฒนาเพื่อนอย่าง OP เริ่มถามคำถามของแท้เช่นนี้


2

ฉันได้แก้ไขปัญหานี้โดยใช้การผสมผสานระหว่างการสืบทอดและลักษณะ (เรียกอีกอย่างว่ามิกซ์อินในบางภาษา) ลักษณะพิเศษมีประโยชน์อย่างยิ่งสำหรับการแก้ปัญหาการตัดขวางแบบนี้ ปกติแล้วจะเป็นฟีเจอร์ภาษา แต่ฉันคิดว่าคำตอบที่แท้จริงคือมันขึ้นอยู่กับฟีเจอร์ของภาษา


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