โหมดมืด
บทที่ 0 — Mindset ก่อนเขียน Code
1. ทำไม Design สำคัญ
🌏 หมายเหตุภาษา (language-agnostic) — ตัวอย่างในบทนี้เขียน Java เป็นหลัก แต่ หลักการใช้ได้กับทุกภาษา (TypeScript, Python, Go, ...) ถ้าคุณไม่คุ้น Java โฟกัสที่ "ทำไมโค้ดนี้ไม่ดี" ก่อน — ไม่ต้องเข้าใจทุก syntax
JDBC สั้น ๆ ก่อนอ่าน — โค้ดข้างล่างใช้ JDBC (Java Database Connectivity = วิธีต่อ Java กับ database):
DriverManager.getConnection(...)= ขอเปิดการเชื่อมต่อ DBStatement= วัตถุที่ใช้ส่งคำสั่ง SQLexecuteUpdate(...)= ยิงคำสั่ง INSERT/UPDATE/DELETEภาษาอื่นมีคำเทียบหมด — Python ใช้
psycopg2.connect(), Node.js ใช้pg.Client()— concept เดียวกัน
java
// Code ที่ทำงานได้
public void processOrder(Map<String, Object> data) {
Connection conn = DriverManager.getConnection(...);
Statement stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO orders ...");
Email email = new Email();
email.send((String) data.get("email"), "Order confirmed");
Logger.log("Order " + data.get("id"));
// ... 200 บรรทัด
}📖 อ่านโค้ดข้างบน — method นี้ทำหลายงานในที่เดียว: เปิด DB connection → INSERT order ลงตาราง → สร้าง Email object → ส่ง email ยืนยัน → บันทึก log (
(String) data.get("email")ต้อง cast เพราะ Map<String, Object> ไม่รู้ชนิด — ดูบทที่ 6 architecture)
ปัญหา:
- ❌ ทำหลายอย่าง — db + email + log + business logic
- ❌ Test ลำบาก (DB จริง, email จริง)
- ❌ เปลี่ยน DB → แก้ method นี้
- ❌ เพิ่ม payment → แก้ method นี้
- ❌ ไม่เห็นว่า "process order" คืออะไร
Code ทำงานได้ ≠ Code ที่ดี
2. นิยาม "Code ดี"
📒 เจอศัพท์อังกฤษเยอะในตารางนี้และตลอดบท? มีตารางคำศัพท์พื้นฐาน (§13)รวมความหมายไว้ท้ายบท เปิดอ่านควบคู่ได้เลย
| Quality (คุณภาพด้านไหน) | คืออะไร |
|---|---|
| Correctness — ความถูกต้อง | ทำงานตามที่ต้องการ |
| Readability — ความอ่านง่าย | คนอื่น (และตัวเองในอนาคต) อ่านเข้าใจ |
| Maintainability — การบำรุงรักษา | แก้ง่าย — ไม่ break อย่างอื่น |
| Testability — การทดสอบได้ | ทดสอบได้ |
| Performance — สมรรถนะ | เร็วพอ |
| Security — ความปลอดภัย | ปลอดภัย |
| Scalability — การขยายระบบ | รองรับการเติบโต |
กฎทอง: Code อ่าน 10 ครั้ง / เขียน 1 ครั้ง → optimize for reading
3. กฎ KISS, DRY, YAGNI
KISS — Keep It Simple, Stupid
🔤 KISS (อ่าน "คิส") — ย่อจาก Keep It Simple, Stupid (เคป-อิท-ซิม-เพิล สตู-พิด) แปลตรงตัวว่า "ทำให้มันง่ายเข้าไว้นะไอ้โง่" — เป็นมุกฝรั่งที่วิศวกรใช้ย้ำเตือน ตัวเอง ว่าอย่าทำซับซ้อนเกินจำเป็น (ไม่ได้ดูถูกคนอื่น) ต้นกำเนิดจาก Kelly Johnson วิศวกรของ Lockheed ปี 1960
💡 ที่มา: เครื่องบินที่ออกแบบควรซ่อมได้ในสนามรบด้วยเครื่องมือพื้นฐาน → "ออกแบบให้ง่ายจนคนโง่ก็เข้าใจ"
java
// ❌ Over-engineered — ใช้ Strategy pattern กับงานง่าย ๆ
public class UserNameFormatter {
private FormatStrategy strategy; // ⚠️ ไม่ต้องเข้าใจ FormatStrategy ตอนนี้ — เป็น pattern ที่จะเรียนในบทที่ 3
public String format(User user) {
return strategy.apply(user.getName());
}
}
// ✅ Simple
String name = user.getName().trim();ใช้ pattern + abstraction เมื่อจำเป็น — ไม่ใช่ "เพื่อให้ดูเทพ"
DRY — Don't Repeat Yourself
🔤 DRY (อ่าน "ดราย" = แห้ง) — ย่อจาก Don't Repeat Yourself (โดนท์ รี-พีท ยัวร์-เซลฟ์ = "อย่าทำซ้ำตัวเอง") — มาจากหนังสือ The Pragmatic Programmer (1999) โดย Andy Hunt และ Dave Thomas
หลักการ: ความรู้แต่ละชิ้นใน system ควรมี representation เดียวที่ชัดเจน — ถ้าต้องแก้กฎ ก็แก้ที่เดียว ไม่ต้องไล่หา
java
// ❌ ซ้ำ (ใช้ BigDecimal เพราะ ห้ามใช้ double กับเงิน — ดู Magic Number §4D ด้านล่าง)
// (.stream(), lambda — ดูบท 05 Functional ถ้ายังไม่คุ้น)
BigDecimal subtotal = items.stream()
.map(i -> i.price().multiply(BigDecimal.valueOf(i.quantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal tax = items.stream()
.map(i -> i.price().multiply(BigDecimal.valueOf(i.quantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add)
.multiply(new BigDecimal("0.07"));
// ✅ Extract
BigDecimal subtotal = items.stream()
.map(i -> i.price().multiply(BigDecimal.valueOf(i.quantity())))
.reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal tax = subtotal.multiply(new BigDecimal("0.07"));⚠️ อย่า DRY มากเกิน — Wrong abstraction = แย่กว่า duplication
"Duplication is far cheaper than the wrong abstraction." — Sandi Metz (แซน-ดี้ เมตซ์ — ผู้เขียน Practical Object-Oriented Design in Ruby (POODR)) (โค้ดซ้ำกันยังถูกกว่าการเลือก abstraction ผิด — รวมโค้ดผิด ๆ เข้าด้วยกันแก้ยากกว่าปล่อยให้ซ้ำ)
YAGNI — You Aren't Gonna Need It
🔤 YAGNI (อ่าน "ยาก-นี่") — ย่อจาก You Aren't Gonna Need It (ยู อาเรนต์ กอน-นา นีด อิท = "คุณยังไม่ต้องใช้มันหรอก") —
Gonnaเป็นภาษาพูดของGoing to— มาจากกระบวนทัศน์ Extreme Programming (XP) โดย Kent Beck ปลายยุค 1990sหลักการ: เขียนเฉพาะที่ต้องใช้ วันนี้ — feature "เผื่ออนาคต" ส่วนใหญ่ไม่เคยถูกใช้
java
// ❌ "เผื่ออนาคต" — ยังไม่ได้ใช้
public class User {
private String name;
private String middleName; // ยังไม่ใช้
private String maidenName; // ยังไม่ใช้
private List<String> aliases; // ยังไม่ใช้
private Map<String, String> meta; // ยังไม่ใช้
}
// ✅ ใส่เมื่อ requirement มี
public class User {
private String name;
}→ ทำ เฉพาะที่ต้องการตอนนี้ — เพิ่มเมื่อ requirement มาจริง
4. Code Smell — กลิ่นไม่ดี
A. Long Method
java
public void processOrder() {
// 300 บรรทัด
}→ split เป็น method เล็ก ๆ ที่ทำ 1 อย่าง
B. God Class
java
public class OrderManager {
// 50 method — query DB, calculate, send email, log, ...
}→ split ตาม responsibility
C. Long Parameter List
java
void create(String name, String email, String phone, String address,
String city, String country, int age, String role, ...)
// ✅ Object
record CreateUserRequest(String name, String email, ...) {}
void create(CreateUserRequest req)D. Magic Number / String
java
if (status == 1) { // ❌ 1 คืออะไร?
discount = 0.07; // ❌ 0.07 คืออะไร?
}
// ✅
final int STATUS_PREMIUM = 1;
final BigDecimal DISCOUNT_RATE = new BigDecimal("0.07"); // ⚠️ ห้ามใช้ double กับเงิน (ดูหมายเหตุข้างล่าง) — Money value object (บทที่ 6 §15)
if (status == STATUS_PREMIUM) {
discount = DISCOUNT_RATE;
}
// ✅✅ better — enum
if (status == OrderStatus.PREMIUM) { ... }⚠️ ทำไม
doubleแย่กับเงิน? —doubleใช้ binary floating-point ที่เก็บ0.1ไม่ได้แม่นยำ (กลายเป็น0.1000000000000000055511...) — บวกเงินซ้ำ ๆ จะคลาดเคลื่อนทีละนิด สุดท้ายตัวเลขผิดทศนิยมเป็นบาท ใช้BigDecimalเก็บเป็น decimal-based ที่แม่นยำ 100% — หรือใช้ Money value object ห่อ (บทที่ 6 §15)
E. Comment ที่ไม่จำเป็น
java
// ❌ Comment ที่ code อ่านได้
i = i + 1; // Increment i
// ❌ Outdated
// Calculate VAT (7%)
double tax = price * 0.10; // 0.10 — ไม่ใช่ 7%
// ✅ อธิบาย "why" ไม่ใช่ "what"
// VAT 7% — applied to subtotal, exclude shipping (per Q3 finance memo)
double tax = subtotal * 0.07;F. Inappropriate Intimacy (ความสนิทสนมเกินงาม)
คือ code smell ที่ class หนึ่งไป "ล้วงลึก" รู้รายละเอียดภายในของอีก class มากเกินไป (เช่นไปดึง field ย่อย ๆ ของมันมาประกอบเอง) — ควรให้เจ้าของข้อมูลจัดการเองแล้วเรียกผ่าน method แทน
java
class Order {
User user;
public void notify() {
// ❌ Order ทำงานกับ internal ของ User
emailService.send(user.getEmail(),
"Hi " + user.getFirstName() + " " + user.getLastName());
}
}
// ✅ User มี method ของตัวเอง
public void notify() {
emailService.send(user.getEmail(), "Hi " + user.getDisplayName());
}5. กฎ Boy Scout (กฎลูกเสือ)
🔤 Boy Scout rule (บอย-สเกาท์ รูล = กฎลูกเสือ) — มาจากกฎที่ลูกเสือฝรั่งสอนเด็ก: "Always leave the campground cleaner than you found it" (ทิ้งค่ายให้สะอาดกว่าตอนมา) ถูกนำมาประยุกต์กับโค้ดโดย Robert C. Martin ในหนังสือ Clean Code (2008)
"Always leave the code better than you found it." — Robert C. Martin (โร-เบิร์ต ซี. มาร์-ติน หรือที่รู้จักในชื่อ Uncle Bob (อันเคิล บ็อบ) = ผู้นิยาม SOLID และผู้เขียน Clean Code, Clean Architecture) (ทิ้งโค้ดไว้ให้ดีกว่าตอนที่เจอเสมอ)
ทุกครั้งที่แตะ code:
- ตั้งชื่อ variable ที่ดีขึ้นถ้าเห็นที่ผิด
- Extract method ถ้าเห็น duplication เล็ก
- ลบ dead code
อย่ารอ "refactor week" — ทำทีละนิด ทุกวัน
6. กฎ Two Hats (กฎสองหมวก)
🔤 Two Hats (ทู แฮทส์ = หมวกสองใบ) — เปรียบเทียบว่าตอนทำงานเรา "สวมหมวก" บทบาทไหน: หมวก เพิ่ม feature (สร้างของใหม่) หรือ หมวก refactor (จัดระเบียบของเก่า) — สำนวนนี้เป็นของ Kent Beck (เคนต์ เบ็ค — ผู้คิดค้น TDD/XP) ในหนังสือ Test-Driven Development: By Example (2002)
แยก mode:
- Adding feature mode — เพิ่ม code ใหม่
- Refactor mode — แก้ structure โดยไม่เปลี่ยนพฤติกรรม
ห้ามทำพร้อมกัน — ถ้า fix bug + refactor ใน PR เดียว → review ลำบาก, regression risk
Workflow:
1. Refactor → ทดสอบยังผ่าน (no behavior change)
2. Add feature → ทดสอบใหม่ผ่าน7. กฎ Premature Optimization
มือใหม่มักอยากเขียนโค้ดให้ "เร็ว" ตั้งแต่แรก แต่นั่นคือกับดัก — ส่วนที่คิดว่าช้ามักไม่ใช่ตัวปัญหาจริง การ optimize ก่อน measure ทำให้โค้ดซับซ้อนโดยเปล่าประโยชน์
กฎ: เขียนให้ชัดก่อน → profile หาจุดช้าจริง → optimize เฉพาะตรงนั้น
"Premature optimization is the root of all evil." — Donald Knuth (โดนัลด์ คนู้ธ — ตัว K ไม่ออกเสียง — นักวิทยาการคอมพิวเตอร์ผู้เขียน The Art of Computer Programming) (การ optimize ก่อนเวลาอันควร คือต้นตอของปัญหาทั้งปวง)
java
// ❌ Optimize ก่อน measure
public void process(List<User> users) {
// Use bitset + native pointer + SIMD ...
// (เพื่อให้เร็ว)
}
// ✅ เขียนชัด → measure → optimize เฉพาะที่ช้าจริง
public void process(List<User> users) {
users.stream()
.filter(User::isActive)
.forEach(this::sendNotification);
}→ Profile + measure ก่อนทุกครั้ง — most optimization = wrong
8. ความเข้าใจระดับ Abstraction
📖 ระดับล่าง = hardware-level —
bit(บิต = 0/1),byte(ไบต์ = 8 bits),register(รี-จิส-เตอร์ = หน่วยความจำใน CPU),assembly(แอส-เซ็ม-บลี = ภาษาเครื่องแบบมนุษย์อ่านได้) ไม่ต้องเข้าใจตอนนี้ — แค่รู้ว่าระดับยิ่งล่างยิ่งใกล้ hardware
กฎ: code ระดับเดียวกัน อยู่ด้วยกัน
java
// ❌ Mix levels
public void processOrder(Order order) {
Connection conn = DriverManager.getConnection(url); // ← low
if (order.getTotal() > 1000) { // ← high
applyDiscount(order); // ← high
}
conn.commit(); // ← low
}
// ✅ Same level
public void processOrder(Order order) {
applyBusinessRules(order);
orderRepository.save(order);
}9. Trade-offs — ทุก decision = trade-off
ไม่มี "best practice" ที่ใช้ได้ทุกที่ — ขึ้นกับ context:
| Decision | Trade-off |
|---|---|
| Microservice | flexibility ↑ vs complexity ↑ |
| Cache | speed ↑ vs consistency ↓ |
| Normalize DB | integrity ↑ vs query speed ↓ |
| Type system strict | safety ↑ vs flexibility ↓ |
| Abstraction | reusability ↑ vs complexity ↑ |
| Test coverage | quality ↑ vs dev speed ↓ |
Senior engineer = รู้ trade-off + อธิบายได้
10. Mental Models ที่ใช้ตลอดเล่ม
A. Coupling vs Cohesion
🔤 สองคำคู่นี้คือหัวใจของ OOP design — Coupling (คับ-พลิ่ง = การเกาะเกี่ยว/พึ่งพา) vs Cohesion (โค-ฮี-ชั่น = การยึดเหนี่ยว/รวมกลุ่ม)
- Coupling (คับ-พลิ่ง) = "ผูกพันกับสิ่งอื่นแค่ไหน" → ต้องการ low
- Cohesion (โค-ฮี-ชั่น) = "ทำสิ่งที่เกี่ยวกัน" → ต้องการ high
java
// ❌ Low cohesion, high coupling
class Helper {
void sendEmail() { ... }
void parseJson() { ... }
void connectDb() { ... }
void calculateTax() { ... }
}
// ✅ High cohesion
class EmailSender { sendEmail() { ... } }
class JsonParser { parse() { ... } }
class TaxCalculator { calculate() { ... } }B. Composition over Inheritance
📖 กางศัพท์ก่อน (สองคำนี้คือหัวใจของ OOP — บทนี้แตะผ่าน ๆ ไว้ก่อน นิยามเต็มอยู่บทที่ 1):
- Composition (การประกอบ) = สร้างของใหญ่จาก "ชิ้นส่วนย่อย" ที่เอามาประกอบกัน — ความสัมพันธ์แบบ "มี-เป็น-ส่วนหนึ่ง" (has-a) เช่น รถ มี เครื่องยนต์
- Inheritance (การสืบทอด) = class ลูก "สืบทอด" คุณสมบัติจาก class แม่ — ความสัมพันธ์แบบ "เป็น-ชนิดหนึ่งของ" (is-a) เช่น หมา เป็น สัตว์ชนิดหนึ่ง
"Composition over Inheritance" = เวลาเลือกได้ ให้ใช้การประกอบ (composition) มากกว่าการสืบทอด (inheritance) เพราะยืดหยุ่นกว่า
💡 โค้ดด้านล่างเป็นแค่ "ภาพประกอบ" ให้เห็นภาพคร่าว ๆ — ยังไม่ต้องเข้าใจทุกบรรทัดตอนนี้ เดี๋ยวบทที่ 1 อธิบายละเอียด
java
// ❌ Inheritance — rigid (สืบทอด — แข็งทื่อ ปรับยาก)
class FlyingCar extends Car implements Flyable { ... }
class AmphibiousCar extends Car implements Swimmable { ... }
class FlyingAmphibiousCar extends ??? { ... } // ❌ multiple inheritance — Java สืบทอดได้แค่ class เดียว → ตัน
// ✅ Composition (pseudo-code — ใช้ Optional<T> ห่อ capability ที่อาจไม่มี)
class Vehicle {
Engine engine;
Optional<Flyable> flight; // มีก็บินได้ ไม่มีก็ไม่บิน
Optional<Swimmable> swim; // มีก็ว่ายได้ ไม่มีก็ไม่ว่าย
}💡 Walkthrough: Strategy pattern (composition แบบรูปธรรม) — สมมติออกแบบ "ระบบนกบิน":
java// 1. แยก behavior เป็น interface (strategy) interface FlyBehavior { void fly(); } // 2. มี implementation หลายแบบ class CanFly implements FlyBehavior { public void fly() { System.out.println("บินได้!"); } } class CantFly implements FlyBehavior { public void fly() { /* no-op */ } } // 3. Bird ใช้ composition — รับ strategy จากภายนอก class Bird { private FlyBehavior flyBehavior; public Bird(FlyBehavior fb) { this.flyBehavior = fb; } public void fly() { flyBehavior.fly(); } } // 4. ใช้ Bird duck = new Bird(new CanFly()); Bird penguin = new Bird(new CantFly()); // เพนกวินไม่บิน — ไม่ต้อง override no-op duck = new Bird(new CantFly()); // สลับ behavior ตอน runtime ได้เทียบ inheritance: ถ้า
Penguin extends Birdแล้วต้องfly()ก็ต้องthrow new UnsupportedOperationException()— ผิด LSP (ดูบทที่ 1 + 2)รายละเอียดเต็มอยู่บทที่ 1 §5 และบทที่ 3 Strategy pattern
C. Separation of Concerns
แต่ละ module ทำงาน 1 อย่าง:
- Service = business logic
- Repository = data access (เข้า DB)
- Controller = HTTP handling (รับ request เว็บ)
- View = presentation (UI)
→ เปลี่ยน 1 ที่ ไม่ break อื่น
📖 คำศัพท์ Service/Repository/Controller มาจากโลก framework (Spring สำหรับ Java, NestJS สำหรับ Node, ...) ดูตัวอย่างจริงในบทที่ 6 Architecture — ถ้ายังไม่เคยใช้ framework ก็เข้าใจตามความหมายไปก่อน
D. Tell, Don't Ask (สั่ง อย่าถาม)
🔤 Tell, Don't Ask (เทล โดนท์ อาสค์ = "สั่ง อย่าถาม") — สั่งให้ object ทำงานเอง อย่าไปดึงสถานะภายในออกมาแล้วตัดสินใจแทนข้างนอก — สำนวนนี้นิยมโดย Andy Hunt + Dave Thomas (The Pragmatic Programmer)
java
// ❌ Ask
if (order.getStatus() == Status.PENDING && order.getAge() > 30) {
order.setStatus(Status.EXPIRED);
}
// ✅ Tell
order.expireIfStale(); // ภายในจัดการเอง11. "เห็นโค้ดเร็วขึ้น" — Skill ที่ฝึก
อ่าน code คือทักษะที่ฝึกได้:
- อ่านโครงสร้าง — class, package, module structure ก่อน
- Trace flow — entry point → flow ของ request
- Test = doc — อ่าน test เพื่อเข้าใจ usage
- Type signature ก่อน body — รู้ว่าทำอะไรจาก signature
- Naming — ถ้า name ดี ไม่ต้องอ่าน body มาก
ฝึก
- Clone open source project → อ่าน 1 feature
- Code review เพื่อน → อธิบาย "why"
- ดู PR ใน GitHub repo ที่ active
12. กฎสุดท้าย — Pragmatism > Purity
🔤 Pragmatism (แพร็ก-มา-ติ-ซึม = ความเป็นนักปฏิบัติ — เน้นว่าได้ผลจริง) > Purity (เพียว-ริ-ตี้ = ความบริสุทธิ์ — เน้นทฤษฎีตรงเป๊ะ)
กฎทุกข้อในเล่มนี้เป็น "แนวทาง" ไม่ใช่กฎตายตัว — เป้าหมายจริงคือระบบที่ทำงานได้ ทีมแฮปปี้ และดูแลได้ระยะยาว ไม่ใช่ 100% SOLID หรือ test coverage เต็ม บางครั้งการ break rule คือทางที่ถูก ใช้วิจารณญาณตามสถานการณ์เสมอ:
- หลักที่ดีในเล่มนี้ทุกอัน → ใช้ "ตามสถานการณ์"
- บางที่ break rule = ถูก
- เป้าหมาย: ระบบทำงาน + ทีมแฮปปี้ + ดูแลได้ระยะยาว
- ไม่ใช่: 100% SOLID, 100% test coverage, 100% functional"Make it work, make it right, make it fast" — แนวคิดจาก Kent Beck (เคนต์ เบ็ค — ผู้คิดค้น TDD/XP, นิยมอ้างใน Test-Driven Development: By Example, 2002) (ทำตามลำดับนี้) (ทำให้มันทำงานได้ก่อน → แล้วทำให้ถูกต้อง → แล้วค่อยทำให้เร็ว)
13. คำศัพท์พื้นฐาน
| คำ | คำอ่าน | ความหมาย |
|---|---|---|
| Abstraction | แอบ-สแตร็ก-ชั่น | ซ่อนรายละเอียด → expose interface เท่านั้น |
| Encapsulation | เอน-แค็พ-ซู-เล-ชั่น | รวม data + behavior ที่เกี่ยวกัน + ซ่อน internal |
| Inheritance | อิน-เฮอ-ริ-แทนซ์ | class ลูกสืบทอดจาก class แม่ (is-a relationship) |
| Polymorphism | พอ-ลี-มอร์-ฟิ-ซึม | interface เดียวกัน แต่ behavior หลายแบบ |
| Coupling | คับ-พลิ่ง | ระดับที่ module ผูกกัน — ต้องการ low |
| Cohesion | โค-ฮี-ชั่น | ระดับที่ method ใน module เกี่ยวข้องกัน — ต้องการ high |
| Dependency | ดี-เพ็น-เด็น-ซี | สิ่งที่ module ของเราต้องใช้ |
| Inversion of Control | อิน-เวอร์-ชั่น ออฟ คอน-โทรล | การพลิกบทบาทว่าใครคุมการเรียกใคร (framework เรียก code เรา ไม่ใช่เราเรียก framework) |
| DI | ดี-ไอ | Dependency Injection — pass dependency เข้ามาผ่าน constructor/parameter |
| Refactor | รี-แฟ็ก-เตอร์ | เปลี่ยน structure โดยไม่เปลี่ยนพฤติกรรม |
| Boilerplate | บอย-เลอร์-เพลท | code ซ้ำที่ต้องเขียนเพื่อ setup (เปรียบเหมือนแบบหล่อหม้อต้ม) |
| SOLID | โซ-ลิด | 5 หลัก OOP design (SRP/OCP/LSP/ISP/DIP) — โดย Robert C. Martin |
| DDD | ดี-ดี-ดี | Domain-Driven Design — เน้นโมเดลตาม business domain (Eric Evans, 2003) |
| TDD | ที-ดี-ดี | Test-Driven Development — เขียน test ก่อน code (Kent Beck) |
| Design Pattern | ดี-ไซน์ แพ็ท-เทิร์น | solution ที่ใช้ซ้ำสำหรับ problem ที่เจอบ่อย |
📚 อ่านต่อ (modern references) —
- John Ousterhout (จอห์น เอาส์-เตอร์-เฮาท์) — A Philosophy of Software Design (2018, ฉบับที่ 2: 2021) — เสนอแนวคิด "deep modules" และวิจารณ์ Clean Code บางจุด ควรอ่านคู่กับ Uncle Bob เพื่อเห็นมุมมองที่ต่าง
- Kent Beck — Tidy First? (2023) — refactor เป็นชุดเล็ก ๆ
- Gary Bernhardt (แกรี่ เบิร์น-ฮาร์ด) — แนวคิด Functional Core, Imperative Shell (2014) — แยก logic บริสุทธิ์ออกจาก side effect
- Bertrand Meyer (เบอร์-ทร็อง ไม-เยอร์) — Object-Oriented Software Construction (1988, 1997) — ผู้บัญญัติ Design by Contract และนิยาม Open/Closed Principle เดิม
- Alan Kay (อลัน เคย์) — ผู้บัญญัติคำว่า "Object-Oriented Programming" และผู้สร้าง Smalltalk
14. Checkpoint
🛠️ Checkpoint 0.1 — Code Smell Hunt
เปิด code project ของคุณ — หา code smell:
- Long method (> 50 บรรทัด)
- Magic number
- God class
- Comment ที่ outdated รายงานเป็น list
🛠️ Checkpoint 0.2 — Refactor Practice
จาก method ใน 0.1 — refactor 1 ตัว
- Extract method
- Rename variable
- Replace magic with constant/enum
🛠️ Checkpoint 0.3 — Trade-off Analysis
List 5 decision ใน project ของคุณ + ระบุ trade-off:
- "ทำไมเราใช้ X แทน Y"
- "What's the cost?"
15. สรุปบท
✅ Code ทำงานได้ ≠ Code ที่ดี — readability, maintainability, testability
✅ KISS, DRY (ใช้ระวัง), YAGNI
✅ Code smell: long method, god class, magic number, inappropriate comment
✅ Boy Scout rule: leave code better than you found it
✅ Two Hats: refactor mode vs feature mode — แยก
✅ Don't premature optimize — measure ก่อน
✅ Coupling ↓ + Cohesion ↑
✅ Composition over Inheritance
✅ ทุก decision = trade-off — context สำคัญ
✅ Pragmatism > Purity — make it work first
Glossary: ../glossary.md · Style guide: ../CONTRIBUTING.md last_verified: 2026-06-03 · review report: ../REVIEW-2026-06-03.md