Site icon Random Thoughts

Reagent is… Nice?

I’ve been procrastinating on writing a web-based admin interface for news.gmane.io… because I just haven’t been able to make up my mind as to what technologies to use.

I hate learning new stuff, but it feels pretty stagnant to tap away in Javascript (on the frontend) and PHP for whatever has to happen on the backend. I really just kinda dislike PHP for no particular reason, but it’s so convenient: If you need a simple API for doing whatever, you write a .php page and that’s it. No dependencies, no setup, pretty good error reporting: Everything built in in Apache.

But I don’t liiiike iiiittt. (Imagine a whiny voice.)

For the Gmane stuff, I had the additional problem that I have a lot of admin logic in Emacs, and I want to keep that. Because it’s really convenient, especially when doing mass updates.

So… it took me weeks to accept it, but if I don’t want to implement a lot of things twice, I had to use Emacs on the backend.

*insert shocked face here*

I wrote a very short PHP component that does the TLS and the auth, and just reads some JSON posted to it, sends it over to Emacs, reads the JSON from Emacs and spits it out to the client. Like… middleware.

I could have done the HTTPS server in Emacs, too, but there’s just too many variables to get that solid, and Apache works.

So. That’s the backend, and what about the frontend?

I have no knowledge of Clojure, ClojureScript, Java or React, so I settled on Reagent.

My first stumbling block was Clojure, of course. I’ve been writing in Common Lisp for my day job for a couple of decades, and Clojure is… not Common Lisp? And I’m not sure what the design philosophy behind it is. Is it perhaps “make it look cool enough so that Java people won’t notice that it’s Lisp”?

Compared to Common Lisp, it’s terse and tends towards line noise, just like Perl. I made the following comment on irc:

(lambda (bar) (foo bar)) is the same as #(foo %)

And got the sarcastic response back:

And I guess (lambda (foo zoo) (bar foo zoo)) is the same as #(bar %1 %2)?

And it is! It was a joke, but that’s exactly what it is. When people are sarcastic, but happen onto the actual language design, that says… something?

And, oy, don’t get me started on the threading operators (-> and –>). Perhaps designed to placate Java developers who can’t read anything but foo.bar().zot().foobar()? More than a few of the design decisions seem predicated on limitations of the Java language (which are then reflected in the JVM), like there not being “real” keyword arguments for functions.

My point is: My quibbles are irrelevant. Whatever the idea behind Clojure was — it worked. People love these tricks, because people love writing code that’s incomprehensible I mean clever.

We now have a Lisp that’s mainstream enough that you can do web development on it instead of writing Javascript. And for that we’re all grateful.

I have not learned Clojure in depth (to put it mildly), but learning enough to write a web page only took a day. I guess I’ll look back upon my first ClojureScript project in shame, but it, like, works, and it’s a lot more fun to add new stuff to it now than it would have been in Javascript.

My major problem with all this is… the tooling isn’t quite all there yet when developing. With leim and Figwheel, everything reloads nicely and magically in the browser while doing stuff, and when doing something egregiously wrong, I get nice error messages:

However, if the breakage isn’t during compilation, the error reporting is really, really bad:

That’s an error message from line 25173 in react-dom.js, and determining where the error in my .cljs file is is… difficult? I thought I must be doing something obviously wrong to not get better error reporting, but googling this stuff shows that people mostly are just putting a lot of prns everywhere, and that’s really primitive.

Even worse are Reagent errors that are less… errorey. I spent an hour on a problem with bind-fields because I thought it took a function parameter, but it wanted a vector. Absolutely no feedback whatsoever — nothing worked, but I didn’t see what the problem was before I googled “reagent-forms” “bind-keys” (with quotes), and the second answer is somebody who’d done exactly what I’d done.

And some of the error messaging seems wilfully obtuse:

This was because of:

Yes, those should be square brackets. (And note: No reporting on what line the error was on.)

*sigh*

But Reagent feels quite nice, and the Hickup HTML syntax is wonderful: The best I’ve seen in any language. Even real Lisps don’t have an HTML-generator syntax that’s that thought-through and regular. I mean… this makes me happy:

[:div
 [:h2 "New edit requests"]
 [:div#requests.log
  (map (fn [req]
         [:div.clickable {:on-click #(show-edit % req)
                         :key (:request-time req)}
			 (:request-time req) " " (:newsgroup req)])
       (:ok data))]]

Here’s the live admin interface in action, handling an edit request:

Exit mobile version