ฉันควรเขียน API อินเตอร์เฟสก่อนการใช้งานหรือไม่


14

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

และถ้าเป็นกรณีนี้ในกรณีของการใช้ไลบรารี่ของบุคคลที่สาม (เช่น Lidgren) ฉันควรจะห่อมันไว้ในส่วนต่อประสานและแก้ไขมันผ่านคอนเทนเนอร์ IOC หรือไม่


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

ใช่และโปรแกรมอินเตอร์เฟซ (หรือคลาสนามธรรมสำหรับเรื่องนั้น) ก่อนที่คุณจะใช้พวกเขา มันจะช่วยให้การรับส่งข้อความจากไคลเอนต์ไปยังเซิร์ฟเวอร์และในทางกลับกัน "ถูกต้อง" ก่อนที่จะถูกติดขัด (และลงทุน) การใช้งาน สไลด์โชว์ที่ดีมากในเรื่อง: วิธีการออกแบบ API ที่ดี & ทำไมมันถึงสำคัญ
Marjan Venema

คำตอบ:


8

น่าเสียดายที่คุณจะพบว่าสิ่งนี้มักทำให้คุณพึงพอใจเป็นส่วนตัว

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

  1. เขียนแอปพลิเคชันโครงกระดูกของคุณเป็นอินเทอร์เฟซคลาสนามธรรม (stubbed) และคลาส (stubbed)
  2. เขียนการทดสอบของคุณกับอินเทอร์เฟซและสตับ (ตอนนี้จะล้มเหลว)
  3. เขียนการใช้งานของคุณ (การทดสอบของคุณจะเริ่มผ่านเมื่อคุณเสร็จสิ้นการใช้งานของคุณ)

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

คะแนนพิเศษบางอย่าง:

  • คอนเทนเนอร์ IoC สะดวก ใช้พวกเขาและ DI เท่าที่คุณสามารถ
  • อย่าห่อห้องสมุดของบุคคลที่ 3 การทำเช่นนี้จะเป็นการลดการเชื่อมต่อระหว่างรหัสของคุณ (รหัสที่คุณควบคุม) และรหัสบุคคลที่สาม (รหัสที่คุณไม่สามารถควบคุมได้)

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

ส่วนไหนที่จะละเมิด YAGNI
MetaFight

การห่อห้องสมุดบุคคลที่สาม
ด่าน Pantry

2
ฉันเดาว่ามันจะลดลงเป็น: อัตราต่อรองของห้องสมุดบุคคลที่สามมีการเปลี่ยนแปลงอย่างไร หากมีโอกาส 0% จากนี้ให้แน่ใจว่า YAGNI แต่นั่นเป็นกรณีที่ไม่ค่อย นอกจากนี้การห่อ libs บุคคลที่สามของคุณอาจทำให้โค้ดอื่น ๆ ของคุณง่ายต่อการทดสอบหน่วย (ตัวอย่างเช่นถ้าคุณไม่สามารถเยาะเย้ยห้องสมุดบุคคลที่สาม)
MetaFight

1
@DanPantry: การตัดไลบรารี่ของบุคคลที่สามไม่ใช่การละเมิด YAGNI แต่เป็นการป้องกันที่จำเป็นมากสำหรับ "การบุกรุกไลบรารี่ของบุคคลที่สามที่มีรหัสของคุณเอง" มันไม่เพียงเกี่ยวกับความสามารถในการสลับไลบรารี แต่ในขณะที่ MetaFight ยังกล่าวว่าการป้องกันการเปลี่ยนแปลงในไลบรารีเวอร์ชันใหม่กว่าซึ่งจะต้องมีการเปลี่ยนแปลงตลอดทั้งรหัสของคุณเอง โดยการห่อห้องสมุด (และโดยเฉพาะอย่างยิ่งประเภทที่เฉพาะเจาะจง: คลาส, enums, structs ฯลฯ ) คุณป้องกันรหัสของคุณเองและมีจุดเดียวที่จะเปลี่ยนเมื่อห้องสมุดมีการเปลี่ยนแปลง (ด้วยเหตุผลใดก็ตาม)
Marjan Venema

13

ใช่คุณควรใช้รหัสกับส่วนต่อประสานมากกว่าที่จะรู้จักการใช้งานและใช่คุณควรสร้างส่วนต่อประสานก่อนแทนที่จะให้พวกมันโผล่ออกมาจากรหัสของคุณเอง

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

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

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

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


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

มีแบบแผนการตั้งชื่อสำหรับ API ที่เป็นเพียงส่วนต่อประสานที่ฉันจะใช้งานทั่วสถานที่หรือไม่? เช่นถ้าฉันทำรูปแบบคำสั่งฉันจะเรียกมันว่า "commandables" หรือไม่?
Snoop

@StevieV มีเช่นที่หลากหลายIBlahดำเนินการโดยBlahหรือดำเนินการโดยBlah BlahImplฉันไม่ชอบทั้งสองและมีแนวโน้มที่จะใช้BlahดำเนินการโดยOralBlah, หรือWrittenBlah ASLBlahแต่ตามปกติสิ่งสำคัญคือการสอดคล้องกับรหัสฐานและความคาดหวังที่มีอยู่ของคุณมากกว่ามาตรฐานทั่วไป
Kilian Foth

4

แทนที่จะเขียนโปรแกรมไปยังอินเตอร์เฟสทำไมจึงไม่ลองดูการพัฒนา / ออกแบบการทดสอบขับเคลื่อน (TDD)

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

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

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

สำหรับการใช้ห้องสมุดบุคคลที่สามฉันขอแนะนำให้ห่อไว้ใน abstractions ของคุณเองตามความเหมาะสม และอย่าให้ลูกค้าของ API "รู้" เกี่ยวกับพวกเขา

โชคดี!

[แก้ไข: เห็นคำตอบของ megaflight - เห็นด้วยอย่างสมบูรณ์]


2
TDD มีความคิดในแง่ของส่วนต่อประสานมากกว่าที่จะบอกเป็นนัยถึงแม้ว่าจะไม่ได้ประกาศอย่างเป็นทางการ
DougM

1
นี่คือคำตอบที่ดี +1 สำหรับการแนะนำ TDD ซึ่งฉันคิดว่าเป็นวิธีแก้ปัญหาที่แท้จริงของ OP ว่าจะเริ่มต้นเมื่อทำงานในโครงการใหม่และฉันจะ +1 อีกครั้งถ้าฉันทำได้สำหรับ "การใช้ TDD จะบังคับให้คุณสำรวจว่าอินเทอร์เฟซนั้น มีความสำคัญและตรงไหนมันไม่สำคัญ "
Benjamin Hodgson

2

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

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


ผมคิดว่าคนที่อยู่ภายใต้อินเตอร์เฟซที่ใช้งาน หากคุณต้องการสร้างชิ้นส่วนที่นำกลับมาใช้ใหม่ได้อินเทอร์เฟซไม่เพียงเป็นการเพิ่ม "ดีที่มี" แต่สิ่งสำคัญที่ต้องดูแล นอกจากการใช้งานจริงแน่นอน
JensG

1

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

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

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

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