จำเป็นต้องมีรูปแบบการออกแบบและระดับของนามธรรมเท่าไร [ปิด]


29

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

นักพัฒนาที่ฉันทำงานด้วยกำลังเขียนโปรแกรมต่าง ๆ เกี่ยวกับประเด็นเหล่านี้

บางฟังก์ชั่นเป็นนามธรรมทุกฟังก์ชั่นเล็กน้อยใช้รูปแบบการออกแบบทุกที่ที่เป็นไปได้

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

ฉันรู้ว่านี่เป็นการแลกเปลี่ยน ฉันจะบอกได้อย่างไรว่ามีสิ่งที่เป็นนามธรรมเพียงพอในโครงการและฉันจะรู้ได้อย่างไรว่ามันต้องการมาก

ตัวอย่างเมื่อเลเยอร์แคชทั่วไปถูกเขียนโดยใช้ Memcache เราจำเป็นต้องจริงๆMemcache, MemcacheAdapter, MemcacheInterface, AbstractCache, CacheFactory, CacheConnector... หรือคือง่ายต่อการรักษาและยังคงรหัสที่ดีเมื่อใช้เพียงครึ่งหนึ่งของชั้นเรียนเหล่านั้นหรือไม่

พบสิ่งนี้ใน Twitter:

ป้อนคำอธิบายรูปภาพที่นี่

( https://twitter.com/rawkode/status/875318003306565633 )


58
หากคุณใช้รูปแบบการออกแบบเป็นสิ่งที่คุณดึงออกมาจากที่เก็บข้อมูลและใช้ในการรวบรวมโปรแกรมแสดงว่าคุณใช้งานมากเกินไป
Blrfl


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

8
ไม่มีวิธีที่คำตอบเดียวของ SE อาจครอบคลุมหัวข้อนี้ได้อย่างเพียงพอ สิ่งนี้ใช้เวลาหลายปีของประสบการณ์และการให้คำปรึกษาในการจัดการ ชัดเจนเกินไป
jpmc26

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

คำตอบ:


52

จำเป็นต้องมีส่วนผสมกี่อย่างสำหรับมื้ออาหาร คุณต้องสร้างยานพาหนะกี่ชิ้น?

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

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

นอกจากนั้นยังไม่มีวิธีตอบคำถามโดยให้ตัวเลข จำนวนของ abstractions จะไม่เหมือนกันจากโปรเจ็กต์หนึ่งไปอีกโปรเจ็กต์จากภาษาหนึ่งไปอีกภาษาหนึ่งและแม้กระทั่งจากนักพัฒนารายหนึ่งไปอีกคนหนึ่ง


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

จำนวนของ abstractions จะไม่เหมือนกันสำหรับส่วนต่าง ๆ ของโครงการเดียวกัน!
T. Sar - Reinstate Monica

คำแนะนำ: การเปลี่ยนจาก Memcache ไปเป็นกลไกการแคชอื่น (Redis?) เป็นการเปลี่ยนแปลงการใช้งาน
Ogre Psalm33

กฎสองข้อของคุณ (แนวทางสิ่งที่คุณต้องการเรียกใช้) ไม่ทำงานดังที่ Tulains แสดงให้เห็น พวกเขายังไม่สมบูรณ์อย่างน่าสมเพชแม้ว่าพวกเขาจะทำ ส่วนที่เหลือของโพสต์นั้นไม่ใช่คำตอบโดยพูดน้อยกว่าที่เราไม่สามารถให้คำตอบที่มีขอบเขต -1
jpmc26

ฉันจะเถียงว่าในกรณีของอินเทอร์เฟซสองรายการและคลาสหลายร้อยคลาสที่ใช้พวกเขาคุณอาจมีบทคัดย่อของคุณยาวเกินไป ฉันเคยเห็นสิ่งนี้ในโครงการที่ใช้สิ่งที่เป็นนามธรรมที่คลุมเครือในหลาย ๆ สถานที่ ( interface Doer {void prepare(); void doIt();}) และมันก็กลายเป็นความเจ็บปวดที่จะสร้างสิ่งใหม่เมื่อสิ่งที่เป็นนามธรรมไม่เหมาะสมอีกต่อไป ส่วนสำคัญของคำตอบคือการทดสอบที่ใช้เมื่อสิ่งที่เป็นนามธรรมต้องเปลี่ยน - ถ้าไม่เคยทำมันจะไม่ทำให้เจ็บปวด
James_pic

24

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

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

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

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


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

@PeteKirkham True แต่แม้กระทั่งรูปแบบการออกแบบทั้งหมดในการกำจัดของคุณอาจไม่เหมาะสมสำหรับปัญหาเฉพาะ ถ้าค้อนขนาดใหญ่ไม่เหมาะที่สุดที่จะถอดน็อตและไม่ต้องใช้ไขควงและไม่ได้วัดเทปเพราะคุณขาดค้อนนั่นไม่ทำให้ค้อนขนาดใหญ่เหมาะกับงานมันแค่ทำ เป็นเครื่องมือที่เหมาะสมที่สุดในการกำจัดของคุณ ไม่ได้หมายความว่าคุณควรใช้ค้อนขนาดใหญ่เพื่อแคร็กแม้ว่า Heck ถ้าเราจริงใจว่าสิ่งที่คุณต้องการคือแคร็กเกอร์ไม่ใช่ค้อน ..
Neil

ฉันต้องการกองทัพของกระรอกที่ได้รับการฝึกฝนสำหรับการแคร็กของฉัน
icc97

6

TL: DR;

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

คำตอบที่ยาว

ส่วนใหญ่คุณอาจจะไม่เคยรู้ว่าคุณกำลังสร้าง abstractions ในระดับใด

เรามองไม่เห็นสิ่งที่เป็นนามธรรมในระดับที่เรามองเห็น

เหตุผลนั้นนำฉันไปสู่ข้อสรุปนี้:

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

สิ่งที่เป็นนามธรรมที่ไม่ดีนั้นเกิดขึ้นกับระฆังเกาส์ในความจริงที่ว่าเมื่อคุณผ่านจุดที่น่ารักไปแล้วก็เริ่มเข้ามา ในทางตรงกันข้ามสิ่งที่ดีก็คือมองไม่เห็นและไม่มีอะไรมากเกินไปเพราะคุณไม่สังเกตว่ามันอยู่ที่นั่น คิดว่ามีกี่เลเยอร์บนเลเยอร์ของ API, โปรโตคอลเครือข่าย, ไลบรารี, ไลบรารี OS, ระบบไฟล์, เลเยอร์ฮาร์แวร์, ฯลฯ แอปพลิเคชันของคุณถูกสร้างขึ้นและรับสิทธิ์

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


2
"ส่วนใหญ่คุณจะไม่มีทางรู้ว่าคุณกำลังสร้าง abstractions ในระดับใด" - ในความเป็นจริงจุดรวมของนามธรรมคือคุณไม่รู้ว่ามันจะถูกนำไปใช้อย่างไรฉันไม่รู้ (และไม่สามารถ ) รู้ได้ว่านามธรรมซ่อนอยู่ในระดับใด
Jörg W Mittag

4

รูปแบบการออกแบบเป็นเพียงวิธีการแก้ไขปัญหาทั่วไป สิ่งสำคัญคือการรู้รูปแบบการออกแบบ แต่เป็นเพียงอาการของรหัสที่ออกแบบมาอย่างดี (โค้ดที่ดียังคงเป็นโมฆะของแก๊งของรูปแบบการออกแบบสี่ชุด) ไม่ใช่สาเหตุ

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

  • คุณต้องการ abstractions ที่จุดอินเทอร์เฟซธรรมชาติเพื่อลดขนาด

  • คุณไม่ต้องการเปลี่ยนพวกเขา

  • คุณต้องการให้พวกเขาแยกสิ่งต่าง ๆ ที่สามารถเป็นอิสระ

  • การมีที่อยู่ผิดสถานที่นั้นเลวร้ายยิ่งกว่าการมีอยู่

  • พวกเขาไม่ควรมีขนาดใหญ่การรั่วไหล


4

refactoring

ฉันไม่เห็นคำว่า "การปรับโครงสร้างใหม่" ที่กล่าวถึงแม้แต่ครั้งเดียว ดังนั้นเราไปที่นี่:

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

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

รูปแบบเป็นเครื่องมือที่ใจ

รูปแบบหรือมากกว่านั้นโดยเฉพาะหนังสือ "Design Patterns" โดยแก๊งสี่นั้นยอดเยี่ยมด้วยเหตุผลอื่น ๆ เพราะพวกเขาสร้างภาษาสำหรับนักพัฒนาที่จะคิดและพูดคุยมันเป็นเรื่องง่ายที่จะพูดว่า "ผู้สังเกตการณ์", "โรงงาน" หรือ "ซุ้ม" และทุกคนรู้ว่ามันหมายถึงอะไรทันที

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

ห้องสมุด

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


2

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

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

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

หลังจากพิจารณาคุณค่าของ abstractions สำหรับโปรแกรมเมอร์ที่ใช้งานแล้วเราสามารถหันมาประเมินและพิจารณาการใช้งานเช่นของ DRY-ness

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


ตัวอย่างเมื่อเลเยอร์แคชทั่วไปถูกเขียนโดยใช้ Memcache เราจำเป็นต้องใช้ Memcache, MemcacheAdapter, MemcacheInterface, AbstractCache, CacheFactory, CacheConnector, ... หรือนี่เป็นการง่ายกว่าที่จะรักษาและยังคงรหัสที่ดีเมื่อใช้เพียงครึ่งหนึ่งของคลาสเหล่านั้นหรือไม่?

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


2

สิ่งที่เป็นนามธรรมได้รับการออกแบบเพื่อให้เข้าใจรหัสได้ง่ายขึ้น ถ้าเลเยอร์สิ่งที่เป็นนามธรรมจะทำให้สิ่งต่าง ๆ สับสนมากขึ้น - อย่าทำ

เป้าหมายคือใช้จำนวน abstractions และ interfaces ที่ถูกต้องเพื่อ:

  • ลดเวลาในการพัฒนา
  • เพิ่มความสามารถในการบำรุงรักษาโค้ด

นามธรรมเฉพาะเมื่อจำเป็น

  1. เมื่อคุณค้นพบว่าคุณกำลังเขียนคลาสที่ยอดเยี่ยม
  2. เมื่อใดจะอนุญาตให้ใช้รหัสที่สำคัญอีกครั้ง
  3. หากการสรุปจะทำให้โค้ดมีความชัดเจนและอ่านง่ายขึ้น

อย่านามธรรมเมื่อ

  1. การทำเช่นนั้นจะไม่ได้เปรียบในการใช้ซ้ำรหัสหรือความชัดเจน
  2. การทำเช่นนั้นจะทำให้รหัสยาวขึ้น / ซับซ้อนขึ้นอย่างมากโดยไม่มีประโยชน์

ตัวอย่างบางส่วน

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

2

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

ปัญหาเกี่ยวกับวิธีการใช้รูปแบบการออกแบบคือเมื่อพวกเขาได้รับการสอนพวกเขานำเสนอกรณีเช่นนี้:

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

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

นอกจากนี้ฉันต้องการพูด Andrei Alexandrescu เมื่อพูดถึงวิศวกรรมซอฟต์แวร์ที่ระบุ:

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

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

มันเป็นเช่นนี้ในเวลาที่เสียงทำนายของ Mike Acton หัวหน้าทีมเกมที่ Insomniac ร้องในหัวของฉัน:

รู้ข้อมูลของคุณ

เขากำลังพูดถึงอินพุตของโปรแกรมและผลลัพธ์ที่ต้องการ และมีอัญมณี Fred Brooks จาก Mythical Man Month:

แสดงผังงานของคุณและซ่อนตารางของคุณให้ฉันแล้วฉันจะยังคงประหลาดใจ แสดงตารางของคุณให้ฉันดูและโดยปกติฉันไม่ต้องการผังงานของคุณ พวกเขาจะชัดเจน

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

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

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


2

สถาปัตยกรรมซอฟต์แวร์คือการประดิษฐ์ภาษา

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

มุมมองนี้ช่วยฉันเมื่อตัดสินใจเลือกประเด็นทางสถาปัตยกรรม

การอ่าน

ภาษานั้นควรเข้าใจได้ง่าย (ทำให้สามารถอ่านโค้ดเลเยอร์ถัดไปได้) รหัสอ่านบ่อยกว่าที่เขียน

หนึ่งแนวคิดควรแสดงด้วยคำเดียว - หนึ่งคลาสหรืออินเทอร์เฟซควรแสดงแนวคิด (โดยทั่วไปแล้วภาษาสลาฟมีสองคำที่แตกต่างกันสำหรับคำกริยาภาษาอังกฤษหนึ่งดังนั้นคุณต้องเรียนรู้คำศัพท์สองครั้งภาษาธรรมชาติทั้งหมดใช้คำเดียวสำหรับแนวคิดที่หลากหลาย)

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

การใช้งาน

ภาษาควรใช้งานง่าย (ทำให้ง่ายต่อการกำหนด "ประโยคที่ถูกต้อง")

หากคลาส / อินเตอร์เฟส MemCache เหล่านี้ปรากฏขึ้นในเลเยอร์ถัดไปนั่นจะสร้างเส้นโค้งการเรียนรู้ที่สูงชันสำหรับผู้ใช้จนกว่าเขาจะเข้าใจเวลาและสถานที่ที่จะใช้คำใดของคำเหล่านี้สำหรับแนวคิดเดียวของแคช

การเปิดเผยเฉพาะคลาส / วิธีการที่จำเป็นทำให้ผู้ใช้ของคุณค้นพบสิ่งที่เขาต้องการได้ง่ายขึ้น (ดูเอกสาร DocBrowns ของ Antoine de Saint-Exupery) การเปิดเผยอินเตอร์เฟสแทนการใช้คลาสสามารถทำให้ง่ายขึ้น

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

สรุป

แนะนำ abstractions หากทำให้การใช้งานง่ายขึ้น (และคุ้มค่ากับค่าใช้จ่ายในการบำรุงรักษาทั้งนามธรรมและการนำไปใช้)

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


1

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

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


-1

อย่างแรกคำพูดของ Twitter นั้นปลอม นักพัฒนาใหม่จำเป็นต้องสร้างแบบจำลองโดยทั่วไป abstractions จะช่วยให้พวกเขา "รับภาพ" ให้ abstractions ทำให้รู้สึกแน่นอน

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


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