Code style ที่สม่ำเสมอเป็นเรื่องสำคัญในทีม — ช่วยให้ review code เร็วขึ้น diff สะอาด และลดเวลาถกเถียงเรื่อง format HCL มีเครื่องมือ built-in terraform fmt ที่ช่วยจัด format อัตโนมัติตาม convention อย่างเป็นทางการ
บทความนี้จะสอนการใช้ terraform fmt, แนวทาง code style ที่ HashiCorp แนะนำ, และวิธี integrate เข้ากับ git hook / CI เพื่อให้ทุกคนในทีม commit code ที่ format ถูกต้อง
คำสั่ง fmt คืออะไร
terraform fmt เป็น sub-command ที่ช่วย reformat ไฟล์ .tf และ .tfvars ให้ตรงตาม canonical style — จัด indent, alignment ของ =, และ whitespace ให้เป็นมาตรฐานเดียว
# format ไฟล์ใน directory ปัจจุบัน
terraform fmt
# format recursive ลงไปใน subfolder
terraform fmt -recursive
# ดูว่าไฟล์ไหน format ไม่ถูก (ไม่แก้จริง — เหมาะกับ CI)
terraform fmt -check
# ดู diff ของการเปลี่ยนแปลง
terraform fmt -diff
# format จาก stdin
echo 'resource "foo" "bar" { x=1 }' | terraform fmt -
สิ่งที่ fmt จัดให้
- Indent 2 spaces (ไม่ใช่ tab)
- Align
=ของ argument ภายใน block เดียวกัน - Blank line ระหว่าง block
- ลบ trailing whitespace
- แก้ quotes ที่ไม่จำเป็น (เช่น
"var.x"→var.xใน interpolation)
ตัวอย่าง Before / After
# Before
resource "aws_instance" "web" {
ami=var.ami_id
instance_type = var.instance_type
tags={Name="web-server"}
}
# After fmt
resource "aws_instance" "web" {
ami = var.ami_id
instance_type = var.instance_type
tags = { Name = "web-server" }
}
Style Guide ที่แนะนำ
นอกจาก fmt ที่แก้ให้อัตโนมัติ ยังมีแนวทางที่ต้องเขียนเองให้สม่ำเสมอ
1. จัดเรียง Argument ภายใน Block
ให้ปฏิบัติตามลำดับ: required argument ก่อน, optional argument ตาม, meta-argument (depends_on, count, for_each, lifecycle) ไว้ท้ายสุด
resource "aws_instance" "web" {
# Required
ami = var.ami_id
instance_type = var.instance_type
# Optional
key_name = aws_key_pair.deploy.key_name
vpc_security_group_ids = [aws_security_group.web.id]
subnet_id = aws_subnet.public.id
tags = {
Name = "web-server"
Environment = var.environment
}
# Meta-arguments (ท้ายสุด)
depends_on = [aws_internet_gateway.main]
lifecycle {
create_before_destroy = true
}
}
2. เขียน Comment เมื่อจำเป็น
- ใช้
#สำหรับ comment บรรทัดเดียว (แนะนำกว่า//) - ใช้
/* ... */สำหรับ comment หลายบรรทัด - อธิบาย “ทำไม” ไม่ใช่ “ทำอะไร” — code บอกว่าทำอะไรอยู่แล้ว
# ใช้ t3.small เพราะ load ยังน้อย เพิ่มทีหลังถ้า traffic โต
resource "aws_instance" "web" {
instance_type = "t3.small"
}
3. เรียง Variable และ Output ตามลำดับที่สมเหตุสมผล
- Group ตาม category (network, compute, database)
- Required variable (ไม่มี default) มาก่อน optional
- เรียง alphabetical ภายใน group ก็ได้ถ้าไม่มี logical order
4. ใช้ Whitespace ให้เหมาะสม
- Blank line คั่นระหว่าง resource block
- Blank line คั่นระหว่าง group ของ argument (required / optional / meta)
- ไม่มี blank line เกิน 1 บรรทัดติดกัน
Integrate กับ Git Pre-commit Hook
Pre-commit hook จะรัน fmt อัตโนมัติก่อน commit — ป้องกัน commit code ที่ format ไม่ถูก
# .git/hooks/pre-commit (ไฟล์ใน local repo)
#!/bin/bash
set -e
CHANGED_TF=$(git diff --cached --name-only --diff-filter=ACM | grep '\.tf$' || true)
if [ -n "$CHANGED_TF" ]; then
terraform fmt -check $CHANGED_TF
if [ $? -ne 0 ]; then
echo "ERROR: HCL files not formatted. Run 'fmt' command."
exit 1
fi
fi
วิธีที่ดีกว่าคือใช้ pre-commit framework ซึ่ง share config ได้ทั้งทีม:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.86.0
hooks:
- id: terraform_fmt
- id: terraform_validate
- id: terraform_tflint
pip install pre-commit
pre-commit install
# ตอนนี้ทุก commit จะรัน fmt + validate + tflint อัตโนมัติ
Integrate ใน CI Pipeline
ใน CI ให้รัน fmt -check -recursive เพื่อ fail build ถ้ามีไฟล์ที่ format ไม่ถูก — ป้องกัน code ที่ lint ไม่ผ่าน merge เข้า main branch
# GitHub Actions ตัวอย่าง
name: Terraform Lint
on: [push, pull_request]
jobs:
fmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.6.0
- name: Check formatting
run: terraform fmt -check -recursive -diff
คำสั่ง validate
คู่กับ fmt ควรใช้ validate ตรวจ syntax และ internal consistency ของ config
# ต้อง init ก่อนรัน validate
terraform init -backend=false
terraform validate
# ตัวอย่าง error ที่ validate จับได้:
# - reference variable ที่ไม่มี declaration
# - argument ที่ไม่มีใน schema ของ resource
# - type mismatch
IDE Integration
- VS Code — extension
HashiCorp Terraformรัน fmt on save ได้ - JetBrains (IntelliJ/GoLand) — plugin “HashiCorp Terraform and HCL” รองรับ format + syntax highlight
- Vim / Neovim — plugin
vim-terraformทำ autofmt on save
ตั้งค่า VS Code auto-format
// .vscode/settings.json
{
"[terraform]": {
"editor.defaultFormatter": "hashicorp.terraform",
"editor.formatOnSave": true,
"editor.formatOnSaveMode": "file"
}
}
Best Practices
- รัน
terraform fmt -recursiveก่อน commit ทุกครั้ง - ติดตั้ง pre-commit hook ในทีมให้ทุกคน — ใช้ pre-commit framework จะ share config ง่าย
- เพิ่ม
terraform fmt -check -recursiveใน CI เพื่อ enforce ระดับ PR - ใช้
terraform validateคู่กับ fmt ตรวจ syntax error - ตั้ง IDE ให้ format on save เพื่อไม่ต้องจำรัน fmt เอง
- เรียง argument ภายใน block: required → optional → meta-argument
- เขียน comment เฉพาะเมื่ออธิบาย “ทำไม” ไม่ใช่ “ทำอะไร”
- commit
.pre-commit-config.yamlและ.vscode/settings.json(ไม่ใส่ใน .gitignore) เพื่อ share config ทีม
สรุป
Code style ที่สม่ำเสมอเริ่มจากการใช้ fmt เป็นเครื่องมือพื้นฐาน — integrate กับ pre-commit hook และ CI เพื่อให้ทุกคนในทีม commit code ที่ format ถูกต้อง ลด overhead ของการ review code เรื่อง cosmetic และหันไปโฟกัสกับ logic ที่สำคัญกว่า ในบทความถัดไปจะพูดถึง validate และ tflint สำหรับการ lint code ลึกกว่าแค่ format — ตรวจ best practice และ bug ที่ syntactically ถูกต้องแต่ผิด pattern

