{"id":69906,"date":"2017-10-24T07:00:39","date_gmt":"2017-10-24T04:00:39","guid":{"rendered":"https:\/\/www.javacodegeeks.com\/?p=69906"},"modified":"2019-02-14T13:19:24","modified_gmt":"2019-02-14T11:19:24","slug":"learning-build-clojure-webapps","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html","title":{"rendered":"Learning to Build Clojure Webapps"},"content":{"rendered":"<p>A while ago I gave a talk at an internal event at Zenika Singapore. We were free to choose a topic so I chose something I thought I didn&#8217;t know enough about &#8211; what it feels like to build a web app in Clojure. This post is a transcript of the talk. I&#8217;ll go into some details on Clojure, which libraries you can use to build web apps and how all of that felt to me.<\/p>\n<h2>Clojure<\/h2>\n<p><a href=\"https:\/\/clojure.org\/\">Clojure<\/a> is a LISP dialect that targets the JVM, Microsofts CLR and JavaScript by means of ClojureScript. It is a functional and dynamic language. One of its specialities are the immutable data structures that rely on structural sharing when appending or removing elements. This allows for good performance even though maintaining immutability.<\/p>\n<p>I got mainly interested in Clojure because<\/p>\n<ul>\n<li>it is very different from all the C based languages around<\/li>\n<li>while still being a general purpose language<\/li>\n<\/ul>\n<p>Due to some of its features like Software Transactional Memory (STM) and atoms it can be especially well suited for building correct concurrent applications.<\/p>\n<p>One aspect that I deem important as well: It seems to be a quite friendly community and I liked both of the user groups I attended, <a href=\"https:\/\/www.meetup.com\/de-DE\/Clojure-Berlin\/\">Clojure Berlin<\/a> and the <a href=\"https:\/\/www.meetup.com\/de-DE\/Singapore-Clojure-Meetup\/\">Clojure Meetup Singapore<\/a>.<\/p>\n<p>If you want to get started with Clojure it&#8217;s best to start with the very common build tool <a href=\"https:\/\/leiningen.org\/\">Leinigen<\/a>. Among other things it offers a simple way to build and run projects, standalone or in the REPL, a feature that is commonly used with LISP dialects.<\/p>\n<p>Using the REPL and Leiningen alone will not be enough for you, you at least need something to edit files. Naturally many people seem to use emacs, besides that there is also <a href=\"https:\/\/cursive-ide.com\/\">Cursive<\/a> (built on IntelliJ), <a href=\"http:\/\/lighttable.com\/\">Lighttable<\/a> (an experimental IDE) and <a href=\"https:\/\/sekao.net\/nightcode\/\">Nightcode<\/a> (a very simple editor with built in REPL).<a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2017\/10\/nightcode.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-69924\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2017\/10\/nightcode.png\" alt=\"\" width=\"720\" height=\"400\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2017\/10\/nightcode.png 720w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2017\/10\/nightcode-300x167.png 300w\" sizes=\"(max-width: 720px) 100vw, 720px\" \/><\/a><\/p>\n<p>To get started with a project you can just install Leiningen and get started by firing up a REPL using <code>lein repl<\/code>.<\/p>\n<p>Let&#8217;s start with a simple operation, adding two numbers.<\/p>\n<div>\n<div id=\"highlighter_271275\" class=\"syntaxhighlighter  java\">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"gutter\">\n<div class=\"line number1 index0 alt2\">1<\/div>\n<div class=\"line number2 index1 alt1\">2<\/div>\n<\/td>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"java plain\">user=&gt; (+ <\/code><code class=\"java value\">2<\/code> <code class=\"java value\">3<\/code><code class=\"java plain\">)<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"java value\">5<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>This already shows two of the more unusual features of Clojure. First, all of the code is represented as a list. That is why even the operation is enclosed in brackets. Second, Clojure uses the prefix notation even when it comes to mathematical operations. But this has also the benefit that you can just increase the number of parameters for the add operation.<\/p>\n<div>\n<div id=\"highlighter_703428\" class=\"syntaxhighlighter  java\">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"gutter\">\n<div class=\"line number1 index0 alt2\">1<\/div>\n<div class=\"line number2 index1 alt1\">2<\/div>\n<\/td>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"java plain\">user=&gt; (+ <\/code><code class=\"java value\">2<\/code> <code class=\"java value\">3<\/code> <code class=\"java value\">4<\/code> <code class=\"java value\">5<\/code><code class=\"java plain\">)<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"java value\">14<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>And if you think about it: That is not that unusual at all. If you see + as the name of a function (which it is) this is very similar to the way you would call a function in a c like language.<\/p>\n<div>\n<div id=\"highlighter_43248\" class=\"syntaxhighlighter  java\">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"gutter\">\n<div class=\"line number1 index0 alt2\">1<\/div>\n<\/td>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"java plain\">plus(<\/code><code class=\"java value\">2<\/code><code class=\"java plain\">, <\/code><code class=\"java value\">3<\/code><code class=\"java plain\">, <\/code><code class=\"java value\">4<\/code><code class=\"java plain\">, <\/code><code class=\"java value\">5<\/code><code class=\"java plain\">)<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>Of course you can also assign the result of a calculation to a variable.<\/p>\n<div>\n<div id=\"highlighter_578656\" class=\"syntaxhighlighter  java\">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"gutter\">\n<div class=\"line number1 index0 alt2\">1<\/div>\n<div class=\"line number2 index1 alt1\">2<\/div>\n<div class=\"line number3 index2 alt2\">3<\/div>\n<div class=\"line number4 index3 alt1\">4<\/div>\n<div class=\"line number5 index4 alt2\">5<\/div>\n<div class=\"line number6 index5 alt1\">6<\/div>\n<\/td>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"java plain\">user=&gt; (def result (+ <\/code><code class=\"java value\">2<\/code> <code class=\"java value\">3<\/code> <code class=\"java value\">4<\/code> <code class=\"java value\">5<\/code><code class=\"java plain\">))<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"java plain\">#'user\/result<\/code><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"java plain\">user=&gt; result<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"java value\">14<\/code><\/div>\n<div class=\"line number5 index4 alt2\"><code class=\"java plain\">user=&gt; (- result <\/code><code class=\"java value\">1<\/code><code class=\"java plain\">)<\/code><\/div>\n<div class=\"line number6 index5 alt1\"><code class=\"java value\">13<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>Besides numeric values there are also other data types, e.g. strings and boolean values that you can use directly.<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<p>It is very easy to create functions as well.<\/p>\n<div>\n<div id=\"highlighter_898963\" class=\"syntaxhighlighter  java\">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"gutter\">\n<div class=\"line number1 index0 alt2\">1<\/div>\n<div class=\"line number2 index1 alt1\">2<\/div>\n<div class=\"line number3 index2 alt2\">3<\/div>\n<div class=\"line number4 index3 alt1\">4<\/div>\n<\/td>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"java plain\">user=&gt; (defn append-mod [val] (str val <\/code><code class=\"java string\">\"-mod\"<\/code><code class=\"java plain\">))<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"java plain\">#'user\/append-mod<\/code><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"java plain\">user=&gt; (append-mod <\/code><code class=\"java string\">\"some-value\"<\/code><code class=\"java plain\">)<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"java string\">\"some-value-mod\"<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>The more interesting data structures are the collections. There are vectors for sequential data.<\/p>\n<div>\n<div id=\"highlighter_969602\" class=\"syntaxhighlighter  java\">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"gutter\">\n<div class=\"line number1 index0 alt2\">1<\/div>\n<div class=\"line number2 index1 alt1\">2<\/div>\n<div class=\"line number3 index2 alt2\">3<\/div>\n<div class=\"line number4 index3 alt1\">4<\/div>\n<div class=\"line number5 index4 alt2\">5<\/div>\n<div class=\"line number6 index5 alt1\">6<\/div>\n<\/td>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"java plain\">user=&gt; (def characters [<\/code><code class=\"java string\">\"a\"<\/code> <code class=\"java string\">\"b\"<\/code> <code class=\"java string\">\"c\"<\/code><code class=\"java plain\">])<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"java plain\">#'user\/characters<\/code><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"java plain\">user=&gt; (characters <\/code><code class=\"java value\">0<\/code><code class=\"java plain\">)<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"java string\">\"a\"<\/code><\/div>\n<div class=\"line number5 index4 alt2\"><code class=\"java plain\">user=&gt; (characters <\/code><code class=\"java value\">1<\/code><code class=\"java plain\">)<\/code><\/div>\n<div class=\"line number6 index5 alt1\"><code class=\"java string\">\"b\"<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>And there are maps, often used with so called keywords as keys.<\/p>\n<div>\n<div id=\"highlighter_273999\" class=\"syntaxhighlighter  java\">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"gutter\">\n<div class=\"line number1 index0 alt2\">1<\/div>\n<div class=\"line number2 index1 alt1\">2<\/div>\n<div class=\"line number3 index2 alt2\">3<\/div>\n<div class=\"line number4 index3 alt1\">4<\/div>\n<\/td>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"java plain\">user=&gt; (def my-map {:key <\/code><code class=\"java string\">\"value\"<\/code> <code class=\"java plain\">:foo <\/code><code class=\"java string\">\"bar\"<\/code><code class=\"java plain\">})<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"java plain\">#'user\/my-map<\/code><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"java plain\">user=&gt; (my-map :key)<\/code><\/div>\n<div class=\"line number4 index3 alt1\"><code class=\"java string\">\"value\"<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>Being a functional language it is very common to do transformation on collections, e.g. using the map operation. This also shows the use of functions as first class citizens as seen by passing in the <code>upper-case<\/code> function.<\/p>\n<div>\n<div id=\"highlighter_480423\" class=\"syntaxhighlighter  java\">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"gutter\">\n<div class=\"line number1 index0 alt2\">1<\/div>\n<div class=\"line number2 index1 alt1\">2<\/div>\n<\/td>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"java plain\">userer=&gt; (map clojure.string\/upper-<\/code><code class=\"java keyword\">case<\/code> <code class=\"java plain\">characters)<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"java plain\">(<\/code><code class=\"java string\">\"A\"<\/code> <code class=\"java string\">\"B\"<\/code> <code class=\"java string\">\"C\"<\/code><code class=\"java plain\">)<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>Important: this doesn&#8217;t modify the existing collection &#8211; it creates a new one. All possible due to the efficient implementation of the data structures.<\/p>\n<h3>Challenges<\/h3>\n<p>It is true that Clojure has a simple syntax that makes it easy to get started. But there are still many things to learn and when beginning it doesn&#8217;t matter that much if something is syntax, a macro or a library call. It can be especially confusing that sometimes there are related but different concepts. For example those are all different ways to create a function, but for different purposes.<\/p>\n<ul>\n<li><code>(defn name [] (body))<\/code><\/li>\n<li><code>(def name (fn [] (body)))<\/code><\/li>\n<li><code>#(body)<\/code><\/li>\n<\/ul>\n<p>One thing that is still difficult for me is to decide how to structure programs in Clojure. It seems to be common to have a lot of functions in the same namespace. I imagine that it is difficult to decide which function is responsible for which data or task.<\/p>\n<p>Finally, at least to me, the docs can be confusing.<\/p>\n<h2>Building Web Apps<\/h2>\n<p>As a general purpose language Clojure can of course be and is used a lot for building web apps as well. Compared to the Java landscape there is a lot less choice, a very common combination is to use three libraries, <a href=\"https:\/\/github.com\/ring-clojure\/ring\">Ring<\/a> as the core library, <a href=\"https:\/\/github.com\/weavejester\/compojure\">Compojure<\/a> for routing and <a href=\"https:\/\/github.com\/weavejester\/hiccup\">Hiccup<\/a> for templating.<\/p>\n<p>Ring is implemented as a pipeline. First there is an adapter that is used to map to an internal request\/response representation and that adapts to an existing web runtime. There is an adapter that use Jetty or another one that only relies on the Servlet API which makes it possible to deploy a Ring app to any servlet container.<a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2017\/10\/ring.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-69925\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2017\/10\/ring.png\" alt=\"\" width=\"329\" height=\"61\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2017\/10\/ring.png 329w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2017\/10\/ring-300x56.png 300w\" sizes=\"(max-width: 329px) 100vw, 329px\" \/><\/a><\/p>\n<p>Next there are the middlewares. Those are like filters in the Java servlet world and can be used to enhance the application. By default there are some middlewares configured e.g. for handling parameters, session or cookies.<\/p>\n<p>In the end a request hits the handler which transforms the request to a response.<\/p>\n<p>Compojure can help you implement the routing for those handlers. This is a simple example that creates one successful route and one function to handle paths that are not found.<\/p>\n<div>\n<div id=\"highlighter_92790\" class=\"syntaxhighlighter  java\">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"gutter\">\n<div class=\"line number1 index0 alt2\">1<\/div>\n<div class=\"line number2 index1 alt1\">2<\/div>\n<div class=\"line number3 index2 alt2\">3<\/div>\n<\/td>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"java plain\">(defroutes app<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"java spaces\">\u00a0\u00a0<\/code><code class=\"java plain\">(GET <\/code><code class=\"java string\">\"\/\"<\/code> <code class=\"java plain\">[] <\/code><code class=\"java string\">\"&lt;h1&gt;Hello World&lt;\/h1&gt;\"<\/code><code class=\"java plain\">)<\/code><\/div>\n<div class=\"line number3 index2 alt2\"><code class=\"java spaces\">\u00a0\u00a0<\/code><code class=\"java plain\">(route\/not-found <\/code><code class=\"java string\">\"&lt;h1&gt;Page not found&lt;\/h1&gt;\"<\/code><code class=\"java plain\">))<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>If you want to get started yourself the easiest way is to use the <a href=\"https:\/\/github.com\/weavejester\/compojure-template\">leiningen-compojure template<\/a> that creates the application skeleton for you.<\/p>\n<div>\n<div id=\"highlighter_742990\" class=\"syntaxhighlighter  java\">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"gutter\">\n<div class=\"line number1 index0 alt2\">1<\/div>\n<\/td>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"java plain\">lein <\/code><code class=\"java keyword\">new<\/code> <code class=\"java plain\">compojure my_project_name<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>This will create the necessary folder structure, a leiningen file, a handler and a test for it.<\/p>\n<p>If you don&#8217;t want to write all the html in Strings yourself like in the example above it&#8217;s time for a templating library. One that is often used in combination with Ring and Compojure is Hiccup. It allows you to write Clojure code that is being translated to HTML.<\/p>\n<div>\n<div id=\"highlighter_92769\" class=\"syntaxhighlighter  java\">\n<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td class=\"gutter\">\n<div class=\"line number1 index0 alt2\">1<\/div>\n<div class=\"line number2 index1 alt1\">2<\/div>\n<\/td>\n<td class=\"code\">\n<div class=\"container\">\n<div class=\"line number1 index0 alt2\"><code class=\"java plain\">user=&gt; (html [:span {:<\/code><code class=\"java keyword\">class<\/code> <code class=\"java string\">\"foo\"<\/code><code class=\"java plain\">} <\/code><code class=\"java string\">\"bar\"<\/code><code class=\"java plain\">])<\/code><\/div>\n<div class=\"line number2 index1 alt1\"><code class=\"java string\">\"&lt;span class=\"<\/code><code class=\"java plain\">\\<\/code><code class=\"java string\">\"foo\\\"\"<\/code><code class=\"java plain\">&gt;bar&lt;\/span&gt;\"<\/code><\/div>\n<\/div>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<p>I developed a very simple application using those libraries: a tool for seeing and adding vocabulary. Once started you can see a list of vocabulary, add more words and look up translations. I wouldn&#8217;t say it&#8217;s production ready for now, one reason being that it stores all the data in memory only :) You can find the <a href=\"https:\/\/github.com\/fhopf\/clojure-vocabulary\">source code on Github<\/a>.<a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2017\/10\/clojabulary.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-69926\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2017\/10\/clojabulary.png\" alt=\"\" width=\"720\" height=\"325\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2017\/10\/clojabulary.png 720w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2017\/10\/clojabulary-300x135.png 300w\" sizes=\"(max-width: 720px) 100vw, 720px\" \/><\/a><\/p>\n<p>It contains a GET and a POST route for reading the list and adding a word and a Hiccup template.<\/p>\n<h2>Conclusion<\/h2>\n<p>It was fun working on a new language and after grasping the basics of Clojure it is easy to get started with a webapp, mainly because of the Leiningen Compojure template that makes it easy to set up a new project. There is a lot of ready made functionality available in the Ring middlewares. Hiccup still feels a bit weird to me, I am not too sure if many frontend developers are keen on working with it.<\/p>\n<p>I wish I would have had more time to prepare the talk and work on the example. There are still a lot of things I have no idea about and I hope I can find some time to continue learning. Even though I don&#8217;t foresee to use Clojure in a project at work anytime soon it can be very benificial to learn about new approaches &#8211; your perception of some language features can change.<\/p>\n<p>If you want to get started with Clojure as well &#8211; I can especially recommend <a href=\"https:\/\/aphyr.com\/posts\/301-clojure-from-the-ground-up-welcome\">Aphyrs series on the basics<\/a>. I have seen a useful talk by different InnoQ people over the years that especially covers the web libraries. <a href=\"https:\/\/www.youtube.com\/watch?v=3Xm_nVqxowk\">A recording by Michael Vitz is available on YouTube<\/a>.<\/p>\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td>Published on Java Code Geeks with permission by Florian Hopf, partner at our <a href=\"http:\/\/www.javacodegeeks.com\/join-us\/jcg\/\" target=\"_blank\" rel=\"noopener\">JCG program<\/a>. See the original article here: <a href=\"http:\/\/blog.florian-hopf.de\/2017\/10\/learning-clojure-webapps.html\" target=\"_blank\" rel=\"noopener\">Learning to Build Clojure Webapps<\/a><\/p>\n<p>Opinions expressed by Java Code Geeks contributors are their own.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>A while ago I gave a talk at an internal event at Zenika Singapore. We were free to choose a topic so I chose something I thought I didn&#8217;t know enough about &#8211; what it feels like to build a web app in Clojure. This post is a transcript of the talk. I&#8217;ll go into &hellip;<\/p>\n","protected":false},"author":559,"featured_media":93,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22],"tags":[],"class_list":["post-69906","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-clojure"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Learning to Build Clojure Webapps - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"A while ago I gave a talk at an internal event at Zenika Singapore. We were free to choose a topic so I chose something I thought I didn&#039;t know enough\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Learning to Build Clojure Webapps - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"A while ago I gave a talk at an internal event at Zenika Singapore. We were free to choose a topic so I chose something I thought I didn&#039;t know enough\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2017-10-24T04:00:39+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2019-02-14T11:19:24+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/clojure-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Florian Hopf\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/fhopf\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Florian Hopf\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/10\\\/learning-build-clojure-webapps.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/10\\\/learning-build-clojure-webapps.html\"},\"author\":{\"name\":\"Florian Hopf\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/ffed07622be537868d71a953742e9d58\"},\"headline\":\"Learning to Build Clojure Webapps\",\"datePublished\":\"2017-10-24T04:00:39+00:00\",\"dateModified\":\"2019-02-14T11:19:24+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/10\\\/learning-build-clojure-webapps.html\"},\"wordCount\":1319,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/10\\\/learning-build-clojure-webapps.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/clojure-logo.jpg\",\"articleSection\":[\"Clojure\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/10\\\/learning-build-clojure-webapps.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/10\\\/learning-build-clojure-webapps.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/10\\\/learning-build-clojure-webapps.html\",\"name\":\"Learning to Build Clojure Webapps - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/10\\\/learning-build-clojure-webapps.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/10\\\/learning-build-clojure-webapps.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/clojure-logo.jpg\",\"datePublished\":\"2017-10-24T04:00:39+00:00\",\"dateModified\":\"2019-02-14T11:19:24+00:00\",\"description\":\"A while ago I gave a talk at an internal event at Zenika Singapore. We were free to choose a topic so I chose something I thought I didn't know enough\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/10\\\/learning-build-clojure-webapps.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/10\\\/learning-build-clojure-webapps.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/10\\\/learning-build-clojure-webapps.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/clojure-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/clojure-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2017\\\/10\\\/learning-build-clojure-webapps.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"JVM Languages\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/jvm-languages\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Clojure\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/jvm-languages\\\/clojure\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Learning to Build Clojure Webapps\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/ffed07622be537868d71a953742e9d58\",\"name\":\"Florian Hopf\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/c1be71f01d810bb91604ed8d73a9a5ecd185562f1adadd9441c8184f4b495187?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/c1be71f01d810bb91604ed8d73a9a5ecd185562f1adadd9441c8184f4b495187?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/c1be71f01d810bb91604ed8d73a9a5ecd185562f1adadd9441c8184f4b495187?s=96&d=mm&r=g\",\"caption\":\"Florian Hopf\"},\"description\":\"Florian is a software developer living in Singapore. He enjoys building search solutions based on Lucene, Solr and Elasticsearch and he's interested in topics like build automation and test driven development.\",\"sameAs\":[\"http:\\\/\\\/blog.florian-hopf.de\\\/\",\"https:\\\/\\\/x.com\\\/https:\\\/\\\/twitter.com\\\/fhopf\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/florian-hopf\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Learning to Build Clojure Webapps - Java Code Geeks","description":"A while ago I gave a talk at an internal event at Zenika Singapore. We were free to choose a topic so I chose something I thought I didn't know enough","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html","og_locale":"en_US","og_type":"article","og_title":"Learning to Build Clojure Webapps - Java Code Geeks","og_description":"A while ago I gave a talk at an internal event at Zenika Singapore. We were free to choose a topic so I chose something I thought I didn't know enough","og_url":"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2017-10-24T04:00:39+00:00","article_modified_time":"2019-02-14T11:19:24+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/clojure-logo.jpg","type":"image\/jpeg"}],"author":"Florian Hopf","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/fhopf","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Florian Hopf","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html"},"author":{"name":"Florian Hopf","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/ffed07622be537868d71a953742e9d58"},"headline":"Learning to Build Clojure Webapps","datePublished":"2017-10-24T04:00:39+00:00","dateModified":"2019-02-14T11:19:24+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html"},"wordCount":1319,"commentCount":0,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/clojure-logo.jpg","articleSection":["Clojure"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html","url":"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html","name":"Learning to Build Clojure Webapps - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/clojure-logo.jpg","datePublished":"2017-10-24T04:00:39+00:00","dateModified":"2019-02-14T11:19:24+00:00","description":"A while ago I gave a talk at an internal event at Zenika Singapore. We were free to choose a topic so I chose something I thought I didn't know enough","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/clojure-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/clojure-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2017\/10\/learning-build-clojure-webapps.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"JVM Languages","item":"https:\/\/www.javacodegeeks.com\/category\/jvm-languages"},{"@type":"ListItem","position":3,"name":"Clojure","item":"https:\/\/www.javacodegeeks.com\/category\/jvm-languages\/clojure"},{"@type":"ListItem","position":4,"name":"Learning to Build Clojure Webapps"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/ffed07622be537868d71a953742e9d58","name":"Florian Hopf","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/c1be71f01d810bb91604ed8d73a9a5ecd185562f1adadd9441c8184f4b495187?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/c1be71f01d810bb91604ed8d73a9a5ecd185562f1adadd9441c8184f4b495187?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/c1be71f01d810bb91604ed8d73a9a5ecd185562f1adadd9441c8184f4b495187?s=96&d=mm&r=g","caption":"Florian Hopf"},"description":"Florian is a software developer living in Singapore. He enjoys building search solutions based on Lucene, Solr and Elasticsearch and he's interested in topics like build automation and test driven development.","sameAs":["http:\/\/blog.florian-hopf.de\/","https:\/\/x.com\/https:\/\/twitter.com\/fhopf"],"url":"https:\/\/www.javacodegeeks.com\/author\/florian-hopf"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/69906","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/559"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=69906"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/69906\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/93"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=69906"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=69906"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=69906"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}