Reusability

Reusability #

Membuat role yang benar-benar reusable lebih sulit dari yang terlihat. Mudah membuat role yang bekerja di satu proyek — tapi membuat role yang bisa dengan mudah digunakan di proyek lain, oleh tim lain, dengan infrastruktur yang berbeda, membutuhkan pertimbangan desain yang lebih dalam. Artikel ini membahas prinsip-prinsip yang membuat role benar-benar reusable, bukan hanya “bisa dipakai ulang kalau situasinya persis sama”.

Masalah Role yang Tidak Reusable #

Role yang tidak reusable biasanya punya satu atau lebih dari ciri berikut:

# ANTI-PATTERN: role yang hardcode nilai spesifik
# roles/nginx/tasks/configure.yml
- name: Deploy konfigurasi nginx
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf

# roles/nginx/templates/nginx.conf.j2
server {
    listen 80;
    server_name app.mycompany.com;     # ← Hardcoded! Tidak bisa digunakan proyek lain
    root /opt/myapp/public;            # ← Hardcoded! Path spesifik proyek ini
    
    location / {
        proxy_pass http://127.0.0.1:8080;  # ← Hardcoded! Port spesifik
    }
}

Role ini hanya bekerja untuk app.mycompany.com dengan path /opt/myapp/public. Untuk proyek lain, kamu harus memodifikasi role — yang berarti versi role di proyek pertama dan kedua bisa berbeda dan tidak sync.


Prinsip 1: Semua Nilai Spesifik Harus Jadi Variabel #

Setiap nilai yang mungkin berbeda antar proyek harus bisa dikustomisasi melalui variabel:

# BENAR: semua nilai spesifik jadi variabel
# roles/nginx/defaults/main.yml
nginx_server_name: "{{ inventory_hostname }}"   # Default: hostname server
nginx_document_root: /var/www/html
nginx_upstream_host: 127.0.0.1
nginx_upstream_port: 8080
{# roles/nginx/templates/nginx.conf.j2 #}
server {
    listen {{ nginx_port }};
    server_name {{ nginx_server_name }};
    root {{ nginx_document_root }};

    location / {
        proxy_pass http://{{ nginx_upstream_host }}:{{ nginx_upstream_port }};
    }
}

Sekarang role ini bisa digunakan untuk app.proyek1.com, api.proyek2.id, atau domain apapun — cukup override variabelnya.


Prinsip 2: Beri Default yang Masuk Akal #

Default yang baik membuat role langsung bisa digunakan tanpa harus mengatur semua variabel:

# roles/nginx/defaults/main.yml

# Default yang masuk akal untuk hampir semua skenario
nginx_port: 80
nginx_worker_processes: "auto"           # Otomatis sesuai jumlah CPU
nginx_worker_connections: 1024
nginx_client_max_body_size: "10m"
nginx_keepalive_timeout: 65
nginx_ssl_enabled: false                 # SSL tidak aktif secara default
nginx_document_root: /var/www/html

# Default yang bergantung pada konteks host
nginx_server_name: "{{ ansible_fqdn }}" # Gunakan FQDN host sebagai default

Dengan default seperti ini, kamu bisa menggunakan role tanpa mengatur satu variabel pun — dan hasilnya tetap masuk akal.


Prinsip 3: Pisahkan Concern dengan Jelas #

Role yang reusable punya batas tanggung jawab yang jelas. Role nginx seharusnya hanya mengurus nginx — tidak mengurus konfigurasi firewall, tidak mengurus monitoring, tidak mengurus deployment aplikasi.

Role nginx:
  ✓ Install nginx
  ✓ Konfigurasi nginx (worker, timeout, dll.)
  ✓ Setup virtual host
  ✓ Setup SSL/TLS
  ✗ Setup firewall — itu tanggung jawab role firewall
  ✗ Deploy kode aplikasi — itu tanggung jawab role myapp
  ✗ Setup monitoring — itu tanggung jawab role monitoring

Role yang mencoba melakukan terlalu banyak hal sulit digunakan kembali karena pengguna mungkin hanya butuh sebagian dari fungsinya.


Prinsip 4: Idempoten di Semua Kondisi #

Role yang reusable harus idempoten — aman dijalankan berulang kali di sistem yang sudah dikonfigurasi maupun yang baru:

# ANTI-PATTERN: tidak idempoten
- name: Buat direktori dan set permission
  command: mkdir -p /opt/app && chmod 755 /opt/app
  # Ini akan selalu "changed" meski direktori sudah ada dengan permission yang benar

# BENAR: idempoten
- name: Pastikan direktori aplikasi ada
  file:
    path: /opt/app
    state: directory
    mode: '0755'
    owner: "{{ app_user }}"
  # Ansible cek kondisi — hanya berubah jika memang perlu berubah

Prinsip 5: Kemampuan Kustomisasi melalui Task Tags #

Role yang reusable memberi pengguna kemampuan untuk menjalankan hanya subset dari task-nya:

# roles/nginx/tasks/main.yml
---
- import_tasks: install.yml
  tags:
    - nginx
    - nginx:install

- import_tasks: configure.yml
  tags:
    - nginx
    - nginx:configure

- import_tasks: ssl.yml
  when: nginx_ssl_enabled
  tags:
    - nginx
    - nginx:ssl

Pengguna role bisa menjalankan hanya bagian yang diperlukan:

# Hanya install, skip konfigurasi
ansible-playbook site.yml --tags nginx:install

# Hanya update konfigurasi tanpa install ulang
ansible-playbook site.yml --tags nginx:configure

# Semua task nginx
ansible-playbook site.yml --tags nginx

Menguji Role Secara Independen #

Role yang bisa diuji secara independen jauh lebih mudah di-maintain dan di-share. Buat direktori pengujian sederhana di dalam role:

roles/nginx/
  ├── tasks/
  ├── defaults/
  ├── ...
  └── tests/
      ├── inventory.ini     # Inventory minimal untuk testing
      └── test.yml          # Playbook untuk menguji role ini
# roles/nginx/tests/test.yml
---
- name: Test role nginx
  hosts: all
  become: true

  pre_tasks:
    - name: Perbarui apt cache
      apt:
        update_cache: true
      when: ansible_os_family == "Debian"

  roles:
    - role: "{{ playbook_dir }}/../"   # Gunakan role dari direktori parent
      vars:
        nginx_port: 8080
        nginx_server_name: "test.local"

  post_tasks:
    - name: Verifikasi nginx berjalan
      systemd:
        name: nginx
      register: nginx_status

    - name: Assert nginx aktif
      assert:
        that:
          - nginx_status.status.ActiveState == "active"
        fail_msg: "Nginx tidak berjalan setelah role dieksekusi"

Ringkasan #

  • Semua nilai spesifik harus jadi variabel — tidak boleh ada hardcode path, domain, port, atau nilai lain yang berbeda antar proyek.
  • Beri default yang masuk akal sehingga role bisa langsung digunakan tanpa mengatur semua variabel — tapi tetap fleksibel.
  • Pisahkan concern — role nginx hanya mengurus nginx, tidak mencampuri tanggung jawab role lain.
  • Idempoten di semua kondisi — aman dijalankan di sistem baru maupun yang sudah dikonfigurasi.
  • Task tags memungkinkan pengguna menjalankan hanya subset dari role — install saja, atau konfigurasi saja, tanpa harus modifikasi role.
  • Uji role secara independen dengan direktori tests/ di dalam role — memastikan role bekerja sebelum di-share atau diintegrasikan.

← Sebelumnya: Dependency   Berikutnya: Parameterized →

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