رویکردهای Imperative و Declarative

دو رویکرد متفاوت

وقتی می‌خواهید یک کار را خودکار کنید، دو راه اصلی دارید:

Imperative — دستوری

شما دقیقاً مراحل را مشخص می‌کنید:

1# اسکریپت imperative
2apt-get update
3apt-get install -y nginx
4systemctl start nginx
5systemctl enable nginx
6echo "server { listen 80; }" > /etc/nginx/sites-available/default
7systemctl reload nginx

شما به سیستم می‌گویید چطور کار را انجام دهد.

Declarative — اعلانی

شما وضعیت نهایی را توصیف می‌کنید:

 1# پیکربندی declarative (مثلاً Ansible)
 2- name: Ensure nginx is installed and running
 3  apt:
 4    name: nginx
 5    state: present
 6
 7- name: Ensure nginx is enabled and started
 8  systemd:
 9    name: nginx
10    state: started
11    enabled: yes
12
13- name: Ensure nginx config is present
14  copy:
15    content: "server { listen 80; }"
16    dest: /etc/nginx/sites-available/default
17  notify: reload nginx

شما به سیستم می‌گویید چه چیزی می‌خواهید، نه این‌که چطور.

تفاوت اصلی

ImperativeDeclarative
مراحل را مشخص می‌کنیدنتیجه را مشخص می‌کنید
«اینکار را بکن، بعد آن کار را بکن»«می‌خواهم سیستم این‌طور باشد»
اجرا به‌ترتیبابزار خودش ترتیب را مدیریت می‌کند
اگر دوباره اجرا شود، ممکن است خطا دهدidempotent — دوباره اجرا امن است
مثال: Bash scriptمثال: Ansible, Terraform, Kubernetes

مثال عملی

فرض کنید می‌خواهید یک فایل پیکربندی را روی سرور قرار دهید.

رویکرد Imperative:

 1#!/usr/bin/env bash
 2set -euo pipefail
 3
 4# بررسی کنید فایل وجود دارد یا نه
 5if [ -f /etc/myapp/config.yml ]; then
 6  echo "Backing up existing config"
 7  cp /etc/myapp/config.yml /etc/myapp/config.yml.bak
 8fi
 9
10# کپی فایل جدید
11echo "Copying new config"
12cp config.yml /etc/myapp/config.yml
13
14# تنظیم مجوزها
15echo "Setting permissions"
16chown myapp:myapp /etc/myapp/config.yml
17chmod 640 /etc/myapp/config.yml
18
19# restart سرویس
20echo "Restarting service"
21systemctl restart myapp

شما باید همهٔ حالت‌ها را مدیریت کنید: فایل وجود دارد؟ backup بگیرید. فایل ندارد؟ فقط کپی کنید.

رویکرد Declarative:

 1# Ansible playbook
 2- name: Ensure config file is present
 3  copy:
 4    src: config.yml
 5    dest: /etc/myapp/config.yml
 6    owner: myapp
 7    group: myapp
 8    mode: '0640'
 9  notify: restart myapp
10
11handlers:
12  - name: restart myapp
13    systemd:
14      name: myapp
15      state: restarted

شما فقط می‌گویید «این فایل باید آنجا باشد، با این مجوزها». Ansible خودش چک می‌کند که آیا فایل وجود دارد، آیا محتوا یکسان است، آیا مجوزها درست است — و فقط در صورت نیاز تغییر می‌دهد.

مزایا و معایب

Imperative

مزایا:

  • کنترل کامل دارید
  • منطق پیچیده راحت‌تر نوشته می‌شود
  • debugging ساده‌تر است — خط‌به‌خط می‌بینید چه اتفاقی افتاده

معایب:

  • باید همهٔ حالت‌ها را خودتان مدیریت کنید
  • idempotent کردن سخت است
  • اگر اسکریپت نیمه‌کاره متوقف شود، سیستم در وضعیت نامشخصی می‌ماند

Declarative

مزایا:

  • Idempotent — می‌توانید بارها اجرا کنید
  • خواناتر است — وضعیت نهایی را می‌بینید، نه مراحل
  • ابزار خودش مدیریت state را انجام می‌دهد

معایب:

  • کنترل کمتر دارید
  • debugging سخت‌تر است — نمی‌دانید ابزار دقیقاً چه کاری کرده
  • یادگیری syntax و قابلیت‌های ابزار زمان می‌برد

کدام را انتخاب کنیم؟

از Imperative استفاده کنید وقتی:

  • منطق خاص و پیچیده دارید
  • workflow چندمرحله‌ای با شرط‌های مختلف دارید
  • می‌خواهید سریع یک کار one-off انجام دهید
  • تیم با Bash راحت‌تر است

مثال: یک deployment pipeline که بسته به نتیجهٔ تست، مسیرهای مختلف دارد.

از Declarative استفاده کنید وقتی:

  • می‌خواهید وضعیت سیستم را مدیریت کنید (configuration management)
  • نیاز به idempotency دارید
  • می‌خواهید تعداد زیادی سرور را یکسان نگه دارید
  • تیم با ابزار configuration management آشنا است

مثال: مدیریت پیکربندی ۱۰۰ سرور production با Ansible.

ترکیب دو رویکرد

در عمل، معمولاً هر دو را با هم استفاده می‌کنید:

 1# Ansible playbook (declarative)
 2- name: Ensure application is deployed
 3  hosts: webservers
 4  tasks:
 5    # declarative: nginx باید نصب باشد
 6    - name: Ensure nginx is installed
 7      apt:
 8        name: nginx
 9        state: present
10
11    # imperative: اجرای یک اسکریپت سفارشی
12    - name: Run custom deployment script
13      script: scripts/deploy.sh
14      args:
15        creates: /opt/myapp/.deployed
16
17    # declarative: سرویس باید running باشد
18    - name: Ensure nginx is running
19      systemd:
20        name: nginx
21        state: started

یا برعکس — یک اسکریپت Bash که Ansible را صدا می‌زند:

 1#!/usr/bin/env bash
 2set -euo pipefail
 3
 4ENVIRONMENT="$1"
 5
 6echo "Deploying to $ENVIRONMENT"
 7
 8# بخش imperative: چک کردن شرایط
 9if [ "$ENVIRONMENT" == "production" ]; then
10  echo "Running pre-production checks..."
11  ./scripts/pre-deploy-checks.sh || exit 1
12fi
13
14# بخش declarative: اعمال پیکربندی
15echo "Applying configuration with Ansible..."
16ansible-playbook -i "inventory/$ENVIRONMENT" deploy.yml
17
18# بخش imperative: تست بعد از deploy
19echo "Running smoke tests..."
20./scripts/smoke-tests.sh

مسیر یادگیری

در این هفته، شما بیشتر با رویکرد imperative (Bash scripts) کار کردید. این پایه است و باید آن را بلد باشید.

در بخش اختیاری این هفته، با Ansible (یک ابزار declarative) آشنا می‌شوید تا ببینید configuration management چطور کار می‌کند.

در هفته‌های بعد:

  • Docker Compose: declarative
  • CI/CD pipelines: معمولاً declarative (YAML configs)
  • Kubernetes: کاملاً declarative (YAML manifests)

بنابراین درک تفاوت این دو رویکرد، به شما کمک می‌کند بفهمید چرا ابزارهای مختلف به شکل متفاوتی کار می‌کنند.

منابع یادگیری

مستندات و مقالات

ویدیوها