Clean code (TH.)

gun27311

kanthakran

Posted on November 12, 2020

Clean code (TH.)

บทความนี้เป็นการสรุปเนื้อหาเท่าที่ผู้อ่านเข้าใจจากหนังสือ
CleanCode ของ Robert C martin หรือลุง Bob

Table Of Contents

  1. Introduction
    1. Clean code คืออะไร
    2. Bad code
    3. หนี้สินทาง software คืออะไร
    4. แนวคิดเรื่อง Clean code (สำคัญ)
  2. หลักการการทำ Clean code
    1. Meaningful Name
    2. Function
    3. Comments
    4. Formatting

Introduction

บทความนี้เป็นการสรุปหนังสือ Clean Code Robert C. Martin
ตามความเข้าใจหากผิดพลาดช่วย Comment กัได้นะเออ

Clean code คืออะไร

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

Bad code

เราอาจจะเคยต้องอ่านโค๊ทต่อจากคนอื่น หรือ เราไม่ได้ทำ Project นั้นนานๆ แล้วกลับมาอ่านสิ่งที่เราจะเจอ

  • ตัวแปลตัวนี้คืออะไรวะ dowData อ่านชื่อแล้วงง
  • function นี้มันทำอะไรวะ genAcTcUserSta
  • อ่าน code แล้วต้องลงไปดูใน function เพราะชื่อไม่สื้อ
  • เรา check if เพื่ออะไรวะ for ตรงนี้ไม่เห็นจำเป็นต้องมีนิ
  • บางตัวแปลไม่ได้ใช้ประกาศทำไม
  • ฯลฯ

สิ่งเหล่านี้ที่เราเจอมาล้วนเป็นหนี้สินทาง software ทั้งสิ้น

หนี้สินทาง software คืออะไร

มันคือสิ่งที่ทำให้เราช้าลง เพราะหนี้สินล้วนมีดอกเบี้ย สิ่งที่จะเกิดผลกระทบ

  • เวลาในการศึกษา code นั้นๆ จะมากขึ้น เช่น มีคนใหม่เข้าทีมอ่านทีหัวแตก (learning curve สูง)
  • การแก้ไขโปรแกรมทำได้ยาก ไม่ว่าจะเพิ่ม feature หรือ fix bug
  • เขียน test ยาก (ถึงกับไม่รู้จะเขียนยังไง)
  • อ่านยากมากๆ อ่าน code แล้วอยากลาออก
  • ฯลฯ

วันหนึ่งจะมีคนพูดว่า "ถ้าอ่านยากขนาดนี้ เขียนใหม่ยังง่ายกว่า"

แนวคิดเรื่อง Clean code

ถ้าเราถามว่า code ทำงานได้ กับ code สวย อะไรสำคัญกว่ากัน
หลายคนคงตอบไม่ยากว่า งานเสร็จ code ทำงานได้สำคัญกว่าอยู่แล้ว
ความเร็วในการออกของสำคัญมากยิ่งเราอยู่ในโลกของ agile และ scrum

ผมก็จะบอกว่าถูกครับ

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

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

แต่เรามักถูกบีบด้วยเวลา และคนเดินมาเร่งมากมาย เวลาเกิดปัญหาเราก็จะบอกว่า

  • ผมมีเวลาแค่นี้ครับ
  • ได้แค่นี้ก็หรูแล้ว
  • มันทำงานได้ก็โอเคร

จริงๆ แล้วไม่ใช่แค่ Programmer ที่จะต้องเข้าใจในคำว่า หนี้สินทาง software ขอเรียก software debt คำนี้มันเกิดตอนที่ ลุง Robert C. Martin อธิบายให้หัวหน้าฟังเพราะบริษัทที่ทำงานนั้นเกี่ยวกับด้านการเงินเลยเกิดคำนี้มาเพื่อให้หัวหน้าเข้าใจ มันแปลว่าหัวหน้า , PM ใครก็แล้วแต่ที่สั่งเรา ต้องเข้าใจ
ในเรื่อง software debt ด้วยเพื่อใช้ในการประเมิณเวลาในการทำด้วย


หลักการในการ Clean Code

Meaningful Names

การตั้งชื่อ

Use Intention-Revealing Names

ชื่อทุกสิ่งที่เราตั้งล้วนต้องมีความหมาย บ่งบอกถึงเจตนาของสิ่งนั้นๆ อย่างชัดเจน เช่น class function val หากชื่อพวกนั้นต้องการ comment แสดงว่าชื่อนั้นยังไม่บอกเจตนาอย่างชัดเจน

// Day of week
var dow 

or

var dayOfWeek
Enter fullscreen mode Exit fullscreen mode

Use Pronounceable Names

ชื่อต้องอ่านออกเสียงได้ หลีกเลี่ยงการใช้

number series : a1 a2 a3

Noise words are another meaningless distinction

ลองนึกภาพว่าคุณมี product class. หากคุณมีชื่ออื่นที่เรียกว่า ProductInfo หรือ ProductData คุณได้สร้างชื่อให้แตกต่างกันโดยไม่ทำให้มีความหมายแตกต่างกัน ข้อมูลและข้อมูลเป็นสัญญาณรบกวนที่ไม่ชัดเจน
คำเช่น a, an และ this
อย่ากลัวที่จะตั้งชื่อยาวหากชื่อนั้นสร้างความแตกต่างอย่างมีความหมายได้

Noise words are redundant

ไม่ควรใส่ type ของตัวแปลไปหลังชื่อ เช่น nameString, dateLong เพื่อเลี่ยงการปิดเบือนข้อมูลเหมือน accountList ด้านบน และ

เพราะว่า IDE สมัยนี้หากเราเอาเมาส์ไปชี้ก็จะแสดง type ให้อยู่แล้วถ้าไม่ใช้ตัวแปร dynamic type

Avoid Disinformation

หลีกเลี่ยงการทำเกิดความเข้าใจผิด หรือทำให้ความหมายเปลี่ยนแปลง ต่างจากความหมายที่เราตั้งใจไว้ เช่น hp,aix, sco ทั้งหมดนี้ล้วนเป็นชื่อของ platfrom linux

การตั้งชื่อโดยใส่คำว่า list accountList การตั้งชื่อแบบนี้เสี่ยงต่อการเข้าใจผิดได้ง่ายว่ามันคือ รายการบัญชีหรือกลุ่มของบัญชีหรือเปล่า เราอาจจะใช้ accounts สำหรับ array account หรือ accountGroup สำหรับกลุ่มของ account

Make Meaningful Distinctions

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

Use Searchable Names

ใช้ชื่อที่ search ได้ หลีกเลี่ยงการใช้ ตัวอักษรตัวเดียว และ ควรใช้ Constants แทน ตัวเลข มันไม่ง่ายเลยที่เราจะหาตัว i ที่เราตั้งการใน โปรเจค

หรือเราจะหาตัวเลข 1 ในโปรเจค ควรตั้ง constant แทน เช่น MAX_DRIVER_IN_CAR

Avoid Encodings

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

Member perfixes

เลี่ยงการใช้คำนำหน้าเช่น m_student ถ้า function เราเล็กพอสิ่งนี้จะไม่เกิดแน่นอน

Class Names

ควรเป็นคำนามเท่านั้น ห้ามใช้กริยา

Method Names

ควรเป็นกริยาเท่านั้น ห้ามเป็นคำนาม

Don't Be Cute

อย่าอวดฉลาดตั้งชื่อตัวแปลเท่ๆ เช่น Eureka ,phoenix, Aileen (แปลว่าแสงสว่าง)

Pick one word per concept

เป็นการนิยามชื่อ protocalManager และ ProtocolController ดูเหมือนกันเลยแต่จะเอาอันไหนละ

Use Solution Domain Name

ใช้การต่อชื่อไปอย่างสอดคล้องกัน createPluralDependentMessageParts
หากทำไม่ได้การเพิ่ม name space ไว้ข้างหน้าจะเป็นทางออกสุดท้าย


Function

Small ต้องเล็ก

1 บรรทัดไม่เกิน 150 อักษร
1 function ไม่ควรเกิน 100 บรรทัด
แต่จะให้ดี ไม่เกิน 20 บรรทัด

Blocks and Indenting

if else if else while statement ไม่ควรเกิน 1 บรรทัด หากเกินควรแยก function

Do One Thing

1 function ควรทำแยกสิ่งเดียว

Function Arguments

ควรน้อยที่สุดเท่าที่เปิดไปได้ และไม่ควรเกิน 3 ถ้าเกินเราอาจจะสร้าง class มารองรับ

Verbs and Keywords

เลือกชื่อที่ดีเป็นกริยาสำหรับ function

Have No Side Effects

function เราต้องไม่มี side effects เพราะหากมีเราจะรู้เลยว่า function เราไม่ได้ทำสิ่งเดียว Do One Thing

public class UserValidator {
 private Cryptographer cryptographer;
 public boolean checkPassword(String userName, String password) {
       User user = UserGateway.findByName(userName);
 if (user != User.NULL) {
       String codedPhrase = user.getPhraseEncodedByPassword();
       String phrase = cryptographer.decrypt(codedPhrase, password);
       if ("Valid Password".equals(phrase)) {
        Session.initialize();
       return true;
     }
   }
 return false;
}
Enter fullscreen mode Exit fullscreen mode

code จาก clean code :Rovert C matin หน้าที่ 44

Extract Try/Catch Blocks

การ try catch ลงใน function เลยอาจจะทำให้ดูน่าเกลียด
หากเราไม่แยกการทำงานของ function ให้ทำงานเพียงอย่างเดียว
(ในการ try catch ควรมีแค่ function เดียวการทำงานเดียวที่เราดัก)

don't
ในตัวอย่างนี้เราจะเห็นได้ว่าเรา try catch ในหลาย function อาจจะทำให้เราสับสนได้ว่า error นี้มาจากกระบวนการไหนของ flow กันแน่

function delete(page){
 try{
  deletePage(page);
  registry.deleteReference(page.name);
  configKeys.deleteKey(page.name.makeKey());
 }catch(error){
   throw Exception("can't delete page "+page.id+" error :"+error)
 }
}
Enter fullscreen mode Exit fullscreen mode

do

function delete(page){
 try{
  deletePageAndAllReferences(page);
 }catch(error){
  throw Exception("can't delete page "+page.id+" error :"+error)
 }
}
function deletePageAndAllReferences(){
  deletePage(page);
  registry.deleteReference(page.name);
  configKeys.deleteKey(page.name.makeKey());
}
Enter fullscreen mode Exit fullscreen mode

เราควร

Don’t Repeat Yourself

อย่าทำซ้ำ เช่นซ้ำซ้อนการทำงานต่างๆ duplication


Comments

code ที่ดีต้องไม่มี comment เราชอบคิดว่ามันซับซ้อนเลยต้องมี comment จริงๆ มันไม่ถูกซะทีเดียวเราควรทำให้ code ดีมากกว่าคิดว่ามันซับซ้อนอ่านยากเลยต้อง comment
comment ที่ควรเขียนมีแค่ Copyright กับ authorship statement

หรือข้อยกเว้นหากเราเขียน libary ที่ซับซ้อนมากๆ การ comment ก็ไม่แปลกอะไรแต่ทางที่ดีที่สุดคือ ทางที่เราไม่ใส่ comment


Formatting

The coding style and readability เราควรจะจัด code style ให้ตรงกัน ซึ่งสามารถกำหนดใน IDE ได้
เช่น 150 ตัวอักษรสำหรับ 1 บรรทัด ฯลฯ

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

Alt text of image

💖 💪 🙅 🚩
gun27311
kanthakran

Posted on November 12, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related