Declarative design patterns programming paradigm

  • declarative-design-patterns
  • design-patterns
  • oop
  • cplusplus
  • python
  • json
  • configuration
  • english

posted on 31 Jan 2026 under category programming

Post Meta-Data

Date Language Author Description
31.01.2026 English Claus Prüfer (Chief Prüfer) Declarative Design Patterns: Modern OOP Pattern for Configuration-as-Model

Declarative Design Patterns: A Modern OOP Approach

EmojiCodeEmojiCodeEmojiCode

Important: This article clarifies a widely misunderstood concept. Declarative Design Patterns are NOT related to functional programming or generic declarative configuration. They are a modern OOP-based design pattern that modifies configuration structures (JSON/XML) directly into internal runtime OOP models which enables a so-called Configuration-as-Model approach.

Title Proposals and Terminology

Before diving deep, it is critical to clarify terminology that has been confused in the programming community:

  • “Declarative Design Patterns” - A specific OOP pattern where JSON/XML configuration structures are converted to internal objects and passed as reference to sub-modules/sub-systems. This is NOT functional programming.
  • “Declarative Configuration” - Traditional configuration files (JSON, XML, YAML) read by applications. This is different from Declarative Design Patterns.
  • “Declarative Programming” - A broad programming paradigm (functional programming, SQL, etc.). This is not the same as Declarative Design Patterns.

Declarative Design Patterns As Umbrella Term

The term “Declarative Design Patterns” serves as an umbrella term for a collection of related patterns that share a common principle: using configuration structures AS the runtime object model, not just as input (configuration) to create separate domain objects. This fundamentally changes how we think about the relationship between configuration and code.

Declarative configurations used in combination with non OOP based languages (Go) or non-OOP paradigms like typical JavaScript frameworks (React, Vue) or TypeScript that rely on functional/reactive patterns rather than true OOP do not benefit from these patterns in the same way—they may even increase programming complexity. However, JavaScript frameworks that embrace true OOP principles (such as the x0 Framework) can successfully implement declarative design patterns.

Using this “Declarative Design Pattern” approach in combination with modern storage technologies, e.g. ODM - JSON Object Document Mapping (MongoDB), and especially runtime class abstraction / mapping (see: python-micro-esb PKI Management Example), inherits many new sub-patterns which altogether form the base of “Declarative Design Patterns”.

Runtime Class Abstraction / Mapping

The most powerful aspect of Declarative Design Patterns is runtime class abstraction / mapping. This technique allows:

  1. Class Mapping: Declarative mapping between configuration identifiers and Python classes
  2. Class Reference Hierarchies: Tree-structured definitions showing parent-child relationships
  3. Property Definitions: Centralized property schemas shared across implementations
  4. Service Metadata: JSON/dictionary structures that define both data AND behavior

This creates a system where configuration structures directly drive object instantiation, property assignment, and method invocation at runtime—eliminating the traditional separation between configuration and domain objects.

The key benefits (especially in large code bases):

  • Clean code / abstraction models
  • Readable / understandable (independently of each other) “module” code
  • Much less code lines
  • Sub-Tree hierarchy inheritance

Core Principles

Declarative Design Patterns are a new class of OOP-based design patterns that leverage structured configuration data (JSON, XML, YAML) as the primary mechanism for building complex object hierarchies. The fundamental principle is:

EmojiCool Configuration structures become the internal object model directly, passed as references/pointers to sub-modules, drastically reducing programming logic and code lines.

The Key Distinction

What Declarative Design Patterns are NOT:

  • ❌ Functional programming constructs
  • ❌ Declarative query languages (SQL, GraphQL)
  • ❌ Infrastructure as Code (Terraform, Kubernetes YAML)
  • ❌ Reactive/declarative UI frameworks (React, Vue)
  • ❌ Simple configuration file loading

What Declarative Design Patterns ARE:

  • ✅ A method to reduce code by using configuration structures directly as runtime object models
  • ✅ A pattern requiring OOP languages (C++, Python) for proper implementation
  • ✅ A technique for modeling complex hierarchical data through declarations
  • ✅ An approach where JSON/XML/YAML structures convert to typed internal objects
  • ✅ A design that passes configuration-derived objects as references to sub-systems

Real-World Implementation: Python with Runtime Class Mapping

A comprehensive implementation of the Declarative Design Pattern in Python is demonstrated in the python-micro-esb PKI Management Example. This example showcases runtime class abstraction / mapping—the most advanced form of declarative design patterns.

Step 1: Define Class Reference Hierarchies

# class_reference.py
class_reference_server = {
    'CertServer': {
        'property_ref': 'Cert',
        'children': {
            'Smartcard': {
                'property_ref': 'Smartcard',
                'children': {
                    'SmartcardContainer': {
                        'property_ref': 'SmartcardContainer'
                    }
                }
            },
            'CertCA': {
                'property_ref': 'Cert',
                'children': {
                    'Smartcard': {
                        'property_ref': 'Smartcard',
                        'children': {
                            'SmartcardContainer': {
                                'property_ref': 'SmartcardContainer'
                            }
                        }
                    }
                }
            }
        }
    }
}

The hierarchical structure declares relationships between classes—CertServer contains both a Smartcard and references a CertCA, each with their own nested structures.

Step 2: Implement Classes with Abstract Base

# service_implementation.py
import abc
from microesb import microesb

class Cert(microesb.ClassHandler, metaclass=abc.ABCMeta):

    def __init__(self):
        super().__init__()

        self.register_property('cert_data', {
            'type': 'str',
            'default': None,
            'required': False,
            'description': 'Generated Certificate Base64 encoded'
        })

    @abc.abstractmethod
    def _load_ref_cert_data(self):
        """ Load referenced certificate data. """

    @abc.abstractmethod
    def _gen_openssl_cert(self):
        """ Generate certificate using OpenSSL. """

    def gen_cert(self):
        self._load_ref_cert_data()
        
        if getattr(self, 'Smartcard') is not None:
            self._hsm_gen_keypair()
        
        self._gen_openssl_cert()
        self._store_cert_data()


class CertServer(Cert):

    def __init__(self):
        self.type = 'server'
        super().__init__()

    def _load_ref_cert_data(self):
        # access child object directly - populated from configuration
        self.CertCA._get_cert_data_by_id()

    def _gen_openssl_cert(self):
        # both current object and child object properties are available
        srv_metadata = {
            "CertServer": self.property_dict,
            "CertCA": self.CertCA.property_dict
        }
        self.cert_data = generate_cert(srv_metadata)

Step 3: Execute with Runtime Class Mapping

# 00-main-ca.py
from microesb import microesb
from class_reference import class_reference_ca as class_reference
from service_properties import service_properties
from class_mapping import class_mapping
from service_call_metadata import service_metadata_ca as service_metadata
from pymongo import MongoClient

# MongoDB connection for ODM integration
client = MongoClient('mongodb://127.0.0.1/')
mongodb = client.get_database('microesb')

# runtime class mapper - the heart of declarative design patterns
class_mapper = microesb.ClassMapper(
    class_references=class_reference,
    class_mappings=class_mapping,
    class_properties=service_properties
)

# execute service - classes instantiated and methods called based on configuration
res = microesb.ServiceExecuter().execute_get_hierarchy(
    class_mapper=class_mapper,
    service_data=service_metadata
)

# store complete object hierarchy to MongoDB
root_object = res[0]['CertCA']['object_instance']
mongodb.cert_hierarchy.insert_one(root_object.json_dict)

EmojiStar Note on ODM Hierarchy Storage: The true potential of hierarchical ODM (Object Document Mapping) storage with MongoDB becomes evident in the 02-main-client.py example, where complex parent-child certificate relationships are stored and retrieved as nested JSON documents. This demonstrates how declarative design patterns combined with document databases eliminate the impedance mismatch between object hierarchies and data storage.

EmojiStar Note on Runnable Examples: The python-micro-esb framework ships with complete runnable examples inside a Docker container that includes MongoDB and all dependencies pre-configured. This allows developers to immediately experiment with the declarative design pattern approach without complex setup.

Step 4: Define Class Aliasing

# class_mapping.py
class_mapping = {
    'CertCA': 'CertCA',
    'CertServer': 'CertServer',
    'CertClient': 'CertClient',
    'Smartcard': 'Smartcard',
    'SmartcardContainer': 'SmartcardContainer'
}

This mapping enables the framework to instantiate classes based on configuration identifiers—a key feature of runtime class abstraction.

EmojiWarning Note on Configuration Structure: The example uses a “flat” 1:1 class mapping model. The real power of this pattern emerges when using mapped “aliases”—where a single configuration identifier can represent different class implementations based on context, enabling polymorphic behavior through declarative configuration rather than code.

Step 5: Finally, Call Service With Service Metadata (Configuration as Behavior)

# service_call_metadata.py
service_metadata_server = {
    'SYSServiceID': 'generateCertServer',
    'data': [
        {
            'SYSBackendMethod': { 'CertServer': 'gen_cert' },
            'CertServer': {
                'id': 'test-server1',
                'CertCA': {
                    'id': 'test-ca1'
                },
                'Smartcard': {
                    'label': 'smartcard_customer1',
                    'user_pin': 'pin2',
                    'SmartcardContainer': {
                        'label': 'testserver1_keypair'
                    }
                },
                'country': 'DE',
                'state': 'Berlin',
                'locality': 'Berlin',
                'org': 'WEBcodeX',
                'org_unit': 'Security',
                'common_name': 'testserver@domain.com',
                'email': 'pki@webcodex.de',
                'valid_days': 365
            }
        }
    ]
}

Notice how SYSBackendMethod declares which method to call on which class—the configuration drives not just data but behavior.

Why This Reduces Code Dramatically

Traditional OOP approaches require:

  1. Defining configuration classes
  2. Writing parsing logic for each field
  3. Creating factory methods or builders
  4. Implementing validation layers
  5. Writing transformation code between config and domain objects
  6. Manually managing object hierarchies and relationships

With Declarative Design Patterns using Runtime Class Mapping:

  1. The dictionary/JSON structure is the model definition
  2. Class mapping enables automatic instantiation from configuration
  3. Property definitions provide validation and defaults
  4. Hierarchical references create object trees automatically
  5. Methods are invoked based on configuration declarations
  6. Child objects are accessible as attributes on parent objects

Code Reduction Example: A complete PKI management system that might require 3000+ lines of traditional OOP code (classes, builders, factories, parsers, hierarchy management) can be reduced to ~500 lines of declarative configuration plus clean, focused implementation classes.

Declarative Design Patterns vs. Declarative Configuration

These concepts are fundamentally different:

Aspect Declarative Configuration Declarative Design Patterns
Purpose Provide settings to an application Model complex object hierarchies
Implementation Config files read at startup Config structures become runtime objects
Code Impact Minimal - just reads values Massive reduction - replaces OOP boilerplate
Language Requirement Any language OOP languages (Python, C++, Java)
Data Flow Config → Code reads values Config → ClassMapper → Objects → Methods
Hierarchy Flat key-value pairs Complex tree structures

Where Declarative Design Patterns Are Not Applicable

Non-OOP Languages (Pure C, Assembly, Go)

Why Declarative Design Patterns don’t work:

  • No native object instantiation from configuration
  • Manual memory management complicates reference passing
  • No dynamic attribute access for runtime property manipulation
  • No class hierarchies for inheritance patterns

Note: This does NOT mean these languages cannot have good configuration. It means the specific Declarative Design Pattern (config-as-model with runtime class mapping) doesn’t translate well.

Simple Applications with Flat Configurations

When the pattern is overkill:

  • Applications with simple key-value configurations
  • No sub-modules requiring configuration access
  • Configuration doesn’t form a hierarchy
  • Overhead of JSON libraries not justified

Performance-Critical Hot Paths

Limitations in performance scenarios:

  • Dynamic attribute access slower than direct member access
  • Dictionary lookups add overhead compared to static attributes
  • Not suitable for tight loops or real-time processing
  • Use dataclasses or named tuples for performance-critical paths

EmojiCheckeredFlag Performance Counterpoint: The above limitations are based on traditional implementation approaches, but AI analysis suggests this is not necessarily true when declarative design patterns are used correctly. By employing smart “static class-instance pre-loading” strategies—remember, the system is fundamentally based on references/pointers—performance can actually be superior. Consider a modified nlohmann::json implementation (similar to Apache Spark’s memory-resident dataset concept) where the complete object model resides in continuous, huge-page-assisted RAM. In such an architecture, the declarative approach eliminates object instantiation overhead entirely, and reference-based access to pre-loaded instances can outperform traditional object creation patterns. The key is architectural design that leverages the reference-based nature of the pattern.

C++ Implementation with Nlohmann::JSON

While the Python examples above demonstrate runtime class mapping, C++ provides another powerful implementation of Declarative Design Patterns through the nlohmann/json library. The http-1.2 Project serves as a reference implementation demonstrating these concepts in production-grade C++ code.

Why C++ Works for Declarative Design Patterns

C++ is inherently suited for generic programming through templates and STL containers. With nlohmann::json, the language gains STL-like JSON access that enables the same configuration-as-model approach seen in Python, but with compile-time type safety and zero-overhead abstractions.

Sample JSON Configuration

From the http-1.2 project (full configuration file):

{
  "global": {
    "path": { "base": "/var/www" },
    "tcp": { "cork": false, "nodelay": true }
  },
  "server": {
    "runas": { "user": "x0-http", "group": "x0-http" },
    "connection": {
      "timeout": "600",
      "ipv4": { "address": "127.0.0.1", "port": 80 }
    },
    "mimetypes": ["html", "js", "json", "css", "png", "jpg", "svg", "woff2"]
  }
}

Hierarchical Access Pattern

The nlohmann::json library enables intuitive, chainable syntax for accessing nested configuration:

#include <nlohmann/json.hpp>
#include <fstream>
using json = nlohmann::json;

try {
    std::ifstream configFile(CONFIG_FILE);
    json jsonData = json::parse(configFile);

    const auto& runAsUser   = jsonData["server"]["runas"]["user"];
    const auto& runAsGroup  = jsonData["server"]["runas"]["group"];
    const auto& basePath    = jsonData["global"]["path"]["base"];
    const auto& serverAddr  = jsonData["server"]["connection"]["ipv4"]["address"];
    const auto& serverPort  = jsonData["server"]["connection"]["ipv4"]["port"];
    const auto& mimeTypes   = jsonData["server"]["mimetypes"];
}
catch (const std::exception& e) {
    std::cerr << "Config file error: " << e.what() << std::endl;
    std::exit(EXIT_FAILURE);
}

STL Move Semantics for Configuration Objects

C++ move semantics enable efficient transfer of configuration structures directly into object instances:

struct NamespaceProps {
    nlohmann::json jsonConfig;
    std::shared_ptr<Filesystem> fsRef;
};

std::map<std::string, NamespaceProps> namespaces;

for (const auto& nsItem : jsonData["namespaces"]) {
    NamespaceProps props;
    props.jsonConfig = std::move(nsItem);
    props.fsRef = nullptr;

    namespaces.emplace(nsItem["hostname"], std::move(props));
}

Direct Configuration-as-Model

With nlohmann::json, configuration structures are moved directly into object constructors, embodying the configuration-as-model principle:

// objects accept nlohmann::json rvalue references in their constructors
std::unique_ptr<MyObject1> objInstance1;
std::unique_ptr<MyObject2> objInstance2;

// configuration members can be defined as immutable (const)
objInstance1.reset(new MyObject1(std::move(jsonData["confgroup1"][0])));
objInstance2.reset(new MyObject2(std::move(jsonData["confgroup1"][1])));

Key Advantages in C++

  1. Zero-Copy Configuration Transfer: std::move enables efficient transfer of configuration hierarchies
  2. Type Safety: Compile-time checks prevent configuration access errors
  3. STL Integration: Native support for std::vector, std::map, and modern iteration
  4. Performance: No runtime overhead compared to hand-coded parsers
  5. Reference-Based Architecture: Objects hold references to configuration, not copies

The http-1.2 implementation demonstrates how these patterns reduce code complexity while maintaining C++’s performance characteristics. The full implementation can be studied at WEBcodeX1/http-1.2/Configuration.cpp.

x0 Framework: Declarative Design Patterns in JavaScript

The x0 Framework demonstrates how Declarative Design Patterns can be applied to JavaScript UI development. Unlike typical React/Vue applications that rely on functional/reactive patterns, x0 embraces true object-oriented principles with proper class hierarchies and object instantiation from configuration. This is what distinguishes it from mainstream JavaScript frameworks and enables the declarative design pattern approach.

Key Features:

  • Cross Objects: Clean OOP model with seamless data exchange—true class-based object orientation
  • Object Chaining / Data Abstraction: Recursive, reusable modeling through declarations
  • Zero Code Duplication: Configuration-driven component instantiation
  • Metadata Modeling: UI components defined through declarative structures

The x0 framework shows that Declarative Design Patterns can extend beyond backend services to frontend UI development when the framework architecture is built on true OOP foundations rather than functional/reactive paradigms.

EmojiAlarm Upcoming Feature: A soon-to-be-released feature for x0 will enable direct hierarchical ODM (MongoDB) backend object mapping to UI elements, which in comparison to other frameworks will lead to a complete elimination of transformation layers between backend and frontend (currently multiple serialization/deserialization steps exist) and a dramatic reduction in overhead and complexity. Specifically, this will allow MongoDB document hierarchies to flow directly into UI component hierarchies, creating a truly unified full-stack declarative design pattern where configuration-as-model extends seamlessly from database to display.


References

  1. python-micro-esb Framework - Runtime Class Mapping
  2. python-micro-esb PKI Management Example
  3. x0 Framework - Declarative Design Patterns for JavaScript
  4. http-1.2 Project - C++ Declarative Design Pattern Example
  5. nlohmann/json - Modern C++ JSON Library
  6. pymongo - Python MongoDB Driver
  7. “Design Patterns: Elements of Reusable Object-Oriented Software” - Gang of Four
  8. Python Abstract Base Classes (abc)