Domain Driven Architecture

October 20, 2017 By: Michael Jerger

dda-pallet series: 3-Convention over Configuration

Our goal is a development environment properly set up straight away from beginning - and additionally to be able to adjust your setup as you like. We are using dda-pallet to describe this infrastructure as clojure code. This blog is part of the "dda-pallet" series and will show step by step how to setup a clojure IDE:

  1. Provision existing Targets
  2. Compose crates
  3. Convention over Configuration with Domain Driven Design.
  4. Execute Pallet local
  5. Plugin Operational Services
  6. Test-driven DevOps

Last time we cloned some git repositories into a created user home in our future IDE. Today we will proceed with the dda-managed-vm crate.

You can think of the dda-managed-vm as a base-vm already having some basic tools installed, like bookmarks, password-store, gpg keys, mail, LibreOffice, etc. But we will find also some more fine grained installations & configurations:

  1. We will configure the user to be installed with our credentials. (Definitions of gpg- or ssh-keys are optional, so that you will not be forced to expose your credentials to an unsafe target system):
    • user name,
    • password,
    • ssh-key and
    • gpg keys
  2. configured bookmarks
  3. a ready to use team-password-store and
  4. a bunch of useful background tools installed, like virtualbox-guest-utils and io-/if-/h-top tools for vm analysis

While applying the dda-managed-vm we will learn how Domain Driven Design fits into the functional DevOps world and why the separation of domain and infrastructure is important - even for infrastructure code.

As a result we should be able to log in to our virtual machine and be able to do various tasks like browsing the internet (for safety reasons using a vm for browsing the internet might be a good idea), use LibreOffice, password-store, GPG and many more. And we will be able to recreate our ready to use vm, whenever we want ...


We have the same preconditions as last time. We will start from a clean virtual machine having xubuntu 16.4.2LTS and ssh-server installed. You can find a more detailed description on how-to create a vm in the first post of this series. Keep the used credentials on your mind for first time provisioning.

Get dda-managed-vm

Let's start and clone the dda-managed-vm:

  1. Clone dda-managed-vm repository from GitHub:
    git clone

Detailed Configuration

For your context, we use the following configuration schema defined in external_config.clj:

(def ExternalConfigSchema
  {:provisioning {:ip s/Str
                  :login s/Str
                  :password s/Str}
   :user {:name s/Str
          :password s/Str
          :email s/Str
          (s/optional-key :ssh) {:ssh-pub-key s/Str
                                 :ssh-prvate-key s/Str}
          (s/optional-key :gpg) {:gpg-public-key s/Str
                                 :gpg-private-key s/Str
                                 :gpg-passphrase s/Str}}})

Now let's put your informations into the configuration file:

  1. Open "user-config.edn" in the repositories root folder:
  2. Adjust your target ip (if you type ifconfig in the remote virtual machine, you will find the IP - in our case) in the line:
    :ip ""
  3. Fill in your provision user credentials of the remote machine (if you've chosen on vm-setup the same credentials as we did, go with "initial - secure1234". If not, replace with yours) in the lines:
       :login "initial"
       :password "secure1234"
  4. Adjust name and password for the user we will create. Password is given unhashed:
       :name "test-user"
       :password "xxx"
  5. Adjust the email, if you want to use git (or for test purposes you may keep the preconfigured dummy email) :
         :email ""
  6. (Optional) Configure your authorized-keys for the new user in order be able to connect by ssh and/or to use GPG. If you don't need them, you can leave the preconfigured snakeoil keys:
        :ssh {:ssh-pub-key "rsa-ssh kfjri5r8irohgn...test.key comment"
              :ssh-prvate-key "123Test"}
        :gpg {:gpg-public-key "-----BEGIN PGP PUBLIC KEY BLOCK----- ..."
              :gpg-private-key "-----BEGIN PGP PUBLIC KEY BLOCK----- ..."
              :gpg-passphrase "passphrase"}

Provision your Virtual Machine

Now it's time to bring our configuration to our virtual machine:

  1. Start your REPL & switch to the instantiate-existing namespace
    (use '
  2. Start provisioning
    Your REPL should look somewhat as follows: In case of success, your REPL will finally show:
  3. We finished provisioning successfully. So let's test the newly provisioned vm. After a reboot you can log on as "test-user" (or with the user you specified in the configuration) and enjoy all the useful software you just installed on the virtual machine: The content of password store. Decrypt a secret. Import bookmarks in your browser.
  4. Inspect Logfiles: If the worst comes to the worst it my be a good idea to know, where logfiles are configured and stored. Logfiles are stored below your REPLs execution location in
    The log-level configuration you will find at:

Domain Driven Design for DevOps

Domain Driven Design is quite important in the object oriented application development. But why should Domain Driven Design be important in a DevOps world?

Lets think about whats cool an uncool:

  • Having a simple and compact configuration like our user-config.edn is cool I think. The DevOps user will be able to easily use our components without being forced to deep dive into ugly details (like the fact that virtual-box-guest utils are breaking xubuntu x-server since 16.04.02 ...).
  • Being forced to clone our ddaArchitecture documentation repositoriy into a code subdir, whenever you are creating a managed vm you may consider as uncool in general. On the other hand we assume this convention will be a good idea to the dda-pallet community.
  • Be able to synergize with worldwide community on the infra level would be cool.
  • Be able to define own Conventions easily would be cool.

This thoughts lead us to the idea to strictly separate conventions (we call it domain) from low-level configurations (we call it infra). Both levels are represented through a data-driven API.

Doing so we enable synergy in building a infra-level abstraction together with a world-wide community. The structure of linux software will be similar enough across companies and countries.

On the domain-level everyone is free to implement it's own abstractions and conventions. The domain layer transforms compact configuration data to large infra configuration data. As domain level is pure data transformation, modifying our convention or develop your own will be a easy thing to do. Test driven development is one of our architecture goals, in domain layer unittests are easy to implement.

Find Domain Driven Desing parts in the code

You can find all this ideas in our code:

  • domain / infra-layer: You will find in every crate infra and domain namespaces representing a layer.
    • infra ns translates the broad infra configuration into action executed on target nodes. Infra configuration is organized along the typical linux package structures.
    • domain ns transforms compact, convention having configuration to broad infra configuration.
    • app ns binds domain and infra together and composes other crates.
  • boundaries: infra, domain and app namespaces are intended to be used from outside. So every input and output will be validated here.
  • schema: At the moment we are expressing our configurations using plumatic schema. In future we may switch to clojures new spec.

Tags: dda-managedvm-crate howto Convention over Configuration clojure ide composition dda-pallet phases

Powered by Cryogen | Free Website Template by Download Website Templates | Impressum