ช่วงเวลาสั้น ๆ ที่ไม่ได้เป็นคุณธรรมอีกต่อไปคืออะไร?


102

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

return (decimal)CostIn > 0 && CostOut > 0 ? (((decimal)CostOut - (decimal)CostIn) / (decimal)CostOut) * 100 : 0;

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

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

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

สาเหตุของการปลดเปลื้องคือ Entity Framework db จำเป็นต้องเก็บสิ่งเหล่านี้เป็นชนิดที่ไม่สามารถใช้ได้ ทศนิยม? ไม่เทียบเท่ากับทศนิยมใน C # และจำเป็นต้องร่าย


153
เมื่อช่วงสั้น ๆ สำคัญกว่าการอ่าน
Robert Harvey

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

29
โดยเฉพาะอย่างยิ่งดูเหมือนว่าแปลกที่จำเป็นต้องแปลง CostIn เป็นทศนิยมเพื่อเปรียบเทียบกับศูนย์ แต่ไม่ใช่ CostOut ทำไมถึงเป็นอย่างนั้น? อะไรในโลกคือประเภทของ CostIn ที่สามารถเปรียบเทียบกับศูนย์ได้โดยการแปลงเป็นทศนิยม? และทำไม CostOut ถึงไม่ใช่ประเภทเดียวกันกับ CostIn
Eric Lippert

12
นอกจากนี้ตรรกะที่นี่อาจผิด สมมติว่าCostOutมีค่าเท่ากับDouble.Epsilonและดังนั้นจึงมากกว่าศูนย์ แต่(decimal)CostOutในกรณีนี้เป็นศูนย์และเรามีการหารด้วยศูนย์ข้อผิดพลาด ขั้นตอนแรกควรจะได้รหัสที่ถูกต้องซึ่งฉันคิดว่ามันไม่ใช่ ได้รับมันถูกต้องทำให้กรณีทดสอบแล้วทำให้มันสง่างาม รหัสที่สง่างามและรหัสย่อมีอะไรเหมือนกันมากมาย แต่บางครั้งความกะทัดรัดไม่ได้เป็นจิตวิญญาณของความสง่างาม
Eric Lippert

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

คำตอบ:


163

เพื่อตอบคำถามของคุณเกี่ยวกับการวิจัยที่ยังมีอยู่

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

ใช่มีการทำงานในพื้นที่นี้

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

ความซับซ้อนของวงจร ÷ Source Lines of Code ( SLOC )

ในตัวอย่างรหัสของคุณอัตราส่วนนี้สูงมากเนื่องจากทุกอย่างถูกบีบอัดไว้ในบรรทัดเดียว

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

ลิงค์

นี่คือการอ้างอิงบางอย่างถ้าคุณมีความสนใจ:

McCabe, T. และ A. Watson (1994), ความซับซ้อนของซอฟต์แวร์ (CrossTalk: วารสารวิศวกรรมซอฟต์แวร์ป้องกัน)

วัตสัน, AH, & McCabe, TJ (1996) การทดสอบแบบมีโครงสร้าง: วิธีการทดสอบโดยใช้การวัดความซับซ้อนของวัฏจักร (NIST Special Publication 500-235) สืบค้น 14 พฤษภาคม 2011 จากเว็บไซต์ McCabe Software: http://www.mccabe.com/pdf/mccabe-nist235r.pdf

Rosenberg, L. , ค้อน, T. , Shaw, J. (1998) ตัวชี้วัดและความน่าเชื่อถือของซอฟต์แวร์ สืบค้นเมื่อ 14 พฤษภาคม 2554 จากเว็บไซต์มหาวิทยาลัยแห่งรัฐ Penn: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.104.4041&rep=rep1&type=pdf

ความเห็นและการแก้ปัญหาของฉัน

โดยส่วนตัวฉันไม่เคยเห็นคุณค่าของความกะทัดรัดอ่านง่ายเท่านั้น บางครั้งความกะทัดรัดช่วยให้อ่านได้ง่าย แต่บางครั้งก็ไม่เป็นเช่นนั้น สิ่งที่สำคัญกว่าคือการที่คุณกำลังเขียนCode ที่ชัดเจนจริงๆ (ROC)แทนที่จะเป็น Write-Only Code (WOC)

เพื่อความสนุกนี่คือวิธีที่ฉันจะเขียนมันและขอให้สมาชิกในทีมของฉันเขียนมัน:

if ((costIn <= 0) || (costOut <= 0)) return 0;
decimal changeAmount = costOut - costIn;
decimal changePercent = changeAmount / costOut * 100;
return changePercent;

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


4
ฉันชอบประโยคของเคสน้อยกว่าศูนย์ อาจมีค่ากับข้อคิดเห็น: ค่าใช้จ่ายจะน้อยกว่าศูนย์ได้อย่างไรกรณีพิเศษคืออะไร
user949300

22
+1 ฉันอาจจะเพิ่มสิ่งที่ชอบif ((costIn < 0) || (costOut < 0)) throw new Exception("costs must not be negative");
Doc Brown

13
@DocBrown: นั่นเป็นข้อเสนอแนะที่ดี แต่ฉันจะพิจารณาว่าการทดสอบเส้นทางรหัสพิเศษสามารถใช้งานได้หรือไม่ ถ้าใช่ให้เขียนกรณีทดสอบที่ฝึกเส้นทางรหัสนั้น ถ้าไม่ใช่ให้เปลี่ยนทั้งหมดเป็น Assert
Eric Lippert

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

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

49

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

ในกรณีพิเศษนี้มันจะปลดเปลื้องdecimalซ้ำไปซ้ำมา; มันอาจจะเป็นภาพรวมที่ดีกว่าถ้าจะเขียนใหม่เหมือน:

var decIn = (decimal)CostIn;
var decOut = (decimal)CostOut;
return decIn > 0 && CostOut > 0 ? (decOut - decIn ) / decOut * 100 : 0;
//                  ^ as in the question

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


1
ฉันอาจจะไปไกลกว่านั้นและปรับโครงสร้าง((decOut - decIn ) / decOut) * 100ให้เป็นตัวแปรอื่น
FrustratedWithFormsDesigner

9
แอสเซมเบลอร์ชัดเจนมากขึ้น: เพียงหนึ่งการทำงานต่อหนึ่งบรรทัด Doh!

2
@FrustratedWithFormsDesigner ฉันจะก้าวไปอีกขั้นและปิดการตรวจสอบตามเงื่อนไขในวงเล็บ
Chris Cirefice

1
@FrustratedWithFormsDesigner: การแยกส่วนนี้ไว้ก่อนที่เงื่อนไขจะผ่านการตรวจสอบแบบหารด้วยศูนย์ ( CostOut > 0) ดังนั้นคุณจะต้องขยายเงื่อนไขให้เป็นสถานะif- ไม่ใช่ว่ามีอะไรผิดปกติกับเรื่องนี้ แต่มันจะเพิ่มความฟุ่มเฟื่อยมากกว่าแค่การแนะนำของท้องถิ่น
wchargin

1
บอกตามตรงว่าการกำจัดนักแสดงดูเหมือนว่าคุณออกอากาศ IMO มากพอถ้ามีคนอ่านยากเพราะเขาจำการคำนวณอัตราพื้นฐานง่ายๆไม่ได้นั่นคือปัญหาของเขาไม่ใช่ของฉัน
Walfrat

7

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

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


casts (ฐานสิบ) อาจเป็นไปตามข้อกำหนดของกฎเกณฑ์ทางธุรกิจ เมื่อต้องรับมือกับนักบัญชีบางครั้งคุณต้องกระโดดผ่านห่วงที่โง่ ฉันคิดว่า CFO จะมีอาการหัวใจวายเมื่อเขาพบบรรทัด "ใช้การแก้ไขภาษี roundoff - $ 0.01" ซึ่งหลีกเลี่ยงไม่ได้เนื่องจากฟังก์ชั่นที่ร้องขอ (จัดหา: ราคาหลังหักภาษีฉันต้องคิดราคาก่อนหักภาษีอัตราต่อรองที่จะไม่มีคำตอบเท่ากับอัตราภาษี)
Loren Pechtel

@ LorenPechtel: เนื่องจากความแม่นยำที่Decimalนักแสดงจะขึ้นอยู่กับขนาดของค่าที่เป็นปัญหาฉันคิดว่ามันยากที่จะจินตนาการถึงกฎเกณฑ์ทางธุรกิจ
supercat

1
จุดดี - ฉันลืมรายละเอียดของประเภททศนิยมเพราะฉันไม่เคยมีโอกาสต้องการอะไรแบบนั้น ตอนนี้ฉันคิดว่านี่คือการเชื่อฟังลัทธิการขนส่งสินค้ากับกฎเกณฑ์ทางธุรกิจโดยเฉพาะเงินจะต้องไม่เป็นจุดลอย
Loren Pechtel

1
@ LorenPechtel: เพื่อชี้แจงจุดสุดท้ายของฉัน: ประเภทจุดคงที่สามารถรับประกันได้ว่า x + yy จะล้นหรือผลผลิต y Decimalประเภทไม่ได้ ค่า 1.0d / 3.0 จะมีตัวเลขทางด้านขวาของทศนิยมมากกว่าที่สามารถรักษาได้เมื่อใช้ตัวเลขที่มีขนาดใหญ่กว่า ดังนั้นการเพิ่มและลบจำนวนที่มากขึ้นจะทำให้สูญเสียความแม่นยำ ประเภทจุดคงที่อาจสูญเสียความแม่นยำด้วยการคูณหรือการหารแบบเศษส่วน แต่ไม่รวมการบวกการลบการคูณหรือการหารด้วยส่วนที่เหลือ (เช่น 1.00 / 7 คือ 0.14 ส่วนที่เหลือ 0.2; 1.00 div 0.15 คือ 6 ส่วนที่เหลือ 0.10)
supercat

1
@ Hulk: ใช่แน่นอน ฉันกำลังถกเถียงกันว่าจะใช้ x + yy ที่ให้ x, y + yx ที่ให้ y หรือ x + yxy และจบลงด้วยการ mish-moshing สองคนแรก สิ่งที่สำคัญคือประเภทของจุดคงที่สามารถรับประกันได้ว่าการดำเนินการหลายอย่างจะไม่ทำให้เกิดข้อผิดพลาดในการปัดเศษของขนาดใด ๆ หากรหัสเพิ่มสิ่งต่าง ๆ เข้าด้วยกันในวิธีที่แตกต่างกันในการตรวจสอบว่าผลรวมตรงกัน (เช่นการเปรียบเทียบผลรวมของผลรวมย่อยของแถวกับผลรวมของผลรวมย่อยของคอลัมน์) การมีผลลัพธ์ออกมาเท่าเทียมกันดีกว่าการปิด "ปิด"
supercat

5

ฉันดูรหัสนั้นและถามว่า "ราคาจะเป็น 0 (หรือน้อยกว่า) ได้อย่างไร" มีกรณีพิเศษอะไรบ้างที่บ่งบอก? รหัสควรเป็น

bool BothCostsAreValidProducts = (CostIn > 0) && (CostOut > 0);
if (!BothCostsAreValidProducts)
  return NO_PROFIT;
else {
   // that calculation here...
}

ฉันคาดเดาชื่อที่นี่: เปลี่ยนBothCostsAreValidProductsและNO_PROFITตามความเหมาะสม


แน่นอนค่าใช้จ่ายอาจเป็นศูนย์ (คิดว่า Xmas แสดง) และในช่วงเวลาที่อัตราดอกเบี้ยติดลบนั้นไม่น่าแปลกใจเกินไปและอย่างน้อยก็ควรเตรียมรหัสที่จะจัดการกับมัน (และไม่ว่าจะโดยการโยนข้อผิดพลาด)
Hagen von Eitzen

ของคุณในการติดตามที่ถูกต้อง
danny117

นั่นมันโง่ if (CostIn <= 0 || CostOut <= 0)สมบูรณ์ดี
เส้นทาง Miles Rout

อ่านได้น้อยกว่ามาก ชื่อตัวแปรน่ากลัว (BothCostsAreValid คงจะดีกว่าไม่มีอะไรที่นี่เกี่ยวกับผลิตภัณฑ์) แต่ถึงอย่างนั้นก็ไม่ได้เพิ่มอะไรให้อ่านง่ายเพราะเพียงแค่ตรวจสอบ CostIn, CostOut ก็ใช้ได้ คุณจะแนะนำตัวแปรพิเศษที่มีชื่อที่มีความหมายหากความหมายของนิพจน์ที่กำลังทดสอบนั้นไม่ชัดเจน
gnasher729

5

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

  1. เติมเต็มความต้องการทางธุรกิจด้วยปริมาณงานที่น้อยที่สุด

  2. หลีกเลี่ยงข้อบกพร่อง

  3. อนุญาตให้เราทำการเปลี่ยนแปลงในอนาคตซึ่งยังคงเติมเต็ม 1 และ 2

นี่คือเป้าหมาย หลักการหรือวิธีการออกแบบใด ๆ (ไม่ว่าจะเป็น KISS, YAGNI, TDD, SOLID, หลักฐาน, ระบบประเภท, metaprogramming แบบไดนามิกและอื่น ๆ ) มีคุณธรรมเพียงเท่าที่พวกเขาช่วยให้เราบรรลุเป้าหมายเหล่านี้

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

บรรทัดมีข้อกังวลสามประการ: ทหารรักษาพระองค์ (ปลอกพิเศษ 0), การคัดเลือกนักแสดงและการคำนวณ ข้อกังวลแต่ละข้อนั้นค่อนข้างเรียบง่ายเมื่อแยกออก แต่เนื่องจากมีการรวมกันในการแสดงออกเดียวกันจึงเป็นการยากที่จะติดตาม

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

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

ดังนั้นปัญหาจะไม่สั้นหรือขาดปัญหาปัญหาคือตรรกะซ้ำและ conflation ของความกังวลที่นำไปสู่รหัสยากต่อการบำรุงรักษา

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


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

3

ความกะทัดรัดไม่ได้เป็นคุณธรรมเลย การอ่านเป็นคุณธรรม

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

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


2

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

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

decimal dIn = (decimal)CostIn;
decimal dOut = (decimal)CostOut;
return dIn > 0 && CostOut > 0 ? ((dOut - dIn) / dOut) * 100 : 0;

(แก้ไข: นี่คือรหัสเดียวกับคำตอบอื่น ๆ ดังนั้นคุณไป)

ฉันเป็นแฟนตัวยงของผู้ประกอบการที่สาม? :ดังนั้นฉันจะปล่อยมันไว้


5
Ternaries เป็นการยากที่จะอ่านโดยเฉพาะอย่างยิ่งหากมีการแสดงออกใด ๆ เกินกว่าค่าเดียวหรือตัวแปรในค่าตอบแทน
Almo

ฉันสงสัยว่านั่นคือสิ่งที่ผลักดันให้คะแนนลบ ยกเว้นสิ่งที่ฉันเขียนเป็นข้อตกลงมากกับ Mason Wheeler ขณะนี้มี 10 คะแนน เขาทิ้งไตรภาคไว้ด้วย ฉันไม่รู้ว่าทำไมคนจำนวนมากถึงมีปัญหากับ? :- ฉันคิดว่าตัวอย่างข้างต้นมีขนาดกะทัดรัดพอสมควรโดยเฉพาะอย่างยิ่ง เปรียบเทียบกับ if-then-else
Paul Brinkley

1
ไม่แน่ใจจริงๆ ฉันไม่ได้ลงคะแนนคุณ ฉันไม่ชอบ ternaries :เพราะมันไม่ชัดเจนสิ่งที่อยู่บนด้านข้างของทั้งสอง if-elseอ่านเหมือนภาษาอังกฤษ: อย่าพลาดความหมายของมัน
Almo

FWIW ฉันสงสัยว่าคุณกำลังลงคะแนนเพราะนี่เป็นคำตอบที่คล้ายกันมากกับ Mason Wheeler แต่เขาได้รับมาก่อน
Bob Tway

1
ตายกับผู้ประกอบการที่สาม !! (เช่นความตายต่อแท็บไม่มีที่ว่างและโมเดลการถ่ายคร่อมและการเยื้องใด ๆ ยกเว้น Allman (อันที่จริง The Donald (tm) ได้ทวีตว่าสิ่งเหล่านี้จะเป็นกฎหมายสามข้อแรกที่เขาออกกฎหมายในวันที่ 20)
Mawg

2

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

return ((decimal)CostIn > 0 && CostOut > 0) ?
       100 * ( (decimal)CostOut - (decimal)CostIn ) / (decimal)CostOut:
       0;

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


4
สาเหตุของการปลดเปลื้องคือ Entity Framework db จำเป็นต้องเก็บสิ่งเหล่านี้เป็นชนิดที่ไม่สามารถใช้ได้ สอง? ไม่เท่ากับ Double ใน C # และต้องทำการร่าย
Bob Tway

2
@ MattThrower คุณหมายถึงdecimalใช่มั้ย double! = decimalมีความแตกต่างใหญ่
pinkfloydx33

1
@ pinkfloydx33 ใช่! พิมพ์ทางโทรศัพท์โดยใช้สมองเพียงครึ่งเดียวเท่านั้น :)
Bob Tway

ฉันต้องอธิบายให้นักเรียนของฉันว่าประเภทข้อมูล SQL แตกต่างอย่างมากจากประเภทที่ใช้ในภาษาการเขียนโปรแกรม ฉันไม่สามารถอธิบายเหตุผลได้ "ฉันไม่รู้!" "Endian น้อย!"

3
ฉันไม่สามารถอ่านสิ่งนี้ได้เลย
Almo

1

สำหรับฉันดูเหมือนว่าปัญหาใหญ่ที่มีความสามารถในการอ่านได้อยู่ที่การจัดรูปแบบที่ไม่ครบถ้วน

ฉันจะเขียนแบบนี้:

return (decimal)CostIn > 0 && CostOut > 0 
            ? (((decimal)CostOut - (decimal)CostIn) / (decimal)CostOut) * 100 
            : 0;

ขึ้นอยู่กับว่าประเภทของCostInและCostOutเป็นประเภทจุดลอยตัวหรือประเภทที่สำคัญบางส่วนของ casts อาจไม่จำเป็น ซึ่งแตกต่างfloatและค่านิยมที่สำคัญได้รับการส่งเสริมโดยปริยายdoubledecimal


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

@PJTraill ฉันต้องพลาดมันเกือบจะเหมือนกัน อย่างไรก็ตามฉันชอบที่จะให้ผู้ให้บริการในบรรทัดใหม่ซึ่งเป็นสาเหตุที่ฉันจะให้รุ่นของฉันยืน
เฟลิกซ์ Dombek

ฉันเห็นด้วยเกี่ยวกับผู้ประกอบการตามที่ฉันได้กล่าวไว้ในความเห็นเกี่ยวกับคำตอบอื่น ๆ - ฉันไม่ได้เห็นว่าคุณได้ทำตามที่ต้องการ
PJTraill

0

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

และถ้าฉันอ่านรหัสอย่างถูกต้องแล้วก็พยายามทำการคำนวณขั้นต้น

var totalSales = CostOut;
var totalCost = CostIn;
var profit = (decimal)(CostOut - CostIn);
var grossMargin = 0m; //profit expressed as percentage of totalSales

if(profit > 0)
{
    grossMargin = profit/totalSales*100
}

3
คุณสูญเสียการหารด้วยศูนย์ส่งกลับศูนย์
danny117

1
และนั่นเป็นเหตุผลที่มันยากที่จะสร้างรหัสของคนอื่นที่มีขนาดกะทัดรัดที่สุดและทำไมมันดีที่มีความคิดเห็นเพิ่มเติมเพื่ออธิบายว่าทำไม / สิ่งต่าง ๆ ทำงานอย่างไร
Rudolf Olah

0

ฉันสมมติว่า CostIn * CostOut เป็นจำนวนเต็ม
นี่คือวิธีที่ฉันจะเขียนมัน
M (เงิน) เป็นทศนิยม

return CostIn > 0 && CostOut > 0 ? 100M * (CostOut - CostIn) / CostOut : 0M;

1
หวังว่าพวกเขาไม่ใช่ทั้งความคิดเชิงลบ: p
Walfrat

2
หารด้วยศูนย์ยังอยู่ที่นั่นหรือไม่?
danny117

@ danny117 เมื่อความกะทัดรัดให้คำตอบที่ไม่ถูกต้องมันจะไปไกล
paparazzo

ไม่ต้องการอัปเดตคำถามและทำให้ใช้งานได้ 100M และ 0M บังคับให้ทศนิยม ฉันคิดว่า (CostOut - CostIn) จะดำเนินการเป็นเลขจำนวนเต็มจากนั้นความแตกต่างจะถูกแปลงเป็นทศนิยม
paparazzo

0

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

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


1
นี่คือที่มาของการปฏิบัติและหลักการทางวิศวกรรมซอฟต์แวร์ ข้อกำหนดที่ไม่ใช้งานได้
hanzolo

0

ความกะทัดรัดไม่ได้เป็นคุณธรรมอีกต่อไปเมื่อ

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

เมื่อไม่มีคำตอบที่ยาวพอ

1
ตกลงสิ่งนี้ควรเป็นความเห็นไม่ใช่คำตอบ แต่เขาเป็นคนใหม่อย่างน้อยก็อธิบายได้ อย่าเพิ่งลงคะแนน & วิ่งหนี! ยินดีต้อนรับบนเรือ Danny ฉันยกเลิก downvote แต่ครั้งต่อไปทำให้เป็นความเห็น :-)
Mawg

2
ตกลงฉันได้ขยายคำตอบเพื่อรวมสิ่งที่ซับซ้อนมากขึ้นที่ฉันได้เรียนรู้วิธีที่ยากและวิธีที่ง่ายเขียนรหัสย่อ
danny117

ขอบคุณสำหรับการต้อนรับ @Mawg ฉันต้องการที่จะชี้ให้เห็นการตรวจสอบเป็นโมฆะคือสิ่งที่ฉันพบปัญหาที่ก่อให้เกิดมากที่สุดในรหัสย่อ
danny117

ฉันเพิ่งแก้ไขผ่าน Android และไม่ได้ขอคำอธิบายของการแก้ไข ฉันเพิ่มการปรับปรุงในแง่ดี (ตรวจพบการเปลี่ยนแปลงและเตือน)
danny117

0

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

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

เมื่อจัดการกับข้อกำหนดที่ไม่สามารถใช้งานได้เช่นโค้ด "readbility" จะต้องมีการกำหนดโดยผู้จัดการฝ่ายพัฒนาและจัดการโดยนักพัฒนานำและเป็นที่เคารพของนักพัฒนาเพื่อให้แน่ใจว่าการใช้งานที่เหมาะสม

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

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

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