Clojure/DevOps Engineer at Red Pineapple Media (Full-time)

Want to work with Clojure in Berlin?

Red Pineapple Media distributes video advertising to more than 50 markets, and we've been expanding consistently since we started 6 years ago.

Our engineering team is built around a strong culture of teamwork. Code reviews, joint presentations and group decisions are standard for us. We'll often pick up the projector and do pair programming on the big wall of our office, or just sit together in one of our quiet rooms to prepare architectural changes or to give peer-to-peer feedback.

We care deeply about continual improvement, and have an RFC process in place to enable team members to influence our evolving standard and practices.

We’re in an exciting phase right now as we’re transitioning to programmatic buying and selling of advertisement space. The number of non-trivial challenges ahead is large, and the learning opportunities rich. From intelligently bidding for advertisement space in real time, to applying clustering and classification techniques to improve ad targeting, our future is full of opportunities for functional-programming goodness 

What attitude are we looking for?

  • You have a strong sense of ownership and responsibility;
  • You’re ready to work independently, clearly define problems, and objectively evaluate tradeoffs of potential solutions;
  • You’re naturally motivated and proud of doing great work;
  • You believe that clear communication (including documentation and Git history) are a key part of good software engineering;
  • Your thought process is guided by rationalism and evidence rather than gut feeling or tradition;
  • You enjoy diversity (including differences of opinion), and have a humble attitude when engaging in discussions;
  • You sincerely welcome constructive criticism, and communicate with regard for the feelings of others.

What do we value in people?

  • Code needs to be read by humans, so you write code and documentation optimising for clarity;
  • You understand the importance of testing and automation, and avoiding repeating the same mistakes;
  • You get things done not only when starting exciting new projects but also when refactoring inelegant legacy code;
  • You're ready to work daily with Linux systems, AWS, Git, Docker and a steadily growing Microservice infrastructure;
  • You’re ready to embrace the DevOps way of life, because an Engineer’s work doesn’t end after ‘git push’;
  • Your studies were in computer science, mathematics, engineering or a related area;
  • Alternatively: you have an awesome GitHub profile to show off :-)
  • You have worked with Clojure, ClojureScript, or other functional programming languages (and you're interested in learning Clojure!);
  • You have worked with distributed systems and have dealt with problems related to concurrency, performance and fault tolerance;
  • Curiosity is a constant in you. You don't settle for the same language or paradigm for too long and are eager to experiment and learn new things.

What we offer

Compensation of €42,000 - €60,000.

Never a dull moment. Besides writing code, we also do our own DevOps, testing, retrospectives, planning, architecture, peer-to-peer evaluation, coffee and cooking.

Small teams, lots of freedom

Every few months we organise in small teams around well-defined business objectives, and we have complete ownership over the approach and process used to achieve them. This includes: planning, work methodology, design, development and maintenance. We also decide when and how to tackle technical debt, and we are the sole owners of these decisions. Then, after some time, we reset the teams and choose new challenges to work on.

A safe haven for functional programmers

Even if your background is in non-functional programming, if you want to do functional programming then Red Pineapple Media is the place for you. You’ll find as many challenges here as learning opportunities. You’ll also have the chance to try new things and explore. We regularly hold research weeks where you can spend your time investigating and building anything you want.

Friendly environment plus quiet rooms

We regularly hold team breakfasts, barbecues, and ping-pong matches. We’re super animal friendly: 4 dog owners, 2 vegans, 1 vegetarian and a cat-loving CEO. Naturally, dogs are welcome in the office. But we also optimise for focus and have quiet rooms where you can do power-naps, meditate or just work in isolation.

Do what you want - and own it

We believe that when given independence and room to grow, people tend to do great things. If you want to learn something new, fix that annoying Elasticsearch performance problem or focus on creating nicer looking brandings or reports, it’s up to you. As long as our business objectives are achieved, you own and control your time and what to do with it.

About Red Pineapple Media

Red Pineapple Media is a passionate, dedicated team of content and marketing professionals connecting advertisers, publishers, and consumers all over the globe. We’re driven by one simple goal: deliver campaigns that mutually benefit the advertiser, publisher, and the consumer. It’s a strategy that has seen us successfully help over 300 advertisers increase their exposure and boost online media ROI in more than 56 markets – and counting.

You can learn more about us at

Get information on how to apply for this position.


Testing Clojure Web Applications with Selenium

This article is brought with ❤ to you by Semaphore.

Selenium is a commonly used set of tools for automating browsers. It allows you to drive a browser interaction with a web page by writing code. It's most often used to write browser-based tests for web applications. Tests can be executed in a development environment or even on a real application as part of a smoke test suite.

Selenium provides support for most popular languages and browsers. This tutorial explains how to use Selenium for testing Clojure web applications. Our setup will be based on clj-webdriver and Firefox, and we will use Compojure to write a very simple web application.

Setting Up the Project


For developing a Clojure application using this tutorial you will need:

  • Java JDK version 6 or later.
  • Leiningen 2.
  • Firefox 39 or lower.

At the time of this writing, if you have a newer version of Firefox, the example might not work for you. If it doesn't, you will need to downgrade Firefox. You can see what's the last version of Firefox that Selenium officially supports on the Selenium changelog page. If you plan to use Selenium-based tests regularly, you might want to hold Firefox updates until Selenium starts supporting them.

Create a Hello World Compojure Application

Compojure is a routing library for Ring, and a popular choice for writing web applications in Clojure. Leiningen provides a Compojure template that allows us to get started with Compojure quickly.

Create a Compojure-based Clojure project:

lein new compojure clj-webdriver-tutorial

The second parameter compojure is the name of the template that's going to be used for creating the application. The last parameter, clj-webdriver-tutorial, is the name of your project.

Navigate to the project directory:

cd clj-webdriver-tutorial

Start the server:

lein ring server-headless

After the server starts, visit http://localhost:3000 in a browser and you should see the Hello World greeting from the application:

Hello World

Compojure Application Structure

The structure of your application should look like this:

├── project.clj
├── resources
│   └── public
├── src
│   └── clj_webdriver_tutorial
│       └── handler.clj
├── target
│   ├── ...
└── test
    └── clj_webdriver_tutorial
        └── handler_test.clj

The file that we're interested in is src/clj_webdriver_tutorial/handler.clj. If you open it, it should contain the following code:

(ns clj-webdriver-tutorial.handler
  (:require [compojure.core :refer :all]
            [compojure.route :as route]
            [ring.middleware.defaults :refer [wrap-defaults site-defaults]]))

(defroutes app-routes
  (GET "/" [] "Hello World")
  (route/not-found "Not Found"))

(def app
  (wrap-defaults app-routes site-defaults))

It defines the access point to the application (/ - the root path), and we can see that this is where that "Hello World" is coming from.

We can also notice that Leiningen created the handler_test.clj file that's using clojure.test to test the handler. Since we're concentrating on clj-webdriver instead, let's remove the test:

rm test/clj_webdriver_tutorial/handler_test.clj

Install clj-webdriver

Install clj-webdriver by adding the project development dependencies to project.clj:

(defproject clj-webdriver-tutorial "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url ""
  :min-lein-version "2.0.0"
  :dependencies [[org.clojure/clojure "1.6.0"]
                 [compojure "1.3.1"]
                 [ring/ring-defaults "0.1.2"]]
  :plugins [[lein-ring "0.8.13"]]
  :ring {:handler clj-webdriver-tutorial.handler/app}
  {:dev {:dependencies [[clj-webdriver "0.7.1"]
                        [org.seleniumhq.selenium/selenium-server "2.47.0"]
                        [javax.servlet/servlet-api "2.5"]
                        [ring-mock "0.1.5"]
                        [ring/ring-jetty-adapter "1.4.0"]]}})

There are several new things in project.clj:

  • We added clj-webdriver "0.7.1".
  • Next, we explicitly added the selenium-server that supports at least Firefox
    1. If you have a newer version of Firefox, you can try upgrading selenium-server to the latest available Selenium version.
  • We also added ring-jetty-adapter to run the application before executing tests.

First clj-webdriver Test

Create the features directory where you will put clj-webdriver tests:

mkdir test/clj_webdriver_tutorial/features

Open test/clj_webdriver_tutorial/features/config.clj and add some common configurations that we will use in tests:

(ns clj-webdriver-tutorial.features.config)

(def test-port 5744)
(def test-host "localhost")
(def test-base-url (str "http://" test-host ":" test-port "/"))

The default configuration states that tests will be executed against the application running on http://localhost:5744. 5744 is the default port for Selenium.

Our first test will check if the home page really displays the "Hello World" message. Since we're testing by opening a real browser, the test needs some setup and teardown. Here are the steps that need to be executed:

  1. Start the server for the application.
  2. Open the root path in the browser.
  3. Check if the "Hello World" message is present on the page.
  4. Close the browser.
  5. Shut down the server.

Let's write a skeleton of that code in test/clj_webdriver_tutorial/features/homepage.clj:

(ns clj-webdriver-tutorial.features.homepage
  (:require [clojure.test :refer :all]
            [ring.adapter.jetty :refer [run-jetty]]
            [ :refer :all]
            [clj-webdriver-tutorial.features.config :refer :all]
            [clj-webdriver-tutorial.handler :refer [app-routes]]))

(deftest homepage-greeting
  (let [server (start-server)]
    (to test-base-url)
    (is (= (text "body") "Hello World"))
    (stop-server server)))

The most important parts are the to and text functions that are used for navigating to a page and extracting text from a node, respectively. They are part of the clj-webdriver Taxi API.

Before running the test, we need to implement the start-server, start-browser, stop-browser and stop-server functions.

The start-server function is the most complex one, as it starts the jetty server on the test port and waits for the server to be started:

(defn start-server []
  (loop [server (run-jetty app-routes {:port test-port, :join? false})]
    (if (.isStarted server)
      (recur server))))

The other functions are much simpler:

(defn stop-server [server]
  (.stop server))

(defn start-browser []
  (set-driver! {:browser :firefox}))

(defn stop-browser []

As they are actually wrappers against respective functions in the clj-webdriver, they can be used directly in a real application test.

Putting in all together and our first code in test/clj_webdriver_tutorial/features/homepage.clj looks like this:

(ns clj-webdriver-tutorial.features.homepage
  (:require [clojure.test :refer :all]
            [ring.adapter.jetty :refer [run-jetty]]
            [ :refer :all]
            [clj-webdriver-tutorial.features.config :refer :all]
            [clj-webdriver-tutorial.handler :refer [app-routes]]))

(defn start-server []
  (loop [server (run-jetty app-routes {:port test-port, :join? false})]
    (if (.isStarted server)
      (recur server))))

(defn stop-server [server]
  (.stop server))

(defn start-browser []
  (set-driver! {:browser :firefox}))

(defn stop-browser []

(deftest homepage-greeting
  (let [server (start-server)]
    (to test-base-url)
    (is (= (text "body") "Hello World"))
    (stop-server server)))

Run the tests suite:

lein test

And you will see that the test passed:

Ran 1 tests containing 1 assertions.
0 failures, 0 errors.

You now have a basic setup for testing Clojure web applications with Selenium.

Cleaning Up

This setup works well, but we have to remember to start the server and the browser before each test, and to shut them down after the tests are done. To make things easier, we can implement test fixtures that will do this automatically before and after every test.

The fixture for handling the server can be implemented as follows:

(defn with-server [t]
  (let [server (start-server)]
    (stop-server server)))

The t parameter stands for test case function. It starts the server before the test case, executes the test function, and stops the server.

The fixture for handling the browser is similar:

(defn with-browser [t]

Using fixtures, we can write a much cleaner test:

(ns clj-webdriver-tutorial.features.homepage
  (:require [clojure.test :refer :all]
            [ring.adapter.jetty :refer [run-jetty]]
            [ :refer :all]
            [clj-webdriver-tutorial.features.config :refer :all]
            [clj-webdriver-tutorial.handler :refer [app-routes]]))

;; Fixtures

(defn start-server []
  (loop [server (run-jetty app-routes {:port test-port, :join? false})]
    (if (.isStarted server)
      (recur server))))

(defn stop-server [server]
  (.stop server))

(defn with-server [t]
  (let [server (start-server)]
    (stop-server server)))

(defn start-browser []
  (set-driver! {:browser :firefox}))

(defn stop-browser []

(defn with-browser [t]

(use-fixtures :once with-server with-browser)

;; Tests

(deftest homepage-greeting
  (to test-base-url)
  (is (= (text "body") "Hello World")))

Note that we passed the :once parameter to the use-fixtures function. This means that the browser will be started once before all tests, and stopped after all tests are finished. The same goes for the server. This should significantly speed up the tests in the file.

In a real application, you can move fixture functions to a separate namespace that is shared by all tests.


Selenium is a valuable tool for testing web applications, and it is indispensable if an application is heavily using JavaScript. Setting up Selenium with Clojure requires several steps covered in the tutorial. Using fixtures, a test setup can be reused, which results in cleaner and faster tests.

You can find more information about common functions for interacting with web pages and inspecting page content in the clj-webdriver Taxi API documentation.

This article is brought with ❤ to you by Semaphore.


How to serve ClojureScript files in development

When I develop ClojureScript projects, I almost always use Figwheel. It’s a great tool, but sometimes my app ended up using stale files. This led to some very confusing debugging sessions. It only happened some of the time, and was always fixed after a hard refresh. I thought about just disabling the browser cache, but I didn’t like ignoring the issue. After seeing colleagues struggle with stale caching too, I decided to figure out what was going on, and fix it once and for all.

Cache-Control rules everything around me

The first thing to do was to add a Cache-Control: no-cache header to all static file responses. Despite the name, no-cache tells the browser it can cache files, but must always validate them with the server before using them. If the browser’s cached version is up-to-date, a compliant HTTP server should return a 304 Not Modified response, otherwise it serves the new file.

If you don’t provide a caching header to an HTTP response, the browser can choose its own caching behaviour. The browser’s caching heuristics are much more aggressive than you want in development, and lead to the weird caching behaviour I was seeing.

I thought this had fixed the issue, but occasionally I would still notice stale files were being used. After looking closely at the compiled output files, I made a surprising discovery.

ClojureScript copies file modification times

ClojureScript (as of March 2018) copies the last-modified date of ClojureScript source files to the compiled JavaScript target files. This is so that the compiler can detect changes to source files. JavaScript from the Closure compiler (e.g. goog.base), gets a modification time that matches the time it was compiled.

Neither of these dates are particularly useful to use as a Last-Modified date header for caching purposes.

  • Closure compiled JavaScript doesn’t change from run to run, so caching based on last modified date will not achieve as high a hit-rate as possible.
  • ClojureScript files that use macros from other Clojure files will copy the ClojureScript files modification date to the compiled JavaScript, even if the macro files have changed and are newer. This was leading to the second round of caching issues that I saw.


To knock both problems on the head once and for all (hopefully), I added a CRC32 checksum based ETag for static file responses. I packaged this up in a library ring-etag-middleware so that other projects could also use it. I also removed the Last-Modified header from the Ring response, as it would bust the browser’s cache unnecessarily.


As best as I can tell, this has completely solved all of the odd caching issues that I was seeing, while still keeping the app snappy to load by reusing as much of the cache as possible. If you are serving ClojureScript files in development and not using Figwheel, I recommend you follow these three steps:

  1. Set a Cache-Control: no-cache header
  2. Add an ETag to your static file responses
  3. Remove the Last-Modified header


Thought Experiment: Namespaced record fields

I don’t like to nest records in Elm. It’s not that big of a deal, but it always seem to be lead to more noise than initially thought. Part of this is that Elm doesn’t have syntax that’s convenient for nested updates. Take a look at this record definition:

type alias Person =
  { name : Int
  , age : Int
  , pet : Pet

type alias Pet =
  { name : String
  , age : Int

If I had a person record and wanted to rename the pet, the code would look like something like this:

-- Can't do this
{ | name = "Fido" }

-- Or this
{ person | pet = { | name = "Fido" } }

-- It has to be this
  pet =
{ person | pet = { pet | name = "Fido" } }

As I said previously, this isn't a big deal but it does leave me with an itch. One way to allieviate this is by avoiding nested records all together:

type alias PersonWithPet =
  { personName : String
  , personAge : Int
  , petName : String
  , petAge : Int

We can make this scale by using extensible record syntax:

type alias Pet a =
  { a |
    petName : String
  , petAge : Int

{- Works with PersonWithPet -}
renamePet : String -> Pet a -> Pet a
renamePet name pet =
  { pet | petName = name }

So, this actually solves the problem but does require me to prefix all fields in the record. What if there was support in the compiler for making this nicer?

Let's switch gears a little bit and talk about my previous language-of-choice, Clojure. Clojure is a Lisp and is dynamically typed. Instead of Records one simply uses maps (in Elm we call it Dict) to group together data. Clojure has its own type to serve as keys in a map, called keywords. They look like this:

:name ;; keyword

;; Person with a Pet
(def person
  { :name "Robin"
    :age 29
    :pet { :name "Fido"
           :age 4 } } )

In Clojure, nested updates is pretty simple. If I wanted to rename the pet using the person definition above, I would do this:

(assoc-in person [:pet :name] "Baldur")

However, sometimes it makes perfect sense to avoid nesting and Clojure has wonderful support for that:

(def person-with-pet
  { :person/name "Robin"
    :person/age 29
    :pet/name "Fido"
    :pet/age 4 } )

But this still requires us prefix everything. This is where namespaced keywords comes into play:

(ns person) ;; namespace is set to person

;; This equals our previous definition
(def person-with-pet
  { ::name "Robin" ;; notice the double colon
    ::age 29
    :pet/name "Fido"
    :pet/age 4 } )

;; This is also the same thing
(def person-with-pet
  #:person{ :name "Robin"
            :age 29
            :pet/name "Fido"
            :pet/age 4 } )

The double colon in the example above will fill in the current namespace as the prefix of the keyword. What could this potentially look like in Elm?

module Pet exposing (Pet)

type alias Pet a =
  { a |
    :name : String ;; expands to pet/name
    :age : Int ;; expands to pet/age

module Person

import Pet as P

type alias PersonWithPet =
  { :name : String -- person/name
  , :age : Int -- person/age
  , :P/name : String -- pet/name
  , :P/age : Int -- pet/age

{- Works in PersonWithPet -}
renamePet : String -> P.Pet a -> P.Pet a
renamePet name pet =
  { pet | :P/name = name }

Is this an improvement? Maybe. It might be better to instead find a good syntax for nested updates, but I wouldn't mind just having a simple syntax to work with flat records.


Langohr 5.0.0 is released


Langohr is a small Clojure RabbitMQ client.

5.0.0 is a release that upgrades Java client dependency to 5.x..

Changes in 5.0.0

RabbitMQ Java Client Upgrade

RabbitMQ Java client dependency has been updated to 5.x.

JDK 8 is Now Required

RabbitMQ Java client 5.x requires JDK 8. It’s a good chance to drop support for older JDKs in Langohr. Langohr 4.x continues to use a JDK 6 and 7-compatible version of the Java client.

Queueing/Blocking Consumers are Removed

RabbitMQ Java client 5.0 removed a long deprecated queueing consumer abstraction that used an internal j.u.c queue for deliveries and acted as an iterator. That consumer implementation never supported automatic connection recovery and isn’t necessary with modern consumer operation dispatch pool.

Langohr follows suit and removes the following functions based on the QueueingConsumer:

  • langohr.basic/blocking-subscribe
  • langohr.consumers/create-queueing
  • langohr.consumers/deliveries-seq

langohr.consumers/deliveries-seq may be reintroduced in the future if a reasonable imlementation for it comes to mind/is contributed.

clj-http Upgrade

clj-http dependency has been updated to 3.8.x.

Change Log

Langohr change log is available on GitHub.

Langohr is a ClojureWerkz Project

Langohr is part of the group of libraries known as ClojureWerkz, together with

  • Elastisch, a minimalistic well documented Clojure client for ElasticSearch
  • Cassaforte, a Clojure Cassandra client built around CQL 3.0
  • Monger, a Clojure MongoDB client for a more civilized age
  • Neocons, a client for the Neo4J REST API
  • Quartzite, a powerful scheduling library

and several others. If you like Langohr, you may also like our other projects.

Let us know what you think on Twitter or on the Clojure mailing list.

About The Author

Michael on behalf of the ClojureWerkz Team




Clojure survey, macrology, Elements of Clojure
View this email in your browser



Libraries & Books.

  • Zach Tellman has finished a complete draft of his book Elements of Clojure. He's also doing an AMA on ClojureVerse next week. Chas Emerick (among many others) has high praise for it:
    "This is a great book that uses Clojure as the medium to explore some of the essential questions in computing, and maybe some ways to find an answer or two. 
    Zach has one of the sharpest minds I've ever encountered. You'd do well to soak this up."
  • I'm a bit late on this, but Sean Corfield has taken over maintenance of core.cache and core.memoize and both have new releases out.
  • Kapok is a new lisp on the Erlang VM
  • Piggieback is seeing some new activity from Bruce Hauman and Bozhidar Batsov
  • Confuse is a library for machine learning classification metrics

People are worried about Types. ?

Recent Developments.



Copyright © 2018 Daniel Compton, All rights reserved.

Want to change how you receive these emails?
You can update your preferences or unsubscribe from this list

Email Marketing Powered by MailChimp


State of Clojure 2018 Results

Welcome to the annual State of Clojure 2018 survey results! Thanks so much for taking the time to check in and provide your feedback. We are very fortunate to have data for some of these questions going all the way back to 2010, giving us a long view on how the data is trending. This year, we had 2325 respondents, about the same as last year.

Rapid Uptake of Clojure 1.9

With the release of Clojure 1.9 in December, we expected to see a shift in version usage, and we did. 72% of developers are already using it with about 60% still using Clojure 1.8 as well. Only a small (6%) number of developers are still using versions 1.7 or older.


We also keep an eye on JDK usage. Uptake of Java 1.9, released last year, has been a bit slower with only 29% adopting Java 1.9 so far and 88% of developers using Java 1.8. Only 6% of developers are using Java 1.7 and less than 1% are still using Java 1.6.

In the editor/IDE world we saw some consolidation this year with both Emacs (50%) and IntelliJ/Cursive (29%) making gains. All other editors saw decreases, although there is still a lot of interesting innovation happening around Atom and VS Code, which was not included but saw a lot of mentions in the comments (~5% of total respondents) - will definitely add next year!


In the ClojureScript world, Figwheel continues to dominate as a critical part of most ClojureScript developer's REPL workflow (76%). Clojurists Together is a new community effort to support open source projects in the community and they have been funding work on Figwheel among other projects. Lumo was a new REPL option this year and made a strong showing of 12%.


In CLJS target environments, we saw an increase of +6% targeting Node (to 29%) and +4% targeting Lambda (to 13%) - both things to watch.

In the build tooling world, the entry of the clj tool is driving a lot of reevaluation and change right now. With so many things in flux, this area is sure to evolve significantly in 2018 and it will be interesting to see where we are in 2019. One important omission in the choices this year was shadow-cljs. There were a lot of mentions in the comments and it's clearly an important tool for many to build and deploy - we'll be sure to add it next year.

Interest surging from JavaScript programmers

When we look at which language communities people are coming from, those answers have been remarkably stable for years, but there was significant movement this year for JavaScript (which vaulted over both Python and Ruby). Clearly people are finding ClojureScript (and its strong resonance with React) as an interesting and viable alternative to JavaScript.


As to where Clojurists hang out, we saw significant increases in use of Reddit (+5%) and Slack (+4%) and some decreases in use of the Clojure mailing lists, IRC, and attendance at both in-person and on-line conferences. One new choice added this year was the ClojureVerse Discourse server - it seems to be a useful midpoint between Slack (high volume live chat) and mailing lists (low volume asynchronous discussion). This was a new option yet 17% of respondents reported using it.


Clojure and ClojureScript used in many domains and industries

One of the things we are always watching is the trend of people using Clojure for their day-to-day work. This year, we continued to see about 2/3 of respondents using Clojure for work (compare that to the very first survey back in 2010 when less than 1/3 were doing so). Web development has always been the most dominant domain - in 2010, 53% were doing web dev and these days fully 82% of Clojure devs are involved in some kind of web development (not surprising given how many Clojure devs are using both Clojure and ClojureScript together).


When looking at the industries using Clojure, we added a few choices this year based on prominent results in last year's "Other" category - entertainment (3%), energy/utility (2%), automotive/manufacturing (2%). We also saw a noticeable increase (+3%) in Financial services. Perhaps due to the new choices, we saw small decreases in the largest and most generic categories, enterprise software and consumer software. 


Interest in hiring stays strong

There are several questions about how Clojure and ClojureScript should change or be prioritized for improvement. The results are largely similar to prior years, although the question format changed a little making it hard to directly compare every detail. The top result is clearly error messages though - while spec has started us down a road, that is still a work in progress which will continue this year. Many people have been using the Expound library for taking spec error output and making the data easier to read.

Hiring and staffing is always an interesting one to watch and that increased this year. We often see the seemingly contradictory dual complaints of companies that need more people and developers that have a hard time finding positions. To a large degree this is either a mismatch in the geographic distribution of jobs and people and/or a mismatch in needs and skill levels. It has been very encouraging to see so many large teams growing and hiring of late though.

The need for more docs and tutorials is also one that has gone up and down over the years and seems to be up again this year. While there are a wealth of resources for new Clojure developers now in every format, it is also sometimes difficult for people to find just the right resource for their experience level and need. There have been many good discussions lately about this and lots of active work in the community.

In general, there have been so many new tools, learning resources, companies, etc of late that it's hard to keep up - 2018 is going to be a great year for Clojure!

Check out the data

If you'd like to dig into the full results, you can find the complete set of data from this and former years here:

Note that we are doing the survey about every 14 months so the last survey occurred in late 2016 rather than 2017.

Thanks again for being part of the community!

Permalink Newsletter 269: Elements, Domains, Revenge!

Issue 269 – March 19, 2018 · Archives · Subscribe

Elements of Clojure Book

Zach Tellman’s book is now a complete draft of the book. It’s all there, folks, after years of anticipation. This book should be read by all Clojurists and has a lot to offer serious programmers of any language. It’s a journey through the difficult topics of naming, abstraction, indirection, and composition. We were lucky enough to get a preview of the material at Clojure SYNC during his talk. Keep an eye out for the publication of his talk.

Apropos Episode 3 YouTube

Apropos is a new show that Ray McDermott has put together. There’s a panel of four Clojurists and we talk about news for 30 minutes, then jump into a REPL. If you’re just interested in the news, you can hear it as a podcast. Of course, watching the show live, so you can participate in the discussion, is the best experience. Subscribe to the YouTube channel and/or the Twitter feed to know when it’s live.

Broad Band Book

Claire Evans has created a study of important women in the history of computing. It starts with Ada Lovelace, of course, but quickly gets deep into the stories of women who were written out of history while engineering software–and basically inventing the techniques we take for granted today–on early computers during World War II and after. I was surprised, angered, and inspired by something in every chapter.

Revenge of the Pragmatists Clojure SYNC Video

Baishampayan Ghose opened Clojure SYNC with this amazing talk about what he learned creating a very early Clojure company. He built a team of 80 Clojure programmers, starting back in 2008.

You can watch the video, download slides, and read the transcript.

How to Be Idle Book

I just finished this book by Tom Hodgkinson. Now, I don’t agree with everything in this book. But it is an intelligent expression of a perspective I don’t encounter every day. I appreciated the many quotes of people from across history praising naps, long walks, and sleeping in. It seems that defending a slower, less ambitious pace is nothing new. Especially since I am building a business, it was good to hear a guilt-free praise of rest.

Domain Specific Languages in Clojure

My new video course about one of the coolest ideas in Computer Science and certainly one of the best features of Lisps: writing interpreters and compilers. It turns out that this is not so hard! But the leverage is enormous! A small amount of code can drastically increase the expressivity of your code.

There are seven lessons so far. We start with some definitions, then quickly move into a Hiccup interpreter. Then we convert the interpreter into a compiler! Along the way, we set up a nice Test-Driven Development workflow we can run from the command line.

The post Newsletter 269: Elements, Domains, Revenge! appeared first on


Copyright © 2009, Planet Clojure. No rights reserved.
Planet Clojure is maintained by Baishamapayan Ghose.
Clojure and the Clojure logo are Copyright © 2008-2009, Rich Hickey.
Theme by Brajeshwar.