Anti-Pattern Datasource #

Data source adalah fitur yang kuat tapi mudah disalahgunakan. Penggunaan yang tidak tepat menghasilkan konfigurasi yang rapuh — plan yang gagal karena resource yang dicari tidak ditemukan, coupling antar workspace yang terlalu ketat, atau konfigurasi yang diam-diam berubah perilakunya karena data source mengembalikan hasil yang berbeda. Artikel ini mengompilasi anti-pattern yang paling sering ditemukan dalam konfigurasi Terraform di production.

Anti-Pattern 1: Filter yang Tidak Spesifik #

Data source yang bisa mengembalikan lebih dari satu hasil adalah bom waktu — ia berjalan baik hari ini, tapi gagal begitu ada resource baru yang cocok dengan filter yang sama.

# ANTI-PATTERN: Filter berdasarkan state saja — terlalu lebar
data "aws_instance" "app_server" {
  filter {
    name   = "instance-state-name"
    values = ["running"]
  }
  # Di environment dev mungkin hanya ada 1 instance running
  # Di production ada 10 — ERROR: Your query returned more than one result
}

# ANTI-PATTERN: Tidak ada filter sama sekali
data "aws_vpc" "main" {
  # Tidak ada filter atau ID — Terraform akan error jika ada lebih dari 1 VPC
}

# BENAR: Filter yang cukup spesifik untuk mengembalikan tepat 1 hasil
data "aws_instance" "app_server" {
  filter {
    name   = "tag:Name"
    values = ["app-server-production"]
  }

  filter {
    name   = "tag:Environment"
    values = [var.environment]
  }

  filter {
    name   = "instance-state-name"
    values = ["running"]
  }
}

Anti-Pattern 2: Data Source sebagai Pengganti Import #

Data source hanya membaca resource — ia tidak membuat Terraform “mengelola” resource tersebut. Menggunakan data source sebagai cara untuk “menggunakan” resource yang seharusnya diimport adalah kesalahpahaman yang umum.

# ANTI-PATTERN: Menggunakan data source untuk resource yang ingin dikelola

# Tim mengelola VPC secara manual dan ingin Terraform ikut mengelola
# tagnya, security group-nya, dll. Tapi mereka menggunakan data source:

data "aws_vpc" "main" {
  id = "vpc-0abcdef1234567890"
}

# Lalu mencoba "update" VPC via resource yang berbeda:
resource "aws_vpc_ipv4_cidr_block_association" "secondary" {
  vpc_id     = data.aws_vpc.main.id  # Referensi ke VPC via data source
  cidr_block = "10.1.0.0/16"
}

# Masalah: Terraform tidak mengelola VPC itu sendiri
# Jika VPC dihapus secara manual, plan akan error
# Tags, DNS settings, dll. tidak bisa dikelola via data source

# BENAR: Import VPC ke Terraform state dan kelola sebagai resource
# terraform import aws_vpc.main vpc-0abcdef1234567890

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  # Sekarang Terraform mengelola VPC ini sepenuhnya
}

Anti-Pattern 3: Overuse terraform_remote_state #

terraform_remote_state menciptakan coupling langsung antara dua workspace — perubahan di workspace sumber bisa memecah workspace yang membacanya.

# ANTI-PATTERN: Setiap workspace membaca state dari banyak workspace lain

# workspace "app" membaca dari 5 workspace berbeda
data "terraform_remote_state" "networking" { ... }
data "terraform_remote_state" "security" { ... }
data "terraform_remote_state" "dns" { ... }
data "terraform_remote_state" "certificates" { ... }
data "terraform_remote_state" "iam" { ... }

# Masalah:
# - "app" workspace tidak bisa dijalankan jika salah satu dari 5 workspace ini
#   belum pernah di-apply (state tidak ada)
# - Setiap perubahan output di workspace manapun bisa memecah "app"
# - Sulit di-test secara terisolasi
# BENAR: Gunakan variable input untuk decoupling

# Workspace app menerima nilai yang dibutuhkan via variable
variable "vpc_id" {
  description = "ID VPC dari workspace networking"
  type        = string
}

variable "private_subnet_ids" {
  description = "List ID private subnet dari workspace networking"
  type        = list(string)
}

# Nilai dioper eksplisit saat apply — tidak ada dependency pada state workspace lain
# terraform apply -var="vpc_id=vpc-abc" -var-file="networking-outputs.tfvars"

Anti-Pattern 4: Data Source untuk Nilai yang Seharusnya Variable #

Menggunakan data source untuk mendapatkan nilai yang sebenarnya bisa dioper sebagai variable membuat konfigurasi bergantung pada kondisi cloud yang mungkin berubah.

# ANTI-PATTERN: Query VPC untuk mendapatkan CIDR, lalu gunakan untuk kalkulasi
data "aws_vpc" "main" {
  id = var.vpc_id
}

# Kalkulasi subnet CIDR dari VPC CIDR yang di-query
resource "aws_subnet" "app" {
  cidr_block = cidrsubnet(data.aws_vpc.main.cidr_block, 8, 1)
  # Masalah: jika CIDR block VPC berubah, kalkulasi subnet juga berubah
  # Perubahan yang tidak terduga pada VPC bisa menyebabkan subnet di-replace
}

# BENAR: Oper nilai yang dibutuhkan sebagai variable eksplisit
variable "vpc_cidr" {
  description = "CIDR block VPC"
  type        = string
}

resource "aws_subnet" "app" {
  cidr_block = cidrsubnet(var.vpc_cidr, 8, 1)
  # Nilai eksplisit — hanya berubah jika variable berubah
}

Anti-Pattern 5: Data Source Tanpa Error Handling #

Data source yang tidak menemukan resource akan error saat plan. Tanpa penanganan yang tepat, ini bisa memblokir seluruh pipeline.

# ANTI-PATTERN: Data source yang mungkin tidak ada di semua environment
data "aws_route53_zone" "main" {
  name = "myapp.com"
  # Di environment dev mungkin tidak ada hosted zone ini
  # → Plan di dev selalu error
}

# BENAR: Gunakan count atau conditional untuk data source yang mungkin tidak ada
variable "create_dns_records" {
  type    = bool
  default = false
}

data "aws_route53_zone" "main" {
  count = var.create_dns_records ? 1 : 0
  name  = "myapp.com"
}

resource "aws_route53_record" "app" {
  count   = var.create_dns_records ? 1 : 0
  zone_id = data.aws_route53_zone.main[0].zone_id
  name    = "app.myapp.com"
  type    = "A"
  # ...
}

Anti-Pattern 6: Data Source yang Query Resource Sendiri #

Beberapa developer menggunakan data source untuk membaca resource yang ada di konfigurasi yang sama. Ini tidak perlu — referensi langsung lebih bersih dan lebih efisien.

# ANTI-PATTERN: Data source untuk membaca resource di konfigurasi yang sama
resource "aws_security_group" "web" {
  name   = "web-sg"
  vpc_id = aws_vpc.main.id
}

# Tidak perlu data source untuk baca security group yang baru dibuat!
data "aws_security_group" "web" {
  name   = "web-sg"
  vpc_id = aws_vpc.main.id

  depends_on = [aws_security_group.web]  # ✗ Berputar-putar
}

resource "aws_instance" "web" {
  vpc_security_group_ids = [data.aws_security_group.web.id]  # ✗ Tidak perlu
}

# BENAR: Referensi langsung ke resource
resource "aws_instance" "web" {
  vpc_security_group_ids = [aws_security_group.web.id]  # ✓ Langsung dan bersih
}

Ringkasan #

  • Filter harus cukup spesifik untuk selalu mengembalikan tepat satu hasil — filter yang ambigu berjalan di dev tapi bisa error di production.
  • Data source bukan pengganti import — jika ingin Terraform mengelola resource, import ke state. Data source hanya membaca, tidak mengelola.
  • Batasi penggunaan terraform_remote_state — coupling yang berlebihan antar workspace membuat konfigurasi sulit dijalankan secara terisolasi. Pertimbangkan variable input sebagai alternatif.
  • Jangan query via data source untuk nilai yang bisa dioper sebagai variable — variable membuat dependency lebih eksplisit dan konfigurasi lebih mudah diprediksi.
  • Gunakan count untuk data source yang mungkin tidak ada di semua environment — mencegah plan gagal hanya karena resource tidak ada di environment tertentu.
  • Referensi langsung ke resource dalam konfigurasi yang sama — tidak perlu data source untuk membaca resource yang ada di konfigurasi yang sama.

← Sebelumnya: Reference   Berikutnya: Apa itu Module? →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact