👶 Code Smells

โค้ดคุณส่งกลิ่นเน่าออกมาหรือเปล่า ?

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

Code smells คือหลักการที่เอาไว้ตรวจว่า โค้ดที่เราออกแบบไว้มันไปผิดหลักการออกแบบหรือเปล่า ซึ่งถ้าผิดมันหมายความว่าโครงสร้างพวกนั้นจะมีปัญหาในอนาคต และมีอีกชื่อนึงคือ Design Smells

❓ โค้ดส่งกลิ่นเน่าแล้วไง ?

คุณอยากทำงานกับโปรเจคแบบนี้ไหม แก้โค้ด 1 จุด bug ผุดกระจาย หรือ เพิ่ม 1 feature แต่ต้องไปแก้ 10 feature ที่ไม่เกี่ยวข้องด้วยไม่งั้นเพิ่ม feature ใหม่ไม่ได้ และอื่นๆอีกมากมาย ซึ่งถ้าไม่โรคจิตพอก็น่าจะตอบว่า "ไม่" แล้วถามต่อว่า แล้วจะมีใครอยากมาทำงานโปรเจคแบบนี้ไหม? คนที่อยู่ในโปรเจคแบบนี้เขาอยากรีบหนีไปทำโปรเจคอื่นไหม? นี่ยังไม่นับรวมเรื่อง deadline ของโปรเจคนี้ที่กำลังบีบเข้ามาด้วยนะ ... แค่นี้ก็น่าจะเห็นภาพแล้วใช่ไหมว่า โค้ดเน่ามันส่งผลเสียยังไง . . . หรือก็เป็นอยู่จนชินกันแล้ว ? 😱

🤢 อาการของกลิ่นเน่า

👃 Rigidity (ดื้อ)

คืออาการของโค้ดที่แก้ไขเพิ่มเติมยาก แม้ว่าจะเป็นแค่เรื่องง่ายๆก็ตาม เช่น แก้ 1 จุด แต่มันไปกระทบกับโค้ดอื่นๆที่เกี่ยวข้องกับมัน ทำให้เราต้องไปตามแก้เพื่อให้มันทำกับแบบใหม่ได้ แย่กว่านั้นอีกแก้ A กระทบ B, แก้ B กระทบ C, แก้ C ดันย้อนมากระทบ A เป็นงูกินหาง

แก้ 1 กระทบ 10 เคยไหมคิดว่าจะแก้โค้ดแค่ 1-2 วันวัน แต่พอทำไปทำมาบางทีกินเวลาเป็น 1-2 อาทิตย์เลย ทำให้เราไม่สามรถประเมินว่างานจะเสร็จเมื่อไหร่ได้เลย 😧

👃 Fragility (เปราะบาง)

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

แก้ 1 จุด bug ผุดเป็นดอกเห็ด เคยไหม bug มันเยอะแก้ยังไงก็ไม่หมด จนคิดว่าเขียนส่วนนั้นใหม่ตั้งแต่ต้นอาจจะเร็วกว่า ปัญหานี้ developer ทุกคนรู้จักดี และบางครั้งรู้ด้วยว่ามันเป็นไฟล์นี้ แต่ไม่มีคนอยากไปแก้มันเพราะกลัวฟาร์มเห็ดจะผลิบาน

👃 Immobility (ย้ายที่ไม่ได้)

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

👃 Viscosity (หนืด)

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

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

👃 Needless Complexity (ซับซ้อนโดยไม่จำเป็น)

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

ซับซ้อนโดยไม่จำเป็น ตัวอย่างที่เจอได้ง่ายสุดๆคือ จะแสดงเลขทศนิยมสูงสุดเพียงแค่ 2 ตำแหน่ง เช่น 3.1415 จะต้องแสดงเป็น 3.14 แต่ developer ไปเขียนสูตรคำนวณเพื่อตัด string หรือไม่ก็ x 100 เข้า แล้วหาร 100 ออกบลาๆ ซึ่งทำไมไม่ใช่ Math.Round() แฟร๊ พูดแล้วขึ้น 😡

👃 Needless Repetition (ใช้โค้ดซ้ำโดยไม่จำเป็น)

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

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

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

👃 Opacity (เข้าใจยาก)

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

🤔 ทำไมโค้ดถึงเน่า ?

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

พูดสั้นๆ กลับไปเก็บ exp มาให้เยอะๆซะ (รวมถึงผมด้วย) เพราะการเขียนซอฟต์แวร์ต้องเรียนรู้ตลอดไปไม่สามารถหยุดเรียนได้ เทคโนโลยีในตอนนี้เปลี่ยนวันต่อวันเลยทีเดียว 🤧

🎯 บทสรุป

โค้ดเน่าทำให้การพัฒนาซอฟต์แวร์กลายเป็นนรก เพราะ โปรเจคประเมินเวลาและค่าใช้จ่ายไม่ได้ ไม่มีคนอยากทำโปรเจคนั้น ดังนั้นจงอย่าทำให้มันเน่า

แล้วจะทำยังไงมันถึงจะไม่เน่า ? ... ออกไปเก็บประสบการณ์ซะ อ่านโค้ดจาก GitHub คนที่เก่งๆ ร่วม Contribute source code กับ GitHub ระดับโลกซักตัว เราจะได้รับคำแนะนำมาเต็มเลย และที่สำคัญที่สุดคือไปศึกษาหลักการออกแบบที่ดีมาซะ

👨‍🚀 คอร์สที่จะช่วยให้โค้ดไม่เน่า