รหัสที่แปลงค่าเป็นตัวแทนที่แตกต่างกันจากนั้นแปลงกลับเป็นจุดเริ่มต้นที่ไม่ดี แต่อย่างไร [ปิด]


35

ผมได้อ่านบทความเกี่ยวกับการเขียนโปรแกรมที่ไม่ดี

มันกล่าวถึง -

"รหัส Yo-Yo" ที่แปลงค่าเป็นตัวแทนที่แตกต่างกันจากนั้นแปลงกลับไปที่จุดเริ่มต้น (เช่นการแปลงทศนิยมให้เป็นสตริงแล้วกลับไปเป็นทศนิยมหรือเติมสตริงแล้วตัดทอน)

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

ใครสามารถอธิบายเพิ่มเติมเกี่ยวกับเรื่องนี้ได้บ้าง


4
การอ่านที่แนะนำ: อภิปราย $ {บล็อก} นี้
gnat

8
เวลาส่วนใหญ่เป็นเพียงการซ้ำซ้อนและมันเกิดขึ้นเพียงเพราะโปรแกรมเมอร์ไม่รู้วิธีที่ดีกว่าในการได้รับสิ่งที่ต้องการ "Roundabout code" that accomplishes in many instructions what could be done with far fewer (eg: rounding a number by converting a decimal into a formatted string, then converting the string back into a decimal)รายการบล็อกให้เป็นตัวอย่างที่ปกติไม่กี่ย่อหน้าต่อมา: if the situation is so that they have to be used?- สถานการณ์นั้นจะเป็นอย่างไร
Konrad Morawski

3
@gnat ฉันไม่เข้าใจว่าทำไมมันถึงเป็นคำถามที่ไม่ดี หากคุณต้องการฉันสามารถแก้ไขเพื่อพูดว่า "เป็นรหัสที่แปลงและแปลงกลับค่าที่ไม่ดี?" และมันจะไม่พอดีกับแม่แบบนั้นอีกต่อไป
djechlin

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

3
decimal myValue = decimal.Parse(dataReader["myColumn"].ToString())เป็นสัตว์เลี้ยงโกรธของฉัน
Matthew

คำตอบ:


125

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

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


5
พูดได้ดี. โปรแกรมเมอร์ทุกคนควรระวังให้มาก
Neil

58
"รหัสที่ไม่มีอยู่ไม่สามารถมีข้อบกพร่องเล็กน้อยในขณะที่รหัสที่มีอยู่มักจะ" ต้องการให้ฉัน +2 คุณ อย่าประมาทคุณค่าของการไม่ต้องเขียนโค้ด
Benjamin Gruenbaum

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

36
@DanielRHicks ดังนั้นเรามาแปลงวันที่ง่าย ๆ (10 พฤศจิกายน 2014) เป็นสตริง -> 10-11-2014 และกลับไปเป็นวันที่ -> (11 oktober 2014) เดี๋ยวก่อนอะไรนะ?
Pieter B

20
@PieterB มีซอฟต์แวร์บัญชีเยอรมันขนาดใหญ่ที่ไม่สามารถใช้งานได้กับคอมพิวเตอร์ที่ไม่มีภาษาเยอรมันเพราะมันทำเช่นนี้ ก่อนอื่นจะแปลงวันที่เป็นสตริงโดยใช้สถานที่ของระบบแล้วพยายามแยกวิเคราะห์ด้วยสถานที่คงที่และบ่นเกี่ยวกับรูปแบบที่ผิดกฎหมาย มันทำเช่นเดียวกันกับตัวเลขและตัวคั่นทศนิยมที่แตกต่างกันยกเว้นว่าจะไม่บ่นที่นั่นมันทำลายข้อมูลและแสดงพฤติกรรมแปลก ๆ เอาวันให้ฉันคิดออก
CodesInChaos

23

มันไม่ดีด้วยเหตุผลสำคัญสามประการ:

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

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


6

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

เป็นตัวอย่างที่การแปลงเป็นสิ่งที่ดี:
หนึ่งมีสี่floatค่าของสัญญาณโดยพลการที่มีขนาดอาจแตกต่างกันโดยปัจจัยสูงถึง 1,000 และหนึ่งจะต้องคำนวณผลรวมภายใน 0.625 หน่วยในสถานที่สุดท้าย การแปลงค่าทั้งสี่ไปdoubleเป็นคำนวณผลรวมและแปลงผลลัพธ์กลับมาให้floatมีประสิทธิภาพมากกว่าวิธีการใช้งานfloatเพียงอย่างเดียว
ค่าจุดลอยตัวมีความแม่นยำที่ดีที่สุดถึง 0.5 หน่วยในสถานที่สุดท้าย (ULP) ตัวอย่างนี้จะต้องมีข้อผิดพลาดในการปัดเศษกรณีที่แย่ที่สุดโดยไม่เกิน 25% เหนือข้อผิดพลาดกรณีเลวร้ายที่สุดที่เหมาะสม การใช้ double จะทำให้ได้ค่าที่แม่นยำภายใน 0.5001 ULP ในขณะที่ความต้องการ 0.625 ULP อาจดูเหมือนถูกจัดทำขึ้น แต่ข้อกำหนดดังกล่าวมักจะมีความสำคัญในอัลกอริทึมแบบต่อเนื่อง ยิ่งระบุขอบเขตข้อผิดพลาดให้แน่นมากเท่าใดความต้องการการวนซ้ำของเคสที่แย่ที่สุดก็จะยิ่งต่ำลง

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

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

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

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


1
ตัวอย่างของคุณไม่ส่งคืนค่าดั้งเดิมซึ่งเป็นสิ่งที่ OP กำลังถาม มันเพียงแค่ส่งกลับค่าที่มีประเภทเดียวกันคำนวณจากหลายอินพุต
CJ Dennis

2

ด้วยเหตุผลต่าง ๆ

  1. มันไม่มีจุดหมายและเพิ่มความซับซ้อน - ทั้งจำนวนของโค้ดที่จะเขียนและดูแลรักษาและจำนวนเวลา CPU ที่ต้องการ

    1. มันอาจสูญเสียความถูกต้องหรือแย่ลงทำลายมูลค่าโดยสิ้นเชิง

    2. มันสูญเสียความทรงจำ (ขึ้นอยู่กับภาษา) ในขณะที่คุณจัดเก็บการแสดงจำนวนที่คุณต้องการมากขึ้น

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


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

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

คำตอบก่อนหน้านี้จะดูกระชับกับฉันมากขึ้นทั้งคู่
ริ้น

0

ทำไม? เพราะแม้แต่สิ่งที่ดีที่สุดของเราก็สามารถทำผิดพลาดได้

ดูสิ่งที่เกิดขึ้นเมื่อ Microsoft พยายามใช้รูปแบบ "ไปกลับ" โดยเฉพาะเพื่อให้แน่ใจว่าการแปลงสตริงแบบลอย <-> มีความปลอดภัย: https://stackoverflow.com/q/24299692/541686


0

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

การแปลงประเภทเดียวกันคุณเสี่ยงต่อการสูญเสียข้อมูล CInt (1.3) = 1

ในภาษาของฉันพื้นฐานเราทำการแปลงเท่านั้น (โปรแกรม VB6 ใช้ 90% ของเวลาในการทำการแปลง ANSI / Unicode สำหรับการเรียก API ทั้งหมดที่รันไทม์)

การแปลงประเภทมีนัยในทุกสิ่งที่เราทำ

 Print 5

สตริง "5" ถูกพิมพ์จากตัวอักษรตัวเลข

form1.caption = "My Form"

ตัวอักษรสตริง Unicode ได้รับการแปลงเป็นสตริง ANSI และส่งไปยัง SetWindowsTextA โดยแพคเกจแบบฟอร์ม

แม้จะใช้งานได้ในระดับพื้นฐาน

a = "5"
b = 3

c = a + b (= 8)

ฉันเป็นโปรแกรมเมอร์รุ่นแปรปรวนในทุกวันนี้ - ฉันไม่ได้คิดถึงประเภท ฉันพึ่งพึ่งการแปลงแบบอัตโนมัติ

อย่างไรก็ตามสัตว์เลี้ยง 3 ตัวของฉันคืออะไร

การกำหนดตัวอักษรสตริงให้กับตัวแปรที่จะใช้ (เสียหน่วยความจำและช้า)

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

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

และอันดับที่ 4 สำหรับโปรแกรมระยะสั้น

หรี่แสงตัวแปรของคุณ 3 ในโปรแกรม 5 บรรทัด

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