My last experience with Ruby

On my last job I tried to go back to Ruby programming language. Not really by choice – but just because it was a language and was familiar with, and my last two jobs in Clojure didn’t really work out for me (not because of the language, really). I even imagined that some things would be easier in Ruby, specially while working with relational databases (something I really did miss while I was working in the Clojure language).

At the time, in my opinion, Rails was still a great framework – maybe a little too complex. And I imagined that somehow there could be better ways of doing Ruby code that could use the best parts of Rails and avoid the worst (like ActiveRecord, for example, maybe even substitute it with Sequel or ROM).

No a year and a half later I’m back to Clojure – and I will probably never go back to Ruby. And the reason is quite simple: I was working with Ruby doing exactly the same code that I did about three years ago. Rails didn’t change that much, but still was a huge mess when you had to upgrade from one version to another. The same problems I had in the past kept happening again and again, and it felt like a huge step backwards for me.

(check (my-code) => (needs :tests))

So, yesterday I made a talk (in Portuguese only, unfortunately) about the difficulties of testing Clojure and ClojureScript code. Specifically, I think the most problematic issue is the lack of “custom matcher libraries”, and how the default error messages are kinda bad and don’t help you identify the problems.

Then, on Clojurians’ #announcements Slack channel, I found that clojure.test Expectations library have a new version. So, why not integrate it on my Check library, and maybe continue developing it?

What is check?

Midje is too magic. Clojure.test is too little. Thinking about findind a “middle ground” I’ve started the “check” project, and I’m using it to test my personal projects like Chlorine, Clover, REPL-Tooling and Paprika. The problem is that, while the API is stable, but it still doesn’t do all the things I want.

Why I tend to avoid core.async?

It’s no surprise that I don’t like core.async very much. For starters, it make my functional composition looks like imperative programming again. There’s also multiple issues that you need to be aware of (like, don’t use async/put! because you will have problems, deadlocks that are difficult to predict, go blocks don’t compose over functions so you loose lots of helper macros like delay).

But the most important reason is that most of the time, I’m working in ClojureScript. And it’s impossible to migrate callback to core.async.

Well, you may be tempted to write something like:

(js/someFunction "i'm async" "lol" #(async/put! some-channel %))

And one day or another you’ll have the dreadful Assert failed: No more than 1024 pending puts are allowed error. There are multiple ways around this problem, but none of then work if you can’t lose messages.

Functional SOLID – Open/Closed Principle

Continuing on the series about SOLID principles on functional programming, the next one is the Open/Closed Principle. The definition from the Wikipedia:

The open/closed principle states “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”; that is, such an entity can allow its behavior to be extended without modifying its source code.

This is kinda interesting on its own way: what’s an “extension”? Considering the context when it was written, and future interpretations of the principle, the idea is that any program should not be re-compiled (re-written, modified, etc) to be extended. The idea of this principle is that local changes should not propagate to other parts of the program: make entities as self-contained as possible, write then in a way that extensions would not depend on modifications on these entities, then “close” then to modifications. I can see two cases for the “open-closed principle” violation, and the first one is the most common:

(defn as-int [some-str]
  (when (re-matches #"\d+" some-str)
    (Integer/parseInt some-str)))

This code returns an Integer if it can parse a string as a number, and nil if it can’t. Now, suppose we want to “extend” this functionality by accepting other objects like Double (truncates to integer) or nil (returns 0). The only way to do it is to change the when to a case, but that means that for every new implementation I’ll have to change this function. Now, a better way is to use protocols:

Quick Post – native apps with ClojureScript

React apps now run on the desktop with Electron. They also run on the desktop with react-native-desktop, or proton-native. In this simple post, I’ll share my (very small!) experience with proton-native:

First, you need Shadow-CLJS. Because of the npm integration, you can literally just:

npm install proton-native react react-dom create-react-class

And then add [reagent "0.8.1"] to dependencies on shadow-cljs.edn file. Then, configure a :node-script target and start to build things. This means that your shadow-cljs.edn file will be:

{:source-paths ["src" "test"]
 :dependencies [[reagent "0.8.1"]]
 :builds {:desktop {:target :node-script
                    :output-to "target/index.js"}}}


Functional SOLID – Single Responsibility Principle

I am a firm believer that we have to learn from the past instead of throwing all away for the future. And this is one of these moments: I have seen multiple talks, presentations, slides telling about SOLID and Design Patterns in functional programmings. Some are serious, some are satires, but most only speaks “you just need functions, really!” on their explanation on the principles, effectively diminishing the usefulness of the principles and also by imagining that, somehow, if we only use functions all our problems on developing software would be solved forever.

So, to counter that, I’m going to re-visit SOLID, but this time I’ll not compare with “OO” – instead, I’ll ask for us to try to grasp the meaning behind each principle. I’m going to use the definitions from Wikipedia, because (1) it’s easier to track changes and (2) it’s condensed from multiple sources, so it’ll probably not reflect a single opinion from an author. I also thought about being one single post, but it became quite complicated, so I’m splitting this post in multiple ones (and probably the one about LSP will be the most extensive of all). So, let’s begin by the first: the Single Responsibility Principle:

The single responsibility principle is a computer programming principle that states that every module, class, or function should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class, module or function

Putting REPL-Tooling to test – VSCode!

Sometimes you make some tooling because you want to use it; sometimes, to experiment; and sometimes to test the waters.

The last tooling in that I did was one of these cases – now there’s a port of Chlorine to Visual Studio Code called Clover!

Now, when I started the project I imagined that VSCode would not have all the features that I have in Atom, nor all the APIs that I want to use – for example I didn’t have any hope of having the inline results in this version.

The thing is, I wasn’t expecting it to be so bad! To begin with, the API: is not really that bad documented, but compared to the Atom, it is incredibly weak. The first thing is that they expect you to use TypeScript so there’s little to no documentation on how to represent objects in pure JavaScript; for example in some cases you can use pure objects, on others you have to instantiate a TypeScript class in the JavaScript code. Also, there are multiple parts of the documentation when they just give you the type signatures and little (or even no) explanation (and let’s make a little detour here: what’s the deal with some people that use static types, that they expect you to understand how any API work just by showing the types of the functions?).

The second part is that VSCode expects you to fit your plug-in infrastructure on what they offer – so, some functionalities will land on the “peek definition” API, others on “Code Lens” and so on. The problem is that they don’t explain what’s a “code lens” for example nor give you any screenshots of the functionality in action – mostly the documentation is some code examples in GitHub repositories so you have to download, install the example extension on your machine and then run it to simply understand how something works.

The second hard part is that you can’t test the API in the devtools – in fact the devtools is almost useless because when you have an error, the stacktrace will point you to a minified JS code in the VSCode internal API. Also, some exception messages are completely obscure and some log errors on the devtools but things work fine on the editor. Well, to summarize: it’s completely useless to depend on the errors.

But the worst part, at least for REPL-Tooling, is that you can’t change the UI of VSCode in any way – and this means no pop-ups, no new elements, no console in the editor, nothing – the only way you have that you can extend the visual components is by implementing a webview – and by webview I am not saying an “electrom webview” when you can access all the Node.JS APIs – I am saying a simple web page when you have to pass your data to and from the editor using JSON. And and that’s all there is – no Date, no JavaScript classes and, of course no Clojure objects.

Rails’ ActiveRecord – the bad and the ugly

I’m known to not be a big fan of ActiveRecord. No, that would be a simplification: I probably hate ActiveRecord and think it adds more problems than it solves, specially after I began to work with functional programming and saw how difficult, if not utterly impossible, is to make ActiveRecord models behave like immutable structures or separate (and maybe even predict) the I/O from the rest of the code.

The ActiveRecord pattern (not the GEM) was created to hide SQL details from the users. The Gem elevates this to extremes: you never know when a query is issue, what query is issued (unless you check the logs), and sometimes a latter clause modifies the way previous clauses work. Also, to extend ActiveRecord, you need to rely on monkey-patches and other internal implementation details, and there are API changes that seem innocent but are tremendously dangerous.

Now, what I want to do in this post is to elaborate the bad and the ugly parts. I’m not gonna talk about the “good parts” because we already know: auto-discovery of fields, fast prototyping, simple CRUDs, and so on. One could argue that this “easy setup, fast prototyping” is not worth the amount of technical debt you’ll have later, but let’s focus on the bad parts instead:

Chlorine, Clematis, REPL Tooling

Recently I began to migrate some of the code on Chlorine to REPL Tooling, so things may become more testable. I already found multiple bugs in this approach and began an integration test methodology using Electron (I say that there are three kinds of developers in the field of automated tests – the ones that don’t test, the ones that do, and test freaks. I’m probably the later).

In the beginning, the idea would be to rewrite the renderer of results and exceptions so that I could fix lots of bugs that they have. So far, it’s progressing slowly, but I already can render datomic results in a meaningful way (the last renderer was interpreting as Java objects, which they indeed are) and fix some bugs with tags and other issues.

Now, one of the things that I wanted in the new renderer is the ability to copy/paste results in a meaningful way – as I’m using UNREPL, there are lots of tags that need to be reinterpreted, like #unrepl/browseable for datafy. These need to be “translated” to something useful for rendering on screen, with links to navigate inner details, but for copy-paste they should have a textual representation that makes sense (probably the hard part).

The results of all these experiments are quite interesting – when you evaluate something and th result is a Java object, there’s a link ... that can be used to navigate inside the object: it’ll show getters, the current class, methods that the object supports, so things like “goto definition for Java object” or “Javadocs” aren’t really necessary.

Then, one of my friends asked for a Vim option. Just for fun, I started Clematis, a port of Chlorine to NeoVim. And it seems they things are progressing faster than I thought!

Chlorine is thriving!

When I started this project, I was experimenting with shadow-cljs to see if I would be able to make an Atom package that would auto reload, run tests on ClojureScript, and se how far could I push ClojureScript in an Atom package.

Now, some months later, I’m seeing the package being used by a bunch of people, and I even discovered some bugs in UNREPL! Now, on this post, I’ll discuss a little bit more in detail the design decisions and my vision on the future of the project.

Chlorine is a clojure and ClojureScript atom package. It connects to a socket repl (opened via lein, boot, clj, shadow-cljs, lumo, or even REBL) and then upgrades the repl to be programmatically oriented with unrepl. Unrepl only works on Clojure, so for ClojureScript we use other techniques. Also, socket repl is a stream protocol, so to emulate a “request-response”, we need to coordinate things so Atom (and other editors) can react to commands and know exactly what’s the correct response for each command sent.

Design decisions

The choice for UNREPL was mostly because there is almost no documentation about prepl so far. Also, Socket REPL is literally everywhere: on Clojure , on ClojureCLR, on Lumo and Plank. Also, I wanted a better way to use ClojureScript, and I still have nightmares trying to use it over nREPL… and with Socket REPL things work fine.

Also, when I started the project Clojure 1.10 was just alpha software, and UNREPL offers us insanely good support for lazy lists, big strings, and other things that I wanted to use out of the box. One of the problems I’m still facing is coordination of evaluate/response, but this will probably be solved after a bunch of other fixes I’ll try.