Welcome to Part I of my VI-part series about Eve, an exciting and fascinating new programming language.
Eve is the culmination of years of research and development by the visionary team who previously founded Light Table. Version 0.2 of Eve launched last month and made a big splash on Hacker News, which is how I first heard about it.
This latest version of Eve makes for some very cool live demos, such as “Flappy Eve”:
Scrolling through the flappy.eve demo for the first time, a few striking features jump out:
So that was my first impression. Here’s my impression after spending hours browsing the examples, pondering over the docs, and watching tech talk videos: Wow!
Eve is a cornucopia of solutions to problems I hadn’t even realized we had. It’s like I’ve been raised in a society of bicyclists, and after seeing a motorized vehicle for the first time, I’m suddenly understanding the limitations of a pedal-based architecture.
After having been exposed to Eve, I can retroactively diagnose various problems in the architecture of mainstream programming stacks. In this series, I’ll try to explain what all these problems are and how Eve solves them.
Your software stack has many layers. The following three layers are usually the “core system” doing the heavy lifting:
But there are also plenty of other layers that the core system talks to:
At a high level, these layers all do the same thing: they process data. They read input values, they compute other values, they mutate internal state, and they output values to pass to other layers. But, when you zoom into each layer, you see countless differences that obscure the fact that they’re all fundamentally about data processing.
You have one or more online database systems. Their data models look like SQL tables, document collections, key-value maps and/or graphs.
You have a remote API that models data as chunks of JSON or XML, or maybe as a GraphQL graph.
You have a running application that models in-memory data structures and variables in a scope chain.
To operate on the database layer, you can send various kinds of SQL or NoSQL queries.
To operate on the API layer, you can query for data via HTTP GET and update data via HTTP POST and friends. If it’s a GraphQL API, you operate with GQL queries and mutations.
To operate on the application layer, you can look up variables from the scope chain, and you can traverse or mutate in-memory data structures.
For each layer of your stack, there are different data models and operations:
Since each layer is different, it creates friction and room for error. You have to reason separately about each one’s properties and guarantees, and use separate programming patterns for each. And you have to write a lot of “glue code”.
Eve has a single low-level data model and a single set of operations which you can use across every layer of your stack.
In Eve, data (a.k.a. state) lives in a set of databases. Different layers of your stack might correspond to different databases, e.g.:
@session
database@browser
database@event
databaseEach database contains records. A record is a key-value mapping that can store primitive values as well as references to other records. Records have a simple bracketed syntax:
There are no tables or collections for holding records within a database, just databases containing linked structures of records.
Eve’s universal data model of linked records is reminiscent of “semantic web” technologies like RDF and JSON-LD. But Eve is more than a uniform data model…
It’s also a uniform set of operations. The three operations search
, commit
and bind
make up the entire functionality of Eve:
search
queries for data, similar to SQL’s SELECT
commit
mutates the state of your data, similar to SQL’s INSERT
/UPDATE
/DELETE
bind
writes special “deduced values”, which are like SQL’s materialized views or MobX’s computed values. I’ll say lots more about the awesomeness of bind
later in this series.It’s amazing that we can control different layers of the stack by using this uniform set of operations on Eve’s uniform data model. For example, here’s how we render a <div>
into the DOM:
Since the DOM tree lives in the @browser
database, rendering a <div>
just means commit
ing a record with tag: "div"
.
Now, for each layer of your stack, there’s only one data model and set of operations:
Since each layer is the same, there’s less friction and room for error. You can reason more easily about properties and guarantees, and use similar programming patterns for each. And you don’t need to “glue” anything together, because everything’s already connected.
The Eve team invented a uniform data model and uniform set of operations that can operate across your entire application stack. To accomplish that feat, they had to identify a higher abstraction that the rest of us didn’t realize was possible.
To wrap your head around this achievement, it helps if you’ve already put in the effort to understand another abstraction leap that debuted this year: GraphQL.
It takes people a while to understand that GraphQL isn’t a database or a server, but rather a graph query language (or “GraphQL” if you will). The point of GraphQL is to change the client’s view of an API from a small rigid set of REST endpoints to a unified linked-data structure that accepts arbitrary graph queries.
Like GraphQL, Eve also isn’t a database backend or a server; it’s a language at a higher level of abstraction than we’re used to. Consider the example code from a section of Eve’s home page titled “A simple model: the world as data”:
When you run that search @slack
block, you’re communicating with the third-party Slack application, which of course has its own internal database. But you get to pretend that everything is part of the Eve data universe — just like GraphQL lets you pretend that arbitrary API calls are part of a big graph universe.
So if you like what GraphQL is doing for the API layer, but just wish someone would do the same thing for all the other layers in one fell swoop… say hello to Eve.
**Next post:**II. When logic programming meets CQRS