/static/codemoomoo2.png

4. Overview of Development Tools

บทความนี้สรุปภาพรวมของเครื่องมือพัฒนาซอฟต์แวร์ (Software Development Tools) ครอบคลุมทั้ง Text Editor, IDE, Compiler/Interpreter, Build System, Debugger, Package Manager, Documentation, CI/CD, Testing และ Code Quality Tools พร้อมตัวอย่างใช้งานจริงบน Linux เพื่อให้ผู้เรียนสร้าง Toolchain ที่เหมาะกับงานของตนเองได้


4.1 แนวคิดของเครื่องมือพัฒนาซอฟต์แวร์

การพัฒนาซอฟต์แวร์ในยุคปัจจุบันเป็นงานที่ซับซ้อนและประกอบด้วยขั้นตอนจำนวนมาก นักพัฒนาจึงไม่สามารถทำงานทั้งหมดด้วยมือหรือเครื่องมือเพียงชิ้นเดียวได้ เครื่องมือพัฒนาซอฟต์แวร์ (Development Tools) คือชุดของโปรแกรมที่ช่วยให้นักพัฒนาเขียน (Write), สร้าง (Build), ทดสอบ (Test), ดีบั๊ก (Debug), และนำขึ้นใช้งาน (Deploy) ซอฟต์แวร์ได้อย่างมีประสิทธิภาพ

4.1.1 Software Development Life Cycle (SDLC)

วงจรการพัฒนาซอฟต์แวร์ (Software Development Life Cycle – SDLC) คือกระบวนการที่กำหนดขั้นตอนการสร้างระบบซอฟต์แวร์ตั้งแต่เริ่มต้นจนถึงการบำรุงรักษา โดยแต่ละขั้นตอนจะมีเครื่องมือที่เหมาะสมเข้ามาช่วย

flowchart LR
    A[วางแผน
Planning]:::gruvblue --> B[วิเคราะห์
Analysis]:::gruvaqua B --> C[ออกแบบ
Design]:::gruvgreen C --> D[พัฒนา
Implementation]:::gruvyellow D --> E[ทดสอบ
Testing]:::gruvorange E --> F[นำขึ้นใช้งาน
Deployment]:::gruvred F --> G[บำรุงรักษา
Maintenance]:::gruvpurple G -.Iterate.-> A classDef gruvblue fill:#458588,stroke:#83a598,color:#ebdbb2 classDef gruvaqua fill:#689d6a,stroke:#8ec07c,color:#ebdbb2 classDef gruvgreen fill:#98971a,stroke:#b8bb26,color:#282828 classDef gruvyellow fill:#d79921,stroke:#fabd2f,color:#282828 classDef gruvorange fill:#d65d0e,stroke:#fe8019,color:#ebdbb2 classDef gruvred fill:#cc241d,stroke:#fb4934,color:#ebdbb2 classDef gruvpurple fill:#b16286,stroke:#d3869b,color:#ebdbb2

แนวคิด SDLC มีหลายโมเดล เช่น

4.1.2 Toolchain ของนักพัฒนา

Toolchain หมายถึงชุดเครื่องมือที่ทำงานร่วมกันตลอดสายการผลิตซอฟต์แวร์ (Software Pipeline) คำว่า "chain" สื่อความหมายว่าเครื่องมือหนึ่งรับผลลัพธ์จากอีกเครื่องมือหนึ่งต่อกันไปเหมือนสายโซ่

flowchart TB
    subgraph Dev["Development Toolchain"]
        direction LR
        A1[Editor/IDE]:::gruvblue --> A2[Compiler/Interpreter]:::gruvaqua
        A2 --> A3[Linker/Bundler]:::gruvgreen
        A3 --> A4[Executable/Artifact]:::gruvyellow
    end
    subgraph QA["Quality Assurance"]
        direction LR
        B1[Linter]:::gruvorange --> B2[Formatter]:::gruvorange
        B2 --> B3[Test Runner]:::gruvred
        B3 --> B4[Coverage]:::gruvpurple
    end
    subgraph Ops["Operations"]
        direction LR
        C1[Version Control
Git]:::gruvblue --> C2[CI/CD]:::gruvaqua C2 --> C3[Registry/Artifact Store]:::gruvgreen C3 --> C4[Deployment]:::gruvred end Dev --> QA QA --> Ops classDef gruvblue fill:#458588,stroke:#83a598,color:#ebdbb2 classDef gruvaqua fill:#689d6a,stroke:#8ec07c,color:#ebdbb2 classDef gruvgreen fill:#98971a,stroke:#b8bb26,color:#282828 classDef gruvyellow fill:#d79921,stroke:#fabd2f,color:#282828 classDef gruvorange fill:#d65d0e,stroke:#fe8019,color:#ebdbb2 classDef gruvred fill:#cc241d,stroke:#fb4934,color:#ebdbb2 classDef gruvpurple fill:#b16286,stroke:#d3869b,color:#ebdbb2

ตัวอย่าง Toolchain สำหรับพัฒนา Web Application ด้วย Python:

ขั้นตอน (Stage) เครื่องมือ (Tool) หน้าที่ (Role)
เขียนโค้ด Neovim / VS Code Text Editor
จัดการ Dependency uv / Poetry Package Manager
รันโปรแกรม Python (CPython) Interpreter
ตรวจคุณภาพโค้ด Ruff Linter + Formatter
ทดสอบ pytest Test Runner
คุมเวอร์ชัน Git VCS
Build/Deploy GitHub Actions + Docker CI/CD + Container

4.1.3 Command-line Tools vs GUI Tools

เครื่องมือพัฒนาซอฟต์แวร์แบ่งออกเป็น 2 กลุ่มใหญ่ตามรูปแบบการใช้งาน

Command-line Interface (CLI) Tools

Graphical User Interface (GUI) Tools

นักพัฒนาในยุคปัจจุบันนิยมผสมผสานทั้งสองแบบ ใช้ CLI สำหรับงานที่ต้อง Automate และ GUI สำหรับงานที่ต้อง Visualize ข้อมูลซับซ้อน

4.1.4 DevEx (Developer Experience)

Developer Experience (DevEx) คือแนวคิดเกี่ยวกับประสบการณ์รวมของนักพัฒนาเมื่อใช้เครื่องมือ แพลตฟอร์ม และกระบวนการในการทำงาน เปรียบได้กับ User Experience (UX) ที่ให้ความสำคัญกับผู้ใช้ปลายทาง แต่ DevEx ให้ความสำคัญกับ "นักพัฒนา" เป็นผู้ใช้งานแทน

หลัก 3 ข้อของ DevEx ที่ดี (ตามงานวิจัยของ Nicole Forsgren และคณะ):

  1. Flow State: ความสามารถในการจดจ่อกับงานโดยไม่ถูกขัดจังหวะ
  2. Feedback Loops: การได้รับผลตอบรับที่รวดเร็วจากการเปลี่ยนแปลงโค้ด
  3. Cognitive Load: ภาระทางความคิดที่ต้องใช้ในการเข้าใจและใช้งานระบบ

สามารถวัดเชิงคุณภาพได้จากสมการดัชนี DevEx เบื้องต้น:

DevEx = w1F + w2R w3C + ε

โดยที่ F คือคะแนน Flow State, R คือความเร็วของ Feedback Loop (เช่น 1/เวลาที่ใช้ Build), C คือ Cognitive Load ที่วัดจากจำนวนขั้นตอน, wi คือน้ำหนักของแต่ละปัจจัย และ ε คือค่าคงที่เพื่อป้องกันการหารด้วยศูนย์

ตัวอย่างปัจจัยที่ส่งผลต่อ DevEx:


4.2 Text Editor และ IDE

Text Editor และ IDE เป็นเครื่องมือหลักที่นักพัฒนาใช้ทำงานทุกวัน การเลือกเครื่องมือที่เหมาะกับภาษาและสไตล์การทำงานมีผลต่อประสิทธิภาพระยะยาวอย่างมาก

4.2.1 Editor: Vim/Neovim, Emacs, Helix, nano

Text Editor คือโปรแกรมแก้ไขไฟล์ข้อความล้วน (Plain Text) ไม่มีการ Compile หรือ Debug ในตัวเอง แต่มีความเบา (Lightweight) และปรับแต่งได้สูง

ตัวอย่างการเปิดแก้ไขไฟล์ hello.py ด้วย editor แต่ละตัว:

# เปิดไฟล์ด้วย nano (เหมาะสำหรับผู้เริ่มต้น)
nano hello.py

# เปิดด้วย Vim
vim hello.py

# เปิดด้วย Neovim
nvim hello.py

# เปิดด้วย Helix
hx hello.py

# เปิดด้วย Emacs ในโหมด terminal
emacs -nw hello.py

4.2.2 Lightweight IDE: VS Code, Zed, Sublime Text, Cursor, Windsurf

Lightweight IDE คือโปรแกรมที่อยู่กลางระหว่าง Text Editor กับ Full IDE มีฟีเจอร์ครบถ้วนพอสมควร เปิดได้เร็ว ใช้ทรัพยากรน้อยกว่า Full IDE

ตัวอย่างการเปิด project ด้วย VS Code จาก command line:

# เปิดโฟลเดอร์ปัจจุบันใน VS Code
code .

# เปิดไฟล์เฉพาะพร้อมระบุบรรทัด
code hello.py:42

# ติดตั้ง Extension จาก CLI
code --install-extension ms-python.python
code --install-extension charliermarsh.ruff

# เปิด Zed
zed .

Full-featured IDE คือ Integrated Development Environment ที่รวมเครื่องมือสำหรับพัฒนาซอฟต์แวร์ไว้ครบในโปรแกรมเดียว ได้แก่ Editor, Compiler/Interpreter, Debugger, Profiler, Build Tool, VCS Integration, Database Tool และอื่น ๆ

JetBrains Suite – ตระกูล IDE คุณภาพสูง แบ่งตามภาษา:

Eclipse: IDE ฟรี Open-source ที่เริ่มจากพัฒนา Java แต่ขยายสู่ภาษาอื่นผ่าน Plugin และเป็น Base ของ IDE อื่น ๆ เช่น STS, Spoon Gear

NetBeans: IDE จาก Apache Foundation รองรับ Java, PHP, C/C++ มักใช้ในงานการศึกษา

เปรียบเทียบการใช้ทรัพยากรของ Editor/IDE ยอดนิยม:

เครื่องมือ ใช้ RAM เริ่มต้น ภาษาหลัก AI Built-in Open-source
nano ~5 MB ทุกภาษา ไม่มี ใช่ (GPL)
Vim ~10 MB ทุกภาษา ผ่าน Plugin ใช่ (Vim License)
Neovim ~15 MB ทุกภาษา ผ่าน Plugin ใช่ (Apache 2.0)
Helix ~30 MB ทุกภาษา ผ่าน LSP ใช่ (MPL 2.0)
VS Code ~300 MB ทุกภาษา Copilot บางส่วน (MIT)
Zed ~150 MB ทุกภาษา Agent Panel ใช่ (GPL v3)
IntelliJ IDEA ~1.5 GB Java/Kotlin AI Assistant Community Edition
Cursor ~400 MB ทุกภาษา ใช่ (เน้น AI) ไม่ใช่

4.2.4 Language-specific IDE

IDE บางตัวถูกออกแบบมาเฉพาะสำหรับภาษาหรือแพลตฟอร์มหนึ่ง ๆ เพื่อให้ประสบการณ์ที่ดีที่สุดในด้านนั้น


4.3 Compiler, Interpreter และ Runtime

การที่ซอร์สโค้ดจะกลายเป็นโปรแกรมที่ทำงานได้นั้น ต้องผ่านกระบวนการแปล (Translation) จากภาษาที่มนุษย์เข้าใจไปเป็นคำสั่งที่เครื่องเข้าใจ กระบวนการนี้ทำโดย Compiler หรือ Interpreter และอาจต้องอาศัย Runtime System ในการรัน

4.3.1 C/C++: GCC, Clang/LLVM, MSVC

GCC (GNU Compiler Collection): Compiler ดั้งเดิมของ GNU Project รองรับหลายภาษา เช่น C, C++, Objective-C, Fortran, Ada, Go เป็น Compiler ที่ใช้คอมไพล์ Linux Kernel

Clang/LLVM: Compiler Front-end (Clang) + Back-end (LLVM) ออกแบบใหม่ให้เป็น Modular มี Error Message ที่ชัดเจนกว่า GCC เป็นเครื่องมือหลักของ macOS/FreeBSD

MSVC (Microsoft Visual C++): Compiler ของ Microsoft สำหรับ Windows ใช้ร่วมกับ Visual Studio

ตัวอย่างการ Compile โปรแกรม C อย่างง่าย:

// hello.c - โปรแกรมตัวอย่างภาษา C
// แสดงข้อความพร้อมรับชื่อจาก argument
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    // ถ้าไม่มี argument ใช้ "World" เป็นค่า default
    const char *name = (argc > 1) ? argv[1] : "World";
    printf("Hello, %s!\n", name);
    return 0;
}

คำสั่ง Compile และรัน:

# Compile ด้วย GCC พร้อม optimization level 2 และเปิด warning ทุกตัว
gcc -O2 -Wall -Wextra -o hello hello.c

# Compile ด้วย Clang
clang -O2 -Wall -Wextra -o hello hello.c

# Cross-compile สำหรับ ARM64
aarch64-linux-gnu-gcc -O2 -o hello-arm64 hello.c

# รัน
./hello Moo
# Output: Hello, Moo!

4.3.2 JVM Language: javac, JVM (HotSpot, GraalVM, OpenJ9)

JVM (Java Virtual Machine) เป็น Virtual Machine ที่รัน Bytecode (.class) ที่ได้จากการ Compile ภาษาตระกูล JVM เช่น Java, Kotlin, Scala, Groovy, Clojure

javac: Compiler ของ Java ที่แปลง .java.class

JVM Implementations:

ตัวอย่างภาษา Java:

// HelloWorld.java - โปรแกรมตัวอย่างภาษา Java
public class HelloWorld {
    public static void main(String[] args) {
        // รับชื่อจาก argument ถ้ามี
        String name = (args.length > 0) ? args[0] : "World";
        System.out.println("Hello, " + name + "!");
    }
}
# Compile เป็น bytecode
javac HelloWorld.java

# รันด้วย JVM
java HelloWorld Moo
# Output: Hello, Moo!

# รันแบบ Native Image ด้วย GraalVM (ถ้าติดตั้งไว้)
native-image HelloWorld
./helloworld Moo

4.3.3 .NET: dotnet CLI, CLR

.NET เป็นแพลตฟอร์มจาก Microsoft ประกอบด้วย

ตัวอย่างสร้าง Console App ด้วย .NET:

# สร้างโปรเจกต์ใหม่แบบ console
dotnet new console -n HelloApp
cd HelloApp

# เพิ่ม dependency
dotnet add package Newtonsoft.Json

# รัน
dotnet run -- Moo

# Build เป็น executable
dotnet publish -c Release -r linux-x64 --self-contained

4.3.4 Interpreter: Python (CPython, PyPy), Node.js, Ruby, Perl

Interpreter คือโปรแกรมที่อ่านและรันโค้ดทีละบรรทัดโดยไม่ต้อง Compile ล่วงหน้า ทำให้เริ่มต้นได้เร็วแต่ทำงานช้ากว่า Compiled Language

เปรียบเทียบการรัน Hello World ในภาษา Interpreter ต่าง ๆ:

# Python
python3 -c "print('Hello, World!')"

# Node.js
node -e "console.log('Hello, World!')"

# Ruby
ruby -e "puts 'Hello, World!'"

# Perl
perl -e "print 'Hello, World!\n'"

4.3.5 Modern Compiled: Rust (rustc), Go (go), Zig, Nim, Gleam

ภาษา Compiled ยุคใหม่ที่เน้น Memory Safety, Concurrency และประสิทธิภาพสูง

ตัวอย่างโค้ด Rust ที่ใช้ memory safety ในตัว:

// hello.rs - โปรแกรมตัวอย่างภาษา Rust
// แสดงชื่อที่รับจาก command-line argument

use std::env;

fn main() {
    // รวบรวม arguments จาก command line
    let args: Vec<String> = env::args().collect();

    // ใช้ match pattern เพื่อเลือก default ถ้าไม่มี arg
    let name = match args.get(1) {
        Some(n) => n.as_str(),
        None => "World",
    };

    println!("Hello, {}!", name);
}
# Compile ด้วย rustc
rustc -O hello.rs -o hello
./hello Moo

# หรือสร้างโปรเจกต์ด้วย Cargo
cargo new hello_proj
cd hello_proj
cargo run -- Moo

ตัวอย่างโค้ด Go:

// hello.go - โปรแกรมตัวอย่างภาษา Go
package main

import (
    "fmt"
    "os"
)

func main() {
    // รับ argument ที่ 1 หรือใช้ "World" เป็น default
    name := "World"
    if len(os.Args) > 1 {
        name = os.Args[1]
    }
    fmt.Printf("Hello, %s!\n", name)
}
# รันโดยตรง
go run hello.go Moo

# Build เป็น binary static link
go build -o hello hello.go
./hello Moo

4.3.6 Cross-compilation และ Target Triple

Cross-compilation คือการ Compile โปรแกรมบนเครื่องหนึ่ง (Host) เพื่อให้ทำงานบนอีกเครื่อง/สถาปัตยกรรมหนึ่ง (Target)

Target Triple คือรหัสระบุแพลตฟอร์มเป้าหมาย ในรูปแบบ <arch>-<vendor>-<os>-<abi> เช่น

ตัวอย่าง Cross-compile ด้วย Rust:

# ติดตั้ง target
rustup target add aarch64-unknown-linux-gnu

# Compile สำหรับ ARM64 Linux
cargo build --release --target aarch64-unknown-linux-gnu

# Go cross-compile (ง่ายกว่ามาก เพราะ built-in)
GOOS=linux GOARCH=arm64 go build -o hello-arm64 hello.go
GOOS=windows GOARCH=amd64 go build -o hello.exe hello.go

4.4 Build System และ Task Runner

เมื่อโปรเจกต์มีไฟล์หลายไฟล์ การ Compile/รันด้วยมือเป็นเรื่องยาก จึงเกิด Build System ขึ้นเพื่อจัดการขั้นตอนเหล่านี้ให้อัตโนมัติ รวมถึง Task Runner ที่ช่วยจัดการงานซ้ำ ๆ ทั่วไป

4.4.1 Make และ Makefile

Make เป็น Build Tool ที่เก่าแก่ที่สุด พัฒนาในปี 1976 ใช้ไฟล์ Makefile กำหนดกฎการ build แบบ Declarative ด้วยแนวคิด "ถ้า target เก่ากว่า prerequisite ให้รัน recipe"

# Makefile - ตัวอย่าง Build C project
# ตัวแปร
CC = gcc
CFLAGS = -O2 -Wall -Wextra
TARGET = hello
SRCS = hello.c util.c
OBJS = $(SRCS:.c=.o)

# กฎ default (เรียกเมื่อพิมพ์ make เปล่า ๆ)
all: $(TARGET)

# Link object files เป็น executable
$(TARGET): $(OBJS)
	$(CC) $(CFLAGS) -o $@ $^

# Pattern rule: Compile .c เป็น .o
%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

# Phony target สำหรับคำสั่งพิเศษ
.PHONY: clean test

clean:
	rm -f $(OBJS) $(TARGET)

test: $(TARGET)
	./$(TARGET) Moo

การใช้งาน:

make          # build ทั้งหมด
make clean    # ลบไฟล์ที่ build
make test     # build แล้ว run test
make -j4      # build แบบ parallel 4 jobs

4.4.2 CMake, Meson, Ninja

CMake: Meta Build System ที่ Generate Makefile, Ninja หรือ Visual Studio Project จาก CMakeLists.txt เป็นมาตรฐานของโปรเจกต์ C/C++ ยุคใหม่

Meson: Meta Build System สมัยใหม่ เขียน Config ด้วย Python-like syntax เน้นความเร็วและอ่านง่าย ใช้ Ninja เป็น Back-end

Ninja: Low-level Build System เน้นความเร็วสูงสุด ไม่ออกแบบมาให้มนุษย์เขียนเอง แต่ให้ Tool อื่น Generate ให้

ตัวอย่าง CMakeLists.txt:

# CMakeLists.txt - ตัวอย่างโปรเจกต์ C++ ด้วย CMake
cmake_minimum_required(VERSION 3.20)
project(HelloApp VERSION 1.0.0 LANGUAGES CXX)

# กำหนด C++ standard
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# เพิ่ม executable จาก source files
add_executable(hello
    src/main.cpp
    src/util.cpp
)

# ระบุ include directory
target_include_directories(hello PRIVATE include)

# Compiler warnings
target_compile_options(hello PRIVATE -Wall -Wextra)

คำสั่ง Build:

# Out-of-source build pattern
mkdir build && cd build
cmake ..                 # Configure (generate build files)
cmake --build . -j8      # Build parallel 8 threads
./hello

4.4.3 Autotools (configure, make, make install)

GNU Autotools เป็นชุดเครื่องมือคลาสสิก (autoconf, automake, libtool) ที่ Generate configure script สำหรับตรวจสอบ Environment ของระบบก่อน Build ใช้ในโปรเจกต์ Open-source เก่า ๆ จำนวนมาก

ขั้นตอนการติดตั้งโปรแกรมจากซอร์สโค้ดแบบคลาสสิก:

# 1. Extract ซอร์สโค้ด
tar -xzf program-1.0.tar.gz
cd program-1.0

# 2. Configure: ตรวจสอบ environment และ generate Makefile
./configure --prefix=/usr/local

# 3. Build
make -j$(nproc)

# 4. Install (ต้องใช้ sudo ถ้าลงในระบบ)
sudo make install

4.4.4 JVM: Maven, Gradle, SBT

Maven: Build Tool มาตรฐานของ Java Community ใช้ pom.xml (XML) มี Central Repository

Gradle: Build Tool สมัยใหม่ ใช้ Groovy หรือ Kotlin DSL ยืดหยุ่นและเร็วกว่า Maven เป็น default ของ Android

SBT (Scala Build Tool): Build Tool สำหรับ Scala และโปรเจกต์ Functional

ตัวอย่าง build.gradle.kts สำหรับโปรเจกต์ Kotlin:

// build.gradle.kts
plugins {
    kotlin("jvm") version "2.0.0"
    application
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
    testImplementation(kotlin("test"))
}

application {
    mainClass.set("com.example.MainKt")
}
./gradlew build    # build โปรเจกต์
./gradlew run      # รัน application
./gradlew test     # รัน unit test

4.4.5 Node.js: npm scripts, pnpm, yarn, Bun

ในโลก JavaScript/TypeScript มี Package Manager หลายตัวที่รวมบทบาทของ Task Runner ไปด้วย

ตัวอย่าง package.json กับ npm scripts:

{
  "name": "my-app",
  "version": "1.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "test": "vitest",
    "lint": "eslint src --ext ts,tsx",
    "format": "prettier --write \"src/**/*.{ts,tsx}\""
  },
  "dependencies": {
    "react": "^18.3.0"
  },
  "devDependencies": {
    "vite": "^5.4.0",
    "vitest": "^2.0.0",
    "eslint": "^9.0.0",
    "prettier": "^3.0.0"
  }
}
npm install            # ติดตั้ง dependencies
npm run dev            # รัน script "dev"
pnpm install           # เร็วและประหยัด disk กว่า
bun install            # เร็วที่สุดในกลุ่ม
bun run build          # เร็วมากเมื่อใช้กับ Bun runtime

4.4.6 Rust: Cargo / Go: go build / Python: Poetry, uv, Hatch

ภาษาสมัยใหม่มักรวม Build และ Package Manager ไว้ใน CLI เดียว

Cargo (Rust):

cargo new my_app       # สร้างโปรเจกต์ใหม่
cargo build            # build แบบ debug
cargo build --release  # build แบบ optimized
cargo run              # build + รัน
cargo test             # รัน unit test
cargo add serde        # เพิ่ม dependency
cargo fmt              # format code
cargo clippy           # lint

Go Toolchain:

go mod init example.com/myapp   # สร้าง go.mod
go get github.com/gin-gonic/gin # เพิ่ม dependency
go build -o app .               # build
go run .                        # build + run
go test ./...                   # test ทุก package
go vet ./...                    # static analysis

Python สมัยใหม่ – uv (เขียนด้วย Rust เร็วกว่า pip 10–100 เท่า):

# สร้างโปรเจกต์
uv init myapp
cd myapp

# เพิ่ม dependency
uv add requests pandas
uv add --dev pytest ruff

# รัน
uv run python main.py

# sync environment จาก uv.lock
uv sync

4.4.7 Task Runner: Just, Task, Mask, Make

Task Runner คือ Tool ที่ออกแบบมาเพื่อรันคำสั่งซ้ำ ๆ ในโปรเจกต์ คล้าย make แต่ไม่ใช่ Build System

ตัวอย่าง justfile:

# justfile - ตัวอย่างคำสั่งที่ใช้บ่อยในโปรเจกต์

# คำสั่ง default เมื่อพิมพ์ just เปล่า ๆ
default:
    @just --list

# รัน server ในโหมด development
dev:
    uv run uvicorn app.main:app --reload --port 8000

# รัน test พร้อม coverage
test:
    uv run pytest --cov=app tests/

# Format + Lint
fmt:
    uv run ruff format .
    uv run ruff check --fix .

# Build Docker image
build tag="latest":
    docker build -t myapp:{{tag}} .

# Deploy ไปยัง production (รับ arg)
deploy env:
    @echo "Deploying to {{env}}..."
    ansible-playbook deploy.yml -e env={{env}}

การใช้งาน:

just             # แสดง list คำสั่ง
just dev         # รัน dev server
just test        # test
just build v1.2  # build พร้อม tag v1.2
just deploy production

4.5 Debugger และ Profiler

การหาสาเหตุของ bug และจุดที่ทำงานช้าเป็นงานสำคัญ Debugger ช่วยให้ดูการทำงานของโปรแกรมทีละขั้น ส่วน Profiler ช่วยวิเคราะห์เรื่องประสิทธิภาพ

4.5.1 GDB (GNU Debugger), LLDB

GDB เป็น Debugger มาตรฐานของ Unix/Linux สำหรับ C/C++/Rust/Go/Fortran รองรับ breakpoint, watchpoint, backtrace, หยุดที่ signal

LLDB เป็น Debugger จากโปรเจกต์ LLVM ใช้เป็น default บน macOS

ตัวอย่างใช้ GDB ดีบั๊ก:

// buggy.c - โปรแกรมตัวอย่างที่มี bug (array out of bounds)
#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};
    int sum = 0;

    // bug: วนเกินขอบเขต array (ควรเป็น i < 5)
    for (int i = 0; i <= 5; i++) {
        sum += arr[i];
    }

    printf("Sum = %d\n", sum);
    return 0;
}
# Compile ด้วย debug symbol (-g) และไม่ optimize (-O0)
gcc -g -O0 -o buggy buggy.c

# เปิด gdb
gdb ./buggy

# คำสั่งภายใน gdb
(gdb) break main          # set breakpoint ที่ main
(gdb) run                 # รันโปรแกรม
(gdb) next                # step ข้าม function (step over)
(gdb) step                # step เข้า function (step into)
(gdb) print sum           # ดูค่าตัวแปร sum
(gdb) print arr[5]        # ดูค่านอกขอบเขต
(gdb) watch sum           # watch การเปลี่ยนแปลงของ sum
(gdb) backtrace           # ดู call stack
(gdb) continue            # รันต่อจนจบหรือถึง breakpoint ถัดไป
(gdb) quit

4.5.2 strace, ltrace

strace – ติดตาม System Call ที่โปรแกรมเรียก ใช้หา bug ระดับ OS interaction

ltrace – ติดตาม Library Call (เช่น libc functions)

# ดู system call ของคำสั่ง ls ทั้งหมด
strace ls /tmp

# ติดตามเฉพาะบาง syscall (เช่น open, read)
strace -e trace=open,openat,read cat /etc/hostname

# วัดเวลาที่ใช้ใน syscall แต่ละตัว
strace -c -f python3 myscript.py

# ดู library call
ltrace -c ./hello Moo

4.5.3 Valgrind (memcheck, callgrind, massif)

Valgrind เป็นชุด tool สำหรับตรวจสอบ memory และ profiling โปรแกรม C/C++

# ตรวจหา memory leak
valgrind --leak-check=full --show-leak-kinds=all ./myprogram

# Profile ด้วย callgrind
valgrind --tool=callgrind ./myprogram
kcachegrind callgrind.out.*  # ดูผลผ่าน GUI

# วัด heap usage
valgrind --tool=massif ./myprogram
ms_print massif.out.*

4.5.4 perf, gprof, flamegraph

perf – เครื่องมือ profiling ใน Linux Kernel ใช้ hardware performance counter

gprof – Profiler ดั้งเดิมของ GNU ต้อง compile ด้วย -pg

Flamegraph – วิธีการแสดงผล profiling ในรูป graph แบบ flame (กราฟเปลวไฟ) ทำให้ดู hotspot ง่าย

# Record profiling data (ต้องใช้สิทธิ์)
sudo perf record -F 99 -g ./myprogram

# แสดงรายงาน
sudo perf report

# สร้าง Flamegraph
sudo perf record -F 99 -g ./myprogram
sudo perf script > out.perf
./stackcollapse-perf.pl out.perf | ./flamegraph.pl > flame.svg

สูตรคำนวณ Sampling Rate Overhead โดยประมาณ:

Overhead ftsample tcpu × 100 %

โดยที่ f คือความถี่ในการ sample (เช่น 99 Hz), tsample คือเวลาที่ใช้ในการเก็บ 1 sample และ tcpu คือเวลา CPU ทั้งหมด ยิ่ง Overhead ต่ำ ยิ่งได้ข้อมูลใกล้ความเป็นจริง

4.5.5 IDE Debugger Integration

IDE สมัยใหม่ผนวก Debugger เข้าผ่าน Debug Adapter Protocol (DAP) ทำให้ใช้ได้โดยไม่ต้องเปิด Terminal แยก

ตัวอย่าง .vscode/launch.json สำหรับดีบั๊ก Python:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Current File",
            "type": "debugpy",
            "request": "launch",
            "program": "${file}",
            "console": "integratedTerminal",
            "justMyCode": false,
            "env": {
                "PYTHONPATH": "${workspaceFolder}"
            }
        },
        {
            "name": "FastAPI Server",
            "type": "debugpy",
            "request": "launch",
            "module": "uvicorn",
            "args": ["app.main:app", "--reload"],
            "jinja": true
        }
    ]
}

4.6 Package Manager และ Dependency Management

Package Manager คือเครื่องมือที่ช่วยติดตั้ง อัปเดต และถอดถอน Library/โปรแกรมได้แบบอัตโนมัติ โดยจัดการ Dependency ระหว่าง package ให้ด้วย

4.6.1 Language-specific Package Manager

แต่ละภาษาโปรแกรมมี Package Manager ประจำของตนเอง เก็บ Library ใน Registry ของตัวเอง

ภาษา Package Manager Registry ไฟล์ Manifest
Python pip, uv, Poetry PyPI requirements.txt, pyproject.toml
JavaScript npm, pnpm, yarn, Bun npm registry package.json
Rust Cargo crates.io Cargo.toml
Go go mod (proxy.golang.org) go.mod
Ruby gem, bundler RubyGems Gemfile
PHP Composer Packagist composer.json
Java Maven, Gradle Maven Central pom.xml, build.gradle
.NET NuGet nuget.org .csproj
Haskell cabal, stack Hackage *.cabal
Elixir mix + hex Hex.pm mix.exs

4.6.2 System-level Package Manager

Package Manager ระดับ OS จัดการซอฟต์แวร์ทั้งระบบ (รายละเอียดอยู่ในหัวข้อ 2.6)

4.6.3 Environment Management: venv, conda, pyenv, nvm, rbenv, asdf, mise

Environment Manager ช่วยให้มีหลาย version ของภาษาหรือ dependency แยกกันในเครื่องเดียว ป้องกันปัญหา "ทำงานได้บนเครื่องของฉัน" (Works on my machine)

ตัวอย่างการใช้ mise:

# ติดตั้ง mise
curl https://mise.run | sh

# ติดตั้งหลาย version
mise install python@3.12
mise install python@3.11
mise install node@20
mise install rust@stable

# กำหนด version สำหรับโปรเจกต์ (สร้าง .tool-versions หรือ .mise.toml)
cd myproject
mise use python@3.12 node@20

# ตรวจสอบ
mise current

ตัวอย่าง venv ของ Python ล้วน ๆ:

# สร้าง virtual environment
python3 -m venv .venv

# เปิดใช้งาน (Activate)
source .venv/bin/activate        # Linux/macOS
# .venv\Scripts\activate         # Windows

# ติดตั้ง package ในนี้เท่านั้น
pip install requests pandas

# Export dependency list
pip freeze > requirements.txt

# ปิด environment
deactivate

4.6.4 Lock File และ Reproducible Build

Lock File เป็นไฟล์ที่เก็บ version ที่ resolve แล้ว (exact version) ของ dependency ทุกตัว รวมถึง dependency ของ dependency (Transitive Dependency) เพื่อให้สร้าง environment ที่เหมือนกันทุกเครื่อง = Reproducible Build

Package Manager Lock File
npm package-lock.json
pnpm pnpm-lock.yaml
yarn yarn.lock
Cargo Cargo.lock
Poetry poetry.lock
uv uv.lock
Bundler Gemfile.lock
Composer composer.lock
go mod go.sum

หลักการสำคัญ:

  1. Commit Lock File ลง Git ทุกครั้งสำหรับ Application
  2. ไม่ commit Lock File สำหรับ Library ที่เป็น Reusable (ให้ผู้ใช้งานเลือก version เอง)
  3. Verify Hash: Lock File ส่วนใหญ่มี Hash ของ package ป้องกันการถูกแก้ไข
  4. Dependabot / Renovate: Tool ช่วย update dependency อัตโนมัติ

4.7 Documentation Tools

เอกสารคือหนึ่งในองค์ประกอบสำคัญของซอฟต์แวร์ที่มักถูกละเลย มีคำกล่าวที่ว่า "If it's not documented, it doesn't exist" เครื่องมือสร้างเอกสารจึงมีบทบาทสำคัญในการผลักดันวัฒนธรรมการเขียนเอกสาร

4.7.1 Markdown และ CommonMark

Markdown คือภาษา Markup น้ำหนักเบา (Lightweight) ที่อ่านรู้เรื่องแม้เป็น plain text พัฒนาโดย John Gruber ปี 2004 ปัจจุบัน CommonMark เป็นมาตรฐานที่กำหนดไวยากรณ์ให้ชัดเจน และ GitHub Flavored Markdown (GFM) เป็น superset ที่เพิ่ม table, task list, strikethrough

ตัวอย่าง Markdown พื้นฐาน:

# หัวเรื่องหลัก (H1)
## หัวข้อรอง (H2)

**ตัวหนา** และ *ตัวเอน* และ ~~ขีดฆ่า~~

- รายการแจกแจง 1
- รายการแจกแจง 2
  - รายการย่อย

1. ลำดับ 1
2. ลำดับ 2

> Blockquote สำหรับการอ้างอิง

`inline code` และ

```python
# code block
print("Hello")

ข้อความลิงก์ Alt text

คอลัมน์ 1 คอลัมน์ 2
A B

### 4.7.2 Pandoc (แปลงเอกสารข้ามฟอร์แมต)

**Pandoc** คือ "Swiss Army Knife" สำหรับแปลงเอกสาร รองรับกว่า 40 format เช่น Markdown, HTML, LaTeX, DOCX, PDF, EPUB, reStructuredText, Org-mode

```bash
# Markdown → PDF (ต้องมี LaTeX)
pandoc document.md -o document.pdf

# Markdown → DOCX
pandoc document.md -o document.docx

# Markdown → HTML พร้อม TOC และ CSS
pandoc document.md -o document.html \
    --toc \
    --standalone \
    --css=style.css \
    --metadata title="เอกสารของฉัน"

# Markdown → EPUB สำหรับ e-book
pandoc chapter*.md -o book.epub \
    --metadata title="หนังสือของฉัน" \
    --metadata author="Moo"

# รวมหลายไฟล์ Markdown เป็น PDF ผ่าน LaTeX engine
pandoc chapter*.md -o book.pdf \
    --pdf-engine=xelatex \
    -V mainfont="Sarabun" \
    -V CJKmainfont="Sarabun"

4.7.3 API Doc: Doxygen, Sphinx, rustdoc, godoc, JSDoc

API Documentation ถูกสร้างโดยอัตโนมัติจาก Comment ในโค้ด ทำให้เอกสารกับโค้ดอยู่ใกล้กันเสมอ

ตัวอย่าง Docstring แบบต่าง ๆ:

# Python with Sphinx/Google style docstring
def calculate_gpa(grades: list[float], credits: list[int]) -> float:
    """คำนวณ GPA จากเกรดและหน่วยกิต

    Args:
        grades: รายการคะแนนเกรด (0.0 - 4.0) ในแต่ละวิชา
        credits: จำนวนหน่วยกิตของแต่ละวิชา

    Returns:
        GPA ในช่วง 0.0 - 4.0

    Raises:
        ValueError: หากความยาวของ grades และ credits ไม่เท่ากัน
        ZeroDivisionError: หากผลรวมหน่วยกิตเป็น 0

    Example:
        >>> calculate_gpa([4.0, 3.5, 3.0], [3, 3, 2])
        3.5625
    """
    if len(grades) != len(credits):
        raise ValueError("grades and credits must have same length")
    total_points = sum(g * c for g, c in zip(grades, credits))
    total_credits = sum(credits)
    return total_points / total_credits
/// คำนวณ GPA จากเกรดและหน่วยกิต
///
/// # Arguments
/// * `grades` - รายการคะแนนเกรด (0.0 - 4.0)
/// * `credits` - จำนวนหน่วยกิตของแต่ละวิชา
///
/// # Returns
/// GPA ในช่วง 0.0 - 4.0
///
/// # Examples
/// ```
/// let gpa = calculate_gpa(&[4.0, 3.5, 3.0], &[3, 3, 2]);
/// assert!((gpa - 3.5625).abs() < 1e-6);
/// ```
pub fn calculate_gpa(grades: &[f64], credits: &[u32]) -> f64 {
    let total_points: f64 = grades.iter().zip(credits)
        .map(|(g, c)| g * (*c as f64))
        .sum();
    let total_credits: f64 = credits.iter().sum::<u32>() as f64;
    total_points / total_credits
}

คำสั่ง generate เอกสาร:

# Rust
cargo doc --open

# Go
godoc -http=:6060     # ดู doc ของ package ที่ติดตั้ง

# Python (Sphinx)
sphinx-quickstart docs
cd docs && make html

# TypeScript (TypeDoc)
npx typedoc --out docs src/index.ts

4.7.4 Static Site: MkDocs, Docusaurus, VitePress, Hugo, Jekyll

Static Site Generator (SSG) สร้าง HTML แบบ static จากไฟล์ Markdown เหมาะทำ Documentation Website, Blog, Landing Page

ตัวอย่าง mkdocs.yml:

site_name: My Project Documentation
site_url: https://docs.example.com
repo_url: https://github.com/example/myproject

theme:
  name: material
  palette:
    - scheme: slate
      primary: deep orange
      accent: orange
  features:
    - navigation.tabs
    - navigation.sections
    - search.suggest
    - content.code.copy

plugins:
  - search
  - mermaid2

markdown_extensions:
  - admonition
  - pymdownx.highlight
  - pymdownx.superfences:
      custom_fences:
        - name: mermaid
          class: mermaid

nav:
  - Home: index.md
  - Getting Started: getting-started.md
  - User Guide:
      - Installation: guide/install.md
      - Configuration: guide/config.md
  - API Reference: api.md
# สร้าง
mkdocs new my-docs
cd my-docs

# รัน dev server
mkdocs serve

# Build เป็น static HTML
mkdocs build

# Deploy ไปยัง GitHub Pages
mkdocs gh-deploy

4.7.5 Man Page และ info

Man Page (Manual Page) คือคู่มือมาตรฐานของ Unix/Linux แบ่งเป็น 8 section เช่น

  1. User Commands (เช่น ls, grep)
  2. System Calls (open, read)
  3. Library Functions (printf)
  4. Device Files (tty)
  5. File Formats (passwd, fstab)
  6. Games
  7. Miscellaneous (ascii, regex)
  8. System Administration (mount, fdisk)
man ls               # ดู man page ของ ls
man 2 open           # ดู man ของ open system call (section 2)
man -k network       # ค้นหา man page ที่มีคำว่า network
man -f printf        # ดูทุก section ที่มี printf
apropos compression  # ค้นหา man page ที่เกี่ยวกับ compression

4.8 Continuous Integration / Continuous Deployment (CI/CD)

4.8.1 แนวคิด CI / CD / CDE

flowchart TB
    A[Commit โค้ด
git push]:::gruvblue --> B[CI Trigger]:::gruvaqua B --> C[Build
สร้าง artifact]:::gruvgreen C --> D[Test
Unit + Integration]:::gruvyellow D --> E{ผ่านทั้งหมด?}:::gruvorange E -->|ไม่ผ่าน| F[แจ้งเตือนผู้พัฒนา
Notify]:::gruvred E -->|ผ่าน| G[Package
Docker Image]:::gruvpurple G --> H[Deploy Staging]:::gruvaqua H --> I{Manual Approval?}:::gruvorange I -->|CD| J[Deploy Production
Manual]:::gruvgreen I -->|CDE| K[Deploy Production
Auto]:::gruvgreen classDef gruvblue fill:#458588,stroke:#83a598,color:#ebdbb2 classDef gruvaqua fill:#689d6a,stroke:#8ec07c,color:#ebdbb2 classDef gruvgreen fill:#98971a,stroke:#b8bb26,color:#282828 classDef gruvyellow fill:#d79921,stroke:#fabd2f,color:#282828 classDef gruvorange fill:#d65d0e,stroke:#fe8019,color:#ebdbb2 classDef gruvred fill:#cc241d,stroke:#fb4934,color:#ebdbb2 classDef gruvpurple fill:#b16286,stroke:#d3869b,color:#ebdbb2

DORA Metrics เป็นมาตรวัดประสิทธิภาพของทีม DevOps 4 ตัว:

  1. Deployment Frequency: ความถี่ในการ deploy
  2. Lead Time for Changes: เวลาจาก commit ถึง deploy
  3. Change Failure Rate: สัดส่วน deploy ที่ล้มเหลว
  4. Mean Time to Recovery (MTTR): เวลาเฉลี่ยในการกู้คืน
Change Failure Rate = Dfailed Dtotal × 100 %

โดยที่ Dfailed คือจำนวน deployment ที่ล้มเหลวและ Dtotal คือจำนวน deployment ทั้งหมดในช่วงเวลาหนึ่ง ทีมระดับ Elite มักมีค่านี้ต่ำกว่า 15%

4.8.2 Pipeline และ Stage

Pipeline คือลำดับของ Job ที่รันเรียงกันใน CI/CD System โดยแบ่งเป็น Stage ต่าง ๆ เช่น Build, Test, Security Scan, Deploy แต่ละ Stage อาจมี Job หลายตัวที่รันพร้อมกันได้ (Parallel Jobs)

แนวคิดสำคัญ:

4.8.3 CI Platform: GitHub Actions, GitLab CI/CD, Jenkins, CircleCI, Drone, Woodpecker CI

GitHub Actions – Built-in กับ GitHub ใช้ YAML ที่ .github/workflows/

GitLab CI/CD – Built-in กับ GitLab ใช้ .gitlab-ci.yml

Jenkins – Self-hosted CI ที่เก่าแก่และยืดหยุ่นที่สุด ใช้ Jenkinsfile (Groovy)

CircleCI, Drone, Woodpecker CI – ทางเลือกอื่นแต่ละตัวมีจุดเด่นต่างกัน

ตัวอย่าง GitHub Actions workflow:

# .github/workflows/ci.yml - สำหรับ Python project
name: CI

# Trigger: เมื่อ push หรือเปิด PR บน main
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    name: Test on Python ${{ matrix.python-version }}
    runs-on: ubuntu-latest

    # ทดสอบบน Python หลาย version พร้อมกัน
    strategy:
      matrix:
        python-version: ['3.11', '3.12']

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v3

      - name: Set up Python
        run: uv python install ${{ matrix.python-version }}

      - name: Install dependencies
        run: uv sync --all-extras --dev

      - name: Lint with Ruff
        run: uv run ruff check .

      - name: Format check
        run: uv run ruff format --check .

      - name: Run tests with coverage
        run: uv run pytest --cov=src --cov-report=xml

      - name: Upload coverage
        uses: codecov/codecov-action@v4
        with:
          files: ./coverage.xml

  build-docker:
    name: Build Docker image
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
      - uses: actions/checkout@v4

      - name: Login to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ghcr.io/${{ github.repository }}:latest
            ghcr.io/${{ github.repository }}:${{ github.sha }}

ตัวอย่าง GitLab CI:

# .gitlab-ci.yml
stages:
  - test
  - build
  - deploy

variables:
  PYTHON_VERSION: "3.12"

cache:
  paths:
    - .venv/

test:
  stage: test
  image: python:${PYTHON_VERSION}-slim
  before_script:
    - pip install uv
    - uv sync --dev
  script:
    - uv run pytest --cov=src
  coverage: '/TOTAL.*\s+(\d+%)$/'

build:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  only:
    - main

deploy:
  stage: deploy
  script:
    - echo "Deploy to production"
  environment:
    name: production
    url: https://myapp.example.com
  when: manual
  only:
    - main

4.8.4 Artifact และ Release

Artifact คือผลผลิตของการ Build เช่น JAR, WAR, Executable, Docker Image, npm package, Wheel (.whl)

Artifact Repository เก็บและแจกจ่าย Artifact:

Release เป็นการแพคเกจ artifact พร้อม release notes และ semantic version


4.9 Testing Tools

การทดสอบเป็นส่วนสำคัญที่ป้องกันไม่ให้ bug หลุดขึ้น production Test Pyramid เป็นหลักการจัดสัดส่วนของ test ที่แนะนำ

flowchart TB
    E2E["E2E / UI Test
(น้อย 5-10%)
ช้า, แพง, บอบบาง"]:::gruvred INT["Integration Test
(ปานกลาง 20-30%)
ทดสอบการทำงานร่วมของ component"]:::gruvyellow UNIT["Unit Test
(มาก 60-70%)
เร็ว, เจาะจง, เชื่อถือได้"]:::gruvgreen E2E --> INT INT --> UNIT classDef gruvgreen fill:#98971a,stroke:#b8bb26,color:#282828 classDef gruvyellow fill:#d79921,stroke:#fabd2f,color:#282828 classDef gruvred fill:#cc241d,stroke:#fb4934,color:#ebdbb2

4.9.1 Unit Testing: pytest, unittest, JUnit, Jest, Vitest, Go test, cargo test

Unit Test ทดสอบหน่วยเล็กที่สุด (function, method) แยกต่างหาก

ตัวอย่าง pytest:

# src/calculator.py
def add(a: int, b: int) -> int:
    return a + b

def divide(a: float, b: float) -> float:
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b
# tests/test_calculator.py
import pytest
from src.calculator import add, divide

# Unit Test ปกติ
def test_add_positive():
    assert add(2, 3) == 5

def test_add_negative():
    assert add(-1, -1) == -2

# Test หลายกรณีด้วย parametrize
@pytest.mark.parametrize("a,b,expected", [
    (10, 2, 5.0),
    (15, 3, 5.0),
    (7, 2, 3.5),
    (-10, 2, -5.0),
])
def test_divide(a, b, expected):
    assert divide(a, b) == expected

# Test exception
def test_divide_by_zero():
    with pytest.raises(ValueError, match="Cannot divide by zero"):
        divide(10, 0)

# Fixture: ข้อมูลใช้ซ้ำ
@pytest.fixture
def sample_data():
    return {"x": 10, "y": 20}

def test_with_fixture(sample_data):
    assert add(sample_data["x"], sample_data["y"]) == 30
# รัน test
pytest                          # รันทั้งหมด
pytest tests/test_calculator.py # รันไฟล์เดียว
pytest -v                       # verbose
pytest -k "divide"              # รันเฉพาะ test ที่มีคำว่า divide
pytest --cov=src                # พร้อม coverage
pytest -x                       # หยุดที่ failure แรก
pytest --lf                     # รันเฉพาะที่ fail ครั้งที่แล้ว

ตัวอย่าง Vitest (TypeScript):

// src/math.ts
export const add = (a: number, b: number): number => a + b;
export const multiply = (a: number, b: number): number => a * b;
// src/math.test.ts
import { describe, it, expect } from 'vitest';
import { add, multiply } from './math';

describe('Math operations', () => {
  it('adds two numbers correctly', () => {
    expect(add(2, 3)).toBe(5);
    expect(add(-1, 1)).toBe(0);
  });

  it('multiplies two numbers correctly', () => {
    expect(multiply(4, 5)).toBe(20);
    expect(multiply(0, 100)).toBe(0);
  });

  it.each([
    [1, 2, 3],
    [2, 3, 5],
    [10, 20, 30],
  ])('add(%i, %i) = %i', (a, b, expected) => {
    expect(add(a, b)).toBe(expected);
  });
});

ตัวอย่าง Go test:

// calculator.go
package calculator

func Add(a, b int) int { return a + b }
// calculator_test.go
package calculator

import "testing"

func TestAdd(t *testing.T) {
    tests := []struct {
        name     string
        a, b     int
        expected int
    }{
        {"positive", 2, 3, 5},
        {"negative", -1, -1, -2},
        {"zero", 0, 5, 5},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if got := Add(tt.a, tt.b); got != tt.expected {
                t.Errorf("Add(%d, %d) = %d; want %d",
                    tt.a, tt.b, got, tt.expected)
            }
        })
    }
}

// Benchmark
func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Add(1, 2)
    }
}
go test ./...              # รันทั้งหมด
go test -v                 # verbose
go test -run TestAdd       # รันเฉพาะ test
go test -bench=.           # รัน benchmark
go test -cover             # coverage

4.9.2 Integration & End-to-End: Selenium, Playwright, Cypress

Integration Test ทดสอบการทำงานร่วมกันของหลาย module

E2E Test ทดสอบระบบทั้งหมดจากมุมมองผู้ใช้

ตัวอย่าง Playwright:

// tests/login.spec.ts
import { test, expect } from '@playwright/test';

test.describe('Login Flow', () => {
  test('successful login redirects to dashboard', async ({ page }) => {
    // ไปหน้า login
    await page.goto('https://app.example.com/login');

    // กรอกฟอร์ม
    await page.fill('input[name="email"]', 'user@example.com');
    await page.fill('input[name="password"]', 'password123');

    // คลิก submit
    await page.click('button[type="submit"]');

    // ตรวจว่า redirect ไป /dashboard
    await expect(page).toHaveURL(/.*dashboard/);

    // ตรวจว่ามีข้อความต้อนรับ
    await expect(page.locator('h1')).toContainText('Welcome');
  });

  test('invalid credentials show error', async ({ page }) => {
    await page.goto('https://app.example.com/login');
    await page.fill('input[name="email"]', 'wrong@example.com');
    await page.fill('input[name="password"]', 'wrongpass');
    await page.click('button[type="submit"]');

    await expect(page.locator('.error-message'))
      .toContainText('Invalid credentials');
  });
});
# รัน Playwright
npx playwright test
npx playwright test --ui            # เปิด UI mode
npx playwright test --headed        # เห็น browser
npx playwright show-report          # ดูรายงาน

4.9.3 Code Coverage: coverage.py, gcov, nyc

Code Coverage วัดว่า test ทดสอบโค้ดกี่เปอร์เซ็นต์ มีหลายระดับ:

  1. Line Coverage: แต่ละบรรทัดถูก execute หรือไม่
  2. Branch Coverage: แต่ละสาขาของ if/else ถูก execute
  3. Function Coverage: แต่ละ function ถูกเรียก
  4. Statement Coverage: แต่ละ statement ถูก execute
Coverage = Lexecuted Ltotal × 100 %

โดยที่ Lexecuted คือจำนวนบรรทัดที่ถูกรัน และ Ltotal คือจำนวนบรรทัดทั้งหมดในโค้ด แต่ทีมควรเน้นคุณภาพของ test มากกว่าการไล่ตามเปอร์เซ็นต์ Coverage 100% ไม่ได้หมายความว่าไม่มี bug

# Python
pytest --cov=src --cov-report=html --cov-report=term-missing
# เปิด htmlcov/index.html ในเบราว์เซอร์

# JavaScript/TypeScript
npx vitest run --coverage

# Go
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

# Rust
cargo install cargo-tarpaulin
cargo tarpaulin --out Html

4.9.4 Mutation Testing, Fuzz Testing

Mutation Testing สร้าง "mutant" (การแก้โค้ดเล็กน้อยที่ควรทำให้ test fail) ถ้า test ยัง pass แสดงว่า test นั้นอ่อนแอ

Fuzz Testing ป้อน input แบบสุ่มเพื่อหา crash, hang, security vulnerability

// Go Fuzz Testing (Go 1.18+)
func FuzzReverse(f *testing.F) {
    // Seed corpus
    f.Add("hello")
    f.Add("12345")

    f.Fuzz(func(t *testing.T, s string) {
        reversed := Reverse(s)
        doubleReversed := Reverse(reversed)
        if s != doubleReversed {
            t.Errorf("Before: %q, After: %q", s, doubleReversed)
        }
    })
}
go test -fuzz=FuzzReverse -fuzztime=30s

4.10 API Testing และ HTTP Client

4.10.1 CLI: curl, HTTPie, xh

curl – CLI คลาสสิกสำหรับ HTTP(S) และโปรโตคอลอื่น ๆ มีบน Linux/macOS/Windows

HTTPie – CLI ที่ทำให้ request HTTP ดูสวยและอ่านง่าย

xh – Alternative ของ HTTPie เขียนด้วย Rust เร็วกว่า

ตัวอย่างเรียก API ด้วย 3 tool:

# curl - GET
curl -i https://api.github.com/users/torvalds

# curl - POST JSON
curl -X POST https://httpbin.org/post \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer TOKEN" \
    -d '{"name": "Moo", "role": "lecturer"}'

# HTTPie - syntax ง่ายกว่ามาก
http GET https://api.github.com/users/torvalds
http POST https://httpbin.org/post \
    name=Moo role=lecturer \
    Authorization:"Bearer TOKEN"

# xh - เหมือน HTTPie แต่เร็วกว่า
xh POST httpbin.org/post name=Moo role=lecturer

# curl แบบสรุปผล timing
curl -w "@-" -o /dev/null -s https://example.com <<'EOF'
     time_namelookup:  %{time_namelookup}s
        time_connect:  %{time_connect}s
     time_appconnect:  %{time_appconnect}s
         time_total:  %{time_total}s
EOF

4.10.2 GUI: Postman, Insomnia, Bruno, Hoppscotch

GUI API Client เหมาะสำหรับสำรวจ API ใหม่, จัดการ collection ของ request, ทำ automated test

4.10.3 IDE Plugin: REST Client (VS Code), HTTP Client (JetBrains)

Extension ของ IDE ช่วยให้ส่ง request ได้จากในไฟล์ .http โดยไม่ต้องออกจาก editor

### ตัวอย่างไฟล์ api.http สำหรับ REST Client (VS Code)

### GET user info
GET https://api.github.com/users/torvalds
Accept: application/json

### Create a post
POST https://httpbin.org/post HTTP/1.1
Content-Type: application/json
Authorization: Bearer {{token}}

{
    "title": "Development Tools",
    "author": "Moo",
    "published": true
}

### Use response from previous request
@postId = {{createPost.response.body.$.id}}

### Get created post
GET https://api.example.com/posts/{{postId}}

4.10.4 API Specification: OpenAPI / Swagger

OpenAPI Specification (OAS) เดิมเรียก Swagger คือมาตรฐานอธิบาย REST API ในรูป YAML/JSON สามารถ generate client SDK, documentation, mock server ได้อัตโนมัติ

ตัวอย่าง OpenAPI (ย่อ):

openapi: 3.0.3
info:
  title: Student API
  version: 1.0.0
  description: API for managing students
servers:
  - url: https://api.example.com/v1
paths:
  /students:
    get:
      summary: List all students
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Student'
    post:
      summary: Create a student
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Student'
      responses:
        '201':
          description: Created
components:
  schemas:
    Student:
      type: object
      required: [id, name]
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
          example: "สมชาย ใจดี"
        gpa:
          type: number
          minimum: 0
          maximum: 4

Tool ที่ใช้กับ OpenAPI:


4.11 Code Quality Tools

โค้ดที่ทำงานได้ ≠ โค้ดที่ดี โค้ดที่ดีต้องอ่านง่าย บำรุงรักษาได้ ทีมอ่านตรงกัน Code Quality Tools ช่วยบังคับมาตรฐานเหล่านี้โดยอัตโนมัติ

4.11.1 Linter: ESLint, Pylint, Ruff, ShellCheck, golangci-lint, clippy

Linter วิเคราะห์โค้ดแบบ static เพื่อหาปัญหาที่อาจเกิดขึ้น เช่น ตัวแปรที่ไม่ใช้, dead code, anti-pattern, bug ที่เห็นได้จากโครงสร้าง

ภาษา Linter แนะนำ หมายเหตุ
Python Ruff เขียนด้วย Rust เร็วกว่า Pylint/Flake8 10-100x
JavaScript/TypeScript ESLint, Biome Biome เขียนด้วย Rust
Shell ShellCheck จับ bug bash/sh ได้มาก
Go golangci-lint รวม linter หลายตัว
Rust clippy มากับ rustup
C/C++ clang-tidy, cppcheck
YAML yamllint
Dockerfile hadolint
Kubernetes kubeval, kube-linter

ตัวอย่างไฟล์ config Ruff pyproject.toml:

[tool.ruff]
line-length = 100
target-version = "py312"

[tool.ruff.lint]
select = [
    "E",    # pycodestyle errors
    "W",    # pycodestyle warnings
    "F",    # pyflakes
    "I",    # isort
    "N",    # pep8-naming
    "UP",   # pyupgrade
    "B",    # flake8-bugbear
    "SIM",  # flake8-simplify
    "RUF",  # Ruff-specific rules
]
ignore = ["E501"]  # ไม่สน line too long (Formatter จัดการเอง)

[tool.ruff.lint.per-file-ignores]
"tests/**/*.py" = ["S101"]  # allow assert ในไฟล์ test
# ตรวจอย่างเดียว
ruff check .

# แก้อัตโนมัติเท่าที่ทำได้
ruff check --fix .

# Watch mode
ruff check --watch .

ตัวอย่าง ShellCheck:

#!/bin/bash
# bad_script.sh - script ที่มี bug ทั่วไป

# bug: ไม่ quote variable ทำให้ path ที่มี space พัง
FILE=/tmp/my file.txt
cat $FILE

# bug: ใช้ $? แทน exit code ของคำสั่งก่อนหน้าทันที
grep "pattern" input.txt
if [ $? -eq 0 ]; then
    echo "Found"
fi
shellcheck bad_script.sh
# จะรายงาน:
# SC2086: Double quote to prevent globbing and word splitting.
# SC2181: Check exit code directly with e.g. 'if mycmd;'

4.11.2 Formatter: Prettier, Black, Ruff, gofmt, rustfmt

Formatter จัดรูปแบบโค้ดให้สวยงามและสม่ำเสมอ ข้อดีคือเลิกทะเลาะเรื่อง indent/bracket กันในทีม

# ตรวจว่า format ถูกต้อง (ใช้ใน CI)
ruff format --check .
gofmt -l .
rustfmt --check src/main.rs
prettier --check "src/**/*.{ts,tsx}"

# Format ทุกไฟล์ (in-place)
ruff format .
gofmt -w .
cargo fmt
prettier --write "src/**/*.{ts,tsx}"

4.11.3 pre-commit Hook

Git Hook คือ script ที่ Git รันอัตโนมัติในจังหวะต่าง ๆ เช่น ก่อน commit, ก่อน push pre-commit framework เป็น tool ยอดนิยมที่ช่วยจัดการ hook หลายตัวรวมกัน

ตัวอย่าง .pre-commit-config.yaml:

# .pre-commit-config.yaml
repos:
  # Hook ทั่วไปสำหรับจัดการไฟล์
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.6.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files
        args: ['--maxkb=500']
      - id: check-merge-conflict

  # Ruff: lint + format Python
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.6.0
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format

  # ShellCheck สำหรับ shell scripts
  - repo: https://github.com/shellcheck-py/shellcheck-py
    rev: v0.10.0.1
    hooks:
      - id: shellcheck

  # Hadolint สำหรับ Dockerfile
  - repo: https://github.com/hadolint/hadolint
    rev: v2.13.0
    hooks:
      - id: hadolint

  # Secret scanner: ไม่ให้ commit API key/password
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.0
    hooks:
      - id: gitleaks

การใช้งาน:

# ติดตั้ง framework
pip install pre-commit
# หรือ uv tool install pre-commit

# ติดตั้ง hook ใน .git/hooks/
pre-commit install

# รันทุก hook กับทุกไฟล์ (ครั้งแรกเท่านั้น)
pre-commit run --all-files

# หลังจากนี้ hook จะรันอัตโนมัติทุกครั้งที่ git commit

วัฒนธรรมที่ดี: รวม pre-commit เข้ากับ CI (pre-commit run --all-files) เพื่อรับประกันว่าคนที่ bypass ด้วย --no-verify จะถูกจับได้ใน Pull Request


ประวัติและวิวัฒนาการของ Development Tools

เพื่อความเข้าใจบริบท เครื่องมือพัฒนาซอฟต์แวร์มีวิวัฒนาการมายาวนานตั้งแต่ยุค Mainframe จนถึง AI-native ปัจจุบัน

flowchart TB
    subgraph Era1["ยุค 1: Mainframe (1950-1970)"]
        direction LR
        A1[Assembler
1950s]:::gruvblue --> A2[FORTRAN Compiler
1957]:::gruvblue A2 --> A3[ed editor
1969]:::gruvblue end subgraph Era2["ยุค 2: Unix Era (1970-1990)"] direction LR B1[ed, ex, vi
1976]:::gruvaqua --> B2[Make
1976]:::gruvaqua B2 --> B3[SCCS/RCS
1972/1982]:::gruvaqua B3 --> B4[GCC
1987]:::gruvaqua end subgraph Era3["ยุค 3: GUI IDE (1990-2005)"] direction LR C1[Visual Basic
1991]:::gruvgreen --> C2[Eclipse
2001]:::gruvgreen C2 --> C3[IntelliJ IDEA
2001]:::gruvgreen C3 --> C4[CVS/SVN
1990/2000]:::gruvgreen end subgraph Era4["ยุค 4: DVCS + Open Source (2005-2015)"] direction LR D1[Git
2005]:::gruvyellow --> D2[GitHub
2008]:::gruvyellow D2 --> D3[Jenkins
2011]:::gruvyellow D3 --> D4[Docker
2013]:::gruvyellow end subgraph Era5["ยุค 5: Cloud-Native + DevOps (2015-2022)"] direction LR E1[VS Code
2015]:::gruvorange --> E2[Kubernetes
2015]:::gruvorange E2 --> E3[GitHub Actions
2019]:::gruvorange E3 --> E4[LSP Protocol
2016]:::gruvorange end subgraph Era6["ยุค 6: AI-Native (2022-ปัจจุบัน)"] direction LR F1[GitHub Copilot
2022]:::gruvred --> F2[Cursor
2023]:::gruvred F2 --> F3[Aider/Zed Agent
2024]:::gruvred F3 --> F4[Claude Code/MCP
2024-2025]:::gruvpurple end Era1 --> Era2 Era2 --> Era3 Era3 --> Era4 Era4 --> Era5 Era5 --> Era6 classDef gruvblue fill:#458588,stroke:#83a598,color:#ebdbb2 classDef gruvaqua fill:#689d6a,stroke:#8ec07c,color:#ebdbb2 classDef gruvgreen fill:#98971a,stroke:#b8bb26,color:#282828 classDef gruvyellow fill:#d79921,stroke:#fabd2f,color:#282828 classDef gruvorange fill:#d65d0e,stroke:#fe8019,color:#ebdbb2 classDef gruvred fill:#cc241d,stroke:#fb4934,color:#ebdbb2 classDef gruvpurple fill:#b16286,stroke:#d3869b,color:#ebdbb2

ปัจจุบันเทรนด์ของ Development Tools เน้น 4 ทิศทาง:

  1. Rust-powered: เครื่องมือใหม่หลายตัวเขียนด้วย Rust เพื่อความเร็ว (Ruff, uv, Biome, Zed, Helix)
  2. AI-assisted: มีผู้ช่วย AI ผนวกเข้าในทุก workflow (Copilot, Cursor, Claude Code)
  3. Local-first + Cloud-sync: ทำงานออฟไลน์ได้ แต่ sync กับ cloud ตามต้องการ
  4. Developer Experience-first: ให้ความสำคัญกับ DevEx มากขึ้นเรื่อย ๆ เพื่อเพิ่ม productivity