Clojure, and Ruby

I’m gonna make a bold claim here. As a language, Clojure is much better than Ruby. But, as a means of working together with other people, Ruby can be better, and Clojure can be a nightmare.

Here’s the problem with this debate: in Ruby it’s easier to actually bootstrap something because of the Rails framework. Clojure doesn’t have anything like that, but the code tends to get less worse as time goes by – as a functional language where everything is immutable by default, there’s less “surface” that’s touched by a piece of code. For example, suppose you have a function – in Clojure, changing that function only affects callers of that function, whereas in a mutable language, the function can mutate an object/value and now everywhere that uses that same object can be affected.

Another reason, that might be counter-intuitive is because of the real framework itself. When an application grows, you might find that you need less constraints and more freedom to do stuff that was not defined originally. Unfortunately, if you are using Rails (or any other framework), this means that you have to find ways around the framework, because it’s a kind of an “all or nothing” – it’s not that easy to basically do something outside of it and then bring that into your workflow, into your web servers and things like that (for example, I once had to integrate a SQS message queue on Rails, to listen to some message and deliver a notification via websocket. It was such a bad experience that we did a Node.JS app that did just that).
(more…)

The COMPLETE Liskov Substitution Principle

LSP (short for Liskov Substitution Principle, not for Language Server Protocol) is probably one of the least understood concept of the SOLID principles. So in this post, I want to actually address the complete principle, not just what people know.

Because of the “typed” nature of the LSP, I’ll try to use a language that people are familiar with, and that I can show in a playground somewhere: Typescript. Truth to be told, I am not a Typescript developer (nor do I actually like the language) so my code might be a little weird. Anyway, moving on:

What people know

The actual text is

Let Φ(x) be a property provable about objects x of type T. Then Φ(y) should be true for objects y of type S where S is a subtype of T.

This is actually hard to read, so people simplify, usually, with:

Objects of a superclass shall be replaceable with objects of its subclasses without changing behavior

Which is correct, but incomplete.
(more…)

A new Chlorine is almost done!

For the last few months, I’ve been working on a new version of Chlorine (now that Pulsar is on a good track). Here I want to share what to expect of this new version.

For a quick TL;DR; it’ll have better ClojureScript (shadow-cljs) support, fix some bugs related to evaluating code and the REPL being “locked” without returning the results or evaluating new commands, and have better configurable parameters. Things will probably break a little bit – it’s not a non-breaking-change, unfortunately – but hopefully it’s good enough that people will want to migrate to the new version.
(more…)

Bun is released – let’s jump the hype (NO)!

Bun 1.0 was released. And again, the JS ecosystem did what they do best – fell up into hype.

I actually have no idea why this happens so much in JS world; maybe it’s a lack of maturity (I mean, Ruby also did the same in the past, then they figured out it’s not always a good idea to throw away everything when a new stuff appears), maybe it’s something else; maybe people are just desperate to have something better in the JS world – who knows?

Anyway, I decided to do some benchmark tests. I was already not impressed, because I did test Bun in the past, but let’s see what happens with this new version:
(more…)

CommonJS is not a problem – the Javascript ecosystem is

Recently I came across this post saying that CommonJS is hurting the JavaScript world. And while I do agree that the CommonJS specification was not a good one, I also disagree a lot with the article. As someone who have strong opinions about the subject, I decided to write a post about it.

So, here’s the problem: supposing that you have a legacy system that’s years old, and that basically is modular, meaning that people write extensions, or libraries, to that. Like for example, NodeJS’ CommonJS. Now, here’s the problem: if that legacy system is flawed, and you need to change somehow, and your solution is “let’s do something that is better in any way than the older model, it’s faster, etc, but also completely incompatible with the old stuff” – meaning that we have to rewrite everything to be able to be used on this new format – then you’re doing it wrong.
(more…)

Clojure does NOT need a “definite web framework”

Few times I feel inclined to answer for a post. There are actually lots of posts that say that Clojure needs “the web framework” like Rails or Django or Phoenix so it’ll be better. Sometimes these ideas have value, sometimes don’t, and sometimes they are simply nonsense at all.

I recently was shown a post that was basically nonsense, and to keep things neutral, I’m not going to link it here. I want to expose why I think these ideas are nonsense, and how a person that’s new to Clojure could think about this lack of frameworks, how to handle this situation, and what to expect from the language.

So, first things first: Clojure is made to be a hosted language. Which means it expects you to use Java libraries, or Javascript ones, if you’re in ClojureScript. Sure, in Javascript things are more difficult mostly because of the weird ecosystem that expects everything to be transpiled first, but most of the time you can use interop just fine.

All this to say: you don’t need to wrap libraries. Most people I know, me included, said sometime that Clojure needs more libraries that wrap over other other things, and while I still would love to just stay on “Clojure-land” most of the time, it’s better to have a stable Java library that we can use over Clojure than an old, unstable, and severely lacking behind features that wrap the Java one to have a “Clojure feel”. Most of the time, you can have a “Clojure feel” with few lines of code anyway.
(more…)

ClojureScript vs Core.Async debate – the last updates.

So, my old post made to Reddit, and as I expected, lots of people complained about my conclusion. I still find damaging that Clojure community have this huge energy on defending “core” solutions, even when they are low-level, impractical, or (in this case) does not work well, if it works at all. But, well, I decided to clarify some of the posts, and answer some of the comments that people told me would, supposedly, “solve” the problem. I already answered these questions on other forums, so I’ll try to re-use some of my comments:

Interop with <p!

Some people asked about interop with <p!. Honestly, when I made the article, this option did not exist. Even then, a Promise can be rejected and resolved with arbitrary data, so to translate this code to ClojureScript means capturing the original result of <p!, check if it’s an ExceptionInfo, with the right type, and extract the right part. It’s also harder to compose IMHO (like, with Promises, you can chain actions, then if any of them fail, you can catch the error and the promise is back to the “success” phase). But at least, now it’s less complicated – although I would say, if you’re going to add a library to your project, why not add funcool/promesa instead of core.async? Remembering that promesa is both faster than core.async, and its constructions can work with any arbitrary data, not only promises, so you can treat all code as if it’s async (or sync), without needing to remember which ones are promises, and which ones are not…

Just .pause and .resume constantly

This works, indeed. For example, with sockets:

(.on socket &quot;data&quot; (fn [data]
                     (.pause rs)
                     (async/put! chan data #(.resume socket))))
(.on socket &quot;end&quot; #(async/close! chan))

But not all callback-based async code in ClojureScript allow you to pause events. Node.JS Socket do, WebSocket in browser don’t. Also, NPM package pg, when you query with a cursor, also will not allow it. In this case, there’s nothing you can do, really – you will either drop messages, or an exception will happen.

Use offer!

(go (>! and put! both are fragile with callbacks, because you can’t really “park” or “block” threads in Javascript. Keep put!ing messages in a channel, and you’ll hit an exception “No more than 1024 pending operations” (or something like that). So people asked me to use offer! or make a sliding buffer, etc. This doesn’t really solves the problem if you can’t drop messages – and I do have lots of cases when this happens. There were some people that told me that dropping messages is part of the life, and I wholeheartedly disagree – there are LOTs of situations when you can’t loose anything – bank transactions, socket messages (you can’t reconstruct the payload if you lost part of it), downloads, etc. There are ways to mitigate this, for example:
(more…)

Advent of Code in SQL – Day 01

Ok, this year I decided to try the Advent of Code. But to level up my SQL game, I decided to do it purely in PostgreSQL. No stored procedures, no tables, just pure logic over SQL (or, at least, PostgreSQL-flavored SQL). I’ll also try to not use PG specific datatypes like JSONB or Arrays/Ranges, but I can’t promise this – the challenge is already hard with the way it is.

So, I decided that the input will be a single table called input with a single record and field, called input. This means that I have to split the input in some way – I’m currently using regexp_split_to_table(input.input, '\n') to generate a table with all the lines when this makes sense.

So, day 1. The first thing is to generate the input:

WITH input AS (SELECT &#039;199
200
208
210
200
207
240
269
260
263&#039; AS input)

The Day 01 problem is kinda simple: you compare a row with the next one and when the next one is greater, you add 1 to a result. So in this case, we do need to split the input into numeric rows. There are two ways of doing this: you either first split then cast, or split and cast in a single query. The first one is easier, so let’s go with that:

WITH depths_as_str as (SELECT regexp_split_to_table(input.input, &#039;\n&#039;) depth FROM input)
  , depths as (SELECT depth  :: integer FROM depths_as_str)

(more…)

Performance optimizations in Reagent – part 2

Have I mentioned that it’s a nightmare to install React Devtools in Electron? Turns out, it’s worth it. But it’s still a pain. If you want to try, you’ll need to first install the extension in a chrome-based browser (like Brave, the one I use) and then install it by code. At Chlorine, what I did was to copy the whole extension folder to a devtools directory and then changed the script to load electron to the script below (see the BrowserWindow.addDevToolsExtension):

const path = require(&#039;path&#039;)
const {app, BrowserWindow} = require(&#039;electron&#039;)

app.on(&#039;ready&#039;, () =&gt; {
  let browser = new BrowserWindow({
    width: 900, height: 600,
    webPreferences: {nodeIntegration: true}})
  browser.loadURL(path.join(&#039;file://&#039;, __dirname, &#039;/index.html&#039;))

  BrowserWindow.addDevToolsExtension(&#039;./devtools&#039;)
})

Originally, the React Devtools was installed at ~/.config/BraveSoftware/Brave-Browser/Default/Extensions/fmkadmapgofadopljbjfkapdkoienihi/4.21.0_0 (tilde is my home folder). If you’re trying to install on Atom editor, you’ll have to open developer tools and issue the following script:

r = require(&#039;remote&#039;)
r.BrowserWindow.addDevToolsExtension(&#039;./devtools&#039;) // or the right directory

This command will fail, but somehow when you reload Atom, the React Devtools will be there. There’s only one feature that I use – highlight which elements were updated. And that’s where our performance tuning starts again.
(more…)