Home | About | Documentation | Discuss

Rationale

Application configuration and initialization are tangential to delivering business value, yet we frequently get bogged down by their incidental complexity. Application development could be a better experience if we only have to focus on the application logic without worrying about configuration, initialization and the sundry development/maintenance tasks that applications frequently need. This should be a solved problem in a repeatable, predictable manner.

What is Bract?

Bract is a Clojure framework to bring power and flexibility to application configuration and initialization workflow. Whether you are developing your application, writing tests or preparing for deployment, Bract has you covered.

Bract aims to:

Bract does not aim to:

Bract is made of bract.core (with Keypin as the only dependency for config support) and a bunch of modules for various purposes. While bract.core is low level and prescribes no style, it is possible to author opinionated Bract modules on top of it. One may even extend Bract to build a custom application framework. Bract is suited for various types of applications, e.g. command-line tools, web services, batch jobs, web applications etc. and integrates well with tangential, yet relevant aspects such as configurable JVM logging.

How it works

The bract.core module is the minimum requirement for using Bract, and is used by all other modules. The essential idea behind Bract is the “inducer function” (fn [context & args]) -> context, also called inducer. One or more (often nested) inducers form the initialization workflow. The context is a map passed to one inducer after another.

Inducer

An inducer’s role is to bring about a certain kind of change. An inducer receives the context map as argument, and must always return either updated or unchanged context. Say for example, a config-reader inducer may discover the config file name from the context and populate the context with loaded config before returning. An inducer usually does not know which other inducers are participating in the workflow. The inducers and their order of invocation are generally decided by either a Bract module (as entry point) or by the application developers. Various inducers are provided by the Bract modules and by the application developers.

Well known keys

An inducer generally needs information to do its job, which it can find in the context and in the optional arguments. The information an inducer finds in the context is usually put in by other inducers that executed earlier. However, inducers only have hard dependency on well-known context (or config) keys. This helps to keep inducers decoupled from each other while encouraging flexible workflows.

Entry point

The top level inducer workflow is usually executed from either a -main or an implicitly called function. An application may very well choose to do its own processing before invoking Bract initialization, but generally Bract modules make the job easier by providing such entry-point functions.

Fork me on GitHub