## Configuration should be "Maintainable" πŸ”§ This principle is the main reason why we choose to use `dhall` [Dhall](https://dhall-lang.org/) is a "simple" language and set of tools which allow for the management of configuration. It focuses on being delightful to maintian, maximizing the productivity and correctness of the user. It is an excellent choice for small teams trying to do hit ambitious goals with a few knowledgable maintainers ### "Maintainable" means we reuse code efficiently To facilicate this, `dhall` provides some programming constructs: - Variables + Strict scoping - Functions - Imports #### Variables + Strict scoping `dhall` uses the `let` keyword to indicate setting a variable We want out code to be declarative, so `dhall` forces us to specify where we want a variable to be in scope An `in` block must _always_ be used to tell `dhall` where and how the variables will be used! ```dhall let x = 5 in x + 10 ``` We can express more complicated variables by using Records and Lists ```dhall let thisGuyIKnow = { person = { name = "Johnnathan Doe", age = 67 } , nicknames = ["JohnnyBoy", "Johnny-O", "KingJohnVI"] , address = { country = "United States" , state = "Pennsylvania" , city = "Philadelphia" } } in "I need to always specify an in block, even if I don't use any of my variables!" ``` yields `"I need to always specify an in block, even if I don't use any of my variables!"` #### Functions We often want to reuse the same code snippet to take some inputs and generate some outputs. We can define functions like this ```dhall let addThese : Natural -> Natural -> Natural = \(x : Natural) -> \(y : Natural) -> x + y in addThese 10 10 ``` yields `20` You'll notice that functions are very restrictive in what they can do, this is intentional for the sake of safety, a principle which [other configuration specification languages try and adhere to](https://developer.hashicorp.com/terraform/language/expressions/function-calls#when-terraform-calls-functions)! #### Imports We want to be able to import code, either from the internet For example, if I want to import the standard library: ```dhall let Prelude = (https://prelude.dhall-lang.org/v19.0.0/package.dhall) ``` Or from a local file For example, if I want to import the file we just made: ```dhall let addThese = ./placeWhereAddTheseIsDefined.dhall ``` For the security conscious, these can be cached, are referentially transparent, and a SHA can be attached optionally to prevent tampering with the source 🦾 ### "Maintiainable" means state is hard to misconfigure To facilicate this, `dhall` provides some programming constructs: - Types - Type Checking - Clear Error-Messages #### Types When we specify a dependency in software, we create an interface. A `type` is how we formalize an interface! As we did in our above example of specifying variables, here we declare a specific type to assert that our variable conforms to. ```dhall let Profile : Type = { person : { name : Text , age : Natural } , address : { country : Text , state : Text , city : Text } } let john : Profile = { person = { name = "John Doe" , age = 67 } , address = { country = "United States" , state = "Pennsylvania" , city = "Philadelphia" } } in john ``` #### Type Checking If I mess up this contract by accident, I want to know as quickly as possible that I messed up so that I can fix it! ```dhall let jane : Profile = { person = { name = "Jane Doe" -- , age = 67 } , address = { country = "United States" , state = "Pennsylvania" , city = "Philadelphia" } } in jane ``` Type checking is also a very difficult thing to build from scratch. Dhall is implemented in Haskell; we trust in Haskell to provide us tooling to write good compilers πŸ™ #### Clear Error-Messages The error message for the above type error is clear as day! πŸŒ… You can get these clear explanations by passing in the `--explain` flag ```dhall You or the interpreter annotated this expression: ↳ { person.name = "Jane Doe" , address = { country = "United States", state = "Pennsylvania", city = "Philadelphia" } } ... with this type or kind: ↳ { address : { city : Text, country : Text, state : Text } , person : { age : Natural, name : Text } } ... but the inferred type or kind of the expression is actually: ↳ { address : { city : Text, country : Text, state : Text } , person : { name : Text } } ``` ### "Maintainable" means good tooling to provide feedback To facilicate this, `dhall` provides some tooling: - Easy Installation - IDE support - CLI Tooling - Interoperability #### Easy Installation You can install Dhall via `brew` for development - [See here](https://formulae.brew.sh/formula/dhall) Via `apt` and other linux package managers if you're building tooling - [See here](https://ubuntu.pkgs.org/20.04/ubuntu-universe-arm64/dhall_1.19.1-1build2_arm64.deb.html) And via `nix` if you're a mad-lad - [See here](https://search.nixos.org/packages?channel=unstable&from=0&size=50&sort=relevance&type=packages&query=dhall) #### IDE Support [VS Code](https://github.com/dhall-lang/vscode-dhall-lsp-server) and IntelliJ idea as well supported, and LSP bindings are included! Dhall also is opinionated about formatting, so everyone's Dhall code looks the same! #### CLI Tooling I never mentioned how to actually run these! You can specify a file like so from the command line: ```shell > dhall --explain --file <MY_FILE.dhall> ``` Or you can pass it in via stdin! ```shell > dhall <<< 'True && False' ``` #### Interoperability JSON, YAML and HCL, HOCOL, TOML, and others already exist! Why do we need another syntax? πŸ™„ Dhall [provides tools](https://docs.dhall-lang.org/tutorials/Getting-started_Generate-JSON-or-YAML.html#) like `dhall-to-json`, `dhall-to-yaml`, `dhall-to-terraform` and other CLI tools which take Dhall expressions and convert them to other standards! ## Footnotes! πŸ‘£ ### More insights on Dhall πŸ€” See [this interview with one of the maintainers of Dhall, Gabriel Gonzalez](https://corecursive.com/040-tech-evangelism-with-gabriel-gonzalez/#crossing-the-chasm) on the [CoRecursive Podcast](https://corecursive.com/) He describes how one of the most important important ways to get adoption of technical tooling is in the [[_Crossing The Chasm]] model. This is one such model which has personally affected my worldview. ☺️ ### FAQs and Reassurances: 😣 -> 😌 #### Why do the records look weird? I don't like it... 😣 The convention for Dhall is to put commas before entries in the record This minimizes diffs when we're adding new things and we don't want to create a change in the previous line just to add a comma and add a newline. After using this, I belive it will be quick to get used to #### Why do functions look weird? I don't like it... 😣 To promote reuse, a lot of functional languages use a techinque called [Currying](https://towardsdatascience.com/what-is-currying-in-programming-56fd57103431) Named after the mathematitian, Haskell Curry, not the cooking style πŸ˜‰ #### Where are my `for` loops!? I don't like it... 😣 Dhall tries to promote a programming style which is [total and pure](https://developer.hashicorp.com/terraform/language/expressions/function-calls#when-terraform-calls-functions) Dhall [provides](https://docs.dhall-lang.org/tutorials/string-matrix.html) the `List/map` and `List/fold` functions via the standard library to help deal with this