-
Notifications
You must be signed in to change notification settings - Fork 0
/
imperativ-vs-deklarativ.html
61 lines (56 loc) · 19.6 KB
/
imperativ-vs-deklarativ.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<!DOCTYPE html><html lang="de-ch"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Imperativ vs. Deklarativ - Finecloud</title><meta name="description" content="Dieser Beitrag ist meine Zusammenfassung (in meinem eigenen Interesse) des ursprünglichen Beitrags in voller Länge: https://leebriggs.co.uk/blog/2022/07/20/nobody-knows-what-declarative-is Immer wieder stösst man im Bereich Infrastructure as Code (IaC) auf die Begriffe imperativ und deklarativ. Doch was bedeuten diese Begriffe? Ist Terraform wirklich deklarativ und Ansible nicht? Diese…"><meta name="generator" content="Publii Open-Source CMS for Static Site"><link rel="stylesheet" href="https://www.finecloud.ch/media/plugins/syntaxHighlighter/prism-black.css"><link rel="canonical" href="https://www.finecloud.ch/imperativ-vs-deklarativ.html"><link rel="alternate" type="application/atom+xml" href="https://www.finecloud.ch/feed.xml"><link rel="alternate" type="application/json" href="https://www.finecloud.ch/feed.json"><meta property="og:title" content="Imperativ vs. Deklarativ"><meta property="og:site_name" content="Finecloud"><meta property="og:description" content="Dieser Beitrag ist meine Zusammenfassung (in meinem eigenen Interesse) des ursprünglichen Beitrags in voller Länge: https://leebriggs.co.uk/blog/2022/07/20/nobody-knows-what-declarative-is Immer wieder stösst man im Bereich Infrastructure as Code (IaC) auf die Begriffe imperativ und deklarativ. Doch was bedeuten diese Begriffe? Ist Terraform wirklich deklarativ und Ansible nicht? Diese…"><meta property="og:url" content="https://www.finecloud.ch/imperativ-vs-deklarativ.html"><meta property="og:type" content="article"><link rel="shortcut icon" href="https://www.finecloud.ch/media/website/finecloud.png" type="image/png"><link rel="stylesheet" href="https://www.finecloud.ch/assets/css/style.css?v=39da73365516a098a9b73b721fc970e2"><script type="application/ld+json">{"@context":"http://schema.org","@type":"Article","mainEntityOfPage":{"@type":"WebPage","@id":"https://www.finecloud.ch/imperativ-vs-deklarativ.html"},"headline":"Imperativ vs. Deklarativ","datePublished":"2022-07-26T05:41","dateModified":"2022-09-03T07:15","description":"Dieser Beitrag ist meine Zusammenfassung (in meinem eigenen Interesse) des ursprünglichen Beitrags in voller Länge: https://leebriggs.co.uk/blog/2022/07/20/nobody-knows-what-declarative-is Immer wieder stösst man im Bereich Infrastructure as Code (IaC) auf die Begriffe imperativ und deklarativ. Doch was bedeuten diese Begriffe? Ist Terraform wirklich deklarativ und Ansible nicht? Diese…","author":{"@type":"Person","name":"Finecloud","url":"https://www.finecloud.ch/authors/finecloud/"},"publisher":{"@type":"Organization","name":"Finecloud"}}</script><meta name="google-site-verification" content="seFY9U12uiEq5U3_MyZiX6XWzk0AVFl9zITr2ZKsytY"></head><body><div class="site-container"><header class="top" id="js-header"><a class="logo" href="https://www.finecloud.ch/">Finecloud</a><nav class="navbar js-navbar"><button class="navbar__toggle js-toggle" aria-label="Menu" aria-haspopup="true" aria-expanded="false"><span class="navbar__toggle-box"><span class="navbar__toggle-inner">Menu</span></span></button><ul class="navbar__menu"><li><a href="https://www.finecloud.ch/" target="_self">Blog</a></li><li><a href="https://www.finecloud.ch/tags/" target="_self">Tags</a></li></ul></nav><div class="search"><div class="search__overlay js-search-overlay"><div class="search__overlay-inner"><form action="https://www.finecloud.ch/search.html" class="search__form"><input class="search__input js-search-input" type="search" name="q" placeholder="search..." aria-label="search..." autofocus="autofocus"></form><button class="search__close js-search-close" aria-label="Close">Close</button></div></div><button class="search__btn js-search-btn" aria-label="Search"><svg role="presentation" focusable="false"><use xlink:href="https://www.finecloud.ch/assets/svg/svg-map.svg#search"/></svg></button></div></header><main><article class="post"><div class="hero"><figure class="hero__image hero__image--overlay"><img src="https://www.finecloud.ch/media/website/download.jpg" srcset="https://www.finecloud.ch/media/website/responsive/download-xs.jpg 300w, https://www.finecloud.ch/media/website/responsive/download-sm.jpg 480w, https://www.finecloud.ch/media/website/responsive/download-md.jpg 768w, https://www.finecloud.ch/media/website/responsive/download-lg.jpg 1024w, https://www.finecloud.ch/media/website/responsive/download-xl.jpg 1360w, https://www.finecloud.ch/media/website/responsive/download-2xl.jpg 1600w" sizes="100vw" loading="eager" alt=""></figure><header class="hero__content"><div class="wrapper"><div class="post__meta"><time datetime="2022-07-26T05:41">Juli 26, 2022</time></div><h1>Imperativ vs. Deklarativ</h1></div></header></div><div class="wrapper post__entry"><p>Dieser Beitrag ist meine Zusammenfassung (in meinem eigenen Interesse) des ursprünglichen Beitrags in voller Länge: <a href="https://leebriggs.co.uk/blog/2022/07/20/nobody-knows-what-declarative-is">https://leebriggs.co.uk/blog/2022/07/20/nobody-knows-what-declarative-is</a></p><div class="post__toc"><h3>Table of Contents</h3><ul><li><a href="#mcetoc_1g8sg1qh415e">Glossar: Imperativ / Deklarativ</a></li><li><a href="#mcetoc_1g8sg1qh415f">Erwartung und Vorurteil</a></li><li><a href="#mcetoc_1g8sg1qh415g">Der Irrtum</a></li><li><a href="#mcetoc_1g8sg1qh415h">Meine Ansicht</a></li></ul></div><p>Immer wieder stösst man im Bereich Infrastructure as Code (IaC) auf die Begriffe imperativ und deklarativ. Doch was bedeuten diese Begriffe? Ist Terraform wirklich deklarativ und Ansible nicht? Diese beiden Begriffe sind nicht einfach Buzzwords, sondern wesentliche Design-Patterns von IaC.</p><h2 id="mcetoc_1g8sg1qh415e">Glossar: Imperativ / Deklarativ</h2><div class="page" title="Page 8"><div class="layoutArea"><div class="column"><p>Beim deklarativen Ansatz definiert der Entwickler den Endzustand und lässt das IaC Tool ermitteln, wie dieser Zustand erreicht werden soll. Im Gegensatz dazu definiert beim imperativen Ansatz der Entwickler den Prozess, mit welchem vom Ist-Zustand aus der Soll-Zustand erreicht wird. <strong>Der Hauptunterschied ist, dass imperative Programme einen Control-Flow haben und deklarative nicht.</strong> Das lässt sich einfach herausfinden indem man die IaC Anweisungen. Verfügen diese über Error-Checks und Überprüfungen ob etwas korrekt ausgeführt wurde, dann handelt es sich um einen Control-Flow.</p><p>Ein einfaches Beispiel einer imperativen Anweisung:</p><pre class="hljs" style="color: #a9b7c6; background: #282b2e none repeat scroll 0% 0%; display: block; overflow-x: auto; padding: 0.5em;"><span class="hljs-keyword" style="color: #cc7832;">if</span> cluster_exists:
echo <span class="hljs-string" style="color: #6a8759;">"you already created that cluster"</span>
<span class="hljs-keyword" style="color: #cc7832;">else</span>:
echo <span class="hljs-string" style="color: #6a8759;">"I'm creating a cluster for you"</span></pre><p>Auf der anderen Seite verfügt der deklarative Ansatz über keinen Control-Flow, das braucht es dort gar nicht, weil sich Terraform selbst um die Logik und den Control-Flow kümmert, deshalb muss sich der Anwender keine Gedanken darüber machen wie der Soll-Zustand erreicht wird, er muss nur definieren wie der Soll-Zustand am Ende sein soll.</p><p>Ein einfaches Beispiel einer deklarativen Anweisung:</p><pre class="hljs" style="color: #a9b7c6; background: #282b2e none repeat scroll 0% 0%; display: block; overflow-x: auto; padding: 0.5em;">terraform {
required_providers {
aws = {
source = <span class="hljs-string" style="color: #6a8759;">"hashicorp/aws"</span>
version = <span class="hljs-string" style="color: #6a8759;">"~> 4.16"</span>
}
}
required_version = <span class="hljs-string" style="color: #6a8759;">">= 1.2.0"</span>
}
provider <span class="hljs-string" style="color: #6a8759;">"aws"</span> {
region = <span class="hljs-string" style="color: #6a8759;">"us-west-2"</span>
}
resource <span class="hljs-string" style="color: #6a8759;">"aws_instance"</span> <span class="hljs-string" style="color: #6a8759;">"app_server"</span> {
ami = <span class="hljs-string" style="color: #6a8759;">"ami-830c94e3"</span>
instance_type = <span class="hljs-string" style="color: #6a8759;">"t2.micro"</span>
tags = {
Name = <span class="hljs-string" style="color: #6a8759;">"ExampleAppServerInstance"</span>
}
}
</pre><p>Der deklarative Ansatz reduziert den Code Umfang erheblich und vermindert damit auch die Fehleranfälligkeit. Zudem muss man sich nicht selbst mit dauern ändernden Cloud APIs herumschlagen.</p><h2 id="mcetoc_1g8sg1qh415f">Erwartung und Vorurteil</h2><p>Die meisten Leute mit denen man über IaC spricht haben die Tendenz zu glauben das ein IaC Tool deklarativ sein muss. Was sehr komisch ist, sind aussagen wie:</p><blockquote><p>Terraform ist deklarativ, Pulumi, Ansible und AWS CDK nicht, deshalb ist Terraform besser als die anderen.</p></blockquote><p>Leute mit solchen Aussagen verraten das sie keine Ahnung haben wovon sie sprechen.</p><h2 id="mcetoc_1g8sg1qh415g">Der Irrtum</h2><p>Das Hauptproblem in der ganzen imperativ vs. deklarativ Debatte besteht darin, das die meisten Leute meinen, wenn man eine Configurations-Sprache, wie zum Beispiel die DSL Sprachen von Terraform, HCL verwendet das automatisch etwas deklarativ macht.</p><p>IaC Tools wie Terraform, Ansible, Pulumi, AWS CDK usw. machen sich alle DAG zu nutzen. DAG steht für <a href="https://www.bigdata-insider.de/was-ist-ein-directed-acyclic-graph-dag-a-1075296/" target="_blank" rel="nofollow noopener noreferrer">Directed acyclic graph:</a></p><blockquote><p>Ein Directed Acyclic Graph (DAG) ist eine abstrakte Struktur, die aus Knoten und Kanten besteht. Die Kanten bilden die Verbindungen zwischen den Knoten und besitzen eine Richtung. Schleifen sind in der Struktur ausgeschlossen. Folgt man der Richtung der Kanten, gelangt man von einem Startpunkt (Startknoten) zu einem Zielknoten und niemals zurück an den Ausgangsknoten. Es entsteht eine topologische Ordnung. Mit DAGs lassen sich beispielsweise kausale Zusammenhänge gut darstellen. </p></blockquote><p>Pulumi, und Terraform erstellen nicht nur ein DAG, sondern ermöglichen es auch, das erstellte Diagramm zu untersuchen! Pulumi verfügt über den Pulumi-Stack-Graph-Befehl und Terraform über den Terraform-Graph-Befehl.<br><br>Dieses Diagramm wird erstellt, wenn man ein Terraform- oder Pulumi-Programm erstellt, und <strong>wird dann von den Engines des jeweiligen Tools ausgeführt, die dieses Diagramm bei jeder Tool-Instanziierung idempotent ausführen.</strong></p><p>Idempotent bedeutet, dass man dieselben Ergebnisse erwarten kann, wenn man immer wieder dasselbe ausführt. <strong>Jedes Infrastruktur als Code-Tool ist (wenn man es korrekt einsetzt) deklarativ und idempotent.</strong> Konfigurationsmanagement-Tools sind im Allgemeinen idempotent, aber nicht unbedingt deklarativ.</p><p>Wieso glauben aber so viele Leute das Pulumi, Ansible und CDK imperativ sind? Die Antwort ist, das die meisten Leute dabei nicht an das eigentliche Tool denken, sondern nur an die Sprache welche verwendet wird. Konfigurationssprachen machen deklarative Zustände leicht verständlich, da Sie keine Bedingungen in Konfigurationssprachen verwenden können, ohne eine Templating Sprache zu verwenden, oder grosse Änderungen an einer DSL vorzunehmen.<br><br>Mit Ansible, Pulumi und AWS CDK kann man jedoch Bedingungen nach Herzenslust verwenden, da sie imperative Sprachen als primäre Authoring-Erfahrung verwenden.</p><p>Nehmen wir das folgende Snippet von Ansible code als Beispiel:</p><pre class="hljs" style="color: #a9b7c6; background: #282b2e none repeat scroll 0% 0%; display: block; overflow-x: auto; padding: 0.5em;"> - name: Set super_group variable for RedHat
set_fact:
super_group: wheel
when: ansible_os_family == <span class="hljs-string" style="color: #6a8759;">"RedHat"</span>
<span class="hljs-attr"> - name:</span> Set super_group variable for Debian
<span class="hljs-attr"> set_fact:</span>
<span class="hljs-attr"> super_group:</span> sudo
<span class="hljs-attr"> when:</span> ansible_os_family == <span class="hljs-string" style="color: #6a8759;">"Debian"</span>
<span class="hljs-attr"> - name:</span> Add local linux user {{ username }}
user:
name: <span class="hljs-string" style="color: #6a8759;">"<span class="hljs-template-variable" style="color: #629755;">{{ username }}</span>"</span>
groups: <span class="hljs-string" style="color: #6a8759;">"<span class="hljs-template-variable" style="color: #629755;">{{ super_group }}</span>"</span>
append: <span class="hljs-literal" style="color: #6897bb;">true</span>
password_lock: <span class="hljs-literal" style="color: #6897bb;">true</span>
shell: /bin/bash
create_home: <span class="hljs-literal" style="color: #6897bb;">true</span>
generate_ssh_key: <span class="hljs-literal" style="color: #6897bb;">true</span>
state: present</pre><p>Hier kann man sehen, das eine <em>when</em> Bedingung definiert ist und dort entschieden wird, ob die Variable <em><span class="hljs-attr">super_group:</span> sudo </em>oder<em> wheel</em> gesetzt wird, oder garnicht. Anschliessend wird ein neuer Linux User erstellt. Es handelt sich in offensichtlich insgesamt um eine imperative Operation, zuerst wird anhand der OS Family eine Variable gesetzt und dann der Benutzer erstellt. Aber damit nicht genug: das Resultat, dieser imerpativen Operation <strong>ist deklarativ.</strong> Damit versuchen wir den Irrtum nun aufzulösen: <strong>Pulumi und Ansible und wie die Tools alle heissen sind als solches, (als Tool) alle deklarativ. Die Sprache jedoch, in welcher man die Infrastruktur beschreibt wird bei Pulumi und Ansible in einer imperativen Form geschrieben.</strong></p><h2>Das Problem mit imperativen Anweisungen</h2><p>Das Problem bei manchen Ansible Playbooks ist, dass diese nicht idempotent geschrieben wurden. Was bitte schön ist <span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);">Idempotenz? </span><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);">Idempotenz bezeichnet die Unveränderbarkeit des Ergebnisses bei einer mehrfachen Verknüpfung oder Funktionsanwendung. Idempotenz ist erreicht, wenn ein IaC-Task nach wiederholtem Ausführen immer dasselbe Resultat erzeugt. Erst durch idempotente Tasks wird ein Gesamtautomatisierungsprozess auch für mehrere Ausführungen robust und zuverlässig.</span></p><p><span style="color: var(--text-primary-color); font-family: var(--editor-font-family); font-size: inherit; font-weight: var(--font-weight-normal);">Wenn man unsorgfältige Ansible Tasks verfasst, kann das dazu führen, dass diese bei wiederholtem ausführen nicht dieselben Resultate erzeugen, im Vergleich zu Terraform, wo dies aufgrund der strikten DSL nicht passieren kann.</span></p><h2>Das Problem mit deklarativen Anweisungen</h2><p>Im Gegensatz dazu gibt es bei Terraform keine wirklich ausgereifte Möglichkeit den Control-Flow zu bearbeiten. Es gibt zwar mechanismen wie das count argument oder ein for_each, das führt dann aber beispielsweise zu folgendem Code:</p><pre class="hljs" style="color: #a9b7c6; background: #282b2e none repeat scroll 0% 0%; display: block; overflow-x: auto; padding: 0.5em;">count = var.enabled ? <span class="hljs-number" style="color: #6897bb;">1</span> : length([some list of resources or datasources])</pre><p>Diese Anweisung ist nichts anderes als die <span class="hljs-attr"><em>when</em> oder <em>state</em> Anweisung im oberen Ansible Beispielcode. Nur ist dieser Code hier deutlich schwerer lesbar und wenige verständlich.</span></p><h2 id="mcetoc_1g8sg1qh415h">Meine Ansicht</h2><p>Anstatt imperativ und deklarativ mit falsch, richtig, besser oder schlechter zu bewerten, sollten wir uns bewusst werden, das wir in den meisten Fällen im IaC Bereich immer mit beidem zu tun haben. Je nach Tool oder Configurations Sprache direkter oder indirekter. Letztendlich erlauben Tools wie Ansible und Pulumi aus meiner Sicht höchste flexibilität und Anpassbarkeit des Control-Flows. Tools wie Terraform hingegen sind ungeeignet für mofizierungen des Control-Flows. Deshalb macht es meiner Meinung nach am meisten Sinn, das Tool oder die Konfigurations-Sprache zu verwenden, welche für den jeweiligen Use-Case am besten geeignet ist. Grundsätzlich lässt sich jede Aufgabe mit entweder dem imperativen oder deklarativen Ansatz lösen. Es gibt aber Aufgaben, die deutlich einfacher mit dem einen oder dem anderen Ansatz gelöst werden können. Es gilt daher situativ zu entscheiden, welcher Ansatz sich für welche Aufgaben am besten eignet und diese dann geschickt zu kombinieren. Beispielsweise kann man Terraform einsetzen, um Basis-VMs direkt von einem Template ausgehend zu erstellen. Nachfolgend kann man dann z.b. je nach OS Familie Ansible einsetzen, um Software-Installationen und Konfigurationen auf dem VMs vorzunehmen.</p></div></div></div></div><footer class="wrapper post__footer"><p class="post__last-updated">This article was updated on September 3, 2022</p><ul class="post__tag"><li><a href="https://www.finecloud.ch/tags/ansible/">ansible</a></li><li><a href="https://www.finecloud.ch/tags/iac/">iac</a></li><li><a href="https://www.finecloud.ch/tags/infrastructure-as-code/">infrastructure as code</a></li><li><a href="https://www.finecloud.ch/tags/terraform/">terraform</a></li><li><a href="https://www.finecloud.ch/tags/tools/">tools</a></li></ul><div class="post__share"></div></footer></article><nav class="post__nav"><div class="post__nav-inner"><div class="post__nav-prev"><svg width="1.041em" height="0.416em" aria-hidden="true"><use xlink:href="https://www.finecloud.ch/assets/svg/svg-map.svg#arrow-prev"/></svg> <a href="https://www.finecloud.ch/monitor-proxmox-mit-grafana-und-prometheus.html" class="post__nav-link" rel="prev"><span>Previous</span> Monitor Proxmox mit Grafana und Prometheus</a></div><div class="post__nav-next"><a href="https://www.finecloud.ch/shellcheck.html" class="post__nav-link" rel="next"><span>Next</span> ShellCheck </a><svg width="1.041em" height="0.416em" aria-hidden="true"><use xlink:href="https://www.finecloud.ch/assets/svg/svg-map.svg#arrow-next"/></svg></div></div></nav></main><footer class="footer"><div class="footer__copyright"><p>Powered by Publii</p></div><button onclick="backToTopFunction()" id="backToTop" class="footer__bttop" aria-label="Back to top" title="Back to top"><svg><use xlink:href="https://www.finecloud.ch/assets/svg/svg-map.svg#toparrow"/></svg></button></footer></div><script>window.publiiThemeMenuConfig = {
mobileMenuMode: 'sidebar',
animationSpeed: 300,
submenuWidth: 'auto',
doubleClickTime: 500,
mobileMenuExpandableSubmenus: true,
relatedContainerForOverlayMenuSelector: '.top',
};</script><script defer="defer" src="https://www.finecloud.ch/assets/js/scripts.min.js?v=6ca8b60e6534a3888de1205e82df8528"></script><script>var images = document.querySelectorAll('img[loading]');
for (var i = 0; i < images.length; i++) {
if (images[i].complete) {
images[i].classList.add('is-loaded');
} else {
images[i].addEventListener('load', function () {
this.classList.add('is-loaded');
}, false);
}
}</script><script defer="defer" src="https://www.finecloud.ch/media/plugins/syntaxHighlighter/prism.js"></script></body></html>