Is Dependency Injection คุ้มค่านอก UnitTesting


17

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

คลาสที่มีปัญหาเริ่มต้นคลาสอื่น ๆ ในคอนสตรัคเตอร์และคลาสที่ใช้นั้นค่อนข้างเฉพาะเจาะจง มันจะไม่ใช้การใช้งานอื่น เรามีเหตุผลในการหลีกเลี่ยงการพยายามโปรแกรมไปยังส่วนต่อประสานหรือไม่?



3
KISS - เป็นแนวทางที่ดีที่สุดเสมอ
ซ้ำ

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

1
การทดสอบมีเหตุผลเพียงพอหรือไม่?
ConditionRacer

ฟังดูไม่เหมือนซ้ำกันจริงๆ หากไม่เคยเกิดขึ้นการออกแบบเพราะไม่ได้ออกแบบเพื่อการเปลี่ยนแปลงในอนาคต แม้แต่นักบินอวกาศด้านสถาปัตยกรรมเท่านั้นที่ออกแบบมาสำหรับการเปลี่ยนแปลงที่จะไม่เกิดขึ้นจากการตัดสินที่ไม่ดี
Steve314

คำตอบ:


13

ขึ้นอยู่กับว่าคุณมั่นใจว่า "ไม่เคย" เป็นสิ่งที่ถูกต้อง (ในช่วงเวลาที่แอพของคุณจะถูกใช้)

โดยทั่วไป:

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

12
เกือบให้ -1 สำหรับ "อย่าแก้ไขการออกแบบของคุณเพียงเพื่อการทดสอบ" ในการรับการทดสอบคือ IMHO หนึ่งในเหตุผลสำคัญสำหรับการเปลี่ยนการออกแบบ! แต่ประเด็นอื่น ๆ ของคุณก็โอเค
Doc Brown

5
@docBrown - (และอื่น ๆ ) ฉันทำแตกต่างจากที่นี่มากมายและบางทีแม้แต่ส่วนใหญ่ ~ 95% ของเวลาการทำสิ่งต่าง ๆ ที่ทดสอบได้ยังทำให้มันยืดหยุ่นหรือยืดออกได้ คุณควรมีสิ่งนั้นไว้ในการออกแบบของคุณ (หรือเพิ่มสิ่งนั้นลงในการออกแบบของคุณ) ส่วนใหญ่เวลาทดสอบจะถูกสาป อีก 5 ~ อาจมีข้อกำหนดแปลก ๆ ที่ป้องกันความยืดหยุ่นประเภทนี้เพื่อประโยชน์อย่างอื่นหรือจำเป็นอย่างยิ่ง / ไม่เปลี่ยนแปลงที่คุณจะพบได้อย่างรวดเร็วหากมีการแตกหักแม้จะไม่มีการทดสอบโดยเฉพาะ
Telastyn

4
อาจแน่ใจ แต่ข้อความแรกของคุณข้างต้นอาจตีความได้ง่ายเกินไปเพราะ "ปล่อยโค้ดที่ออกแบบมาไม่ดีอย่างที่มันเป็นเมื่อข้อกังวลเดียวของคุณคือความสามารถในการทดสอบ"
Doc Brown

1
ทำไมคุณถึงพูดว่า "การสร้างอินเทอร์เฟซที่จะมีผู้สืบทอดเพียงคนเดียวเท่านั้นที่ไร้ประโยชน์"? อินเทอร์เฟซสามารถทำงานเป็นสัญญา
kaptan

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

12

เรามีเหตุผลในการหลีกเลี่ยงการพยายามโปรแกรมไปยังส่วนต่อประสานหรือไม่?

ในขณะที่ข้อได้เปรียบของการเข้ารหัสกับอินเทอร์เฟซค่อนข้างชัดเจนคุณควรถามตัวเองว่าสิ่งใดที่ได้มาโดยไม่ทำเช่นนั้น

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

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

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


2
+1 สำหรับการอ้างอิง YAGNI ที่นี่เป็นอาร์กิวเมนต์สำหรับ DI ไม่ใช่ข้อโต้แย้ง
Doc Brown

4
@DocBrown: พิจารณาว่า YAGNI สามารถใช้ที่นี่เพื่อแสดงว่าไม่ได้ใช้ DI ฉันคิดว่านั่นเป็นข้อโต้แย้งมากกว่า YAGNI ที่เป็นมาตรการที่มีประโยชน์สำหรับทุกสิ่ง
Steven Evers

1
+1 สำหรับสมมติฐานที่ฟุ่มเฟือยที่รวมอยู่ใน YAGNI ซึ่งตีเราในหัวไม่กี่ครั้ง
Izkata

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

@ back2dos: การคาดคะเนที่ DI นั้นมีประโยชน์เพราะ 'อาจจะเป็นข้อกำหนด' และ "ใครจะรู้" เป็นรถไฟแห่งความคิดที่แม่นยำว่า YAGNI มีจุดประสงค์เพื่อต่อสู้ แต่คุณใช้มันเป็นข้ออ้างสำหรับเครื่องมือและโครงสร้างพื้นฐานเพิ่มเติม
Steven Evers

7

ขึ้นอยู่กับพารามิเตอร์ต่าง ๆ แต่นี่คือเหตุผลสองสามข้อที่คุณยังต้องการใช้ DI:

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

บรรทัดล่าง: คุณอาจมีชีวิตอยู่ได้โดยไม่มี DI ในกรณีนั้น แต่มีโอกาสที่การใช้ DI จะจบลงด้วยโค้ดที่สะอาดกว่า


3

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

ประโยชน์เพิ่มเติมของการพึ่งพาการฉีดและการใช้อินเทอร์เฟซแทนการเรียนมีประโยชน์เมื่อขยายโปรแกรมประยุกต์ แต่พวกเขายังสามารถดัดแปลงไปยังซอร์สโค้ดในภายหลังค่อนข้างง่ายและปลอดภัยโดยใช้การค้นหาและแทนที่ - แม้ในโครงการขนาดใหญ่มาก


2
 > Dependency Injection worth it **outside** of UnitTesting?
 > Are we justified in avoiding trying to program to an interface?

คำตอบมากมายสำหรับคำถามนี้สามารถถกเถียงกันว่า "คุณอาจจำเป็นต้องใช้เพราะ .. " เป็น YAGNI หากคุณไม่ต้องการที่จะไม่ทำเงิน

หากคุณถามว่าสาเหตุใดที่อยู่นอกเหนือจาก unittests จำเป็นต้องตั้งโปรแกรมให้อินเทอร์เฟซ

ใช่ , พึ่งพาการฉีดมูลค่ามันนอกของ unittesting ถ้าคุณต้องการความผกผันของการควบคุม ตัวอย่างเช่นหากการนำโมดูลไปใช้งานต้องการโมดูลอื่นที่ไม่สามารถเข้าถึงได้ในเลเยอร์

ตัวอย่าง: ถ้าคุณมีโมดูลgui=> businesslayer=> =>drivercommon

ในสถานการณ์นี้businesslayerสามารถใช้driverแต่ไม่สามารถใช้driverbusinesslayer

หากdriverต้องการฟังก์ชั่นระดับสูงคุณสามารถใช้ฟังก์ชั่นนี้businesslayerซึ่งใช้อินเตอร์เฟซในcommonเลเยอร์ driverต้องการทราบอินเตอร์เฟสในcommonเลเยอร์เท่านั้น


1

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

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

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


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

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

1

พึ่งพาการฉีดยังทำให้มันชัดเจนว่าวัตถุของคุณHASอ้างอิง

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

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


0

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

ฉันขอเสนอทางเลือกอื่นสำหรับสถานการณ์ของฉันโดยเฉพาะ

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

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