ทำไม DRY ถึงสำคัญ?


81

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

ฉันไม่น่าจะต้องแก้ไขอีกในเร็ว ๆ นี้

ดูเหมือนว่าจะมีงานน้อยลงที่จะไป ...

function doStuff1(){/*.a.*/}
function doStuff2(){/*.b.*/}
function doStuff3(){/*.c.*/}

และถ้าฉันต้องการเพิ่มอะไรบางอย่าง ...

function doStuff4(){/*.d.*/}

และถ้าฉันต้องการลบฉันก็จะลบมัน

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

ทำไมต้องเป็น DRY เมื่อดูเหมือนว่าการตัดแปะ + แบบเร็วจะทำงานได้น้อยลงมาก


11
เพราะความแห้งยังคงเร็วกว่าเมื่อคุณทำถูกต้องแล้วถ้าคุณทำผิดพลาดใน ผลกระทบอื่น ๆ ทั้งหมด
Daniel Little

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

14
ฉันคิดว่าคุณสามารถสรุปได้ด้วย: การเปลี่ยนแปลงเพียงจุดเดียวนั้นง่ายต่อการบำรุงรักษา
Falcon

17
หากคุณไม่สามารถตอบคำถามนี้ได้ด้วยตนเองคุณจะต้องได้รับประสบการณ์การพัฒนาและการบำรุงรักษาที่แท้จริงมากขึ้น
David Heffernan

15
@ เวย์นฉันรู้สึกถึงความวุ่นวายในแหล่งข้อมูลราวกับว่าโปรแกรมเมอร์หลายล้านคนตะโกนออกมาด้วยความหวาดกลัว
ไม่ระบุตัวตน

คำตอบ:


121

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

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

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

เมื่อพิจารณาถึงคำแนะนำดังกล่าวดูเหมือนว่าในกรณีของคุณ

ทำซ้ำกระบวนการเดียวกันสองสามครั้งด้วยการปรับแต่งเล็กน้อย

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

ทำไมต้องเป็น DRY เมื่อดูเหมือนว่าการตัดแปะ + แบบเร็วจะทำงานได้น้อยลงมาก

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


2
เอ่อเพียงเพื่อความชัดเจนฉันไม่ได้เสนอให้แห้งไม่ดีคำถามนี้เป็นมากกว่าการสนับสนุนปีศาจ ฉันกำลังมองหาการตอบสนองเชิงตรรกะฉันสามารถเชื่อมโยงกับคนที่คิดว่า cut + paste + tweak code นั้นใช้ได้
ไม่ระบุตัวตน

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

16
ฉันจะขีดเส้นใต้ข้อผิดพลาดง่าย ๆ อย่างหนึ่งของ DRY: การรวมโค้ดที่คล้ายกัน หากคุณมีสองกรณีการใช้งานที่ไม่เกี่ยวข้องตามหน้าที่ แต่เกิดขึ้นจะมีรหัสที่คล้ายกันมากมันเป็นเรื่องง่ายที่จะผสานทั้งสองเพราะแห้งเป็นสิ่งที่ดี น่าเสียดายที่เมื่อเราต้องการที่จะพัฒนาคุณมักจะพบว่าตัวเองมีหน้าที่ไม่ต้องแยกฟังก์ชั่นอีกครั้งจากนั้นก็ไปยังไซต์การโทรทั้งหมดและพิจารณาอย่างรอบคอบว่าควรจะเรียกที่นี่ ... ตัวอย่าง: การพิมพ์โครงสร้าง LLVM (ประเภทที่คล้ายกันทั้งหมดถูกรวมเข้าเป็นหนึ่งเดียว) ทำให้ไม่สามารถแมป IR กลับไปที่รหัสเดิมได้
Matthieu M.

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

1
@ MatthieuM เป็นตัวอย่างที่ไม่เป็นธรรม LLVM จะใช้พิมพ์ที่มีโครงสร้างเป็นการเพิ่มประสิทธิภาพ ; นั่นคือกลุ่ม LLVM ตัดสินใจที่จะจ่ายราคา IR ที่เข้าใจยากเพื่อผลประโยชน์ด้านประสิทธิภาพ DRY มักเป็นปัญหาการบำรุงรักษา แต่ในกรณีนี้เป็นการตัดสินใจที่ชัดเจนเพื่อลดการบำรุงรักษา
Benjamin Hodgson

47

เพราะ DRY จะทำงานน้อยลงในภายหลัง


DRY: (อย่าทำซ้ำตัวเอง)

ฟังก์ชั่นหนึ่งการโต้แย้ง

def log(arg):
    print(arg)

C&P: (คัดลอกและวาง)

ฟังก์ชั่น 26 ล้านล้านทำในสิ่งเดียวกัน แต่มีความแตกต่าง 2 อย่าง

def logA():
    print('a')

def logB():
    print('b')

...ad infinitum...

แล้วเราจะปรับปรุงการพิมพ์ของเราเพื่อระบุสิ่งที่จะพิมพ์?

แห้ง:

def log(arg):
    print(arg + "Printed from process foo")

เสร็จสิ้น

C & P:

คุณจะต้องกลับไปเปลี่ยนทุกฟังก์ชั่นเดียว


คุณคิดว่าจะแก้ไขข้อใดได้ง่ายขึ้น


10
นอกจากนี้คุณต้องเขียนชุดทดสอบที่คล้ายกันมากเท่าที่คุณมีฟังก์ชั่นที่ซ้ำกัน
9000

คุณได้แสดงแนวคิดอย่างเพียงพอแล้ว แต่ในทางปฏิบัติแล้วไม่มีใครทำสิ่งที่คุณอธิบายด้วยฟังก์ชั่น gazillion ไม่ได้เป็นแบบนั้น
Robert Harvey

@ Robert ฉันหวังว่าจะไม่! ฉันเลือกงานง่าย ๆ เพื่อพยายามอธิบายแนวคิดให้ดีขึ้นและทำไมมันถึงเป็นสิ่งที่ดี
จอห์น

11
@ Robert - คุณได้อ่านบทความใด ๆ ที่thedailywtf.com ;) - มีบางอย่างที่ทำเช่นนั้น
HorusKol

1
@ 9000 ไม่ได้ถ้าคุณไม่ได้มีห้องทดสอบใด ๆ : p (ซึ่งจริง ๆ แล้วมักจะอาจจะมีกรณีในบางโครงการ ... น่าเสียดายที่ ... )
Svish

16

เพราะนำไปใช้กับตัวอย่างของคุณ:

  • + อ่านง่าย

    รหัสน้อยมักจะแปลว่าเสียงน้อย (ไม่เสมอ...)

  • + ความยืดหยุ่น

    หากคุณต้องเปลี่ยนพฤติกรรมของdoStuffXคุณจะต้องฆ่าตัวตายหรือใครก็ตามที่เขียนมัน

  • + ความสามารถในการขยาย

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

  • + ประสิทธิภาพค่าใช้จ่าย

    รหัสน้อยที่นี่หมายถึง:

    • => การพัฒนาน้อยลง => ลดต้นทุน
    • => น่าจะน้อยลงสำหรับข้อผิดพลาด => เวลาการสนับสนุนน้อย => ลดค่าใช้จ่าย
  • + (เป็นไปได้) การเพิ่มประสิทธิภาพที่มีการจัดการ

    ทั้งนี้ขึ้นอยู่กับภาษาคอมไพเลอร์ / ล่ามอาจมีโอกาสที่ใหญ่กว่าของการกำหนดว่าทั่วไปdoStuffไม่เสมอสิ่งที่เหมือนกันเกือบมักหนึ่งสายหลังจากที่อื่นและสามารถinlineหรือพยายามที่จะเพิ่มประสิทธิภาพของมัน doStuffXอาจจะไม่ได้สำหรับรูปแบบของ X

  • + การทดสอบและคุณภาพ

    การทดสอบนั้นง่ายกว่า: doStuffต้องทำการทดสอบและนั่นก็คือ ก็ไม่ว่า แต่ที่ครอบคลุมอยู่แล้วมากขึ้น เพียงความคาดหวัง IO ของมันแตกต่างกันไปและจะต้องมีการทดสอบภายใต้เงื่อนไขที่แตกต่างกัน แต่ก็ยังคงมีมากขึ้นในการทดสอบและการบำรุงรักษามากขึ้นdoStuffXกว่ารูปแบบทั้งหมดของ

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


13

เนื่องจากทุกคนทำงานได้ดีมากในการอธิบายปัญหาการบำรุงรักษาด้วยรหัสซ้ำฉันจะพูดอย่างนี้:

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

แน่นอนว่ามีบางครั้งที่จำเป็นต้องคัดลอก / วาง ในฐานะนักพัฒนา UI ฉันพบว่ามีบางครั้งที่ฉันต้องละเมิดหลักการ DRY มันแย่มากฉันประจบประแจงทุกครั้งที่มันเกิดขึ้นและขอบคุณมันหายาก แต่มันจะเกิดขึ้น

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

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


ฉันไม่แน่ใจว่าฉันเห็นด้วยกับเจ้านายที่บอกคุณว่า "เสร็จแล้วหรือถูกไล่ออก" เป็นเหตุผลที่ดีในการละเมิด DRY หนี้ทางเทคนิคเมื่อคุณมีเวลาที่จะทำมันถูกต้องมันประหยัดเวลาจริง ๆ หรือไม่?
ไม่ระบุตัวตน

1
@Incognito ผมพยายามที่จะเป็นบิตแดกดัน :)
bedwyr

7

ฉันไม่น่าจะต้องแก้ไขอีกในเร็ว ๆ นี้

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

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


คำตอบที่ยอดเยี่ยม แต่แม้ว่าฉันอาจจะไปกับมันได้แล้วผู้ที่ยากจนที่ได้รับการดูแลหลังจากฉันล่ะ ;)
ไม่ระบุตัวตน

โปรดดู: "บ่อยครั้งกว่าที่คุณจะต้องทำงานกับโค้ดที่ต้องได้รับการบำรุงรักษา" :)
อเล็กซ์

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

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

6

ตามที่ฉันระบุไว้ในคำตอบของคำถามอื่นแนวทางของฉันมีดังต่อไปนี้:

  1. ครั้งแรกที่ฉันแก้ปัญหาบางอย่างฉันเพิ่งทำเสร็จ
  2. ครั้งที่สอง (เช่นเมื่อฉันแก้ปัญหาที่คล้ายกัน) ฉันคิดว่า: หืมบางทีฉันอาจจะทำซ้ำตัวเอง แต่ฉันจะไปคัดลอกและวางอย่างรวดเร็วในตอนนี้
  3. ครั้งที่สามที่ฉันคิดว่า: หืมฉันซ้ำตัวเอง -> ทำให้เป็นเรื่องปกติ!

เช่นได้ถึง 2 หลักการอื่น (YAGNI) ชนะเหนือ DRY แต่เริ่มจาก 3 (หรือ 4 ถ้าฉันขี้เกียจจริงๆ!) ดูเหมือนว่าฉันจะต้องการมันและฉันก็เลยตาม DRY

ปรับปรุง

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

ดังนั้นฉันจึงเริ่มการรีแฟคเตอร์สององค์ประกอบเหล่านี้ (แต่ละอันประกอบด้วยคลาส 8 C ++): ฉันต้องการสถาปัตยกรรมทั่วไปสำหรับทั้ง A และ B แล้วเพิ่มคุณสมบัติที่เราต้องการโดยการกำหนดคลาสย่อย ด้วยวิธีนี้ส่วนประกอบใหม่ A และ B จะได้มาจากส่วนประกอบที่มีอยู่

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

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

ข้อดี: เรามีฟังก์ชั่นการทำงานเกือบเสร็จแล้วและเมื่อเราแก้ไขข้อบกพร่องทั้งหมดที่เราทำเสร็จแล้ว เราได้บันทึกการปรับโครงสร้างและการทดสอบ A และ B ทั้งหมดใหม่

ข้อเสีย: สองสัปดาห์ที่ผ่านมาทีมอื่นเปลี่ยนส่วนประกอบอีก C ซึ่งใช้โดย A และ B พวกเขาปรับ A และ B แต่ A 'และ B' ก็หักและเราต้องเปลี่ยนด้วยตนเอง นี่เป็นข้อผิดพลาดใหม่ที่เราต้องแก้ไข งานพิเศษนี้อาจไม่จำเป็นหาก A 'และ B' แบ่งปันรหัสส่วนใหญ่กับ A และ B

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


5

เพียงชี้แจงให้ชัดเจนเพราะฉันไม่พบสิ่งนี้ในคำตอบอื่น ๆ :

แห้งเป็นหลักการของการพัฒนาซอฟต์แวร์ที่มีวัตถุประสงค์เพื่อลดความซ้ำซ้อนของข้อมูลของทุกชนิด

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

หลักการ DRY ตามที่ Andy Hunt และ Dave Thomas กล่าวถึงไม่ได้ จำกัด อยู่ที่การป้องกันการทำซ้ำรหัส นอกจากนี้ยังสนับสนุนการสร้างรหัสและกระบวนการอัตโนมัติใด ๆ กระแทกแดกดันผลลัพธ์ของการสร้างรหัสอาจซ้ำรหัสได้ ...

เหตุผลที่อธิบายไว้แล้วอย่างละเอียดในคำตอบอื่น ๆ แต่ความคิดเห็นของเหยี่ยวสรุปได้ดีพอ IMHO:

จุดเปลี่ยนแปลงเดียวนั้นง่ายต่อการดูแลรักษา


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

3

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

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

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

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

เป็นที่เข้าใจได้ว่าคุณภาพของรหัสมักจะลดลงเมื่อรหัสวิวัฒนาการ แต่ฉันเคยเห็นกรณีที่ฟังก์ชั่นหลายพารามิเตอร์ที่มีสปาเก็ตตี้ if-then-else ในร่างกายเป็นผลมาจากความพยายามในการปรับโครงสร้างที่ดี

(1) ฉันใช้คำว่า "code" แต่ก็ใช้กับการออกแบบได้เช่นกัน


มันจะมีประโยชน์ในการยกตัวอย่างของ "แห้งมากเกินไป" เนื่องจากเป็นจุดสิ้นสุดของสเปกตรัม
ไม่ระบุตัวตน

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

2

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

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

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

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

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

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


1

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


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

1

ฉันมีโครงการเก่าที่ผู้พัฒนาอดีตบางคนไม่สนใจ DRY เลย ดังนั้น codebase ทั้งหมดจึงเต็มไปด้วยวิธีการช่วยเหลือเช่น GetSystemTimeAsString (), LogToFile () และอื่น ๆ อีกมากมาย วิธีการบางอย่างถูกปรับแต่งเล็กน้อยตามความต้องการพิเศษ แต่ส่วนใหญ่เป็นเพียงการคัดลอกและวาง

น่าเสียดายที่วิธีการบางอย่างมีข้อบกพร่องที่ละเอียดอ่อนเช่นอาเรย์ถ่านไม่นานพอในบางกรณีการใช้สิ่งที่ไม่ปลอดภัยเช่น strcpy () เป็นต้น

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

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


1

ใช่ไม่ต้องกังวลเกี่ยวกับแห้งถ้าคุณเขียนรหัสใบปลิว

แต่ DRY มีความสำคัญแน่นอนถ้าคุณวางแผนที่จะเก็บรหัสไว้


1

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

หากโปรแกรมควรประมวลผลวิดเจ็ตแต่ละไฟล์มี woozles สามรายการและเป็นหลายลูปของแบบฟอร์ม

for (i=0; i<3; i++)
  thisWidget.processWoozle(i);

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

#define WOOZLES_PER_WIDGET 3

และแต่ละวงถูกเขียนใหม่

for (i=0; i<WOOZLES_PER_WIDGET; i++) ...

การออกแบบดังกล่าวอาจทำให้ง่ายต่อการเปลี่ยนจำนวนของ woozles ต่อวิดเจ็ต

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

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


0

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

ฉันต้องการเพิ่มเสียงคัดค้านเล็กน้อยให้กับการอภิปราย

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

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

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

2
สัญลักษณ์แสดงหัวข้อย่อยที่สองของคุณถูกต้องทั้งหมด
Jim G.

1
@Ozz ความภาคภูมิใจในงานฝีมือของคุณเป็นสิ่งสำคัญยิ่งสำหรับโปรแกรมเมอร์ที่ดี แต่บางที "โปรแกรมเมอร์ในมุมมอง" ควรรวมถึงความกังวลสำหรับ "ความพึงพอใจของลูกค้า"
James Anderson

0

<tl;dr>

ฉันไม่สามารถอ่านคำตอบซ้ำทั้งหมดดังนั้นฉันอาจพลาดบางสิ่ง (และจะทำซ้ำตัวเอง <= ดูว่าฉันทำอะไรที่นี่?)

นี่คือรายการของสิ่งที่ยอดเยี่ยมเกี่ยวกับการป้องกันการทำสำเนารหัส!

  1. ทดสอบได้ง่ายขึ้น: คุณจะต้องทดสอบ 'คัดลอก' ของรหัสหนึ่งเท่านั้น
  2. แก้ไขได้ง่ายขึ้น: คุณจะต้องพบข้อบกพร่องใน 'คัดลอก' ของรหัสและแก้ไขครั้งเดียว
  3. ง่ายต่อการอัปเดต (เหมือนด้านบน): การเปลี่ยนแปลงที่ต้องการมักจะสามารถจัดการได้โดยการแก้ไขโค้ดในสถานที่น้อยมากเพราะคุณใช้เวลาในการนำรหัสมาใช้ใหม่อย่างถูกต้องและไม่ได้คัดลอกบรรทัดเดียวกันไปยังหลายร้อยหรือหลายพันแห่งในแหล่งต่างๆ
  4. ง่ายต่อการนำมาใช้ซ้ำ: เมื่อ (ไม่ซ้ำกันในบางแห่ง) และถูกเก็บไว้ในวิธีการตั้งชื่อทั่วไปที่เหมาะสมมันง่ายต่อการค้นหาและใช้แทนการเขียนของคุณเอง
  5. ง่ายต่อการอ่าน: รหัสที่ซ้ำกันนั้นยากที่จะอ่านเพราะมันไม่จำเป็นโดยละเอียด มันมีหลายบรรทัดที่ไม่ได้เป็นส่วนหนึ่งของตรรกะและฟังก์ชั่นเฉพาะที่ตั้งใจ (เช่นคำสั่งทั่วไปที่ใช้ในการตั้งค่าขั้นตอนสำหรับการดำเนินการที่จะเกิดขึ้นหรืองานซ้ำง่ายทั่วไปที่จำเป็นในหลาย ๆ สถานที่) โค้ดที่สะอาดจะทำให้ตรรกะและฟังก์ชั่นการทำงานเกิดขึ้นเนื่องจากไม่มีการซ้ำซ้อนที่ทำให้พื้นที่โค้ดว่างเปล่า
  6. ง่ายต่อการดีบักเนื่องจาก (1) และ (5)
  7. ประหยัดเวลาและเงินของคุณและทำสิ่งที่สนุกมากขึ้นในอนาคต สร้างรหัสที่แข็งแกร่งยิ่งขึ้นโดยเฉพาะ นี่คือบรรทัดล่างและเป็นผลรวมของทั้งหมดข้างต้น หากผู้คนจำนวนมากใช้ฟังก์ชั่นเดียวกันdoFoo1(a, b)มีโอกาสที่ดีกว่าที่ข้อผิดพลาดที่น่ารำคาญ & เคสขอบจะถูกเปิดเผยและแก้ไข หากทุกคนคัดลอกรหัสและสร้างdoFoo2(specialA)... doFuu2^n(a, b, c)จากนั้นพวกเขาจะทำซ้ำปัญหาdoFoo1และสร้างงานมากขึ้นอย่างเป็นรูปธรรม

</tl;dr>

รุ่นยาว:

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

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

สิ่งที่ฉันพบว่าเป็นอันตรายในการทำสำเนารหัส:

  1. ฟังก์ชั่นนี้ใช้งานได้หรือไม่? สมมติว่าคุณพบฟังก์ชั่นที่ทำ (หรือดูเหมือนจะทำสิ่งที่คุณต้องการ) คุณจะรู้ได้อย่างไรว่ามันควรจะทำงานได้อย่างถูกต้องหรือว่าเป็นแค่โค้ดที่ซ้ำและถูกทอดทิ้ง
  2. รหัสซ้ำซ้อน บางครั้งผู้คนทำซ้ำรหัสให้ใช้และลืมมัน (พวกเขาสามารถทำซ้ำได้อีกในอนาคต) ณ จุดหนึ่งมีคนเอาสายไปยังฟังก์ชั่นที่ซ้ำกันในบางสถานที่ในความพยายามที่จะ refactor แต่ฟังก์ชั่นที่ไม่ได้ใช้ยังคงอยู่แม้ว่าจะไม่ได้ใช้งานอย่างแข็งขัน
  3. ยากที่จะหาสิ่งที่คุณกำลังมองหา รหัสที่ซ้ำกันใช้พื้นที่และทำให้การค้นหาสิ่งที่มีประโยชน์และจำเป็น (โดยใช้เครื่องมืออย่าง grep) เป็นงานที่ยากกว่าที่จะเป็นเมื่อคุณได้รับผลลัพธ์หลายสิบหรือหลายพันที่คุณควรได้รับเพียงเล็กน้อยเท่านั้น
  4. (เคยถูกกล่าวถึงก่อนหน้านี้): บำรุงรักษายาก แต่ก็ยากที่จะใช้เพื่อการบำรุงรักษาและการถดถอย หากรหัสการทดสอบซ้ำกันและไม่ได้ดึงข้อมูลอย่างถูกต้องไปยังฟังก์ชั่นอื่น ๆ จะทำซ้ำ ทุกคนจะรำคาญกับการเขียน API ที่ใช้งานง่ายและง่ายต่อการอ่านเพื่อทำให้ QoL ดีขึ้นหรือไม่ จากประสบการณ์ของฉันไม่บ่อยครั้งที่มีคนคิดว่าเรื่องเร่งด่วนกว่านี้จนกว่ามันจะหลุดพ้น
  5. การทำสำเนารหัสเป็นการยากที่จะอ่านเพราะมันจะทำให้โค้ดไม่ต้องอยู่ในสถานที่ที่ความฟุ่มเฟื่อยไม่ได้เพิ่มข้อมูลเกี่ยวกับหน้าที่การใช้งานที่ตั้งใจไว้: ตัวอย่างเช่นการเรียกใช้เมธอดทั่วไปที่ใช้ ตั้งค่าพื้นฐานสำหรับฟังก์ชั่นที่ต้องการหลายประเภททำให้การทำงานที่แท้จริงนี้ออกมาได้ยากขึ้น
  6. เรื่องนี้ได้รับการกล่าวถึงมาก หากรหัสผิด gal หรือคนที่ไม่ดีบางคนจะต้องค้นหาและเปลี่ยนแปลงการใช้รหัสนั้นทุกครั้ง ตัวอย่างเช่นหากมีคนใช้การเรียก SQL injection ที่ไม่ปลอดภัยไปยัง mysql_query ในสถานที่น้อยมากใน Class ที่มีการจัดระเบียบที่ต้องการมันจะง่ายต่อการแก้ไขและใช้ PHP PDO แทน แต่ถ้าพวกเขาใช้มันในกว่าพันที่คัดลอกการโทร และยิ่งกว่านั้นการแก้ไขมันจะต้องได้รับการว่าจ้างจากภายนอกหรือในบางครั้งมีอันตรายมากกว่านั้นรหัสจะต้องถูกเขียนใหม่ตั้งแต่ต้น
  7. รหัสซ้ำเป็นนิสัยที่ไม่ดี หากคุณฝึกฝนอะไรบางอย่างมันจะกลายเป็นลักษณะที่สองอย่างช้าๆและมันจะส่งผลกระทบต่อคนรอบข้าง Junior devs เห็นคุณทำและทำด้วย คุณควรฝึกฝนสิ่งที่คุณเทศนาและสร้างนิสัยในการทำสิ่งที่ถูกต้อง คุณเรียนรู้เพิ่มเติม การเขียนโค้ดที่ไม่ซ้ำซ้อนนั้นยากและท้าทายมากขึ้น มันเป็นนิสัยที่คุ้มค่า

บันทึกล่าสุดเกี่ยวกับการป้องกันการทำซ้ำรหัสที่ผิดเพี้ยน & สรุปสิ่งต่าง ๆ :

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

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

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