The pull toward JavaScript has never been stronger. While ClojureScript remains an extremely expressive language, the JavaScript ecosystem continues to explode with tools like v0 , Subframe & Paper generating entire UI trees and even full websites. I found the feedback loop of these tools extremely quick and often use v0 to prototype specific components or interactions. To benefit from these new…
Recently I was trying to create a knowledge base of sorts, dozens of markdown files with various contents. My little treasure trove of context windows that I feed to Cursor, Claude and friends. To get a better overview of whats in my library I wanted to add some tags and descriptions to each entry. Cursor was quick to spit out a few hundred lines to detect missing tags and update them as needed…
After using Simon Willison's excellent llm CLI tool for a while, I found myself wanting a better way to browse through my conversation history. Terminal output is great for quick interactions, but finding anything again or reviewing it can be challenging. That's why I built llm-web-ui - a simple browser interface for your LLM conversations. What is llm-web-ui? It's a read-only web interface that…
Like everyone I've been exploring AI tools and reading Simon Willisons excellent blog I discovered how he uses LLMs to generate one-off Python tools . In this post I'm gonna share a bit more about how I generate Babashka scripts in similar ways. It's all in the context While Claude is pretty good at Clojure already it often generated code that didn't quite work. One particular case that kept…
The other day, my flatmate mentioned that a colleague had a 700 page PDF with a bunch of tables that would be nice to have in a spreadsheet. With the understanding that those problems are a thing of the past and poor impulse control, we went ahead and started playing with Gemini Advanced and other LLMs trying to extract the data. This blogpost details some of the steps that were necessary to do…
When I joined Gatheround I had a clear vision that for my next job I wanted to be part of a team again. To share the ups and downs, work more closely with product and design folks and to learn more about building software products. The years of consulting, albeit full of variety, left me longing for depth. Thanks to a friend I got introduced to and ended up joining Lisa, Perry and Alexander on…
Hi there! Welcome back — to you as much as to me. It's been a while that I've published anything but here we go: a little quality of life improvement for anyone driving a Node.js REPL from ClojureScript. The Problems There's two issues I often run into when working with ClojureScript and Node.js REPLs: many values are async, resulting in a <#Promise> return value uncaught errors will cause the…
At work we've been using feature flags to roll out various changes of the product. Most recently the rebrand from Icebreaker to Gatheround . This allowed us to continuously ship small pieces and review and improve these on their own pace without creating two vastly different branches of changes. With the rebrand work in particular there were lots of places where we needed relatively small, local…
Lately I've spent some time setting up a blog for a friend. Ghost is where it's at these days when it comes to blogging — unless you're a nerd like me who loves to mess around with static site generators every now and then. 😅 Ghost provides many beautiful themes out of the box but most of them don't seem to support localization, which would be a nice thing to have for my friends blog. So I did…
The other day I was looking for a way to turn a map into a bunch of vars. I know a macro is what will get the job done but I write macros so rarely that it always takes me a while to figure it out. In the end I ended up with something like this: (defmacro def-all [m] (->> (for [[n v] m] `(def ~(symbol n) ~v)) (into []))) Using macroexpand you can see that this translates to the a bunch of def…
Roman wrote a nice post on working inside ClojureScript REPLs, also touching on how to deal with promises . If you're unfamiliar, the problem is that in Javascript many operations return promises and unlike in Clojure you cannot block until the promise is resolved. Instead you have to handle the resulting value asynchronously. So if you for instance use fetch that could look something like this:…
Foreign libraries of ClojureScript libraries have always been a bit of an issue in cljdoc. With a namespace like the one below cljdoc would try to require "react" and then fail because "react" isn't a namespace it could find on the classpath. (ns foo.bar (:require ["react" :as react])) No more! After some recent work by Fabien Rozar the analyzer will now walk all files packaged with a library for…
I've been running this blog for more than eight years now. Over these years it went through multiple rewrites, occasionally satisfying my urge to play with new toys. Now I'm in the middle of the next rewrite and I'm realizing some things that I'd love to have done from the start. UUIDs For Every Post Eventually the time will come where you want a unique identifier for a piece of content. Maybe it…
In a project I’m currently working on we’re making use of Google's Firebase to store domain data and run cloud functions. In Firestore, which is Firebase’s database offering, every document is essentially a Javascript object. While interop in ClojureScript is pretty good we ended up converting the raw data of these documents to ClojureScript data structures using js->clj . This also meant we’d…
Through my work on cljdoc I spent a lot of time looking at documentation and implementing code to render documentation. This made me more aware of the various facilities in Clojure documentation generators (codox, cljdoc, ...) and I would like to use this post to share that awareness with the wider Clojure community. 1. Backtick-Quote Function Arguments & Special Keywords Whenever referring to an…
The recent appearance of Clojurists Together , friends working on OpenBounty , as well as recently finding a lot of energy to work on a documentation platform for the Clojure ecosystem stirred some thoughts about sustainable OpenSource. Let's say one thing right out of the gate: sustainable OpenSource isn't really a goal on it's own. What the community (users as well as maintainers) strives for is…
Or: How to use Maven snapshots without setting your hair on fire. Ever depended on a Clojure library with a version that ended in -SNAPSHOT ? That's what's called a Maven snapshot. Maven snapshots are a handy tool to provide pre-release builds to those who are interested. In contrast to proper releases a SNAPSHOT release can be "updated". And that's where the trouble comes in. Let's say you depend…
Yet another post on properly using the Closure Library from within ClojureScript. This time we'll discuss how to require different namespaces from Closure and the edge-cases that may not be immediately intuitive. Namespaces, Constructors, Constants When requiring things from Closure you mostly deal with its namespaces. Most namespaces have functions defined in them, some also contain constructors…
This is a short post on a problem that eventually occurs in any Javascript app: debouncing. While there are various approaches to this problem I want to focus on one that relies on nothing else than the Closure Library . Why Debounce Debouncing is a technique to limit the rate of an action. Usually this rate is specified as an interval in which the action may be executed at most once. If execution…
I've been working remotely for a bit over a year now. Most projects went pretty well. Some not so much. I've worked with fully distributed teams and as a satellite worker with on-site teams. I'm not an expert—but I've learned some things. What follows are some basic ideas to make remote teams work. I hope these help companies and remote workers set things up for success. Focus on Self Sufficiency…
In the last projects I've been working on I've come accross the situation that I needed to load some external script (Stripe, Google Maps, ...) at a certain point and then do something with the features exposed by this newly imported library. Some times you might be able to circumvent loading a library at runtime by bundling it with your main application but even then you might want to consider…
Every now and then I come across the situation that I need to compare previous and next props passed to a Reagent component. Every time again I fail to find some docs and figure it out by trial and error. Props vs. Children In React everything passed to a component is called props . Children passed to components are passed as props.children . In Reagent things are a bit different and Reagent’s…
A small dump of things I read to learn more about Om/Next. Most of these I stumbled upon while lurking in #om on the Clojurians Slack . Thinking in Relay This is Facebook's high level overview for Relay. It explains the reasoning for colocating queries and how data masking allows developers to write components that are not coupled to their location in the UI tree. Om/Next Quick Start This is the…
Just like with most server side software we often want to make minor changes to the behaviour of the code depending on the environment it's run in. This post highlights language and compiler features of ClojureScript making parameterized builds easy peasy. On servers environment variables are a go-to solution to set things like a database URI. In ClojureScript we don't have access to those. You…
About two weeks ago something awesome happened: the very first ClojureBridge workshop in Berlin. After months of planning things finally got real. ClojureBridge aims to increase diversity within the Clojure community by offering free, beginner-friendly Clojure programming workshops for women. Many of you probably got the "news" : there's a lack of diversity in programming communities. Many…
Little tip. Long headline. In any project there are often settings that are specific to the context the project is run in (think of an environment parameter) and then there are parameters that are specifc to the developer/workstation they're run on. This is a guide to separate these two things nicely in Leiningen-based Clojure projects. So you have a project setup that uses environ to determine…
I saw this paper being mentioned again and again in my Twitter feed. Basically not even knowing what "formal methods" really means I was intrigued by the claim that it's easy to read. And it has been. The paper describes how Amazon used a specification language to describe designs of complex concurrent fault tolerant systems finding bugs and verifying changes in the process. The specification…
A while back I wanted to setup hotkeys for the various apps I use. Mostly because I was annoyed by the cognitive effort you need to make to figure out how often you need to press Alt + Tab exactly to get to the app you want. It seemed like a good idea to use Capslock as a modifier key. This way I could be sure I wouldn't override any other keybindings. Figuring out how to do this I stumpled upon…
In Clojure, Java interoperability or “interop” is a core feature. In Clojurescript, interop with Javascript libraries does not work out-of-the-box across optimization modes. Extern files or “externs” required for advanced optimizations are often hard to find. To fix this a few newly found friends and I created CLJSJS . CLJSJS is an effort to package Javascript libraries with their respective…
Boot is a build system for Clojure projects. It roughly competes in the same area as Leiningen but Boot's new version brings some interesting features to the table that make it an alternative worth assessing. <aside> If you don't know what Boot is I recommend reading this post by one of Boot's authors first: <a href="http://adzerk.com/blog/2014/11/clojurescript-builds-rebooted/">Clojurescript…
In a previous post I described how to upload files from the browser directly to S3 using Clojure and Clojurescript. I now packaged this up into a small (tiny, actually) library: s3-beam . An interesting note on what changed to the process described in the earlier post: the code now uses pipeline-async instead of transducers. After some discussion with Timothy Baldridge this seemed more appropriate…
For a few months now I've been working on and off on a little "data-project" analyzing patents published by the US Patent & Trademark Office. Looking at the time I spent on this until now I think I should start talking about it instead of just hacking away evening after evening. It started with a simple observation: there are companies like Apple that sometimes collaborate with smaller companies…
For a sideproject I wanted to deploy a Clojure uberjar on a remote server using Docker. I imagined that to be fairly straight foward but there are some caveats you need to be aware of. Naively my first attempt looked somewhat like this: FROM dockerfile/java ADD https://example.com/app-standalone.jar / EXPOSE 8080 ENTRYPOINT [ "java", "-verbose", "-jar", "/app-standalone.jar" ] I expected this to…
In a project I'm working on we needed to enable users to upload media content. In many scenarios it makes sense to upload to S3 directly from the browser instead of routing it through a server. If you're hosting on Heroku you need to do this anyways. After digging a bit into core.async this seemed like a neat little excuse to give Clojure's new transducers a go. The Problem To upload files…
After using Vim for more than four years my recent contacts with Lisp encouraged me to take another look at Emacs. I used to make jokes about Emacs just as Emacs users about Vim but actually it seems to be a pretty decent piece of software. Being a Vim user in the Clojure community sometimes feels weird. You are happy with Vim. Running Clojure code with right from the editor works well these days.…
Over the weekend I sat down to play around with Docker/Dokku and was able to set up a small machine on DigitalOcean that basically offers Heroku-like deployment. It was surprisingly simple so here is some rough outline that should get you going. <aside>This guide is slightly opinionated and things can be done differently. I decided to settle for the way thats closest to Heroku to keep things…
Back when I lived at home my dad used to make fun of my mechanical skills. He said if everyone just sits in front of computers the whole day no one will know how to drill a hole at some point. He would like what follows. Woodworking Masterclasses is an online course to woodworking. It's the first time that I've seen such high quality material about learning a craft. They offer a simple monthly…
Hirschman credits the stability of early America with the fact that discontents could simply travel west until they felt sufficiently freed from its rules and restrictions. [...] <br> There’s no limit on the number of possible subreddits, stack exchange sites, or wikipedia pages that can be made, so a user can always keep traveling west until they find something that’s worth sticking around to…
Living in a world where consumerism appears to be the predominant behaviour it seems more and more exciting to me to live a less materialistic lifestyle. What follows are some of the things that stimulated my thinking — maybe they do the same for you. After stumbling upon Bruce Hauman’s blog while trying to figure out some Clojure stuff I discovered another post on his blog where he talks about…
Telegram is a new messenger built by Pavel and Nikolai Durov. They previously founded vk.com, Europe's second largest social network after Facebook (especially popular in Russia). A Few Reasons Why It's Great Unlike most other messaging apps their clients (Android, iOS) source code and the underlying protocols are released with an open source license (GPL v2) The founders note that they have no…
Earlier this year I came to the “very” surprising conclusion that I'm not doing enough sports in relation to the hours I spend in front of a computer every day. I decided to run a marathon this September . I didn't. I did something else though that was fun and kind of sporty as well. After starting runnning in March it was pretty amazing to see how quickly your stamina improves and longer…
When O'Reilly promoted their cyber monday I somehow really got into a shopping spree. First book I finished now is Code Simplicity by Max Kanat Alexander . The book doesn't hold on to the scientific approach that the blurb promises but once I made my peace with that it became a good read. Some of the things I liked most: It provides good reasoning why an iterative process usually provides better…
I go through periods of self-doubt about my qualifications as a web developer. I have a sense I’m not alone in this. Our field is by nature a generalists’ field, where expertise involves synthesis of concepts and technologies, not complete mastery of a single, static topic. It’s hard to know how to tell if you’re good at your job. This post on A List Apart resonated with me a lot. Liza Danger…
<p style='display:none'></p> Just found this quote by Steve Jobs on 37signals’ blog. It's taken from The Lost Interview that was conducted shortly after Steve left Apple and founded NeXT. The question was: “What's important to you in the development of a product?” You know, one of the things that really hurt Apple was after I left John Sculley got a very serious disease. It’s the disease of…
After not being active here for the last couple of months I thought a bit about what to do with this blog and came up with some changes and ideas. More regular updates and smaller linked-list style posts. Writing full length posts about more complex topics is nice but not something I can do regulary right now. Still there are often things I find and would like to share. I also hope that this gets…
Wow. It has been quite a while since I wrote anything here. Almost 5 months, phew. So what I have to say is that I'm going to visit the US from 26th of October to 10th of November . I plan to be in New York City the first weekend, spend some time around Philadelphia within the week after that and then go to Miami for another week. I'd love to meet some interesting people, have some beers, crash…
For quite a while now there is this idea of being data-driven and analyzing everything that is happening on your platform in order to identify potential changes that could improve your core metrics such as user engagement. There are quite a few services allowing you to send events triggered by users to their servers that provide you great interfaces to actually make some sense of the data you…
Communication is a central part of working in teams. I believe having asynchronous communication channels and making heavy use of them can have great effects on productivity, transparency and therefore happiness and fun within teams. Here are a few reasons why. Interruptions There are dozens of studies about the consequences of being interrupted while performing demanding tasks. They usually…
After moving to Berlin I kind of failed to continue some regular sports activity. This is two years ago now. Today I'm going to change that. Today I'm starting to run. Why Running The answer is as simple as it gets: because it can be done everywhere at any time and without any organizational effort such as finding a partner for going climbing, which I did back then in my old hometown. Running a…
After toying around with Zsh for a while I stumbled upon Fish or more precisely Ridiculous Fish which is a fork of the original Fish Shell . Since Fish does not have a configuration framework like oh-my-zsh you have to setup your prompt with additional Git information yourself. I consider this an advantage though as you can't just take a bunch of configuration files from somewhere without having…