Skip to content

Commit

Permalink
Add code refactoring article
Browse files Browse the repository at this point in the history
  • Loading branch information
RachaneeSaeng committed Oct 16, 2024
1 parent 80db6a7 commit 88c2882
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 1 deletion.
8 changes: 7 additions & 1 deletion .vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,12 @@ function sidebarPractices(): DefaultTheme.SidebarItem[] {
base: "/paths/practices/design/",
items: [{ text: "Design Patterns", link: "design-patterns" }],
},
{
text: "Coding Practices",
collapsed: true,
base: "/paths/practices/coding/",
items: [{ text: "Code Refactoring", link: "code-refactoring" }],
},
],
},
];
Expand Down Expand Up @@ -907,4 +913,4 @@ function sidebarWordPress(): DefaultTheme.SidebarItem[] {
],
},
];
}
}
86 changes: 86 additions & 0 deletions paths/practices/coding/code-refactoring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Code Refactoring
ทุกคนพยายามเขียนโค้ดที่ดี และไม่มีโปรแกรมเมอร์คนไหนที่ตั้งใจเขียนโค้ดที่ไม่ดีซึ่งส่งผลเสียต่อโปรเจกต์โดยไม่จำเป็น แต่บางครั้งเราก็เพิ่มโค้ดที่ไม่ดีเข้าระบบทั้งโดยตั้งใจและไม่ตั้งใจ

คำถาม: เมื่อไหร่เราจะพูดได้ว่าระบบของเราจำเป็นต้องได้รับการ Refactor?
คำตอบ: เมื่อมี Technical Debt ในระบบมากเกินไป

#### Technical Debt คืออะไร?
Technical Debt เปรียบเหมือนการกู้เงินจากธนาคารที่ทำให้คุณสามารถซื้อของได้เร็วขึ้น **แต่** คุณต้องจ่ายดอกเบี้ยทีหลัง

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

#### สาเหตุของ Technical Debt
Technical Debt เกิดได้จากหลายสาเหตุ เช่น
+ Business Pressure: เมื่อมีเวลาจำกัด คุณอาจเลือกใช้ solution ที่ทำได้เร็วแต่ไม่เป็นไปตาม best practices
+ Lack of understanding of technical debt consequences: ความไม่เข้าใจผลกระทบของ technical debt ทำให้ไม่เห็นความสำคัญที่จะจัดสรรเวลาให้ทีมจัดการ tech debt อย่างเหมาะสม
+ Failing to combat component coherence: โครงสร้างโค้ดที่เชื่อมโยงกันอย่างแน่นแฟ้นทำให้การเปลี่ยนแปลงในส่วนหนึ่งของโปรเจกต์อาจส่งผลกระทบต่อส่วนอื่นๆ จึงมีการหลีกเลี่ยงที่จะแตะโค้ดส่วนนั้นไปโดยปริยาย
+ Lack of tests: หากไม่มีการทดสอบรองรับ การเปลี่ยนแปลงเล็กๆ ก็อาจทำให้เกิดบั๊กใหญ่ในระบบได้ คนเลยหลีกเลี่ยงที่จะแตะโค้ดที่ขาด tests
+ Lack of documentation: การขาดเอกสารอธิบาย logic ทำให้การปรับปรุงระบบหรือการนำคนใหม่เข้าทีมยากขึ้น และอาจทำให้การพัฒนาชะงักหากบุคลากรสำคัญออกจากโปรเจกต์
+ Lack of interaction between team members: การสื่อสารไม่ดีในทีมทำให้คนในทีมมีข้อมูลที่ไม่ตรงกัน
+ Long-term simultaneous development in several branches: ทำให้สะสม technical debt และเพิ่มมากขึ้นเมื่อทำการรวมโค้ด
+ Delayed refactoring: ยิ่งเลื่อนการ Refactor ออกไป โค้ดยิ่งล้าสมัยและแก้ไขยากขึ้นเรื่อยๆ
+ Incompetence: นักพัฒนาอาจไม่รู้วิธีหรือไม่เชี่ยวชาญในการเขียนโค้ดที่มีคุณภาพ

## วิธีการทำ Code Refactoring
หลักการทำ Refactoring ควรทำเป็นการเปลี่ยนแปลงเล็กๆ เรื่อยๆ ซึ่งแต่ละครั้งทำให้โค้ดดีขึ้นเล็กน้อยแต่ยังคงทำงานได้ตามปกติ

โดยขั้นตอนการทำ code refactoring มีดังนี้

### 1. ตรวจหา Code Smells
มี code smells หลายแบบที่สามารถพบได้บ่อยๆเช่น

**1.1 Bloaters:** โค้ด เมธอด หรือคลาสที่ใหญ่จนเกินไป จนจัดการได้ยาก
+ Long Method: เมธอดที่มีโค้ดมากเกินไป โดยปกติเมธอดที่ยาวเกินกว่า **10** บรรทัดควรถูกตั้งคำถามแล้วว่าควรถูกแยกออกหรือไม่
+ Large Class: คลาสที่มีฟิลด์หรือเมธอดมากเกินไป
+ Primitive Obsession: การใช้ฟิลด์ primitive แทนการสร้างคลาสที่เหมาะสม
+ Long Parameter List: เมธอดที่มีพารามิเตอร์มากกว่า **3-4** ตัว
+ Data Clumps: กลุ่มของตัวแปรที่ใช้ร่วมกันในหลายส่วนของโค้ดควรถูกแยกออกมาเป็นคลาส

**1.2 Object-Orientation Abusers:** การใช้ OOP ไม่ถูกต้อง
+ Alternative Classes with Different Interfaces: คลาสสองคลาสที่ทำหน้าที่เหมือนกันแต่ใช้ interface ที่ต่างกัน
+ Refused Bequest: Subclass ใช้แค่บางส่วนของเมธอดหรือฟิลด์ที่สืบทอดมาจากคลาสหลัก
+ Switch Statements: มีการใช้ switch statement หรือ if statements ที่ซับซ้อนเกินไป
+ Temporary Field: ฟิลด์ชั่วคราวที่ใช้งานเฉพาะในบางสถานการณ์ และไม่มีประโยชน์ในสถานการณ์อื่นๆ

**1.3 Change Preventers:** โค้ดที่ทำให้คุณเมื่อคุณต้องไปแก้ไขในหลายๆ ส่วนพร้อมกันเมื่อต้องทำการเปลี่ยนแปลงจุดเดียว
+ Divergent Change: ต้องเปลี่ยนแปลงหลายๆ เมธอดที่ไม่เกี่ยวข้องกันเมื่อทำการเปลี่ยนแปลงคลาส
+ Shotgun Surgery: ต้องทำการเปลี่ยนแปลงเล็กๆ ในหลายๆ คลาสพร้อมกัน
+ Parallel Inheritance Hierarchies: การสร้าง subclass ใหม่จะต้องสร้าง subclass อื่นๆ เพิ่มด้วย

**1.4 Dispensable:** สิ่งที่ไม่จำเป็นและควรถูกกำจัดออกไปเพื่อทำให้โค้ดสะอาดขึ้น
+ Comments: เมธอดที่เต็มไปด้วยคอมเมนต์ ถ้าเขียนโค้ดให้ชัดเจนเพียงพอ คอมเมนต์ก็ไม่จำเป็น
+ Duplicate Code: โค้ดที่เหมือนกันหรือคล้ายกันในหลายส่วน
+ Lazy Class: คลาสที่มีขนาดเล็กมากหรือไม่มีประโยชน์
+ Dead Code: โค้ดที่ไม่ถูกใช้งาน
+ Speculative Generality: คลาส เมธอด ฟิลด์ หรือพารามิเตอร์ที่ไม่ได้ถูกใช้งาน

**1.5 Couplers:** การเชื่อมโยงระหว่างคลาสมากเกินไป
+ Feature Envy: เมธอดที่เข้าถึงข้อมูลจากคลาสอื่นมากกว่าข้อมูลของตัวเอง
+ Inappropriate Intimacy: คลาสหนึ่งที่ใช้ฟิลด์ภายในหรือเมธอดของอีกคลาส
+ Message Chains: การเรียกเมธอดต่อเนื่องกันหลายขั้นตอน เช่น $a->b()->c()->d()
+ Middleman: คลาสที่ทำหน้าที่เพียงแค่ส่งต่อการทำงานไปยังคลาสอื่น

**1.6 Other Smells:**
+ Incomplete Library Class: ไลบรารีที่ไม่สามารถตอบสนองความต้องการได้

### 2. ทำการ Refactor โดยใช้ Refactoring Techniques
การ Refactor สามารถทำได้หลายวิธี โดยมี 6 ประเภทหลัก ได้แก่:
+ การจัดการเมธอด
+ การย้ายฟีเจอร์ระหว่างคลาส
+ การจัดการข้อมูล
+ การทำให้เงื่อนไขง่ายขึ้น
+ การทำให้การเรียกเมธอดง่ายขึ้น
+ การจัดการ generalization

สามารถดูเทคนิคและตัวอย่างได้ใน [Refactoring Cheatsheet](https://rachanee.medium.com/code-refactoring-c268b7665262)
คุณ[เปิ้ล](https://medium.com/@rachanee)ผู้เขียนได้รวบรวมทั้งหมด **66** เทคนิคในการ refactor code ออกมาเป็น cheatsheet ไว้ด้านล่างสุดของบทความ คุณสามารถนำไปใช้ได้เลย


## Reference
+ [Refactoring Guru](https://refactoring.guru/refactoring)


0 comments on commit 88c2882

Please sign in to comment.