Deklarative Programmierung
Was ist deklarative Programmierung?
Die deklarative Programmierung ist eine Methode zur Abstraktion des Kontrollflusses für die Logik, die eine Software zur Durchführung einer Aktion benötigt. Mit ihr wird angegeben, was die Aufgabe oder das gewünschte Ergebnis ist.
Die deklarative Programmierung ist ein High-Level-Programmierkonzept, das das Gegenteil der imperativen Programmierung ist. Es handelt sich um einen Programmieransatz, bei dem die Programmierer Code schreiben, der beschreibt, was sie tun wollen und welche Ergebnisse sie erreichen wollen, und nicht, wie sie die Ergebnisse erreichen wollen. Es ist die Aufgabe des Compilers des Programms, das Wie herauszufinden.
Deklarative Modelle stützen sich auf vorkonfigurierte Fähigkeiten in der Sprache, ohne dass von Fall zu Fall explizite Anweisungen gegeben werden, welche Schritte zu unternehmen sind, um eine bestimmte Aufgabe zu erfüllen. Deklarative Programmierung findet sich typischerweise in Datenbanken und Konfigurationsmanagementsoftware, gepaart mit einer domänenspezifischen Sprache (DSL).
Deklarative Programmierung und Kontextunabhängigkeit
Da deklarative Programme nur das endgültige Ziel (das Was), nicht aber die zur Erreichung dieses Ziels erforderlichen Schritte (das Wie) angeben, gelten sie als kontextunabhängig. Das bedeutet, dass dieselben Ausdrücke in diesem Programm dieselbe Bedeutung haben und daher in verschiedenen Kontexten verwendet werden können.
In der Programmiersprache C zum Beispiel sind while/if-Ausdrücke zusammen mit der Reihenfolge der folgenden Ausdrücke fest durch die Sprache definiert. Daher haben sie immer die gleiche Bedeutung, unabhängig davon, wo sie verwendet werden. Mit anderen Worten: Die Ausdrücke sind kontextunabhängig.
Vorteile der deklarativen Programmierung
Deklarative Programme sind einfacher zu handhaben, da sie nur die Berechnungslogik ausdrücken, ohne den Code durch Kontrollflüsse zu verkomplizieren. Solche Programme haben auch weniger unklare Prozeduren, implizite Abhängigkeiten und veränderbare Zustände, was die Programmierung ebenfalls vereinfacht.
Und die deklarative Programmierung minimiert die Veränderlichkeit. Unveränderliche Objekte im Code verbessern die Lesbarkeit und machen ihn leicht verständlich, auch ohne viele Kommentare. Unveränderlicher Code lässt sich auch leichter aktualisieren, testen, debuggen und verwalten und bleibt sicher und gültig, da Hintergrundprozesse keine Änderungen ohne das Wissen des Programmierers vornehmen können. Schließlich ist unveränderlicher Code nachvollziehbar, so dass der Programmierer verfolgen kann, welche Daten sich in welchen Teilen der Anwendung ändern, und dementsprechend bei jeder Änderung nur diese Teile neu laden kann.
Die deklarative Programmierung minimiert auch die Nebeneffekte eines Zustands, das heißt eine Situation, in der eine Funktion etwas ändert, das außerhalb ihres Anwendungsbereichs liegt, wie zum Beispiel die Änderung des Werts einer Variablen oder die Erzeugung einer nicht deterministischen Ausgabe.
Beispiel für deklarative Programmierung
Wenn ein Administrator bei der Konfigurationsverwaltung eine Datei auf einen Server kopieren muss, folgt ein iterativer Ansatz in Pseudocode dieser Konstruktion mit if/then-Anweisungen:
Eine Alternative zur deklarativen Programmierung in Pseudocode folgt einem anderen Aufbau:
In dem deklarativen Codeschnipsel gibt es keine bedingte Logik. Stattdessen zeigt er an, welche Aktion der Benutzer wünscht und welche Server an der Aktion beteiligt sind.
Wie deklarative Programmierung funktioniert
Deklarative Programmierung beruht auf Einschränkungen und Logik (Regeln), um den Aufbau und das Ergebnis zu definieren, sowie auf deklarativen Sätzen (daher der Name), die einfach die Absichten des Programmierers erklären.
Constraints (Einschränkungen) definieren die Eigenschaften, die in einem bestimmten Programmierszenario wahr sind, zum Beispiel Gleichheiten und Ungleichheiten. Sie geben an, wie sich Variablen zueinander verhalten. Constraints sind entweder in die Sprache eingebettet oder werden in Softwarebibliotheken eingerichtet.
In ähnlicher Weise drückt die logische Programmierung Fakten und Regeln über den Bereich aus, in dem der Entwickler arbeitet. Damit diese Form der Programmierung funktioniert, werden Steuerung und Logik voneinander getrennt. Logische Programmierung mit Constraints kombiniert die beiden oben genannten Verfahren.
Die deklarative Programmierung wird in der Regel mit einer domänenspezifischen Sprache praktiziert, da der Kontrollfluss getrennt von der Logik existieren muss, eingebettet in die Sprache selbst.
Arten der deklarativen Programmierung
Die drei Haupttypen der deklarativen Programmierung sind:
Constraint-Programmierung
Die Constraint-Programmierung, auch bekannt als Constraint-Optimierung, ist ein Programmierparadigma, bei dem Constraints deklarativ für einen Satz von Entscheidungsvariablen angegeben werden. Die willkürlichen Beschränkungen helfen bei der Modellierung des zu lösenden Problems, ohne die auszuführenden Schritte zu spezifizieren.
Logische Programmierung
Bei der logischen Programmierung werden logische Sätze verwendet, die bestimmte Regeln und Fakten sowie logische Schlussfolgerungen auf der Grundlage der verfügbaren Daten ausdrücken. Diese Sprachen verwenden Abfragen zur Anzeige relevanter Daten, eine Basis bestehender Logik (Prädikate) und Formeln, die Fakten (Atome) angeben.
Constraint-logische Programmierung
Constraint-logische Programme enthalten Beschränkungen in einem Klauselwerk. Für die Ausführung wird ein Interpreter verwendet. Er durchsucht die Klauseln rekursiv (mit den in einem Constraint-Speicher abgelegten Constraints), um ein bestimmtes Ziel zu beweisen.
Deklarative Programmierung versus imperative Programmierung
Die deklarative Programmierung verlässt sich auf die zugrunde liegenden Komponenten einer bestimmten Sprache, um die notwendigen Schritte zum Erreichen des angegebenen Ergebnisses auszuführen. Bei der deklarativen Programmierung gibt es keine typischen Programmierkonstrukte wie Schleifen (Loops) und Wenn-dann-Bedingungen (if/then), da sie instruktiv sind.
Bei der deklarativen Programmierung liegt der Schwerpunkt auf dem Endergebnis, während bei der imperativen Programmierung der Schwerpunkt auf dem Weg dorthin liegt. Wenn Sie zum Beispiel in ein Taxi steigen, sagen Sie dem Fahrer, wohin Sie fahren wollen. Sie sagen ihm nicht, wie Sie dorthin kommen, indem Sie ihm eine Wegbeschreibung geben. Die Abbiegeanweisungen sind mit der imperativen Programmierung vergleichbar.
Bei der deklarativen Programmierung kann der Compiler Entscheidungen über das Wie treffen, während dies bei der imperativen Programmierung nicht der Fall ist. Außerdem enthält sie keine veränderlichen Variablen, während die imperative Programmierung dies tut.
Die deklarative Programmierung baut auf den Fähigkeiten der imperativen Programmierung auf, ermöglicht es dem Entwickler jedoch, sich auf die Lösung von Problemen zu konzentrieren und nicht auf die Feinheiten des Codeaufbaus. Außerdem vereinfacht sie die Codestruktur.
Viele Programmiersprachen ermöglichen die Kombination von imperativen und deklarativen Programmen. Die Programmiersprache Java beispielsweise bietet Entwicklern die Möglichkeit, den Code mit Kommentaren zu versehen, wodurch der traditionell entwickelte Code um deklarative Fähigkeiten erweitert wird.
Im folgenden Codeschnipsel gibt der Kommentar @Enumerated an, dass die Eigenschaft clientGesture ein enumerierter Typ ist, der als Textstring in der zugrunde liegenden Datenbank gespeichert werden soll:
@Enumerated(EnumType.STRING)
private Gesture clientGesture;
Andere moderne Programmiersprachen haben ähnliche Möglichkeiten der deklarativen Programmierung.
Anwendung der deklarativen Programmierung
Die relationale Datenbank ist ein beliebtes deklaratives Programmierkonzept. Ein Programmierer schreibt Anweisungen in einer domänenspezifischen Sprache namens Structured Query Language (SQL), um die Datenbank zu steuern. Eine SQL-Abfrage, die eine Reihe von Datensätzen aus einer Datenbank abruft, verwendet keine Schleifen oder bedingte Logik. Stattdessen enthält sie SELECT * FROM <Tabellenname>, wodurch die Datenbank angewiesen wird, die angeforderten Datensätze zurückzugeben.
Konfigurationsmanagement-Tools wie Chef, Puppet und Microsoft PowerShell Desired State Configuration (DSC) verwenden alle den deklarativen Programmieransatz. Jedes Tool basiert auf einer iterativen Sprache, einschließlich Ruby, Python und PowerShell. Der Benutzer definiert über die domänenspezifische Sprache, was das Tool tun soll, und das Tool führt die Aufgabe aus, ohne Informationen darüber zu benötigen, wie es zu tun ist.