รหัสสะอาด: ผลที่ตามมาของวิธีการสั้น ๆ ที่มีพารามิเตอร์น้อย


15

เมื่อเร็ว ๆ นี้ระหว่างการตรวจสอบรหัสฉันพบรหัสซึ่งเขียนโดยเพื่อนร่วมงานคนใหม่ซึ่งมีลวดลายที่มีกลิ่น ฉันสงสัยว่าการตัดสินใจของเพื่อนร่วมงานขึ้นอยู่กับกฎที่เสนอโดยหนังสือ Clean Code ที่มีชื่อเสียง (และอาจเป็นโดยหนังสืออื่นที่คล้ายคลึงกันเช่นกัน)

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

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

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

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

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

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


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

7
2. หากคุณขาดคำอธิบายปัญหาคุณจะไม่มีประสบการณ์เพียงพอที่จะหักล้างตำแหน่งของเพื่อนร่วมงาน
Robert Harvey

4
3. หากคุณมีรหัสที่ใช้งานได้คุณสามารถโพสต์โพสต์ไว้ใน Code Review และให้พวกเขาดูได้ มิฉะนั้นนี่เป็นเพียงส่วนรวมที่หลงทาง
Robert Harvey

5
@RobertHarvey "ค่าที่เป็นผลมาจากการคำนวณถูกกำหนดให้กับคุณสมบัติที่จะใช้ในวิธีการส่วนตัวหลายวิธีตลอดทั้งชั้น" ไม่ดูเหมือน DTO ที่เคารพตัวเองกับฉัน ฉันเห็นด้วยว่าความจำเพาะอีกเล็กน้อยจะเป็นประโยชน์
topo Reinstate Monica

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

คำตอบ:


13

ในฐานะที่เป็นคนที่อ่านโค้ดสะอาดและดูซีรี่ส์ Clean Coders หลายครั้งและมักสอนและสอนคนอื่นในการเขียนโค้ดที่สะอาดกว่าฉันสามารถรับรองได้ว่าการสังเกตของคุณถูกต้อง - ตัวชี้วัดที่คุณพูดถึงล้วนถูกกล่าวถึงในหนังสือ .

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

รหัสที่สะอาดไม่เสนอว่าวิธีการควรสั้นโดยมีอาร์กิวเมนต์น้อยที่สุด แต่พร้อมแนวทางเหล่านั้นก็แนะว่าเราต้อง folow Sหลักการ OLID เพิ่มการทำงานร่วมกันและลดการมีเพศสัมพันธ์

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

นอกจากนี้คลาสสะอาดควรมีความเหนียวแน่นซึ่งหมายความว่าวิธีการส่วนใหญ่ใช้คุณลักษณะส่วนใหญ่ ดังนั้นคลาสที่มีความเหนียวแน่นสูงสุดคือคลาสที่ทุกเมธอดใช้คุณลักษณะทั้งหมดของมัน ตัวอย่างเช่นในแอพแบบกราฟิกคุณอาจมีVectorคลาสที่มีแอททริบิวต์Point aและPoint bมีวิธีการเพียงอย่างเดียวscaleBy(double factor)และprintTo(Canvas canvas)ทั้งสองทำงานกับทั้งสองแอททริบิวต์ ในทางตรงกันข้ามคลาสที่มีความเหนียวน้อยที่สุดคือคลาสที่แต่ละแอ็ตทริบิวต์ถูกใช้ในวิธีเดียวเท่านั้นและแต่ละเมธอดจะใช้มากกว่าหนึ่งแอ็ตทริบิวต์ เฉลี่ยเป็นของขวัญชั้นไม่ใช่เหนียว "กลุ่ม" ของชิ้นส่วนเหนียว - คือไม่กี่วิธีใช้แอตทริบิวต์a, bและcในขณะที่การใช้งานส่วนที่เหลือcและd - หมายความว่าถ้าเราแบ่งชั้นเป็นสองเราก็จบด้วยวัตถุที่มีความเหนียวสองชิ้น

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

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


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

1
SRP เป็นแนวทางที่สำคัญที่สุด แหวนเดียวที่จะปกครองพวกเขาทั้งหมดและทุกสิ่งที่ SRP ที่ทำได้ดีส่งผลให้มีวิธีการที่สั้นกว่า ตัวอย่าง: ฉันมีคลาสด้านหน้าที่มีเพียง 2 สาธารณะและประมาณ 8 วิธีที่ไม่ใช่แบบสาธารณะ ไม่มีมากกว่า ~ 3 บรรทัด; ทั้งชั้นประมาณ 35 LOC แต่ฉันเขียนชั้นนี้สุดท้าย! ตามเวลาที่รหัสพื้นฐานทั้งหมดถูกเขียนคลาสนี้เป็นหลักเขียนเองและฉันไม่ต้องแน่นอนไม่สามารถทำให้วิธีการที่ใหญ่กว่า ฉันไม่ได้พูดว่า "ฉันจะเขียนวิธีการเหล่านี้ใน 5 บรรทัดถ้ามันฆ่าฉัน" ทุกครั้งที่คุณใช้ SRP มันจะเกิดขึ้น
Radarbob

11

ฉันเข้าใจว่าตัวสร้างคลาสมีหน้าที่รับผิดชอบทั้งหมดในการสร้างวัตถุที่ถูกต้องและหน้าที่หลักของมันคือการกำหนดคุณสมบัติ (ส่วนตัว) ของวัตถุ

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

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

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

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

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

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

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

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

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

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


2
upvote เนื่องจาก: 1.เน้น SRP "... วิธีการขนาดเล็ก ... ทำตามธรรมชาติ" 2.วัตถุประสงค์ของตัวสร้าง - สถานะที่ถูกต้อง 3. "ปฏิบัติตามแนวทางการเข้ารหัสบางอย่างในขณะที่ไม่สนใจผู้อื่น" นี่คือ Walking Dead ของการเข้ารหัส
Radarbob

6

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

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

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