This is a weblog about computing, culture et cetera, by . Read more.

On JSONfeed

I love it when people link to their RSS feed and it’s actually Atom.

I love it when people link to their RSS feed and it’s actually Atom.

There’s a new alternative to RSS and Atom called JSON Feed. It’s like RSS except that it uses JSON instead of XML. Having written a couple of RSS parsers in my life, I reckon this is a good idea: in many programming languages, parsing and producing XML is a huge hassle compared to dealing with JSON. If you try to consume random RSS feeds, you’ll quickly discover how broken they are.

Based on my experience, it’s common to produce XML by concatenating strings or using a string-based templating language. It’s also common to get this slightly wrong – the content is poorly escaped or the tags are mismatched. In contrast, especially in dynamic languages, JSON is easy to produce by serializing a datastructure. This means that coders in hurry are more likely to produce syntactically valid JSON than syntactically valid XML.

Caveat lector: I do not have experience in consuming random JSON files. My picture might be way too rosy.

The IndieWeb wiki offers some criticism of feed files. I subscribe to approximately 200 blogs and the point about feeds becoming out of date or broken is valid. Feeds just mysteriously break even though the HTML version of the blog continues to work. Sometimes people relocate their feeds without setting up a redirect. The trouble is that the publishers never notice because they don’t read their own feeds. It’s up to the reader to let them know.

A new feed format won’t fix this problem, but then again, I don’t know what would fix it.

I have yet to create a JSON feed for quanttype, but I might as well do it. If someone creates a JSON feed module for Hakyll, let me know.

clojure.spec for configuration validation

Some tools do not require configuration at all.

Some tools do not require configuration at all.

In March, I wrote about configuring Clojure web applications. I recommended storing the configuration in EDN files and loading them with Maailma. Something I didn’t mention at all was validating the configuration.

The problem

What happens if you mistype a configuration key? Clojure is not known for great error messages and you’ll witness this unless you validate your configuration.

Let’s say you use HTTP Kit’s HTTP server and your configuration file looks something like this:

{:http/server {:potr 3000}}

Maybe you start the server like this:

(require '[org.httpkit.server :refer [run-server]])

(defn start-server [config]
  (run-server app {:port (get-in config [:http/server :port])}))

But uh oh, there was a typo in the config! It should say :port instead of :potr. HTTP Kit is going to receive {:port nil}. Can you guess the error message?

boot.user=> (run-server app {:port nil})

Of course. What if you instead pass the whole configuration submap to HTTP Kit?

(defn start-server [config]
  (run-server app (get config :http/server)))

This time you won’t get any error message. The server will quietly ignore the configuration and start at the default port 8090.

I’m using HTTP Kit as an example, but this problem is not specific to it. It’s just rare in the Clojure ecosystem to give useful error messages on bad input, and Clojure’s dynamism does not help here.

This is why configuration validation matters. You’ll save yourself a lot of debugging time by using a bit of time on validation.

The clojure.spec solution

Clojure 1.9 is going to ship with clojure.spec, a library for specifying validating data. My impression is that it’s primarily intended as a development and testing tool. I do not have much experience with that yet, but it works nicely for writing configuration validation code.

Let’s write a spec for the configuration above.

(require '[clojure.spec.alpha :as s])

;; The top level has one required key, :http/server,
;; specified below
(s/def ::config (s/keys :req [:http/server]))

;; :http/server has one required unquailified key, :port,
;; which should be a valid port number.
(s/def :http/server (s/keys :req-un [:http/port]))
(s/def :http/port (s/int-in 0 65536))

(defn validate-config [config]
  (when-not (s/valid? ::config config)
    (s/explain ::config config)
    (throw (ex-info "Invalid configuration." (s/explain-data ::config config))))

Let’s try this with our example configuration.

boot.user=> (validate-config {:http/server {:potr 3000}})
In: [:http/server] val: {:potr 3000} fails spec: :http/server
at: [:http/server] predicate: (contains? % :port)
clojure.lang.ExceptionInfo: Invalid configuration.

Much better, and it took only a couple of lines of code!

What is functional analysis?

Studying functional analysis will help you understand wavelets.

Studying functional analysis will help you understand wavelets.

I took an introductory course on functional analysis. Let me tell you about it. (See also: descriptive set theory, forcing.)

Functional analysis is the study of infinite-dimensional vector spaces. These spaces are usually (always?) spaces of functions. For example, consider the sequence spaces \(\ell^p\) where \(1 \leq p < \infty\). They’re defined as follows: \[ \ell^p := \{ (x_n)_{n=1}^\infty : \| x \|_p := (\sum_{n=1}^\infty | x_n |^p)^\frac{1}{p} < \infty \} \]

Here \(\| x \|_p\) is the norm. You can also consider them spaces of functions of type \(\mathbb{N} \rightarrow \mathbb{K}\), where \(\mathbb{K}\) is the scalar field.

All the \(\ell^p\) spaces are complete. Thus they’re Banach spaces. Banach spaces, or complete normed vector spaces, are central to functional analysis because the functions in them are quite well-behaved. Consider the following results:

What about the name? Functional analysis is not related to functional programming. A functional is a function from a vector space to its scalar field. Of course, in the case of function spaces it is a function of functions. Functionals often come up in functional analysis – for example the Hanh-Banach theorem above is about functionals.

Why do people care about functional analysis? A big reason is that it gives tools for studying partial differential equations. Unfortunately I’m not familiar enough with the matter to say how it helps, except that having well-behaved functions is always nice.

For more posts, see archive.