` เช่น:
- `x86_64-unknown-linux-gnu` – Linux 64-bit x86
- `aarch64-apple-darwin` – macOS Apple Silicon
- `x86_64-pc-windows-msvc` – Windows 64-bit MSVC
- `armv7-unknown-linux-gnueabihf` – Raspberry Pi 32-bit
- `wasm32-unknown-unknown` – WebAssembly
---
## ตัวอย่าง Cross-compile
```bash
# 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
---
## 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
CC = gcc
CFLAGS = -O2 -Wall -Wextra
TARGET = hello
SRCS = hello.c util.c
OBJS = $(SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
```
---
## การใช้งาน Make
```bash
make # build ทั้งหมด
make clean # ลบไฟล์ที่ build
make test # build แล้ว run test
make -j4 # build แบบ parallel 4 jobs
```
Phony target สำหรับคำสั่งพิเศษ:
```makefile
.PHONY: clean test
clean:
rm -f $(OBJS) $(TARGET)
test: $(TARGET)
./$(TARGET) Moo
```
---
## 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 เน้นความเร็วสูงสุด ไม่ออกแบบมาให้มนุษย์เขียนเอง
---
## ตัวอย่าง CMakeLists.txt
```cmake
cmake_minimum_required(VERSION 3.20)
project(HelloApp VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(hello
src/main.cpp
src/util.cpp
)
target_include_directories(hello PRIVATE include)
target_compile_options(hello PRIVATE -Wall -Wextra)
```
---
## คำสั่ง Build CMake
```bash
# 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 GNU Autotools
**GNU Autotools** เป็นชุดเครื่องมือคลาสสิก (autoconf, automake, libtool) ที่ Generate `configure` script สำหรับตรวจสอบ Environment ของระบบก่อน Build
ใช้ในโปรเจกต์ Open-source เก่า ๆ จำนวนมาก
```bash
# 1. Extract ซอร์สโค้ด
tar -xzf program-1.0.tar.gz
cd program-1.0
# 2. Configure
./configure --prefix=/usr/local
# 3. Build
make -j$(nproc)
# 4. Install
sudo make install
```
---
## 4.4.4 JVM Build Tools
**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
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")
}
```
```bash
./gradlew build && ./gradlew run && ./gradlew test
```
---
## 4.4.5 Node.js Package Managers
ในโลก JavaScript/TypeScript มี Package Manager หลายตัวที่รวมบทบาทของ Task Runner ไปด้วย
- **npm:** Built-in กับ Node.js เก่าที่สุดและใช้กันมากที่สุด
- **pnpm:** ใช้ symlink จาก Global Store ช่วยประหยัด disk space
- **yarn:** พัฒนาโดย Facebook แก้ปัญหาความเร็วของ npm รุ่นเก่า
- **Bun:** JavaScript Runtime + Package Manager + Bundler + Test Runner ในตัวเดียว เขียนด้วย Zig
---
## ตัวอย่าง package.json
```json
{
"name": "my-app",
"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"
}
}
```
---
## คำสั่ง Package Manager
```bash
npm install # ติดตั้ง dependencies
npm run dev # รัน script "dev"
pnpm install # เร็วและประหยัด disk กว่า
bun install # เร็วที่สุดในกลุ่ม
bun run build # เร็วมากเมื่อใช้กับ Bun runtime
```
---
## 4.4.6 Modern Language Toolchain
**Cargo (Rust):**
```bash
cargo new my_app # สร้างโปรเจกต์ใหม่
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
```bash
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
**uv** เขียนด้วย Rust เร็วกว่า pip 10–100 เท่า
```bash
# สร้างโปรเจกต์
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
**Task Runner** คือ Tool ที่ออกแบบมาเพื่อรันคำสั่งซ้ำ ๆ ในโปรเจกต์ คล้าย `make` แต่ไม่ใช่ Build System
- **Just:** ใช้ `justfile` syntax คล้าย Makefile แต่เรียบง่ายและไม่มี dependency graph ที่ซับซ้อน
- **Task:** ใช้ YAML config (Taskfile.yml) เขียนด้วย Go
- **Mask:** Task Runner ที่เขียน config เป็น Markdown
---
## ตัวอย่าง justfile
```just
default:
@just --list
dev:
uv run uvicorn app.main:app --reload --port 8000
test:
uv run pytest --cov=app tests/
fmt:
uv run ruff format .
uv run ruff check --fix .
build tag="latest":
docker build -t myapp:{{tag}} .
```
---
# 4.5 Debugger และ Profiler
---
## 4.5 Debugger และ Profiler
การหาสาเหตุของ bug และจุดที่ทำงานช้าเป็นงานสำคัญ
- **Debugger** ช่วยให้ดูการทำงานของโปรแกรมทีละขั้น
- **Profiler** ช่วยวิเคราะห์เรื่องประสิทธิภาพ
ทั้งสองเครื่องมือเป็นทักษะที่นักพัฒนาควรมีในระดับสูง
---
## 4.5.1 GDB และ LLDB
**GDB** เป็น Debugger มาตรฐานของ Unix/Linux สำหรับ C/C++/Rust/Go/Fortran รองรับ breakpoint, watchpoint, backtrace, หยุดที่ signal
**LLDB** เป็น Debugger จากโปรเจกต์ LLVM ใช้เป็น default บน macOS
```c
// buggy.c - มี bug (array out of bounds)
int main() {
int arr[5] = {1, 2, 3, 4, 5};
int sum = 0;
for (int i = 0; i <= 5; i++) // bug: i <= 5
sum += arr[i];
return 0;
}
```
---
## คำสั่ง GDB
```bash
gcc -g -O0 -o buggy buggy.c # Compile ด้วย debug symbol
gdb ./buggy
```
```text
(gdb) break main # set breakpoint
(gdb) run # รันโปรแกรม
(gdb) next # step over
(gdb) step # step into
(gdb) print sum # ดูค่าตัวแปร
(gdb) watch sum # watch การเปลี่ยนแปลง
(gdb) backtrace # ดู call stack
(gdb) continue # รันต่อ
(gdb) quit
```
---
## 4.5.2 strace, ltrace
**strace** – ติดตาม System Call ที่โปรแกรมเรียก ใช้หา bug ระดับ OS interaction
**ltrace** – ติดตาม Library Call (เช่น libc functions)
```bash
# ดู system call ของคำสั่ง ls ทั้งหมด
strace ls /tmp
# ติดตามเฉพาะบาง syscall
strace -e trace=open,openat,read cat /etc/hostname
# วัดเวลาที่ใช้ใน syscall แต่ละตัว
strace -c -f python3 myscript.py
```
---
## 4.5.3 Valgrind
**Valgrind** เป็นชุด tool สำหรับตรวจสอบ memory และ profiling โปรแกรม C/C++
- **Memcheck:** ตรวจหา memory leak, use-after-free, uninitialized read
- **Callgrind:** วัด function call count และ CPU cost
- **Massif:** วิเคราะห์การใช้ heap memory ตลอดเวลา
- **Helgrind:** ตรวจหา race condition ใน pthread programs
---
## ตัวอย่างการใช้ Valgrind
```bash
# ตรวจหา 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 ง่าย
```bash
sudo perf record -F 99 -g ./myprogram
sudo perf report
sudo perf script > out.perf
./stackcollapse-perf.pl out.perf | ./flamegraph.pl > flame.svg
```
---
## สมการ Sampling Rate Overhead
โดยที่ f = ความถี่ในการ sample (เช่น 99 Hz), tsample = เวลาที่ใช้ในการเก็บ 1 sample, tcpu = เวลา CPU ทั้งหมด
ยิ่ง Overhead ต่ำ ยิ่งได้ข้อมูลใกล้ความเป็นจริง
---
## 4.5.5 IDE Debugger Integration
IDE สมัยใหม่ผนวก Debugger เข้าผ่าน **Debug Adapter Protocol (DAP)** ทำให้ใช้ได้โดยไม่ต้องเปิด Terminal แยก
```json
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": false
}
]
}
```
---
# 4.6 Package Manager และ Dependency Management
---
## 4.6 Package Manager และ Dependency Management
**Package Manager** คือเครื่องมือที่ช่วยติดตั้ง อัปเดต และถอดถอน Library/โปรแกรมได้แบบอัตโนมัติ
โดยจัดการ Dependency ระหว่าง package ให้ด้วย
ครอบคลุม 4 ระดับ:
1. Language-specific Package Manager
2. System-level Package Manager
3. Environment Management
4. Lock File และ Reproducible Build
---
## 4.6.1 Language-specific Package Manager
แต่ละภาษามี Package Manager ประจำของตนเอง เก็บ Library ใน **Registry** ของตัวเอง
| ภาษา | Package Manager | Registry |
| --- | --- | --- |
| Python | pip, uv, Poetry | PyPI |
| JavaScript | npm, pnpm, yarn, Bun | npm registry |
| Rust | Cargo | crates.io |
| Go | go mod | proxy.golang.org |
| Ruby | gem, bundler | RubyGems |
| PHP | Composer | Packagist |
| Java | Maven, Gradle | Maven Central |
| .NET | NuGet | nuget.org |
---
## 4.6.2 System-level Package Manager
Package Manager ระดับ OS จัดการซอฟต์แวร์ทั้งระบบ
- **apt/dpkg:** Debian, Ubuntu
- **dnf/rpm:** Fedora, RHEL
- **pacman:** Arch Linux
- **zypper:** openSUSE
- **brew:** macOS (และ Linuxbrew บน Linux)
- **winget, Chocolatey, Scoop:** Windows
---
## 4.6.3 Environment Management
**Environment Manager** ช่วยให้มีหลาย version ของภาษาหรือ dependency แยกกันในเครื่องเดียว ป้องกันปัญหา "Works on my machine"
- **pyenv:** จัดการ Python หลาย version
- **nvm:** จัดการ Node.js หลาย version
- **rbenv:** จัดการ Ruby หลาย version
- **asdf:** Universal Version Manager
- **mise:** Fork ของ asdf เขียนด้วย Rust
- **venv:** Python virtual environment (built-in)
- **conda / mamba:** สำหรับ Data Science
---
## ตัวอย่างการใช้ mise
```bash
# ติดตั้ง 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 สำหรับโปรเจกต์
cd myproject
mise use python@3.12 node@20
mise current
```
---
## ตัวอย่าง venv ของ Python
```bash
# สร้าง 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
**Lock File** เป็นไฟล์ที่เก็บ version ที่ resolve แล้ว (exact version) ของ 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` |
| go mod | `go.sum` |
---
## หลักการสำคัญของ Lock File
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
---
## 4.7 Documentation Tools
เอกสารคือหนึ่งในองค์ประกอบสำคัญของซอฟต์แวร์ที่มักถูกละเลย
มีคำกล่าวที่ว่า "If it's not documented, it doesn't exist"
เครื่องมือสร้างเอกสารจึงมีบทบาทสำคัญในการผลักดันวัฒนธรรมการเขียนเอกสาร
---
## 4.7.1 Markdown และ CommonMark
**Markdown** คือภาษา Markup น้ำหนักเบาที่อ่านรู้เรื่องแม้เป็น plain text พัฒนาโดย John Gruber ปี 2004
**CommonMark** เป็นมาตรฐานที่กำหนดไวยากรณ์ให้ชัดเจน
**GitHub Flavored Markdown (GFM)** เป็น superset ที่เพิ่ม table, task list, strikethrough
---
## ตัวอย่าง Markdown พื้นฐาน
```markdown
# หัวเรื่องหลัก (H1)
## หัวข้อรอง (H2)
**ตัวหนา** และ *ตัวเอน* และ ~~ขีดฆ่า~~
- รายการแจกแจง 1
- รายการแจกแจง 2
1. ลำดับ 1
2. ลำดับ 2
> Blockquote สำหรับการอ้างอิง
[ข้อความลิงก์](https://example.com)
```
---
## 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 → EPUB
pandoc chapter*.md -o book.epub \
--metadata title="หนังสือของฉัน" \
--metadata author="Moo"
```
---
## 4.7.3 API Documentation Tools
**API Documentation** ถูกสร้างโดยอัตโนมัติจาก Comment ในโค้ด ทำให้เอกสารกับโค้ดอยู่ใกล้กันเสมอ
- **Doxygen:** สำหรับ C/C++/Java/Python รองรับ UML Diagram ผ่าน Graphviz
- **Sphinx:** มาตรฐานของ Python ใช้ reStructuredText หรือ Markdown
- **rustdoc:** Built-in กับ Rust compiler สร้างเอกสารจาก `///` comments
- **godoc / pkg.go.dev:** Built-in กับ Go
- **JSDoc / TypeDoc:** สำหรับ JavaScript/TypeScript
- **javadoc:** สำหรับ Java
---
## ตัวอย่าง Python Docstring
```python
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: หากความยาวไม่เท่ากัน
"""
return sum(g * c for g, c in zip(grades, credits)) / sum(credits)
```
---
## ตัวอย่าง Rust Docstring
```rust
/// คำนวณ GPA จากเกรดและหน่วยกิต
///
/// # Arguments
/// * `grades` - รายการคะแนนเกรด (0.0 - 4.0)
/// * `credits` - จำนวนหน่วยกิตของแต่ละวิชา
///
/// # Examples
/// ```
/// let gpa = calculate_gpa(&[4.0, 3.5], &[3, 3]);
/// ```
pub fn calculate_gpa(grades: &[f64], credits: &[u32]) -> f64 {
// ...
}
```
---
## คำสั่ง Generate Documentation
```bash
# Rust
cargo doc --open
# Go
godoc -http=:6060
# Python (Sphinx)
sphinx-quickstart docs
cd docs && make html
# TypeScript (TypeDoc)
npx typedoc --out docs src/index.ts
```
---
## 4.7.4 Static Site Generator
**Static Site Generator (SSG)** สร้าง HTML แบบ static จากไฟล์ Markdown เหมาะทำ Documentation Website, Blog, Landing Page
- **MkDocs + Material:** ง่ายที่สุด ใช้ Python เขียน Config เป็น YAML
- **Docusaurus:** จาก Meta ใช้ React รองรับ Versioning, i18n
- **VitePress:** จาก Vue.js เร็วและ modern ใช้ Vite
- **Hugo:** เขียนด้วย Go build เร็วที่สุด
- **Jekyll:** เขียนด้วย Ruby เป็น engine ของ GitHub Pages เดิม
- **Zola:** SSG ที่เขียนด้วย Rust
---
## ตัวอย่าง mkdocs.yml
```yaml
site_name: My Project Documentation
theme:
name: material
palette:
- scheme: slate
primary: deep orange
features:
- navigation.tabs
- search.suggest
nav:
- Home: index.md
- Getting Started: getting-started.md
- API Reference: api.md
```
---
## คำสั่ง MkDocs
```bash
# สร้าง
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
**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 Page
```bash
man ls # ดู man page ของ ls
man 2 open # ดู man ของ open system call
man -k network # ค้นหา man page ที่มีคำว่า network
man -f printf # ดูทุก section ที่มี printf
apropos compression # ค้นหา man page ที่เกี่ยวกับ compression
```
---
# 4.8 CI / CD
---
## 4.8.1 แนวคิด CI / CD / CDE
- **Continuous Integration (CI):** การรวมโค้ดจากหลายนักพัฒนาเข้าด้วยกันบ่อย ๆ (อย่างน้อยวันละครั้ง) โดยมีการ Build และ Test อัตโนมัติทุกครั้ง
- **Continuous Delivery (CD):** การเตรียมซอฟต์แวร์ให้พร้อม Deploy ตลอดเวลา (แต่การ Deploy ยังทำด้วยมือ)
- **Continuous Deployment (CDE):** การ Deploy อัตโนมัติสู่ production ทุกครั้งที่โค้ดผ่านการทดสอบ
---
## CI/CD Pipeline Diagram
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#3c3836', 'primaryTextColor':'#ebdbb2', 'primaryBorderColor':'#928374', 'lineColor':'#ebdbb2', 'background':'#282828'}}}%%
flowchart TB
A[Commit
git push]:::gruvblue --> B[CI Trigger]:::gruvaqua
B --> C[Build]:::gruvgreen --> D[Test]:::gruvyellow
D --> E{ผ่าน?}:::gruvorange
E -->|ไม่ผ่าน| F[Notify]:::gruvred
E -->|ผ่าน| G[Docker Image]:::gruvpurple
G --> H[Deploy Staging]:::gruvaqua
H --> I{Approval?}:::gruvorange
I -->|CD| J[Manual Deploy]:::gruvgreen
I -->|CDE| K[Auto Deploy]:::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
**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 = จำนวน 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)
**แนวคิดสำคัญ:**
- **Trigger:** เหตุการณ์ที่จุดประกาย Pipeline
- **Runner/Agent:** เครื่องที่รัน Job
- **Artifact:** ผลผลิตของ Job
- **Cache:** ข้อมูลที่เก็บไว้ใช้ซ้ำ
- **Secrets:** ข้อมูลลับเก็บแยกจาก config
---
## 4.8.3 CI Platforms
- **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
```yaml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.11', '3.12']
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v3
- run: uv sync --all-extras --dev
- run: uv run pytest --cov=src
```
---
## GitHub Actions: Build Docker
```yaml
build-docker:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v5
with:
push: true
tags: ghcr.io/${{ github.repository }}:latest
```
---
## ตัวอย่าง GitLab CI
```yaml
stages: [test, build, deploy]
variables:
PYTHON_VERSION: "3.12"
test:
stage: test
image: python:${PYTHON_VERSION}-slim
before_script:
- pip install uv
- uv sync --dev
script:
- uv run pytest --cov=src
deploy:
stage: deploy
when: manual
only: [main]
```
---
## 4.8.4 Artifact และ Release
**Artifact** คือผลผลิตของการ Build เช่น JAR, WAR, Executable, Docker Image, npm package, Wheel (`.whl`)
**Artifact Repository** เก็บและแจกจ่าย Artifact:
- **Docker Hub, GHCR, GitLab Registry:** สำหรับ Container Image
- **npm Registry, Maven Central, PyPI:** สำหรับ Library
- **Nexus, Artifactory:** Self-hosted สำหรับ Enterprise
- **GitHub/GitLab Releases:** สำหรับ Release binary
**Release** เป็นการแพคเกจ artifact พร้อม release notes และ semantic version
---
# 4.9 Testing Tools
---
## 4.9 Testing Tools และ Test Pyramid
การทดสอบเป็นส่วนสำคัญที่ป้องกันไม่ให้ bug หลุดขึ้น production
**Test Pyramid** เป็นหลักการจัดสัดส่วนของ test ที่แนะนำ:
- **E2E / UI Test:** น้อย 5-10% (ช้า, แพง, บอบบาง)
- **Integration Test:** ปานกลาง 20-30%
- **Unit Test:** มาก 60-70% (เร็ว, เจาะจง, เชื่อถือได้)
---
## Test Pyramid Diagram
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#3c3836', 'primaryTextColor':'#ebdbb2', 'primaryBorderColor':'#928374', 'lineColor':'#ebdbb2', 'background':'#282828'}}}%%
flowchart TB
E2E["E2E / UI Test
(5-10%)
ช้า, แพง, บอบบาง"]:::gruvred
INT["Integration Test
(20-30%)
ทดสอบการทำงานร่วม"]:::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
**Unit Test** ทดสอบหน่วยเล็กที่สุด (function, method) แยกต่างหาก
เครื่องมือยอดนิยมในแต่ละภาษา:
- Python: pytest, unittest
- Java: JUnit
- JavaScript/TypeScript: Jest, Vitest
- Go: go test
- Rust: cargo test
---
## ตัวอย่าง pytest
```python
# tests/test_calculator.py
import pytest
from src.calculator import add, divide
def test_add_positive():
assert add(2, 3) == 5
@pytest.mark.parametrize("a,b,expected", [
(10, 2, 5.0), (15, 3, 5.0), (7, 2, 3.5),
])
def test_divide(a, b, expected):
assert divide(a, b) == expected
def test_divide_by_zero():
with pytest.raises(ValueError):
divide(10, 0)
```
---
## คำสั่ง pytest
```bash
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)
```typescript
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.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
```go
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; want %d", got, tt.expected)
}
})
}
}
```
---
## คำสั่ง Go test
```bash
go test ./... # รันทั้งหมด
go test -v # verbose
go test -run TestAdd # รันเฉพาะ test
go test -bench=. # รัน benchmark
go test -cover # coverage
```
---
## 4.9.2 Integration & E2E Testing
**Integration Test** ทดสอบการทำงานร่วมกันของหลาย module
**E2E Test** ทดสอบระบบทั้งหมดจากมุมมองผู้ใช้
- **Selenium:** เก่าแก่ที่สุด รองรับ WebDriver หลาย browser
- **Playwright:** จาก Microsoft รองรับ Chromium, Firefox, WebKit ในตัว auto-wait ดีมาก
- **Cypress:** ทำงานในเบราว์เซอร์โดยตรง debug ง่าย UI สวย
---
## ตัวอย่าง Playwright
```typescript
import { test, expect } from '@playwright/test';
test('successful login redirects to dashboard', async ({ page }) => {
await page.goto('https://app.example.com/login');
await page.fill('input[name="email"]', 'user@example.com');
await page.fill('input[name="password"]', 'password123');
await page.click('button[type="submit"]');
await expect(page).toHaveURL(/.*dashboard/);
await expect(page.locator('h1')).toContainText('Welcome');
});
```
---
## คำสั่ง Playwright
```bash
npx playwright test
npx playwright test --ui # เปิด UI mode
npx playwright test --headed # เห็น browser
npx playwright show-report # ดูรายงาน
```
---
## 4.9.3 Code Coverage
**Code Coverage** วัดว่า test ทดสอบโค้ดกี่เปอร์เซ็นต์ มีหลายระดับ:
1. **Line Coverage:** แต่ละบรรทัดถูก execute หรือไม่
2. **Branch Coverage:** แต่ละสาขาของ if/else ถูก execute
3. **Function Coverage:** แต่ละ function ถูกเรียก
4. **Statement Coverage:** แต่ละ statement ถูก execute
---
## สมการ Code Coverage
โดยที่ Lexecuted = จำนวนบรรทัดที่ถูกรัน และ Ltotal = จำนวนบรรทัดทั้งหมด
แต่ทีมควรเน้นคุณภาพของ test มากกว่าการไล่ตามเปอร์เซ็นต์ Coverage 100% ไม่ได้หมายความว่าไม่มี bug
---
## คำสั่ง Coverage
```bash
# Python
pytest --cov=src --cov-report=html --cov-report=term-missing
# 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 นั้นอ่อนแอ
- mutmut, cosmic-ray (Python)
- PIT (Java), Stryker (JS)
- cargo-mutants (Rust)
**Fuzz Testing** ป้อน input แบบสุ่มเพื่อหา crash, hang, security vulnerability
- AFL++, libFuzzer
- cargo fuzz (Rust), go test -fuzz (Go 1.18+)
- Atheris (Python)
---
## ตัวอย่าง Go Fuzz Testing
```go
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)
}
})
}
```
```bash
go test -fuzz=FuzzReverse -fuzztime=30s
```
---
# 4.10 API Testing และ HTTP Client
---
## 4.10.1 CLI Tools
**curl** – CLI คลาสสิกสำหรับ HTTP(S) และโปรโตคอลอื่น ๆ มีบน Linux/macOS/Windows
**HTTPie** – CLI ที่ทำให้ request HTTP ดูสวยและอ่านง่าย
**xh** – Alternative ของ HTTPie เขียนด้วย Rust เร็วกว่า
---
## ตัวอย่าง curl
```bash
# 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 และ xh
```bash
# 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
```bash
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 API Clients
**GUI API Client** เหมาะสำหรับสำรวจ API ใหม่, จัดการ collection ของ request, ทำ automated test
- **Postman:** ครบที่สุด แต่ login บังคับและ sync cloud
- **Insomnia:** เรียบง่ายกว่า open-source บางส่วน
- **Bruno:** Fully open-source, git-friendly (เก็บ request เป็นไฟล์ `.bru`)
- **Hoppscotch:** Web-based (PWA) open-source
- **Yaak, Kreya:** ทางเลือกใหม่ ๆ
---
## 4.10.3 IDE Plugin
Extension ของ IDE ช่วยให้ส่ง request ได้จากในไฟล์ `.http` โดยไม่ต้องออกจาก editor
```http
### 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"
}
```
---
## 4.10.4 OpenAPI / Swagger
**OpenAPI Specification (OAS)** เดิมเรียก Swagger คือมาตรฐานอธิบาย REST API ในรูป YAML/JSON
สามารถ generate client SDK, documentation, mock server ได้อัตโนมัติ
```yaml
openapi: 3.0.3
info:
title: Student API
version: 1.0.0
servers:
- url: https://api.example.com/v1
paths:
/students:
get:
summary: List all students
```
---
## OpenAPI Schema
```yaml
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
```
---
## OpenAPI Ecosystem
Tool ที่ใช้กับ OpenAPI:
- **Swagger UI / Redoc / Scalar:** สร้างเอกสาร interactive
- **openapi-generator:** generate client SDK กว่า 50 ภาษา
- **Prism, WireMock:** สร้าง Mock Server
- **Spectral:** Linter สำหรับ OpenAPI spec
---
# 4.11 Code Quality Tools
---
## 4.11 Code Quality Tools
โค้ดที่ทำงานได้ ≠ โค้ดที่ดี
โค้ดที่ดีต้องอ่านง่าย บำรุงรักษาได้ ทีมอ่านตรงกัน
**Code Quality Tools** ช่วยบังคับมาตรฐานเหล่านี้โดยอัตโนมัติ
แบ่งเป็น 3 กลุ่มหลัก:
1. Linter (วิเคราะห์โค้ด)
2. Formatter (จัดรูปแบบ)
3. Pre-commit Hook (บังคับใช้ก่อน commit)
---
## 4.11.1 Linter
**Linter** วิเคราะห์โค้ดแบบ static เพื่อหาปัญหาที่อาจเกิดขึ้น เช่น ตัวแปรที่ไม่ใช้, dead code, anti-pattern, bug
| ภาษา | Linter | หมายเหตุ |
| --- | --- | --- |
| Python | Ruff | เขียนด้วย Rust เร็วกว่า Pylint 10-100x |
| JS/TS | ESLint, Biome | Biome เขียนด้วย Rust |
| Shell | ShellCheck | จับ bug bash/sh |
| Go | golangci-lint | รวม linter หลายตัว |
| Rust | clippy | มากับ rustup |
| C/C++ | clang-tidy, cppcheck | |
| Docker | hadolint | |
---
## ตัวอย่าง Ruff Config
```toml
[tool.ruff]
line-length = 100
target-version = "py312"
[tool.ruff.lint]
select = [
"E", "W", # pycodestyle
"F", # pyflakes
"I", # isort
"N", # pep8-naming
"UP", # pyupgrade
"B", # flake8-bugbear
"SIM", # flake8-simplify
"RUF", # Ruff-specific
]
```
---
## คำสั่ง Ruff
```bash
# ตรวจอย่างเดียว
ruff check .
# แก้อัตโนมัติเท่าที่ทำได้
ruff check --fix .
# Watch mode
ruff check --watch .
```
---
## ตัวอย่าง ShellCheck
```bash
#!/bin/bash
# bad_script.sh - script ที่มี bug ทั่วไป
# bug: ไม่ quote variable
FILE=/tmp/my file.txt
cat $FILE
# bug: ใช้ $? แทน exit code โดยตรง
grep "pattern" input.txt
if [ $? -eq 0 ]; then
echo "Found"
fi
```
```text
shellcheck bad_script.sh
# SC2086: Double quote to prevent globbing
# SC2181: Check exit code directly
```
---
## 4.11.2 Formatter
**Formatter** จัดรูปแบบโค้ดให้สวยงามและสม่ำเสมอ ข้อดีคือเลิกทะเลาะเรื่อง indent/bracket กันในทีม
- **Prettier:** มาตรฐานของ JS/TS/JSON/CSS/HTML
- **Biome:** Prettier + ESLint เขียนด้วย Rust
- **Black:** "Uncompromising" formatter ของ Python
- **Ruff format:** เข้ากันได้กับ Black
- **gofmt / goimports:** Built-in ของ Go
- **rustfmt:** Built-in ของ Rust
- **shfmt:** สำหรับ shell script
- **clang-format:** สำหรับ C/C++
---
## คำสั่ง Formatter
```bash
# ตรวจว่า 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 หลายตัวรวมกัน
ช่วยรับประกันว่าโค้ดที่ commit เข้ามาผ่านมาตรฐานคุณภาพเบื้องต้น
---
## ตัวอย่าง pre-commit Config
```yaml
repos:
- 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']
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.6.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format
```
---
## เพิ่มเติม Hooks
```yaml
# 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
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
```
---
## การใช้งาน pre-commit
```bash
# ติดตั้ง 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 เพื่อจับคนที่ bypass ด้วย `--no-verify`
---
# ประวัติและวิวัฒนาการของ Development Tools
---
## ประวัติและวิวัฒนาการ
เพื่อความเข้าใจบริบท เครื่องมือพัฒนาซอฟต์แวร์มีวิวัฒนาการมายาวนานตั้งแต่ยุค Mainframe จนถึง AI-native ปัจจุบัน
แบ่งเป็น 6 ยุคหลัก:
1. **Mainframe** (1950-1970)
2. **Unix Era** (1970-1990)
3. **GUI IDE** (1990-2005)
4. **DVCS + Open Source** (2005-2015)
5. **Cloud-Native + DevOps** (2015-2022)
6. **AI-Native** (2022-ปัจจุบัน)
---
## ยุค 1-2: Mainframe และ Unix
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#3c3836', 'primaryTextColor':'#ebdbb2', 'primaryBorderColor':'#928374', 'lineColor':'#ebdbb2', 'background':'#282828'}}}%%
flowchart LR
subgraph Era1["Mainframe (1950-1970)"]
A1[Assembler
1950s] --> A2[FORTRAN
1957]
A2 --> A3[ed editor
1969]
end
subgraph Era2["Unix Era (1970-1990)"]
B1[vi
1976] --> B2[Make
1976]
B2 --> B3[SCCS/RCS
1972/1982]
B3 --> B4[GCC
1987]
end
Era1 --> Era2
---
## ยุค 3-4: GUI IDE และ DVCS
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#3c3836', 'primaryTextColor':'#ebdbb2', 'primaryBorderColor':'#928374', 'lineColor':'#ebdbb2', 'background':'#282828'}}}%%
flowchart LR
subgraph Era3["GUI IDE (1990-2005)"]
C1[Visual Basic
1991] --> C2[Eclipse
2001]
C2 --> C3[IntelliJ
2001] --> C4[CVS/SVN]
end
subgraph Era4["DVCS (2005-2015)"]
D1[Git
2005] --> D2[GitHub
2008]
D2 --> D3[Jenkins
2011] --> D4[Docker
2013]
end
Era3 --> Era4
---
## ยุค 5-6: Cloud-Native และ AI-Native
%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#3c3836', 'primaryTextColor':'#ebdbb2', 'primaryBorderColor':'#928374', 'lineColor':'#ebdbb2', 'background':'#282828'}}}%%
flowchart LR
subgraph Era5["Cloud-Native (2015-2022)"]
E1[VS Code
2015] --> E2[Kubernetes
2015]
E2 --> E3[GitHub Actions
2019] --> E4[LSP
2016]
end
subgraph Era6["AI-Native (2022-now)"]
F1[Copilot
2022] --> F2[Cursor
2023]
F2 --> F3[Aider/Zed
2024] --> F4[Claude Code/MCP
2024-2025]
end
Era5 --> Era6
---
## เทรนด์ปัจจุบัน 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
---
## สรุปภาพรวม
Development Tools เป็นรากฐานของการพัฒนาซอฟต์แวร์สมัยใหม่ ครอบคลุม:
- **Editor/IDE** → เขียนโค้ด
- **Compiler/Interpreter** → แปลโค้ด
- **Build System** → จัดการการ build
- **Debugger/Profiler** → หา bug และวัด performance
- **Package Manager** → จัดการ dependency
- **Documentation** → เขียนเอกสาร
- **CI/CD** → automation
- **Testing** → ทดสอบคุณภาพ
- **Code Quality** → บังคับมาตรฐาน
การเลือก Toolchain ที่เหมาะกับงานคือกุญแจสู่ DevEx ที่ดี
---
# คําถาม - ข้อสงสัย