Clojure, as programming language, has notably powerful features.
However, they are far from a random list, but make a very powerful and cohesive set, due to the synergy between them: “interaction or cooperation giving rise to a whole that is greater than the simple sum of its parts”.
There are plenty of resources available in the Web exposing them, i.e.:
Among them, we will take as reference Clojure Rationale, which enumerates:
The best way to realize the power of this synergy is actually putting those features into practice. And precisely that is actually the purpose of this post series:
Getting hands-on experience in Clojure REPL driven development (RDD)
Regarding RDD, one problem of Clojure is the time demanded for the REPL to get started.
It is due partially to time demanded by the JVM, but partially to Clojure itself as well. This time, and just having to restart the REPL, is incompatible with the “flow” you get working with RDD.
Therefore, several “reloaded workflows” have sprung out in Clojure ecosystem in order to fix this situation, giving us the chance to restart just the application under development, instead of the REPL. They use to complement “state managers”, meaning by “state” how the components required by our application are loaded. The “classic” on these subjects is Stuart Sierra’s Clojure Workflow Reloaded.
The most widely adopted state managers / reloaded workflows in Clojure ecosystem are:
One of the best articles I happened to read on RDD, and on reloaded workflows in particular, is the Guide to the Duct Framework, which shows a demo of a reloaded workflow in a strictly practical fashion, building a REST API from the ground up, and showing step-by-step the whole path. This approach is particularly illuminating for getting hands-on experience in RDD.
A project I’ve worked on was based on Luminus, a well known project template in the Clojure ecosystem, which tidily packages and integrates a vast set of tools widely adopted in the Clojure ecosystem. As its state manager, Luminus chose mount, and from then on I have adopted it as well.
The best tutorial explaining an example project on mount I have been able to find out so far is the official tutorial and example supplied with it.
In order to get a tutorial like that Duct’s Guide, but for a project based on mount instead of integrant, I have built an API similar to the one shown in mount’s tutorial and example: the accounts API of a toy digital bank. And this post will show how its implementation evolved, step by step, in a typical RDD way.
Instead of explaining each of those steps here, in the post series, we have kept track of them by means of git branches and pull requests, and then depict here just what, in our opinion, wouldn’t be clear enough by just taking a look at each of those PRs.
In contrast with that mount example, this post:
We will implement the following ones:
GET /accounts/:account-id
: details of the single account with the account-id
setGET /accounts/:account-id/transactions
: list of transactions already performed on the account with the account-id
setPOST /accounts/:account-id
: creating (executing) a transaction on the account with the account-id
set;We will implement de following transactions:
{
"amount": 1000.00,
"description": "appartment rent - march 2021"
}
Positive amount
, no account
(attribute exclusive for transfers
)
{
"amount": -1000.00,
"description": "appartment rent - march 2021"
}
Negative amount
{
"amount": -1000.00,
"account": "account-1",
"description": "appartment rent - march 2021"
}
Negative amount
, setting target account’s id in account
Each of those endpoints will be implemented with the following two modules:
db
: Datomic database managementweb
: REST API; mainly, Pedestal interceptorsThe aspects exposed in the previous two sections, Endpoints, and Application Structure, will determine this post series’ structure, as well as the implementation path exposed below, along pull request sequence, in the following iterative approch:
Among these parts of the series, the most important one is part 3, 1.4, RDD session demo, as it actually fulfills the most the whole series goal: getting hands-on experience in Clojure REPL driven development (RDD).
But before beginning those steps, let’s tackle initial project setup which, due to its very own nature, is not reflected in any PR.
We will use clj-new.
We need to add the following alias inside your :aliases
map in ~/.clojure/deps.edn
:
;; add this inside your :aliases map:
:new {:extra-deps {com.github.seancorfield/clj-new
{:mvn/version "1.1.297"}}
:exec-fn clj-new/create
:exec-args {:template "app"}}
Then, let’s create the project:
$ clojure -X:new :name accounts/accounts
We are thus ready to begin coding.
We will take as reference the following articles:
Each of them has been an excellent tutorial for me, for its corresponding tool above. Hence, if you don’t have experience in any of them, I’d suggest to read them before going on with this series, as we assume that level of understanding about each.
Hence, we are now ready to begin coding !
Come, join us to next part , where we will implement account view endpoint !
Till then !