# Uncle Bob - Naming

การทำ Clean Code ตอนที่ 2.2 จากวีดีโอของ 🧓 **ลุงบ๊อบ** หรือ [**Robert C. Martin**](https://en.wikipedia.org/wiki/Robert_C._Martin) หนึ่งในมหาเทพวงการคอมพิวเตอร์ ซึ่งในรอบนี้เราจะมาดูกันว่า ป๋าแกมีมุมมองใน **ตัวชื่อของต่างๆ** ยังไงกันบ้างถึงจะคลีนกันฮ๊าฟ 😘 ส่วนใครที่ยังไม่ได้อ่านตอนก่อนหน้าก็กดอ่านได้จากลิงค์นี้เบย [🧓 **Uncle Bob - Part 2.1**](https://www.saladpuk.com/basic/clean-code/uncle-bob-part-2)

{% hint style="success" %}
**แนะนำให้อ่าน**\
บทความนี้เป็นส่วนหนึ่งของบทคอร์ส [👶 **Clean Code**](https://www.saladpuk.com/basic/clean-code) หากเพื่อนๆแมวน้ำสนใจศึกษาเรียนรู้ว่าการทำ Clean Code ว่ามันคืออะไร? มีอะไรบ้าง? บลาๆ ก็สามารถกดที่ชื่อบทความสีฟ้าๆเข้าไปอ่านได้เลยครัช
{% endhint %}

## 🧐 ไฟล์ในโปรเจค

### 📄 จำนวนบรรทัด

ลุงบ๊อบได้ลองเอาโปรเจคของแกมา 7 ตัว แล้วเอามาวิเคราะห์หาความสัมพันธต่างๆดู แล้วก็พบจุดที่น่าสนใจที่เกี่ยวกับ **ไฟล์ในโปรเจค** ตามรูปด้านล่าง

![จำนวนบรรทัดต่อ 1 ไฟล์ในโปรเจค](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MEgSN5JKJxixJwDmuRy%2F-MEgVB7ulSHbGL4KFq-E%2Fimage.png?alt=media\&token=0f396c2b-ea24-4b84-b757-fdc1a55008ed)

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

> 🧓 ขนาดไฟล์และจำนวนบรรทัด - จะมากหรือน้อยมันขึ้นอยู่กับ รูปแบบในการเขียนโค้ดที่ทีมจะเลือกใช้ (Coding Standard) ก็แค่นั้นแหละ

{% hint style="info" %}
**Coding Standard**\
เป็นมาตรฐานที่บังคับให็ทุกคนในทีมต้องทำตามเวลาเขียนโค้ด เพราะทุกคนจะได้เขียนของต่างๆออกมาเหมือนๆกัน เช่น รูปแบบการตั้งชื่อ รูปแบบการคอมเมนต์ รูปแบบการจัดการไฟล์ บลาๆ ซึ่งถามว่าไม่ใช้ได้ป่ะ? คำตอบคือได้นะ แต่ลองจินตนาการว่าเราต้องไปแก้โค้ดของคนอื่น แล้วต่างคนต่างเขียน ต่างคนก็มีสไตล์เป็นของตัวเอง แล้วเรายังอยากจะไปอ่านโค้ดที่มี 3-4 สไตล์ป่ะ? นั่นแหละข้อเสียของการไม่มี Coding Standard
{% endhint %}

### 🌭 จำนวนตัวอักษร

ถัดมาลุงแกก็ค้นพบว่า โปรเจคทั้ง 7 ตัวที่ไม่เกี่ยวข้องอะไรกันแต่กลับมี **จำนวนตัวอักษรต่อ 1 บรรทัด** ใกล้เคียงกันมาก ตามรูปด้านล่าง

![จำนวนตัวอักษรต่อ 1 บรรทัด](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MEgSN5JKJxixJwDmuRy%2F-MEg_P8lwJMgeZ9SeL3n%2Fimage.png?alt=media\&token=e6e4589a-5549-443b-ad96-e7755fac3ad7)

จากรูปด้านบนมันแสดงให้เห็นว่า **ไม่มีคนชอบโค้ดยาวๆ** และจุดที่เหมาะสมในการเขียนโค้ดควร **ไม่เกิน 30-40 ตัวอักษร** (เราไม่ได้เขียนโค้ดภาษาไทย ดังนั้นอ้างไม่ได้นะเฟร้ย)

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

## 🏷️ การตั้งชื่อ

**ชื่อเกี่ยวข้องกับทุกอย่างในโปรเจค** ไม่ว่าจะเป็น ชื่อโปรเจค ชื่อโฟเดอร์ ชื่อไฟล์ ชื่อคลาส ชื่อเมธอด ชื่อตัวแปร บลาๆ ซึ่ง 💖 **หนึ่งในหัวใจหลักของการทำ Clean Code คือการตั้งชื่อ** นี่แหละ

> 🧓 ถ้าเราไม่ใส่ใจในการตั้งชื่อ เราจะไม่สามารถเขียนโค้ดที่อธิบายตัวมันเองได้เลย

### ❌ อย่าตั้งชื่อคลุมเครือ

อะไรก็ตามที่ไม่ชัดเจน เราก็ต้องไปใส่คอมเมนต์อธิบายมันต่ออะดิ ตามโค้ดด้านล่าง

```csharp
int d; // elapsed time in days
```

### 🔹 ตัวแปรต่างๆ

การตั้งชื่อตัวแปรให้ **ดูที่ Scope ของมัน** ซึ่งถ้า **Scope สั้นให้ตั้งชื่อสั้น** แต่ถ้า **Scope ยาวให้ตั้งชื่อยาว** ตามตัวอย่างด้านล่าง

{% hint style="info" %}
**อธิบายเพิ่มเติม**\
Scope ในกรณี้นี้หมายถึง **Life Cycle ของสิ่งนั้นๆ** โดยปรกติของทุกอย่างมันจะมีชีวิตอยู่ได้แค่ภายในวงเล็บปีกกา { } เท่านั้น ซึ่งมันมีชีวิตอยู่มากหรือน้อย ขึ้นอยู่กับว่ายังมีใครใช้หรืออ้างอิงมันอยู่หรือเปล่า ซึ่งถ้าไม่มีแล้ว โดยปรกติเดี๋ยวมันก็จะมีตัว **Garbage collector** มาคอยทำลายของพวกนั้นทิ้ง เพื่อคืนหน่วยความจำนั่นเอง
{% endhint %}

#### **Short Scope**

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

```csharp
var input = Console.ReadLine();
if(input == "something")
{
    // ทำไรซักอย่าง
}
```

ตัวอย่างตัวแปรที่จบภายในบรรทัดเดียว หรือที่เราเรียกกันว่า inline variable ลุงแกจะตั้งชื่อแค่ 1 ตัวอักษรยังได้เลย

```csharp
return int.TryParse("1", out int v)? v : 0;
```

#### Long Scope

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

```csharp
var rawMoneyText = Console.ReadLine();
if(string.IsNullOrWhiteSpace(rawMoneyText))
{
    throw new ArgumentNullException();
}
// ผ่านไปอีกซัก 10 บรรทัด
if(int.TryParse(rawMoneyText, out int money))
{
    // ทำไรซักอย่าง
}
```

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

### 🔹 คลาส & เมธอด

ของพวกนี้จะ **ตรงข้ามกับตัวแปร** เพราะถ้า **Scope สั้นให้ตั้วชื่อยาว** แต่ถ้า **Scope ยาวให้ตั้งชื่อสั้น** และ เราควรจะ **ตั้งชื่อเป็น High Level & Abstraction** ด้วย โดยลุงแกให้เหตุผลที่ทำแบบนั้นว่า

{% hint style="info" %}
**เกร็ดความรู้**\
**High Level & Abstraction** หมายถึง เราจะตั้งชื่อเป็น การทำงานระดับบน ไม่ต้องอธิบายว่าจริงๆมันทำงานยังไง เพราะ เวลาอ่านเราจะได้เข้าใจไอเดียว่าของพวกนี้ใช้ทำอะไร โดยไม่ต้องไปสนใจรายละเอียดการทำงานจริงๆของมัน เช่น CreateUser หากเป็น Low Level มันจะเขียนออกมาประมาณว่า InsertNewUserToMongoDB ไรงี้ ซึ่งมันเป็นการตั้งชื่อที่ลงรายละเอียดถึงระดับการทำงานลึกๆละ
{% endhint %}

#### Long Scope

> 🧓 สาเหตุที่ Scope ยาวเราจะต้องตั้งชื่อให้สั้นๆ เพราะ โค้ดที่เรียกใช้ของพวกนี้เขาไม่ต้องการรู้การทำงานจริงๆ ดังนั้นชื่อมันเลยควรจะเป็น High Level ยังไงล่ะ ตามตัวอย่างด้านล่างเบย

**คลาส & เมธอด**

* &#x20;**public class จะนิยมตั้งชื่อสั้นๆ** เพราะคนที่เรียกใช้ ไม่ได้สนใจหรอกว่าจริงๆมันจะต่อกับ printer ประเภทไหน แค่รู้ว่าคลาส Printer ทำงานได้กับเครื่องพิมพ์ได้ทุกตัวก็พอ
* **public method จะนิยมตั้งชื่อสั้นๆ** เพราะคนที่เรียกใช้ก็ไม่สนใจหรอกว่าจริงๆมันต้องทำงานยังไงถึงจะสั่งพิมพ์ได้ แต่รู้ว่าสั่งผ่านเมธอด Print ก็จะพิมพ์เอกสารได้นั่นเอง

```csharp
public class Printer
{
    public void Print() { ... }
}
```

#### Short Scope

> 🧓 สาเหตุที่ Scope สั้นเราจะตั้งชื่อยาวๆ เพราะ โค้ดที่มาเรียกใช้ของพวกนี้ ส่วนใหญ่จะเป็นของที่อยู่ในวงจำกัด และส่วนใหญ่จะอยู่ในระดับ Low Level เรียกใช้กันเองแล้ว ดังนั้นมันเลยต้องตั้งชื่อให้ละเอียดเพื่อความชัดเจน ตามตัวอย่างด้านล่าง

**คลาส**

โค้ดด้านล่าง เราจะเห็นว่า inner class ในบรรทัดที่ 5 มันถูกใช้แค่ภายใน class Printer เท่านั้น ดังนั้นมันจะต้องถูกตั้งชื่อให้อ่านแล้วรู้เรื่องว่ามันมีไว้เพื่อกำหนดค่าเพจสำหรับเอาไว้พิมพ์ ไม่ได้มีไว้ใช้อย่างอื่นนะ

```csharp
public class Printer
{
    // โค้ดต่างๆของของคลาสนี้
    
    private class PageSetupInformation { ... }
}
```

**เมธอด**

โค้ดด้านล่าง เราจะเห็น private method บรรทัดที่ 11\~14 มันถูกใช้แค่ภายใน class Printer เท่านั้น ดังนั้นมันจะถูกตั้งชื่อให้อ่านแล้วรู้ว่ามันแต่ละเมธอดมีหน้าที่อะไรที่ชัดเจน ชื่อมันเลยจะยาวเมื่อเทียบกับ เมธอด Print ในบรรทัดที่ 3 เพราะมันถูกเรียกใช้จากภายนอกได้

```csharp
public class Printer
{
    public void Print()
    {
        connectToPrinter();
        checkInks();
        checkPapers();
        startPrint();
    }
    
    private void connectToPrinter() { ... }
    private void checkInks() { ... }
    private void checkPapers() { ... }
    private void startPrint() { ... }
}
```

### 🔹 คลาสลูก

คลาสลูก **ยิ่งห่างจากชั้นแม่ชื่อยิ่งยาว** เพราะ ลักษณะของคลาสลูกมันจะเจาะจงกับตัวงานมากขึ้น ดังนั้น ยิ่งคลาสลูกยาวเท่าไหร่ มันเลยต้องอธิบายตัวมันเองให้ชัดเจนมากยิ่งขึ้นนั่นเอง ลองดูตัวอย่างของตระกูล Exception ดูก็ได้

![IOException ชัดเจนมาก](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MEh0xp3lkq9G2yeTzGk%2F-MEh2v1fOHsQ21h4Tw3Y%2Fimage.png?alt=media\&token=190df8d9-a81d-4cec-92e3-e123aed8b88e)

## 🥳 ตัวอย่าง

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

### 😕 ชื่อไม่สื่อ

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

#### 👎 Bad Code

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MEh0xp3lkq9G2yeTzGk%2F-MEh4IC5VVvUTL78a5hY%2Fimage.png?alt=media\&token=ccb6cbd7-25b7-41ab-bd81-9882e49b2c63)

#### 👍 Good Code

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

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-MEh0xp3lkq9G2yeTzGk%2F-MEh4rgnlH9mGf_PzVUW%2Fimage.png?alt=media\&token=896bbb1d-d1cf-4bf0-ba8d-93332a73598b)

### 😵 ชื่อคล้ายกัน

ลองดูตัวแปร 2 ตัวด้านล่างดิ๊ว่ามันต่างกันตรงไหน? แล้วตอนเราจะเรียกใช้งาน เราจะเลือกถูกตัวแปรป่ะตอนใช้งาน? แล้วถ้ามันมีมากกว่า 2 ตัวอ่ะ?

```csharp
var XYZControllerForEfficientHandlingOfStrings
var XYZControllerForEfficientStorageOfStrings
```

### 💩 ซับซ้อนโดยไม่จำเป็น

#### 👎 Bad Code

```csharp
if(x > 50)
{
    a = 1;
}
else
{
    a = 100;
}
```

#### 👍 Good Code

```csharp
a = x > 50? 1 : 100;
```

> จุดนี้ลุงแกไม่ได้พูดเรื่องนี้หรอก แต่แกบ่นเรื่องตัว lO มันดูแล้วคล้ายกับเลข 1 กับเลข 0 แต่ IDE สมัยใหม่ๆไม่มีปัญหาพวกนี้แล้ว แมวน้ำเลยแถมเรื่องนี้ให้

### 🤬 ชื่อเป็นซีรี่

เจอบ่อยมากในหมู่ เด็กจบใหม่ หรือ คนที่มีประสบการณ์น้อยๆ จะชอบตั้งชื่อตัวแปรประมาณนี้

#### 👎 Bad Code

```csharp
int a1, a2, a3;
int x, y, z;
```

#### 👍 Good Code

ก็ตั้งชื่อให้มันสื่อไปเลย แมวน้ำชอบโดนสวนกลับว่า ก็มันทำงานได้แล้วจะไปเสียเวลาตั้งทำไม? ผมเข้าใจของผมอยู่แล้ว ฮ่วยยยย (เบิดคำซิเว่า) โปรแกรมเมอร์มันทำงานเป็นทีมเฟร้ย ใช่เอ็งเข้าใจเอ็งแก้ได้ แต่คนในทีมไม่เข้าใจมันก็ maintenance ยากขึ้นเฟร้ย !! คิดแล้วโมโหขอบ่นหน่อย

```csharp
int age, score, grade;
```

### 👹 ชื่อน่ารำคาญ

#### Suffixes

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

```csharp
Product product;
ProductData pd;
ProductInfo pi;
```

#### Prefixes

โค้ดด้านล่างเป็นการใส่คำขึ้นต้นที่น่ารำคาญ เช่นพวก A กับ The ดังนั้นอย่าไปใส่

```
Product aProduct;
Product theProduct;
```

### 🥴 ชื่อคลุมเครือ

ลองดูเมธอด 3 ตัวด้านล่างดูดิ๊ แล้วบอกหน่อยว่าเมธอดบรรทัดที่ 2 กับ 3 มันต่างกันตรงไหน? แล้วทำไมเมธอดบรรทัดที่ 3 ไม่เติม s ล่ะในเมื่อมันได้ collection กลับมา?

```csharp
public Account GetActiveAccount() { ... }
public List<Account> GetActiveAccounts() { ... }
public List<Account> GetActiveAccountInfo() { ... }
```

### 🙊 ชื่ออ่านไม่ได้

ถ้าสิ่งที่เราตั้งชื่อมันอ่านออกมาเป็นเสียงไม่ได้ มันจะทำให้เรามีปัญหาเวลาจะบอกคนอื่นว่า สิ่งที่มันมีปัญหาคือจุด !@#$%^&\* นี้นะ 😑

```csharp
string ioactpwd; // ไอ้นี่มันอ่านว่ายังไง? ย่อจากอะไร?
```

## 🙌 ส่งท้ายบท

> 🧓 สรุป 2 บทที่ผ่านมา เราพยายามที่จะทำให้ **โค้ดอธิบายตัวมันเองได้** โดยการ **ไม่เขียนคอมเมนต์** และ ตั้งชื่อให้สื่อความหมาย ซึ่งเราสามารถ **Extract method ออกไปได้เรื่อยๆ** ตราบใดที่มันอ่านแล้วไม่เป็นภาษาคน ซึ่ง
>
> * ไฟล์จะใหญ่ จะหลายบรรทัด ก็ช่าง(หัว)มัน เพราะเราต้องการโค้ดที่แก้ไขได้ง่าย
> * อย่าเขียนโค้ดยาวๆ เพราะไม่มีคนชอบอ่านโค้ดยาวๆ สมองมนุษย์ไม่ได้เก่งเรื่องจำ แต่เก่งเรื่องวิเคราะห์

🐈 ของบางอย่างแมวน้ำก็ไม่ได้ลงรายละเอียดให้นะ เพราะมันถูกเขียนไว้ใน [👶 **Clean Code**](https://www.saladpuk.com/basic/clean-code) ตัวหลักอยู่แล้ว ดังนั้นถ้าสนใจก็ไปกดอ่านเอาเองเด้อ

🌊 บทความนี้ยังไม่จบอย่างที่บอกว่ามันจะแบ่งเป็น 6 ส่วน นี่เป็นแค่ตอนที่ 2 เท่านั้นเอง ดังนั้นตามอ่านกันยาวๆต่อได้จากบทความหลัก หรือไม่อยากพลาดก็ติดตามได้จาก [**Facebook: Mr.Saladpuk**](https://www.facebook.com/mr.saladpuk) ฮั๊ฟ

{% hint style="success" %}
**แนะนำให้อ่าน**\
ในบทความถัดๆไปเราจะเจอหลักในการออกแบบเยอะม๊วก ดังนั้นแมวน้ำแนะนำให้รู้จักหลักในการออกแบบพื้นฐาน 5 ตัว โดยเพื่อนๆสามารถไปอ่านได้จากลิงค์นี้ครัช [👦 **SOLID Design Principles**](https://www.saladpuk.com/basic/solid)
{% endhint %}

## 🎥 วีดีโอลุงบ๊อบ

{% embed url="<https://www.youtube.com/watch?v=2a_ytyt9sf8>" %}
