Log4j2 and Clojure quick setup

As we all know, java logging is a mess and I believe most developers are wondering how output to terminal or file, can be a rocket science?

Those who want to save some sanity and keep things simple, I'm sure are already are using Timbre.

But, my use case was different - the application had to log as much as possible, but that had to be fast as possible and provide plenty of configurable options for the end user, without touching source code.

From these tests 3 years ago, log4j2 seems like ultimate solution, especially if properly configured (check Recommendation section in given link).

Setup

Without further ado, let's see how to get this up and running. I'll assume Leiningen is used.

In project.clj add this:

 :dependencies [...
                 [clojure.tools.logging "0.6.0"]
                 [org.apache.logging.log4j/log4j-api "2.13.0"]
                 [org.apache.logging.log4j/log4j-core "2.13.0"]
                 [org.apache.logging.log4j/log4j-jcl "2.13.0"]
                ...]

log4j-api and log4j-core are obligatory. log4j-jcl is router for Apache Commons Logging and is a good thing to have, especially because clojure.tools.logging order of detection will pick up Apache Commons library before Log4j, if found in classpath. Many libraries depends on Apache Commons and you can end up scratching your head, wondering why logger isn't working properly.

If you don't want log4j-jcl as dependency, this behaviour can be mitigated by setting clojure.tools.logging.factory property at JVM startup. In Leiningen project.clj this line will do the work:

:jvm-opts ["-Dclojure.tools.logging.factory=clojure.tools.logging.impl/log4j2-factory"]

log4j2.xml configuration

Log4j2 has tons of configuration options, but I wanted this behavior:

  • All logs should go to folder logs by default and the folder must be created if is not present.
  • User can override logs folder with logPath property.
  • Application logs (debug, info, error) goes to logs/application.log.
  • Errors and exceptions goes to logs/error.log.
  • Both files must be rotated after size reaches 100 MB. After they are rotated, older files must be gzipped.
  • After 5 rotations, delete old files. This will assure disk is not filled up with old log archives.
  • Application logs everything to console as well.

Here is configuration that will do above. Put it in resources/log4j2.xml file so Log4j can find it, but also so it can be shipped with jar or uberjar.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <!-- console output -->
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d %p %m%n" />
    </Console>

    <!-- default output -->
    <RollingFile
        name="RollingFile"
        bufferedIO="true"
        fileName="${sys:logPath:-logs}/application.log"
        filePattern="${sys:logPath:-logs}/application.%i.log.gz">
      <PatternLayout pattern="%d %p %m%n" />
      <Policies>
        <SizeBasedTriggeringPolicy size="100MB" />
      </Policies>
      <DefaultRolloverStrategy max="5" />
    </RollingFile>
    
    <!-- errors output -->
    <RollingFile
        name="RollingFileErrors"
        bufferedIO="true"
        fileName="${sys:logPath:-logs}/error.log"
        filePattern="${sys:logPath:-logs}/error.%i.log.gz">
      <PatternLayout pattern="%d %p %m%n" />
      <Policies>
        <SizeBasedTriggeringPolicy size="100MB" />
      </Policies>
      <DefaultRolloverStrategy max="5" />
    </RollingFile>
  </Appenders>

  <Loggers>
    <Root level="all" includeLocation="false">
      <AppenderRef ref="RollingFile" level="DEBUG"/>
      <AppenderRef ref="RollingFileErrors" level="ERROR"/>
      <AppenderRef ref="Console" />
    </Root>
  </Loggers>
</Configuration>

Notice that I'm using RollingFile appender for taking care of rotating logs and keeping their size to max 100 MB. Be aware that it will add overhead; for ultimate performance, File appender can be used with asynchronous logger and leave to external services like logrotate to perform file rotations. Or, use Console appender and let init service like systemd route all logs to syslog or whatever system logging facility is installed.

In my case, I could not rely that logrotate will be present on system where application is run (macOS, Windows, Linux not properly configured,...).

Nice thing about Log4j is ability to override provided log4j2.xml with custom configuration, using log4j.configurationFile property, like:

java -Dlog4j.configurationFile=custom.xml -jar app.jar

Log2j has excellent performance page explaining what to use when and their appenders page will give enough details for every appender.

Enjoy!

Permalink

PurelyFunctional.tv Newsletter 366: Is the Clojure philosophy bad for beginners?

Issue 366 – February 24, 2020 · Archives · Subscribe

Clojure Tip 💡

Is the Clojure philosophy bad for beginners?

People often ask if Clojure’s philosophy is bad for beginners, so I’d like to address it in the context that I set up in the last issue. In short, if it’s true that Clojure libraries shouldn’t anticipate all of the needs of the user, doesn’t it make it hard for beginners to use the library? My short answer is I don’t know.

Here’s the code from last week that the CSV library expects the users to write themselves:

(defn rows->maps [csv]
  (let [headers (map keyword (first csv))
        rows (rest csv)]
    (map #(zipmap headers %) rows)))

Any experienced Clojure programmer could write something like this with no sweat. But could a beginner? I doubt they could do it without some help. Some of the concepts are at least intermediate level, like combining map with zipmap.

It reminds me a lot of the troubles the Smalltalk group had teaching beginners that I talk about in my recent podcast episode. Here’s a quote from The Early History of Smalltalk.

It started to hit home in the Spring of ’74 after I taught Smalltalk to 20 PARC nonprogrammer adults. They were able to get through the initial material faster than the children, but just as it looked like an overwhelming success was at hand, they started to crash on problems that didn’t look to me to be much harder than the ones they had just been doing well on. One of them was a project thought up by one of the adults, which was to make a little database system that could act like a card file or rolodex. They couldn’t even come close to programming it. I was very surprised because I “knew” that such a project was well below the mythical “two pages” for end-users we were working within. That night I wrote it out, and the next day I showed all of them how to do it. Still, none of them were able to do it by themselves. Later, I sat in the room pondering the board from my talk. Finally, I counted the number of nonobvious ideas in this little program. They came to 17. And some of them were like the concept of the arch in building design: very hard to discover, if you don’t already know them.

Seventeen nonobvious ideas in two pages of code. And this is a language designed for children! What hope does Clojure have of being beginner-friendly?

Alan Kay’s conclusion was that programming is hard. It has to be taught like we teach reading—over many years with many examples and lots of guidance. There are a lot of ideas that aren’t hard when they are taught, but they are hard to discover on your own. We need to learn them and pass them on to the next generation. Programming is culture.

So when people say it’s unfriendly to ask beginners to write the code above, I agree, but I think the solution is not to wrap it up in a function and give it to them. I think the solution is to teach them to do it themselves. That’s passing on culture, and in fact that’s what the clojure.data.csv Readme does. Beginners solve their problem and learn a bit of Clojure at the same time.

The extra advantage is they are learning something that is useful elsewhere. They’re not learning the ins and outs of the options of that particular library. They’re learning to use the core library and transform data in a Clojury way. We need to teach the next generation.

I don’t think we can blame a language for programming being hard. Clojure is hard, JavaScript is hard, Smalltalk is hard. Each language might make some things easy, but there will always be hard things. We need to pass down the culture that we have built up for a few generations now. It’s more work for us experienced folks, and, yes, more work for the beginner. But the beginner will be better off! Honestly, would you rather know how to write your own parser or know the specific combination of options you need for one particular parsing library? I just think it’s a matter of education, not coding.

Book update 📖

Chapter 6 is out! Buy it now: Grokking Simplicity.

Also, the liveBook is ready for prime time! This means you can preview the content of the book before buying and you can read it online after you buy. Amazing!

You can buy the book and use the coupon code TSSIMPLICITY for 50% off.

Podcast episode🎙

In my most recent episode, we are reading from The Early History of Smalltalk by Alan Kay. Listen/watch/read here. Be sure to subscribe and tell your friends.

A new episode is coming soon. In it, I read Lambda: the Ultimate GOTO by Guy Steele, Jr.

Clojure Challenge 🤔

Last week’s challenge

The challenge in Issue 365 was to model a Starbucks coffee. There were no submissions 🙁 I guess modeling problems aren’t that fun? Let’s try something different.

This week’s challenge

Number of hands of poker

Poker users a 52-card deck, where each card is unique. After shuffling, a player gets five random cards. How many different hands are there? Remember, in poker, the order of the cards in your hand does not matter.

Write a function that takes the number of cards in a hand h and the number of cards in the deck d and calculates how many possible hands there are.

(defn combinations [d h]
  .....
)

Hint: there is a mathematical formula for combinations already!

As usual, please reply to this email and let me know what you tried. I’ll collect them up and share them in the next issue. If you don’t want me to share your submission, let me know.

Rock on!
Eric Normand

The post PurelyFunctional.tv Newsletter 366: Is the Clojure philosophy bad for beginners? appeared first on PurelyFunctional.tv.

Permalink

Four short links: 24 February 2020

  1. YOLO Creator Leaves Computer Vision — Joseph Redmon, creator of YOLO (You Only Look Once) has stopped doing computer vision because of its uses. But basically all facial recognition work would not get published if we took Broader Impacts sections seriously. There is almost no upside and enormous downside risk.
  2. schema tool to infer and instantiate schemas and translate between data formats. Supports JSON, GraphQL, YAML, TOML, and XML.
  3. Overtonean open source audio environment designed to explore new musical ideas from synthesis and sampling to instrument building, live-coding, and collaborative jamming. We combine the powerful SuperCollider audio engine with Clojure, a state of-the-art lisp, to create an intoxicating interactive sonic experience.
  4. An Architectural Risk Analysis of Machine Learning Systems — a comprehensive approach to identifying different types of risk in each component and process of a generic machine learning system.

Permalink

Ep 068: Static on the Line

Each week, we discuss a different topic about Clojure and functional programming.

If you have a question or topic you’d like us to discuss, tweet @clojuredesign, send an email to feedback@clojuredesign.club, or join the #clojuredesign-podcast channel on the Clojurians Slack.

This week, the topic is: “Serving static assets.” We tease apart the layers involved in serving static assets and are surprised by how many we find.

Selected quotes:

  • “You’d think that serving up plain old files would be nice and simple.”
  • “MIME types are an explosion of complexity.”
  • “Simplicity is the only remedy for complexity. Abstraction is not a remedy for complexity.”

Permalink

Babashka: A quick example

At JUXT, we try to reduce the number of tools we use to the bare minimum.

The less tools we need to learn to do our work, the more time we can devote to learning each tool well.

Our standard operating system is GNU/Linux (Arch Linux), which we use on both developer laptops and servers. Our standard document format is AsciiDoc (of the Asciidoctor variety). All our documents (contracts, client reports, web pages, blog articles, policy documents, etc.) are stored in AsciiDoc and we generate HTML and/or PDF from these. Adding in git and keybase, we’ve pieced together a capable company document production, approval and management system.

Building document PDFs with make and asciidoctor-pdf.

Sometimes, a document might require some custom build logic. For example, a report might contain a table of data extracted from a Crux database. Naturally we use GNU Make and bash to knit together these customised builds, but whenever you try to do something complex, you can end up thrashing around in the long grass.

For example, we have a document named ETH001.adoc which includes an image stored as ETH001/boy-and-computer.jpg. The PDF version of the document can be generated using a Make rule:

target/pdf/%.pdf: %.adoc brand/juxt-theme.yml
   asciidoctor-pdf -r asciidoctor-diagram -o $@ $<

This means that a change to the original Asciidoc source file, or a change to the theme we use to build the PDFs, will result in the asciidoctor-pdf executable being run and the resulting PDF rebuilt.

However, since the PDF also contains images, if those images change (sometimes we’re in the process of enhancing images in Gimp), we want the PDF to be rebuilt. But how is it possible to let Make know about these dependencies?

Well, we could go through the source file and look for any image:: tags. Here’s one:

image::ETH001/boy-and-computer.jpg[width=300pt]

Then we can add an additional dependency rule inside the Makefile:

target/pdf/ETH001.pdf: ETH001/boy-and-computer.jpg

Maintaining these rules might be a pain, and we’ll quickly forget to do it. My sed and awk skills might be up to the tasks of grep’ing out the include:: lines of each file, but …​ I’d much rather be using Clojure. I’m always struck by the startling contrast between the consistency and elegance of the Unix line-by-line data processing model and the inconsistency and ugliness of the syntax of the individual tools. This is what makes Lisps such as Clojure all the more extraordinary - an easy-to-learn, consistent syntax which can scale up to the tackle the most ambitious of problems.

Until now, I probably wouldn’t bother writing a Clojure program for this task. Clojure is a little too slow to start up to be suitable for scripting.

Enter Babashka!

Babashka is a Clojure-like scripting language written by @borkdude (Michiel Borkent), of clj-kondo fame. Babashka is close enough to Clojure so I can avoid having to clutter my memory with the myriad of different syntaxes of Unix tools (bash, sed, awk, grep). I can leverage my Clojure familiarity for the boring task of writing scripts.

So let’s write a script (depend_images.clj) that will go through our 50 odd AsciiDoc files, extract out each line that brings in an image, and print a Make dependency rule between the document and that image:

(doseq
  [adoc (.listFiles (java.io.File. "."))
   :when (.isFile adoc)
   :let [[_ basename] (re-matches #"(.*).adoc" (.getName adoc))]
   :when basename
   line (line-seq (io/reader adoc))
   :let [[_ match] (re-matches #"image::(.*)\[.*\]" line)]
   :when match]
  (println
   (format "target/pdf/%s.pdf: %s" basename match)))

In our Makefile we can add a depend target that will run this script:

depend:
	bb depend_images.clj > images.mk

We can run the target with make:

$ make depend

On my machine, that takes about 170ms. That’s perfectly acceptable for my use-case.

The resulting file (images.mk) can be included in the Makefile with the following:

include images.mk

That’s it.

winking babushka
"Remember, learn Lisp and use it everywhere. Everything else is mind clutter."

Epilogue

I’m looking forward to reaching for babashka at times where I’d normally reach for bash (or awk, or sed). Of course, there are plenty of alternative solutions to these simple problems. However, it’s a tribute to the design of Clojure that the language feels so naturally consistent, and can achieve similar feats to a compendium of Unix tools, each with their own syntactic idiosyncrasies.

For many many years, I’ve wished for a Clojure-like replacement for classic shell-scripting. This may just be it.

Permalink

Grumpy chronicles: The question of utils

This is an ongoing mini-series of lessons learned from writing a tiny blog engine in Clojure. Code we will be discussing today.

The problem

Every project has a utils namespace. Usually, it’s a huge single namespace with all the tiny code bits that need to be used from more than one place in the project.

As the project starts to grow, a single namespace becomes hard to keep organized. You might notice that functions are in more or less random order, related things are not necessarily be grouped together. That lowers discoverability and reuse, the main reason utils exist in the first place.

Mixed Clojure/Script projects have another issue: many of the utils only make sense on a single platform, while others need to be cross-compiled. Unfortunately, you can’t create utils.clj, utils.cljs AND utils.cljc all at the same time. And keeping everything in utils.cljc would mean putting #?(:clj) or #?(:cljs) around 2/3 of the functions.

The solution

I split utils into a family of namespaces grouped by domain. E.g. numbers — one namespace, collections — another, time, urls, files, etc. Grumpy is a small project (<2000 LoC), yet we already have 17 such libraries:

└── core
    ├── coll.cljc
    ├── config.clj
    ├── files.clj
    ├── fragments.cljc
    ├── jobs.clj
    ├── log.cljc
    ├── macros.clj
    ├── macros.cljs
    ├── mime.cljc
    ├── posts.clj
    ├── routes.clj
    ├── time.clj
    ├── transit.clj
    ├── transit.cljs
    ├── url.cljc
    ├── web.clj
    └── xml.clj

This is a joy to work with. If I need to do something with a file, I go to grumpy.core.files. If what I need is not there, I create a function right there, where it belongs. And it feels good: things stay neatly organized, writing new code does not increase a tech debt. Each namespace is essentially a small library: useful, focused, comprehensible, with clear mission and scope, no more and no less. If everybody loves good reusable libraries, why not organize your own project like it?

And don’t worry if some namespaces start small. For example, grumpy.core.log is just a single one-line function:

(defn log [& args]
  (apply println #?(:clj (time/format-log-inst)) args))

What matters is that semantically it’s its own area of responsibility, so it has to go into its own namespace.

It also makes thinking about dependencies somewhat easier. You have a two-part graph: reusable libraries and business code. The bottom half can depend on the top half, but not vice versa. Here’s how it looks in Grumpy right now (arrows means “depends on”):

Normally depending on “business” namespaces might be complicated if there are special conditions, how namespaces should be loaded, dependency loops, etc. The utility namespaces are the direct opposite of that. They guarantee not to depend back on “business” code, just like an external library would! If you put your code in the top half, the rest of the project can always reference it with zero effort.

The rule

Single-file utils namespaces are very convenient for people and, just like entropy, they have a tendency to appear almost on their own. You have to take active action to prevent this from happening. I even go as far as declaring it a principle:

A catch-all util namespace is not allowed.

If you want to make a piece of code reusable, figure out to which sub-library, semantically, it should go. This creates a clear point for making a decision, forcing everyone to decide here and now, but in the long run, it will save you a lot of headaches.

Permalink

State of Clojure 2020 Results

Ten years ago, Chas Emerick ran the first State of Clojure survey. In 2010, most users had been using Clojure for just weeks or months, and few were using it as a language for serious work. This year, we see consistent and growing use for work, steady interest in the key value propositions of Clojure, and an ever-evolving community of users.

Clojure at Work

One of the questions we have been asking since 2010 is whether respondents are using Clojure for work, hobby projects, tinkering, or studies. This year, we saw the highest percentage yet of Clojure use at work:

Clojure uses

Additionally, we saw a small shift in company size to bigger companies - an increase of 3% in companies of size 1000+ (and reduction in companies size 1-10).

Clojure organization size

We also asked respondents for the first time how many people were using Clojure at their organization. As expected, many Clojure teams are small. As a high-leverage tool, Clojure is a great fit for small highly-productive teams. However, it was also great to see many respondents at companies with 40 or even 100+ Clojure developers.

Clojure devs at organization

A question we’ve been asking since 2010 (with some variation in wording and choices), is in what domains Clojure is being used. The top results have not changed too much over the years but we did see a noticeable increase this year in "enterprise applications", to its highest level ever.

Clojure domains

Feedback comments indicate Clojure is a tool yielding high leverage for both companies and teams:

  • "Clojure continues to be a force multiplier and a vital enabler for our production system."

  • "Clojure enables our small team to do more with less."

  • "Clojure is by far the best language I have to use at work, and it is a pleasure to solve problems using it. It is almost perfect."

  • "Clojure is powering our data driven insurance ERP. I cannot think of a better approach. Many thanks!"

  • "Hard to find too many complaints about Clojure: it’s a wonderful language with a great community. I plan to stay with this language + community for a long time. We have basically bet the company’s technical strategy on it."

  • "I love using Clojure and ClojureScript and have moved all our development projects using various different languages (PHP, Python, C#, Javascript) to only using Clojure and ClojureScript"

  • "Our startup is built solely on Clojure and Clojurescript and we are very happy with it."

Clojure’s use continues to grow at hundreds of companies, with an ever higher percentage of developers using it at work for their core business.

Values

Since 2015, we have asked a question about which aspects of Clojure users valued the most. The weighted ranking of those answers has remained virtually identical since 2015. The most important things to Clojure users are: functional programming, the REPL, immutable data, ease of development, and host interop. Indeed these are all things intrinsic to the Clojure experience and align strongly with the reasons Clojure exists.

The open feedback comments often praised the steady arc of Clojure’s development and tradition for growing without breaking:

  • "Clojure is an awesome lisp, lovingly created with taste and refinement. It is a pleasure to think and implement in the abstractions provided."

  • "Great work, team! This is the most stable technology I’ve used in my many years doing software development."

  • "I love what you are doing with the language and community. In the world of churn and constantly pumping changes just to create 'buzz' clojure is like a safe zone where my sanity is kept alive."

  • "I really like the simplicity of Clojure and the functional nature of it. I also like the fact that the team doesn’t slap on a ton of features like every other language out there."

  • "Thanks for sticking to the principles: lean, conservative, essential, no frills, production grade software that brought back Lisp to the mainstream."

Community

Again this year we surveyed the most popular forums where Clojurists interact with each other. Some new and/or rising entries included in-person Clojure conferences (we saw many new ones this year!), the new Ask Clojure site, Telegram chats, and Discord.

Clojure forums

We also collect information on how users are involved in the Clojure ecosystem. The response this year were very similar to last year but we did see mild upticks in helping new Clojure users, advocating for Clojure in their organization, and maintaining open source libraries, all great contributions!

Clojure involvement

In feedback comments, many people enjoyed the kind and responsive Clojure community:

  • "The Clojure community is absolutely fantastic. Being able to post a question and get thoughtful & insightful answers quickly is immensely valuable. Thank you for fostering such an incredible community."

  • "Clojure (Script) is a great, well-thought out language that has helped me tremendously in my work. However, it also exposed me to a wonderful community of thoughtful developers who have given me wonderful new insights, while remaining a friendly and welcoming community"

  • "Wonderful language and a uniquely insightful community. It has helped me rediscover my love for programming."

Deep Dives

Clojure developers will be particularly interested in the version and tooling related questions in the survey.

One new question we asked this year was about the primary developer operating system to give us better guidance about tool-related work. As expected, MacOS was the leader (55%), followed by Linux (35%) and Windows (9%):

Clojure developer operating system

For primary development tool, there were only minor updates this year. Emacs dropped slightly to 43%, IntelliJ/Cursive rose slightly to 32%, and VS Code with Calva had the biggest increase to 10%.

Clojure development environment

Clojure users have a wealth of fine development environments, each suited to different communities and tastes, and we’re glad to see them all getting better day by day.

For many years, the survey has included a question about "build tools", but this idea of a single monolithic tool has become increasingly less reflective of how people are managing Clojure projects, where they may use multiple tools for different parts of their process, particularly in mixed Clojure/ClojureScript projects. In response to this, we tailored this question more tightly to dependency management and made it multi-select this year:

Clojure dependency management

Looking at previous years, we continue to see strong (but slightly reduced) use of Leiningen, and a steady increase in use of clj/deps.edn. For ClojureScript work, shadow-cljs has made big strides over the last couple years, with big support from Clojurists Together.

In the greater world of Java and the JVM, Java has migrated to a new release strategy where releases come out every spring and fall, and every 3 years there is a "long term support" (LTS) release - 8, 11, and (presumably) 17. Java 9 introduced a major change with the module system and in all JVM communities this has caused a significant user base to remain on Java 8. Clojure reflects this as well (although probably shows more shift to Java 11 than other language communities):

Java versions

Releases like Java 9, 10, 12, and soon 13 are effectively dead when the next release comes out and we would recommend sticking primarily to the LTS releases and maybe the latest release, if it’s not an LTS release.

One aspect of Java 11 that is underappreciated is significant work to make Java work better in containers like Docker. If you are deploying in containerized environments with Java 8, you should really be looking closely at the changes in Java 11 and considering an upgrade.

Clojure itself has been using Java 8 as the baseline JVM for a couple years and will continue to do so (while also supporting newer versions of Java). When running Clojure, we recommend Java 8 or 11 right now.

Since last year, we’ve seen strong uptake of Clojure 1.10.0 and 1.10.1. The latter was a maintenance release this year with error handling improvements building on the changes in Clojure 1.10.0 and mitigations for some Java performance regressions in their service releases after Java 8u201. Use of Clojure 1.8 and earlier continues to dwindle:

Clojure versions

In addition to the prior dependency management question, we also added a new question on how respondents are starting their apps in production. Based on feedback, it’s likely the wording and answer choices will need some fine-tuning next year, but there is some interesting feedback in the results:

Running production apps

The majority of users are using launchers like Leiningen or clj to start their production apps, more so than by building jars or uberjars and launching them directly with Java. We do see a small group also experimenting with Graal native images (particularly common with smaller scripting apps).

Full Results

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

Thanks again for using Clojure and ClojureScript and participating in the survey!

Permalink

Clojure survey feedback

I just published the results from the State of Clojure 2020 Survey, but I also wanted to post some thoughts on the open feedback section at the end. I read through all the responses there (about 645 responses from the 2500+ people that completed the survey). As usual, a large percentage (about 65%) were expressions of either thanks or general happiness, so thanks for those, they are fun to read and feel appreciated.

I’ll also shout out some people in the community that came up many times - Sean Corfield for his tireless library work and help for beginners, Daniel Compton for his work with Clojurists Together (and his many other efforts), and Michiel Borkent for his work on scripting and tooling around graal, clj-kondo, sci, etc. Kudos to them, and to anyone else I missed in the responses!

I also tried to categorize and sort through the top requests that I saw and here’s the rough tally I came up with (subject to a lot of interpretation of course) for Clojure:

  • 20+ mentions
    • Spec 2
    • More or better beginner or getting started docs
    • More jobs or more people to hire for jobs
  • 10+
    • Best practices docs on specific topics - spec, core.async, code organization, etc
    • Error messages
    • Graal native image support
  • 3<x<10
    • Startup performance (specifically more for apps, related to namespace loading, not scripting cases)
    • Reference docs or docstrings/examples
    • Runtime performance
    • Data science
    • More involvement by community in road map
    • Static analysis tools
    • Java interop, specifically around Java 8+ functional APIs
    • Web framework
    • General lib stagnation/abandonment
  • Fewer - stack traces, debugger, various tools.deps improvements, etc

So that’s a lot of stuff, but the good thing is, there’s a high degree of overlap between this list and what we consider priorities for the core team and direction. Spec 2 has not had a lot of active commits, but has been in active design off and on and I want nothing more than to get back to it and finish it, which should happen this year.

For the next Clojure version (presumably 1.11), we plan to fix the Graal locking issue and have also talked about several other possible features including Java interop for functional APIs, startup performance, etc. There are a few small improvments for error messages queued up, but I think we’re likely to see the best changes come out of spec and new directions towards function specs.

In the community, we also see active work around data science/machine learning/AI with things like libpython-clj, Neanderthal, and the Clojure data science online meetup. I don’t think the core team actively needs to drive any of that and we are supportive and in touch with people as needed. Michiel Borkent’s clj-kondo is a great static analysis tool that has also pushed the state of Graal with Clojure further, and again this is mostly community-led (with the exception of the issue mentioned above).

For docs, I definitely feel the need there, particularly for beginners, and there are certainly things to do, just a matter of balancing it with all the things above. I definitely appreciate everyone writing or building things in the community to help new Clojurists. I’ve also written a big chunk of core.async docs, but they have enough holes that I haven’t gotten them out there yet.

Hiring/getting hired in a Clojure job is a perennial issue. Jobs exist, and people exist, but the distribution of those in geography or experience are often out of whack. Probably the best place to make those connections are at in-person conferences, and I’m happy that we’ve seen so many new conferences spring up over the last couple years in multiple continents.

If you want to dive more deeply into this feedback and see what you can do to help, the response can be downloaded as part of the full results..

Permalink

Firebase Authentication With Clojure

Today we'll be adding Firebase Authentication to a static website that's generated with Clojure. Part of The Solo Hacker's Guide To Clojure. Prerequisites: Landing Pages.

If you cloned Mystery Cows before 18 Feb 2020, run git pull. Besides adding a new authentication branch, I added some Bootstrap compilation code to the landing-page branch in place of using Bootstrap Magic. See Landing Pages.

Demo

(As always, you can also see what we'll be building at cows.jacobobryant.com.)

In the Mystery Cows project, checkout the authentication branch. Run ./task setup again to install some more Firebase dependencies. But before you start the dev server, you'll need to do some setup for Firebase Authentication.

First, copy .firebaserc from the project you created last time to the Mystery Cows project. The contents should look like this:

{
  "projects": {
    "default": "your-project-id"
  }
}

Next, go to the Firebase console for your project (firebase.google.com). Go to Develop -> Authentication -> Sign-in method. First enable "Email/Password," and then also enable "Email link (passwordless sign-in)." After that, enable sign-in with Google. If you're using a custom domain for your project, add it under "Authorized domains."

Now you can run the dev server (./task dev) and open localhost:5000. You should see that the mailing list sign-up form we had before has been replaced with an actual sign-in form. If you create an account, you should see it show up in the Firebase console.

The code

Run git diff landing-page authentication to see what changed.

task

Note the two dependencies we've added for firebaseui-web (a drop-in sign-in form). You could instead link directly to the CDN, but I self-host them because I had a user once who was blocking gstatic.com.

public/js/main.js

We've replaced the mailing list sign-up code with some initialization code for firebaseui-web. (Note that the links for Terms of Service and Privacy Policy will give 404 errors. If you're working on a Serious Project, you can get started with some auto-generated ones.)

public/css/main.css

I've removed A CSS rule that was messing up the sign-in form. I've instead added the CSS inline in the next file.

src/cows/core.clj

We're now generating three separate pages: a landing page, a login page, and an app page (which is where we'll start putting our ClojureScript next time). Be sure to take a look at ensure-logged-in and ensure-logged-out.

Do it yourself

Since you've already set up authentication from the Firebase console, there's not too much left to do for your own project. Copy over task and public/js/main.js from Mystery Cows. Run ./task dev and start working on the login and app pages in src/cows/core.clj. When you're done, you could run ./task deploy, though for a Serious Project you'd want to leave the mailing list signup form until later.

Next time, we'll add some simple React components to the app page using ClojureScript, Rum and Shadow CLJS. We might also get to some very basic CRUD (using Firestore) and state management.

Permalink

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.