Livebook as an educational tool

We welcome Alex Koutmos as a guest writer on our blog, to share his experiences on using Livebook as a learning tool for Elixir.

For the past few months, Hugo Baraúna and I (Alex Koutmos) have been working on a new book for Elixir called Elixir Patterns. When we started brainstorming about what topics we should cover in the book and what the layout should be, Hugo had the brilliant idea of also creating Livebook documents to augment what was being covered in the book. Prior to that, I had only used Livebook a handful of times for some small PoC type things. While my impressions of Livebook were positive from my initial experimentation, I had no idea how amazing a tool it was until we started writing Elixir Patterns.

In fact, since we started writing the book, I now find myself reaching for Livebook more and more as a tool for prototyping and experimentation. In addition, it has also become a great tool for exploring my production database similar to how Mark Erickson describes in his blog post.

It’s amazing to see how the same tool can cover such a wide array of use cases ranging from education to business intelligence. I think this is largely in part to the amazing developer experience (or DX for short) that you get when you use Elixir and its ecosystem. Let’s unpack the topic of DX in Elixir before discussing how Livebook fits into the larger picture.

The Elixir developer experience

While I may be a little biased given I have been working closely with Elixir for the last 6 years, I believe that Elixir has one of the best developer experiences out there (the 2022 Stack Overflow Most loved, dreaded, and wanted also backs up this claim 😉).

Everything in the language and ecosystem is so beautifully connected that it makes development nothing short of a pleasure. For example, the same tooling that generates the documentation for the language itself, is also the same tooling that generates the documentation for Elixir libraries available on Hex.pm. This means that any time you are exploring a new library or framework, everything feels familiar and accessible. This consistency and ease-of-use extends even to the Elixir interactive shell where you can explore the documentation of your project libraries, the Elixir language and even the Erlang standard library right from your IEx session.

The fact that so much tooling is accessible to you right out of the box enables you to really focus on completing your task at hand. When your programming language, runtime and tooling support you in your endeavours, you feel like you have superpowers. So how does Livebook fit into this theme of empowering the developer? I am glad you asked 😄.

How Livebook augments Elixir’s DX

According to the tag line on the Livebook homepage, Livebook allows you to “write interactive & collaborative code notebooks in Elixir“. We’ll put aside the “collaborative” portion of that for a moment and focus on the “interactive” bit. By “interactive”, what Livebook effectively gives you is a fully fledged Elixir development environment, right in the browser. You can access the same documentation that you can from Hex or IEx right in the browser, you have code completion, you can install libraries from Hex on the fly, and you can create robust documents using markdown, Mermaid.js, and graphics with VegaLite (using Kino and Kino VegaLite).

You may be wondering how hard all of this is to set up and run on your machine? In true Elixir fashion, setting up Livebook could not be simpler. If you are already using Elixir and have it set up on your machine, all you need to do is run mix escript.install hex livebook and then start the Livebook server with livebook server from your CLI. If you are new to Elixir and do not have the runtime set up on your machine, the Livebook team has just announced Livebook Desktop. Just download the Livebook app on your machine and you are off to the races.

Livebook as a learning tool

One example of how we use Livebook in Elixir Patterns is when we talk about implementing an HTTP stress tester using Task.async_stream/3. By leveraging Kino, we were able to create an interactive HTTP stress tester where you can configure the parameters of the stress test and plot out the results. This can help visualize the effects of your code changes like in the example below where test run 1 was run with a concurrency of 1 and test run 2 was run with a concurrency of 10 with a total number of requests being 100 across both tests. It is very easy to see how with the increased :max_concurrency value passed to Task.async_stream/3, the test was able to execute in less time overall:

HTTP stress tester using Task.async_stream/3

In addition, Livebook and the libraries in the livebook-dev GitHub organization are under active development and there are great features being released regularly to enhance your development experience. A few such features that I am particularly excited about (partly because I worked on them 😉) are the ability to visualize application/supervision trees, and trace process messages.

In the spirit of enabling the user, these visualization tools are useful for when you need to understand how your application (or perhaps a library that you are using) is organizing its processes. In the example below, I have several layers of supervisors each with a couple processes and links between some of the supervisors and processes:

Another useful tool that I added to Kino (thanks to help from José Valim and Jonatan Kłosko) was the ability to trace messages that are sent between processes. In the example below, a TaskSupervisor (#PID<0.460.0>) spawns two task processes (#PID<0.461.0> and #PID<0.462.0>) which then proceed to read from a named Agent process called SecretAgent.

I believe that tools such as these will help future developers get better acquainted with the Elixir programming language and the amazing runtime that is the Erlang Virtual Machine. Whether you are a seasoned Elixir veteran, or just starting out, having tools like these are a great way to raise the DX bar. With that being said, let’s take Livebook for a test drive and see how you can create visuals such as these!

Rendering directed graphs with Livebook

Under the hood, Kino uses Mermaid.js in order to render diagrams and visualizations. You can create your own Mermaid.js diagrams by creating markdown code blocks that are annotated with mermaid. Let’s see how we can use this in order to render a graph constructed with the Erlang :digraph module.

We’ll start off by creating a new graph and also defining the vertices of the graph:

# Create new graph instance
graph = :digraph.new([:acyclic])

# Add vertices
:digraph.add_vertex(graph, :a, "Start")
:digraph.add_vertex(graph, :b, "Choice 1")
:digraph.add_vertex(graph, :c, "Choice 2")
:digraph.add_vertex(graph, :d, "End")

After you have defined the vertices for your graph, you can then add edges connecting the vertices in the graph:

:digraph.add_edge(graph, :a, :b)
:digraph.add_edge(graph, :a, :c)
:digraph.add_edge(graph, :b, :d)
:digraph.add_edge(graph, :c, :d)

After adding the edges to your graph, you can fetch all of the edges in the graph data structure and combine the edges in a format that Mermaid.js can understand in order to render the graph:

mermaid_edges =
  graph
  |> :digraph.edges() # Get all of the edges in the graph
  |> Enum.map_join("\n", fn edge ->
    {_, vertex_1, vertex_2, _} = :digraph.edge(graph, edge) # Get the edge vertices
    {_, vertex_1_name} = :digraph.vertex(graph, vertex_1) # Get the label for the first vertex
    {_, vertex_2_name} = :digraph.vertex(graph, vertex_2) # Get the label for the second vertex

    # Mermaid.js format for graph edges: VERTEX_1_ID[VERTEX_1_label] --> VERTEX_2_ID[VERTEX_2_label]
    "#{vertex_1}[#{vertex_1_name}] --> #{vertex_2}[#{vertex_2_name}];"
  end)

# Delete the graph instance so you don't leak ETS tables :)
:digraph.delete(graph)

Finally, once you have the Mermaid.js edge definitions, all you have to do is wrap them in a simple markdown block and pass the markdown to Kino.Markdown.new/1:

Kino.Markdown.new("""
```mermaid
graph TD;
#{mermaid_edges}
```
""")

And with that, you can now run your Livebook code block and you’ll have a beautiful diagram like the one below:

Closing thoughts

All in all, I think Livebook is an excellent tool and a huge value-add to the Elixir ecosystem. Whether you need it for proof-of-concept work, learning, or business intelligence, Livebook is more than up to the task. Be sure to checkout our Elixir Patterns book if you are interested in learning about recipes and patterns specific to Elixir/OTP. You can download the PDF with the first two chapters as well as the accompanying Livebooks for free! Those chapters cover the Erlang standard library and learn about useful tools like the :crypto, :digraph, :ets and :persistent_term modules to name a few.

Lastly, I’d like to say a huge THANK YOU to all of the maintainers of Livebook and the supporting libraries! A lot of work went into all these tools and your efforts are much appreciated!