clojure 2026-10-22

Hey everyone, My name is Thiago and I work with the Clojure Team here at Nubank. One of the things occupying my hammock time recently is what Nubank could do better or differently to support a healthy and thriving Clojure community. To help us make better decisions, we’re looking for people to take part in a short survey about how people choose and evaluate programming languages. We’re interested in your real-world experience: what you value, what influences your decisions, and what you think makes a language compelling for a project or team. It takes around 10 minutes, and we’d really appreciate your perspective. https://form.typeform.com/to/o6vhOeof Another way of helping, if you are so inclined, would be to share this in other corner o the internet where people who don't love Clojure (yet?) congregate. Thank you!

👍 2
👍🏼 1
👋 3
👋🏼 1
✅ 6

Just to check I'm understanding :req! correctly -- I could now change:

[{:keys! [worldsingles-application members actioner database]
    {:keys! [& :redis-pubsub] pubsub :redis-pubsub} :worldsingles-application
    :as service}]
to
[{:keys! [worldsingles-application members actioner database]
    {:req! {pubsub :redis-pubsub}} :worldsingles-application
    :as service}]
Yes? (I have several similar nested destructurings introduced during earlier alphas)

Another example from our code at work:

{:keys! [& :productId] product-id :productId :as subscription}
could now be
{:req! {product-id :productId} :as subscription}

Alex Miller (Clojure team) 2026-10-22T17:33:00.326629Z

I think so if I'm reading correctly

I guess I'll find out shortly... 😄

😂 1

I couldn't quite understand what the :req! directive was about, but I do now with these examples.

➕ 2

Ditto, thanks for the examples, @seancorfield!

oh man my brain is still having a tough time with the nested destructuring 😅 I can recognize the pattern of :keys! -> :req! here, where :req! is letting you bind a keyval to a symbol without needing the extra vector-form specifying that it's required > {:keys! [& :productId] product-id :productId :as subscription} vvvv > {:req! {product-id :productId} :as subscription} but from your https://clojurians.slack.com/archives/C02BJCKN0R4/p1792693240003769 in #C02BJCKN0R4 @seancorfield, I'm struggling to understand the 1st listed change. Could you explain the mechanics of it to me?

@sludwig.dev Previously, I had required keys and matching bindings for :caches and :environment and then a required key (unbound) for :database at the top level. And I had a nested destructuring of the :database value that required and bound :pooled-db. So, I had to duplicate :database -- in the top-level required keys and in the specific (nested) binding for it. With :req! I can now indicate that :database is required where I bind it to the nested map (with the required & bound :pooled-db).

The incoming map is specified to have the following required structure:

{:caches ... :environment ... :database {:pooled-db ...}}
(and any extra keys I don't care about)

Ahhh ok I think I see! Much appreciated; that's helped a lot

In the second example, there's really no way to avoid mentioning worldsingles-application twice, since I need it as a required key, and bound for use in the function, and I need to declare the :redis-pubsub key is required inside it, and bound to pubsub. But I think that's fine.

And, in news that will surprise no one, we have Clojure 1.13 Alpha 10 in production (all apps, one server, so far; will deploy to the other servers on Monday since I'm on vacation tomorrow). And that includes some uses of the new :req! feature!

12
🎉 23

Have you noticed any differences in the performance profile of the app?

No, because for the past month we've been battling system environment issues at our datacenter that have caused general performance problems (and I'm getting really pretty pissed off at our hosting company who still can't figure out the problem).

Ah, sorry to hear that. I’ve recently worked on a library where the upcoming changes in 1.13 made me look a bit harder at the performance profile of array map traversal, as they now probably will be considerably more common than previously. I’m curious if the array map cutover limit being raised to 64 can be felt in practice.

I had hoped to be able to observe changes, as we moved through 1.13 alphas in production, but if there are any impacts, they're too small to see against the other noise we're currently trying to resolve (I just opened another support ticket with our hosting company due to increased problems overnight that started at 2:30 am Eastern -- very frustrating).

For what it’s worth, we’re running on Hetzner, and it’s been rock solid since we switched to them.

We switched away from http://Fly.io, in order to (ultimately) sleep better at night.

We've been with DataBank for many, many years... and EdgeWebHosting before that for many, many years (DataBank acquired EWH)... and it's mostly been great... but something happened on September 25th at 7 am and no one has been able to track down the cause... Our main API's average response time tripled suddenly, and we've also started to see spikes of really poor performance in the middle of the night (on a specific schedule). So, we're convinced it's something problematic in DataBank's cloud infrastructure but they can't figure it out.

We've toyed with migrating, several times, but our database is enormous (it contains about 25 years of online dating historical data at this point) so that would be... hard... and we're a very, very small team so we rely on DataBank's expertise for managing the database as well as the cloud/network infrastructure for us 😐

Yeah, we don’t have that amount of data on our hands, but it still took a considerable effort to migrate. Essentially, we ran the two infrastructures side by side for a while, until deciding to switch over. It helped a lot that object storage remained on S3 afterwards, and Rama’s backup/restore handled the rest, data-wise. Even so, there were a ton of things to think about.

With Fly, we had a lot of incidents like the one you describe. Where we’re 95% sure that it’s on their end, but each time we still have to start from the assumption that there’s something wrong on our side. The worst ones were transient in nature, so the willingness from their side to investigate them didn’t really extend post them being resolved for now. Possibly unique to Fly, but we also experienced instances where we’re pretty sure that the infrastructure was degraded, but their status pages showed nothing.

With Hetzner, we’re closer to the metal, so it’s much easier to determine what’s our fault and not. And bar one instance (if I recall correctly), it’s all been on our side.

If we were building this system from scratch, we'd architect it very differently 🙂 When it started (2001), it was ColdFusion and SQL Server on Windows. When I got involved (2009), we migrated to an open source clone of ColdFusion and MySQL on Linux. About 16 years ago, we started the migration to Clojure. It's all still running today with MySQL and Linux. Three backend rewrites overall, two frontend rewrites.

And it's been on EWH/DataBank almost the entire 25 years.