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.

ETags

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.

Summary

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:

Cognitect has recently released the results of their State of Clojure Survey for 2018. For the lasttwo Clojure survey’s, I have reviewed the free-form answers at the end of the survey and tried to summarise the zeitgeist of community feeling. I enjoy it each time, and so here’s this years analysis.

Some comments have been lightly edited for spelling, clarity, and brevity.

Error messages

Error messages have been one of the top complaints about Clojure since the surveys started, and this year they have gotten worse with the introduction of specs on core macros. I’m not the onlyone who has noticed this either. In 2015 Colin Fleming gave a talk on improving Clojure’s error messages with Grammars. In previous surveys there was hope that spec would be able to use this approach to improve error messages; Ben Brinckerhoff has recently shown a proof-of-concept that gives some similar (excellent) error messages in Expound.

My primary wish would be for more helpful error messages (e.g a la Elm) in Clojure and Clojurescript.

I was excited about spec initially; however, I find the error messages so large, noisy and unhelpful that I don’t want to use it. To put it another way: when there’s a spec failure, my heart sinks; knowing that the next few minutes are probably going to be frustrating and painful.

Spec was supposed to help with error messages, but it just made them worse. Stuff like (let [f/x 42] f/x) now emit insane error messages. But it looks like the Clojure dev team has moved on to improving command line tools now? Can we please just get error messages fixed before a ton of people get frustrated and jump ship? The current state of errors in Clojure is an embarrassment to the community.

Error messages is a big show stopper. I am trying to get Clojurescript adopted for web and react-native development withing our organization for few years, but I always see the same pattern: people get some error during project setup/configuration and get stuck forever because they have no idea what the error means at all and how get it fixed. Please please improve error reporting. :)

A big problem for new starters, an issue that has been singled out time and time again over the years, is poor error messages that lead to difficult debugging of code structure. That Clojure 1.9 has actually made these error messages harder to understand is a disaster. […] I hope I’m wrong and that I’ll understand the grand plan eventually.

Please please please please enhance the error messages. An incredible error reporting would make this language out of this world, and that would make the biggest difference.

Spec

Comments ranged from loving spec to disliking it. There were also requests for more guidance on how to apply spec to real-world use-cases and how to integrate it into whole programs.

OMG Spec is amazing. It’s dramatically changing the way I program. I’ve been starting new projects out by writing specs before nearly any other code. The result is that I am able to extend my hammock time to the keyboard, and think through my domain model with composable, high level descriptions implemented as specs. The fact that these high level descriptions then become so useful in so many different ways — generative testing, value conformation for data api parsing, more useful error messages, etc — is a stunning thing to behold. I’m excited to see how the fruits of these ideas permeate through our and other communities.

The presence of “spec” on some of those lists made me want to rate everything else “important” so I could show how unimportant it is. […]

spec is awesome, but its dogmatism leaves us needing tools like spec-tools, which makes working with spec clunky.

There needs to be more guidance, development and reliance on spec from both Cognitect and community.

Docs

Documentation in all forms has been another perrenial complaint but this is starting to improve. clojure.org continues to add more guides this year on Programming at the REPL and Higher Order Functions among other things. Martin Klepsch’s cljdoc holds a lot of promise to improve the state of third-party documentation, by automatically generating and publishing docs for published JARs.

We should take example of how Rust community/documenation is run: BIG focus on newcomers, features MUST be perfectly documented before being shipped. This serve advanced users as well. No offense, but Rich Hickey should understand what good documentation is, or delegate completely to people who do so that he can focus and making a even greater language (his strong point).

I feel the true weak points are confusing error messages, not enough friendly guides/tutorials for the early to beginner Clojurist, and a lack of solid CLJ/S example projects. These are key because it is difficult to know the right way without “blessed” examples.

Please provide a good set of tutorials on Javascript Interop such as how to translate a ES6 or higher JS file into ClojureScript.

The documentation is really awful - incomplete, vague, no examples, no semantic precision - not up to the standards of what one normally sees for programming language documentation.

Please improve the docstrings. They are the worst of any programming language I have ever used.

Really, the core documentation is not written for beginners or even intermediates

What I miss most is a book which teaches how to approach problems with Clojure. I mean primarily not “best practices” or “design patterns” or language independent algorithms. Nor a kind of language reference or few lines long mini examples, but complex, advanced examples with detailed explanations about the pros and cons of certain solutions applied/not applied.

Startup time

Startup time continues to be an issue for people. As serverless computing becomes more mainstream, this may end up pushing people from Clojure to ClojureScript, or elsewhere.

Startup time is really really really really really long

Startup time never used to be an issue for me, as my services were long running and persistent. Lately however, I’ve been using Docker for jobs. Startup time becomes an issue here. Continued improvements in total app startup time will pay dividends going forward.

Marketing/adoption/staffing

There were lots of comments this year in this category. Even after 10 years, Clojure still unknown or seen as being extremely niche to many people, especially among business stakeholders. Hiring seems to be less of an issue than in years past. There is still a large contingent of programmers looking to work with Clojure in remote positions, although it’s hard to say whether this proportion is any higher than in other language communities.

I recently hired a programmer with no Clojure experience. She was writing lovely idiomatic Clojure within a month. The biggest difficulty was overcoming her initial fear of parentheses.

To use Clojure(Script) more it would help if there was marketing for it. It’s still largely unknown, and therefore hard to sell to other companies.

There is always an uphill battle in pushing Clojure as an enterprise solution, this seems to mostly occur to lack of marketing. Non-technical decision makers care about branding.

I’ve found that some folks really dislike lisps passionately. One of our vendors indicated that his customers and employees were highly critical of the use of Clojure as an extension point.

Unfortunately, this year my organization in ceasing its use of Clojure for production projects after many years of using it. Staffing and on-boarding external resources are the 2 main reasons for doing so.

Hard to convince managers at work to use Clojure because of the perception that its a fringe language

I wish it was easier to find a remote (non US-only) remote Clojure/Clojurescript job for people with no major Clojure experience :)

I believe “JavaScript converts” will be an important source of growth for Clojure moving forward.

We find Clojure a joy to use and hiring Clojure engineers or those excited and capable of learning Clojure has been a big advantage, contrary to common wisdom. Clojure positions tend to self select for strong candidates.

Language

Enterprise Java tends to lean heavily on reflection to pull components together (e.g., Spring, annotation-driven JUnit and JAX-RS). To incorporate Clojure into those environments, lots of component-specific wrappers are needed. It is easy to slip a little Java into a Clojure codebase, but this has made the reverse difficult.

I would love to see some more work on improving clojure.test. It works, but I wish there was less stateful macro magic and more flexibility with fixturing and test structure

I’m increasingly finding that I’m writing more cljc than clj or cljs but find it really frustrating that cljs seems to be a second citizen to clj. It would be much better if there was actually a core Clojure library/api that was actively supported by both, with clear variances between them.

I would love to see some work towards using JVM MethodHandle’s to obviate the need for the compiler’s direct linking. Seems we could have our var cake, and eat it too.

We have a relatively large codebase and 20+ build targets (fat jars/advance compilation js files). we’d like better AOT support and ability to incrementally compile this code base as most changes only affect a few targets. right now AOT compile is pretty black box and not very amenable to building tooling.

Language Development Process

This hasn’t changed in a long time, and I don’t see it changing in the future, but it has been persistently highlighted by many people as a big issue.

For long term success of Clojure/ClojureScript, it’s important for the Clojure core team & project to be more open and welcoming like other open source projects. The view from outside of the Cognitect bubble is that the language and community aren’t healthy at all, and I fear for it’s long run viability.

The core team seems to be extra cautious and move really slowly on the language and core libraries. And the roadmap for releasing new versions is really opaque to the community.

Cognitect has continued to be good technical stewards of Clojure, but poor stewards of the relationship between the core team and the rest of the community. Many (most?) senior Clojure programmers want nothing to do with contributing to Clojure or any projects owned by Core (like the site) because the process is designed to frustrate and prevent meaningful contributions.

Cognitect need to climb a few rungs down the ivory tower and engage with the community as if it were in fact made up of human beings trying to do their jobs.

I don’t know what direction the core team is taking Clojure, and the top issues (startup time, poor error messages, lack of involvement with the community and numerous improvements to Java interop in JIRA being ignored) have not changed significantly over the past 5 years. I never felt welcomed to contribute, and seeing how Skummet and other large efforts from the community were largely ignored was not encouraging.

More attention to JIRA issues/patches/contributions would be great. […] I painstakingly write a patch and jump through the JIRA hoops; but there it languishes. The dev team’s complete silence is not encouraging. Makes me feel more of an outsider, less of a part of the community.

Community

By and large, people found the community welcoming, and personally I have found it to be one of the best things about working with Clojure. However there is a persistent undercurrent of eliteness from some Clojure programmers which really puts people off the language.

I find Clojure a great language, but I haven’t noticed any increase in market (or mind) share. Quite the opposite, it seems to be going nowhere, possibly dying a slow death I hope I’m wrong, but, for now anyway, I’ve given up on it.

Thanks, Alex et al! I’m still extremely happy with Clojure, and appreciate the community. I worry a bit about the possibility of clj/s losing user share and dwindling, which I didn’t worry about a year ago. I hope like hell that that won’t happen, and try to do at least a bit toward preventing it.

That defn podcast is bloody marvelous

Being in the Clojure community since around 1.2, I loved the language then, and I like the direction, it’s been taking since. The community is great, very friendly and even its most controversial figures are usually polite, intelligent people. Heck, even the local troll from the mailing list is occasionally helpful, stays on point in his threads and sticks with the conversation, even after blowing stuff up.

clojure.org changes so infrequently (like once a year, if that?) that I’m concerned the language is not being enthusiastically supported and will soon fade away. It makes me nervous to invest time and money in a language that seems to have no vitality.

Clojure conferences lack diversity in both attendees, speakers, and programs. I hope the merging of Conj and West will improve that this year.

People who give to the Clojure community are role models. I’m serious about this. I’ve woken up and thought “what would Bruce Hauman do” more than once. I talk with my daughters about the Clojure community.

Cognitect is doing an awesome job, making programming fun again! Alex Miller is very helpful.

Effort community makes to promote diversity, particularly in terms of women is good, although there is a long way to go.

I am doing Clojure for some time now and what does not bring me joy is the fact that the message to other communities (other languages) is clear: “we are better and smarter”. […] I think we can do better without thinking that we are.

I didn’t want to tick the unpleasant communities cause it is not […] lately [however], […] I started noticing a kind of “elitism” especially from people that are frequent speakers or started working early with the language.

I have multiple colleagues, all great developers, all former Clojure developers. Whenever Clojure comes up they never fail to mention how alienating the “smarter than you” attitude sometimes present in the community can be.

I’m worried about the perceived shrinking of the Clojure community

I’ve gotten to know a few more female developers using Clojure in the past year, and have learned that some parts of the community are scaring/driving women away. This includes unpleasant interactions on Slack and working to avoid certain people at Conj.

Not to put too much stock in the oversimplified Gartner hype curve model, it does seem like Clojure is passing through what they call the trough of disillusionment.

Please consider supporting Clojurists Together, even launching initiatives for the community to help through it.

Libraries

More guidance on how to compose and select libraries remains a common common issue for people in this section, as well as improving the state of library documentation.

The plethora of web app (both client & server side) frameworks is both bad and good. Too many to choose from (no standard like rails) and also lots of options. Also, limited security options, especially w.r.t. use of session state, async handlers & server-less designs.

I frequently find myself frustrated by looking for a library that will help me do “X”. There are many choices out there, each of which does some subset of what one might want in that arena, but a different subset.

It is sad that I often find interesting Clojure or ClojureScript libraries that are abandoned and haven’t been updated for a long time

Need more quality open source projects for machine learning and data visualization libraries. Great to see the advances from conj but for a language that has a front end tool built in, there is no excuse for someone not to build a great visualization library for data science.

No de-facto web framework, Pedestal is in dire need of documentation, Schema is deprecated and Spec isn’t ready, New CLI tools in Clojure 9 competing with Leiningen/Boot. All of these complaints have something in common: it looks like the Clojure core team is actively hostile towards the larger community. All community-built tools/libraries are open to attack and replacement by the core team and there’s always fear of a major destabilizing revolution everyday.

Several widely used library started to stall… sustainability might become a concern… [Ed: hopefully Clojurists Together can help here]

Other targets

As in previous years, there are a smattering of people asking for alternative platforms to target other than JS and the JVM. LLVM, Go, and Web Assembly all had interest from people.

Is it posible to use Clojure with the Go ecosystem? That would be amazing

It is hard to watch Go get so much mind-share. Clojure on the JVM is great, but it would sure be nice if I could build a Clojure application that didn’t need the JVM.

I still long for a low-level oriented Clojure dialect to be able to produce small clj executables with low overhead and systems programming capacity, but one can dream!

Typing

Requests for static typing were down from previous years. I attribute that mostly to spec gaining wider adoption and understanding.

Clojure needs to make a better case for why static typing is not necessary for maintainable, large, multi-contributor codebases and how the REPL dev process helps with that.

I still love Clojure as a whole more than any other. I’d love to address long-term maintenance. The difficulty of stepping back into a codebase after some time can be more challenging than with Haskell or PureScript. I wish the compiler could do more for me. Spec is huge though, really enjoying it. It still takes a good amount of discipline to use well, but I’m thankful for it.

I used Clojure for one work project because a coworker recommended it. Overall it was a good experience, but the lack of a type system made maintaining that particular project too difficult. Tools like Plumatic Schema and Typed Clojure helped in some ways but didn’t end up pulling their weight. Regardless, the Clojure service continues to run today and it’s better than the Ruby service it replaced.

ClojureScript

ClojureScript continues to improve, although getting the tooling setup remains a pain point, as does integrating NPM modules. There are recent improvements on that front though, so this may not be such an issue in 12 months time. I have heard lots of good things about shadow-cljs, it seems to be a strong tool to investigate for ClojureScript usage, especially if you work with a lot of NPM modules.

ClojureScript has had a serious push this year… ;)

For CLJS, we really need to get npm deps working. Right now it’s hard to get right, or at least there’s no up-to-date tutorials available..?

I find I spend more time than I should configuring my development environment so it works well. This is particularly bad in React Native, but cljs/figwheel can still be frustratingly complex to get right.

Lack of async/await support in CLJS is holding it back. The JS community has settled on promises and async/await as the primary asynchronous patterns, and although core.async is useful for certain things, shoehorning existing JS code into it is very kludgy.

Nothing has made a bigger improvement to my ClojureScript workflow in the past couple of years than shadow-cljs.

Way faster cljs compile flow due to smart caching of intermediate artifacts

Self-hosted dependencies handled very well

NPM support in ClojureScript seems to be a little bit tricky and not working all the time for all the libs. But has been improved a lot in the past.

Probably my biggest frustration has been trying to use libraries from JS in a full-on ClojureScript front-end app.

Setup/tooling

Tooling on the Clojure side seems to be somewhat less of an issue this year, but setting up ClojureScript projects with all the things that you need remains an issue for many people.

Clojure is now mature and stable enough to start focusing in tooling. Many JVM tools are not Clojure specific and for people coming to Clojure from non-jvm languages diagnosing problems is a barrier (more with systems in production). From GC issues, to debugging exceptions, to attaching to a process in runtime to peek at some memory or patch something. It was pretty easy to do with gdb in linux, it should be much more easily done with Clojure.

Fast track to CLJS web dev for junior devs, in one piece in one place. There is not that much essential knowledge/tooling needed to get started that it can’t fit in a CreateReactApp-like solution. Too much content, too many sources, don’t help. No need to be exhaustive.

Git-based deps seem like a bad idea. clj build tool is otherwise cool, if a bit unnecessary given the prevalence and quality of leiningen, along with the stability afforded through maven central/clojars.

I think we should pay more attention to interactive programming. Like what Bret Victor proposes, beyond the REPL.

Making changes to libraries then having to jar them just to test is hard (checkouts never worked for me (or others) with cljs). I hope Alex Miller’s recent work will fix that.

Once Figwheel and Reagent and tests were set up, my experience as a developer was very positive - barring some bad times with advanced Closure optimization bugs. Really happy with ClojureScript myself, but it would be hard to convince a friend to start using it, because there is no clear or standard way to develop.

Compliments

As always, the survey was dominated by positive comments. Here were some of my favourites.

Clojure has ruined every other language for me. Every time I have to do something in another language, I always wish it was in clojure. It’s just so easy to get things done in clojure. I love the language and hope to use it forever.

Clojure’s still the language I find myself turning to most frequently when given a choice. It just feels natural, the toolkit simple and yet powerful enough to express pretty much anything at a whim.

I’ve been using Clojure professionally for at least 4 years and these have been the most productive years of my career. I’m looking forward to using spec more fully. I’m looking forward to seeing what improvements come to the language in the next few years and have no desire to leave. Thanks so much for this language, community, and way of working.

Conclusion

When I went to write this years summary, I re-read the previous posts to remind myself of where we were a few years ago. While some areas have improved, I was struck by how many of the comments could have been lifted from previous years survey results. There was a worrying trend in the community and adoption sections that people perceive Clojure to be shrinking. Perception doesn’t always match reality, and it may be (as a commenter noted) that Clojure is entering the trough of disillusionment phase of the Gartner Hype Cycle. However I think there are a lot of low-hanging fruit around that could significantly improve the experience and ecosystem around Clojure without changes to the core language.