What’s happening on Brazil?

I don’t really like to talk about non-technical things here, but… sometimes the circumstances push me to do it.

We are facing strange times: covid-19. We, as people, plural. There’s no individuals in this matter, because if only one person takes action, nothing will change. If only one country, again nothing will change. We need union, more than ever.

Then, comes Brazil. People simply believe that “our climate is warmer”, “the pandemic is nothing to worry about”, and “it’s just a small flu” – I’m not talking only about the bizarre declarations of the president, but from the common person. Our approximate numbers (approximate because we’re not testing all cases: I, personally, know three people that had the exact right symptoms for Covid-19 that didn’t receive any testing, and were asked to just “rest at home, and if it becomes worse search a medic”. One of then, as soon as he felt a little better, was visiting his friends and eating food at restaurants) keep skyrocketing, and fake news are appearing here and there that these numbers were fabricated by the enemies of the current government.

So, there are only guidelines – no official laws, no real restrictions. They all have to be decided by local authorities, and all against the president (that, on this day, made some insinuations that he can start a coup if people don’t obey him!) that I really hope doesn’t have all the power he thinks he have.
(more…)

The History of Chlorine

Before I even started with Clojure, I was analyzing LightTable – the idea of that editor was to support better integrations between the code you’re writing and the code that’s running. It was a really good experience, but the main problem I had is that it was in the very beginning, with few plug-ins and bad documentation. I tried to make the parinfer plug-in work in the editor, but it had lots of bugs and then I simply changed back to Atom. At the time, proto-repl was the best package to work with Clojure, and I made some small changes to it (so I could add some callbacks to when a new connection to nREPL was made, and other small issues) to improve my workflow.

Fast forwarding a little bit, I started my first Clojure job at Nubank. Most people were using InteliJ, but I felt that by using Atom I had a different approach on problem solving, specially those hard parts where the fast feedback of “run in the REPL and see the results in your editor, then browse over the keys” could give better insights about what’s happening. I tried to implement some features that proto-repl didn’t have at the time (and Chlorine still does not have some) like “automatically add nREPL port”, and “watch expressions” (almost the same as watch variables in a debugger). These ended up in a package called clojure-plus, that still exist today.

I also began to experiment with ClojureScript (at the time, only Figwheel was available – Figwheel-main didn’t even exist!) and found that existing tools didn’t provide the same power that I had with Clojure. It also didn’t have autocomplete, goto var definition, and so on. To ease a little bit these problems, I ended up adding on clojure-plus some CLJS support – when you tried to evaluate a .cljs file, it would try to connect to ClojureScript, reserve a REPL, then evaluate the code over there.
(more…)

Implementing a nREPL Client

Some people asked me on how did I implement the nREPL client on Chlorine. So, I’m writing this post!

nREPL is a simple protocol. It uses “sessions” that are used to isolate evaluation contexts and other things (for example, on Chlorine every connection connect to two REPLs: one “primary” and one “auxiliar” that is used to run commands like autocomplete / goto var definition, and so on). On nREPL, this isn’t necessary: you just connect to a single REPL and use two different sessions. Just for the record, because the way Chlorine works, I didn’t implement it like this (because I would have to rewrite lots of code – maybe in the future).

Now, to explain the protocol, let’s separate things in parts: the first thing I do (and I was already doing in the past) is to connect to a socket. Then, I looked at the documentation for nREPL to understand how to send and receive commands to the REPL. Now, there are some details on the way that every operation is implemented that I simply ignored because it was not necessary to understand then from the perspective of my application…
(more…)

nREPL on… Chlorine?

When I started the Chlorine project, I just thought it would be great if I could target all Clojure-like REPLs that already exist but didn’t have tooling support. At the time, this would include Lumo and Plank, mostly. Also, Shadow-CLJS and Figwheel have some “clunky run-some-code-and-transform-in-cljs” way of working that simply didn’t click with me.

Now, almost a year later, Chlorine supports Clojure, ClojureScript (Shadow-CLJS, Lumo, Plank, or even over clj), ClojureCLR, Arcadia, Babashka, Clojerl (Clojure on Erlang) and Joker (Clojure on Go, also a linter). But the reality is that working with a pure Socket REPL is really hard – a socket REPL works exactly like a regular one, printing namespaces after each code, and so on. Also, there are some strange decisions on some REPLs, mostly likely ClojureScript (that is the second most used Clojure flavor), so things are not always easy. To put things in perspective, currently Chlorine uses 3 ways to evaluate code: It uses unrepl, that only works on Clojure, or uses internal APIs of shadow-cljs (that obviously only works for shadow-cljs), and for other implementations it uses a kind of a hack – it evaluates the code, inside a trycatch, and it returns a vector where the first element is a symbol in a specific format that Chlorine will understand and then link that with the response. This “hacky way” is currently being used for every other implementation except Clojure and Shadow-CLJS. Things work (autocomplete works too), but it is not pretty and sometimes have strange results.

As a matter of fact, I was already thinking about removing UNREPL (it’s really hard to implement new features on it, and some good ideas only work in theory – for example, the ability to evaluate long strings / collections and render only a part at a time aren’t that good with lots of edge-cases) and, to do it, I though about a better, non-hacky way to evaluate things on some Socket-REPLs (that, again, would only work on some REPLs – ClojureScript REPLs will probably never support “upgradable REPLs” because of the way they work) – the only thing that I had to understand is how to implement this “upgraded REPL”…

Then, recently, Babashka added an initial support for nREPL, with an insane low amount of lines. So, I’ve tried to implement a way to evaluate code over nREPL… and it was really simple to do it, using a npm library that already did it. But implementing like this meant that the user would need to know if the host/port to connect is a Socket REPL, or a nREPL (and the user does not know – lots of tools like lein and shadow-cljs show an nREPL port to be connected).
(more…)

REPL-Tooling Clients

Chlorine, Clover and Clematis are all implementations of the same library: REPL-Tooling. In this post I will show you how to create a new implementation of it in a way that’s completely disconnected from any editors, so you can grasp the general concepts.

Suppose I want to do an implementation for an editor that doesn’t run JavaScript – so it’ll connect by some kind of socket. In this example I’m going to use WebSockets because… why not?

We’re going to create a shadow-cljs node project and add repl-tooling as a dependency. We will also had some more dependencies: mostly ws for websockets and the same react libraries that we use for reagent (react, create-react-class and react-dom) – repl-tooling still needs reagent, and probably in the future I will split it into two different libraries (one for the REPL handling and other for the visual rendering part). This supposedly is not to much of a problem because ClojureScript compiler will probably remove these parts in the dead code elimination process anyway. So, our package.json file will just be like this:

{
  "name": "ws-repl",
  "devDependencies": {
    "shadow-cljs": "^2.8.83"
  },
  "dependencies": {
    "create-react-class": "^15.6.3",
    "install": "^0.13.0",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "ws": "^7.2.1"
  }
}

And our shadow-cljs.edn file:

{:source-paths ["src"]

 :dependencies [[repl-tooling "0.4.0"]]
 :builds {:node {:output-to "index.js"
                 :target :node-script
                 :main ws-repl.core/main}}}

The first step is when someone connects to the WebSocket. Then, we’ll just create a connection to the client, and send a list of supported commands – for now, is just the “connect” command:
(more…)

My 2019 retrospective

If I could say something about 2019, it would be: what a year!

It was probably one of the best years of my life, even with all the fears I had to face, the strength I had to find, and lots of other difficulties that are normal for every year.

The year began with a trip to Uruguay – Montevideo. The reason for that trip was something very different from what I am used to: it was to find if it was a good place to live. After that, my wife and I made two more trips for documentation, and probably by August, 2020, we’ll be leaving Brazil! This is a huge roadmap in my life, and I’ll probably write more about it later.

This was also a big year for open-source contributing: this was the year that Chlorine became popular, so I’ve been investing my time on it. It is wonderful and kinda scary to have a successful project (people start to rely on it to be working!), and it also taught me a lot about organizing projects – even personal ones. Chlorine also evolved a lot thanks for multiple contributors, and now I can easily recommend it as a real alternative to any other plug-in out there.

This was also the first year that I was invited to talk on meetups, instead of sending papers. On the total, I think there were about 4 invitations, two to explain functional programming on an university here in São Caetano / Brazil (where I live currently). Speaking of events…
(more…)

Ubiquitous interface – how to integrate things in Clojure

Inspired by this thread on Reddit, I decided to write a little bit about my experience integrating things in Clojure.

The first thing to understand is that Clojure have an ubiquitous interface: EDN. And it is important to understand what this means. In the beginning, I made this mistake of “Death By Specificity” on my now abandoned Relational project: to abstract things that don’t need to be abstracted.

But can we do even better? How about we de-abstract (concretize? Is this a real word?) things that are already abstracted?
(more…)

Strange decisions in Clojure – keyword inheritance

First, a disclaimer: the opinions on these posts are my own, and they reflect (for me) a design decision on the language that I don’t understand, specially considering other decisions that seems to contradict it. I also want to say that Clojure (and ClojureScript) is my favorite language, the one that I enjoy writing on my free time and professionally, so by no means this is a rant on the whole language!

Well, this is a new “series” on this blog: what is on the Clojure language that I don’t like, that I feel is out-of-place, and sometimes I can’t understand? In this first post, “keyword inheritance”. And what is that?

Clojure allows us to use derive to generate a “parent-child” inheritance against keywords. So, for example:

(isa? ::dog ::animal) ; => false
(derive ::dog ::animal)
(isa? ::dog ::animal) ; => true

This will change the way multimethods work too: so, for example, if derive is used and a multimethod expects an ::animal and you send a ::dog, it’ll use the implementation for ::animal:

(defmulti cry :type)
(defmethod cry ::animal [_] "Some animal crying")

(cry {:type ::wolf})
; Execution error (IllegalArgumentException) at user/eval152 (REPL:1).
; No method in multimethod 'cry' for dispatch value: :user/wolf
(cry {:type ::dog})
; => "Some animal crying"

(more…)

Introduction to Kafka with Clojure

Recently I was trying to study Kafka, but I didn’t find a single resource that would give me a quick introduction and hands-on experience with it and Clojure. So, I’m making my own here! Don’t expect a “too deep introduction” – this is just the quick-and-dirty introduction about the concepts, and then I’ll show some code examples in Clojure

Kafka is a messaging system similar to RabbitMQ and SQS. The great differential is that it’s faster than both solutions, and works very well in cluster mode. Installing Kafka locally is quite complicated so you probably will wants to use the docker-compose.yaml file below:

version: '2'
services:
  zookeeper:
    image: confluentinc/cp-zookeeper:5.3.1
    hostname: zookeeper
    container_name: zookeeper
    ports:
      - "2181:2181"
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
  kafka:
    image: confluentinc/cp-enterprise-kafka:5.3.1
    hostname: broker
    container_name: broker
    depends_on:
      - zookeeper
    ports:
      - "9092:9092"
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: 'zookeeper:2181'
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://broker:29092,PLAINTEXT_HOST://localhost:9092
      KAFKA_METRIC_REPORTERS: io.confluent.metrics.reporter.ConfluentMetricsReporter
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0
      CONFLUENT_METRICS_REPORTER_BOOTSTRAP_SERVERS: broker:29092
      CONFLUENT_METRICS_REPORTER_ZOOKEEPER_CONNECT: zookeeper:2181
      CONFLUENT_METRICS_REPORTER_TOPIC_REPLICAS: 1
      CONFLUENT_METRICS_ENABLE: 'true'
      CONFLUENT_SUPPORT_CUSTOMER_ID: 'anonymous'

This file will create the Kafka broker (like a single node of the messaging) and will add Zookeeper (that will allow you to coordinate between different Kafkas, decide which node is the leader, and also participate on the node election when the leader goes down, and other things). You will connect into 9092 port, and then listen and send messages from there.
(more…)