00:00:00.800
Our last speaker for today is Martin Verzilli, who is the CTO at one of our sponsors, Manasté. He has over 20 years of experience in the software industry. He watched the birth of Crystal, and now, 13 years later, he's going to talk about the technical challenges they faced to keep it alive. So, let's welcome Martin.
00:00:33.280
Thank you. When I heard that the theme of this conference was the long term, I got really excited. I said to myself, 'I really want to be here,' because I've been doing a bunch of things for a long time, and I find a specific joy in the long term. There's a depth that you don't get any other way; there are no shortcuts, you need to let time pass.
00:00:40.880
It’s either that or I'm about to turn 40 and this is a midlife crisis. Either way, they are both valid reasons. I want to focus on an aspect of long-term things which is change. I think it was kind of a sub-theme today; I heard it in many talks. The idea, particularly from the NITAS talks, was that to survive and remain relevant, you need to be constantly adapting, and adapting requires intentional change.
00:01:08.240
But there's an aspect of change that I want to review with you, which is the interplay between change and identity. Sometimes we say that change is necessary for long-term relevance, but certain changes feel like you won't be the same after taking them. Then there's the question of whether the reason for my project or any other aspect of life still exists after this change. Is it still worth continuing after this change?
00:01:22.640
The complementary question is whether you consider your identity as all of that big lump of stuff, or is it just a feature? Maybe you can consider removing some of your requirements for your identity to move on. I will use a real-life example from Crystal, something that happened to us a long time ago, and it's still relevant to some extent for the project. I guess the first step is to talk a bit about Crystal.
00:01:48.000
How many of you know Crystal, the programming language? Oh, that's quite a few! I wasn't expecting this, so I guess I can move a bit faster. Crystal is a programming language inspired by Ruby, with a standard library almost copied from Ruby. The main thing with Crystal is that we wanted to capture the vibe of programming in Ruby in a compiled programming language.
00:02:02.720
This means we needed to write a compiler where you can throw anything at it, and it sorts out the types for you. This way, you still get that typing sensation you experience from Ruby. If you see this example where you have an array that returns either a needle or a string, you just get one random element from it and the compiler knows it's either going to be a string or a needle without you having to tell it anything.
00:02:29.199
There's also a bit more power because you can ask if a certain variable is not nil, and then the compiler knows that it's a string; it's not nil. So we call this nil tracing, and it's attempting to tackle the million-dollar mistake of having nil be a part of every type. Being a much younger language, we also wanted to have a solid concurrency model from the beginning.
00:02:56.760
We took inspiration from Go for this, using CSP coroutines to communicate between green threads and fibers. This allows us to reuse code easily, and we made it really easy to bind to C libraries. For instance, you can perform exponentiation natively in Crystal without having to rely on an external library.
00:03:19.440
Now, let me share the origin story. In 2011, we were at Manasté, the company where I work, in Argentina. We were primarily a Ruby shop, but we had experience releasing and deploying various applications in C#, Java, and Erlang. Out of those, we were the happiest with Rails; it felt good to write and model in.
00:03:27.840
However, some of those applications started to struggle when they became more successful and were put under more stress. Being a bunch of programming language nerds at the company, we made the dubious decision to create a programming language to solve this. So, we began discussing what a compiled version of Ruby would look like. The first consideration was how to make a compiler that's smart enough to recognize when a value can be nil.
00:03:53.199
For instance, here you can see a Ruby script that does something not particularly useful—it takes either a nil value or a float depending on a random call. I ran it three times, and on the third time, I encountered a runtime error. In contrast, the same code compiled and run with Crystal would produce a compile-time error.
00:04:07.120
This lead to excitement as we realized we could distinguish errors before runtime. Then, since we were using LLVM and compiling to code, it was really fast and had a low memory footprint.
00:04:28.640
However, I need to admit that benchmarks can be misleading, and showing a benchmark out of context is not ideal. I'm trying to illustrate the point of our observations back then, particularly with a caveat—if you call line 43 instead of line 42, Ruby will convert gracefully, while Crystal may crash because it will overflow and throw an exception.
00:04:48.000
This doesn't imply that Ruby is inferior; Ruby is our beloved language. However, we needed to introduce some requirements from developers in Crystal that were different from what they were used to in Ruby. For example, we required developers to specify the type of empty collections for proper type checking.
00:05:10.559
This was a significant departure from how Ruby operated. It was something we stood by from the very beginning of the language, and while developers didn't seem to care at first, I mention it now because it will become relevant later.
00:05:36.240
We didn't create Crystal to just play around; we wanted it to succeed. Initially, it was merely an experiment or a playground for us. But one day, one of our colleagues posted about it on Hacker News, and it became the number one trending post for three weeks. Suddenly, we were getting contributions and people discussing it, even posting benchmarks that were out of context.
00:05:58.160
This surge of interest made us think that perhaps there was real value in pursuing this further. So, we came up with a motto: 'Fast as C, sleek as Ruby.' We wanted to be as expressive as Ruby while aiming for C-like performance. In hindsight, maybe it was a mistake to define ourselves in reference to others.
00:06:21.840
In retrospect, we decided to document what the goals of the language were. We aimed for it to have the same syntax as Ruby or at least resemble it as closely as possible, to maintain the ease of use that Ruby developers enjoyed. We wanted to ensure that developers never had to specify a type for a variable or method argument, which wasn't entirely true since I showed before that annotations were required.
00:06:45.560
We wanted to mimic Ruby's metaprogramming features with compile-time evaluations. We introduced a macro system, but it wasn't as powerful as Ruby's dynamic features, yet it was a step towards achieving our goals.
00:07:02.280
It's been 13 years since then, and we are still evolving. Why did we evolve? Because we wanted to ensure that Crystal could thrive and be relevant moving forward. We constantly reassess whether the changes we make align with our original intentions.
00:07:18.280
For instance, we had to reconsider whether we could survive without certain changes. Would Crystal still be Crystal after these changes? These are the types of profound questions that arise when managing a project like ours, and they have accompanied us throughout our journey.
00:07:43.120
In particular, there was a moment when we had to make a significant decision regarding type annotations for variables. Initially, we introduced this requirement to help manage compiler complexity. However, this raised identity questions among the community. They questioned the reasons for Crystal's existence. Could Crystal survive without these compromises?
00:08:06.840
Some community members reacted negatively to the proposed changes, indicating that they felt let down. We had to re-evaluate our original goals, asking ourselves if changing the language would detract from what we sought to achieve.
00:08:29.920
In the end, we decided to proceed with the changes, understanding that failing to adapt could lead to the project's demise. We noted that maintaining Ruby compatibility wasn't our primary goal; we wanted to offer a unique value proposition.
00:08:50.600
As we advanced, the changes led to a fork in the road for the community, but the majority stayed with us. We shifted our motto to 'A language for humans and computers,' a phrase that aligned better with our intentions and helped us continue the project.
00:09:10.880
Four years ago, we reached version 1.0. It was no longer just a toy; it became production-ready, and many businesses now depend on it. This brings us both joy and responsibility.
00:09:29.600
This milestone means we commit not to break existing functionality moving forward unless we introduce newer versions. However, it remains a challenge. As I mentioned earlier, we have a functional compiler now, but we still want to enhance developer experience.
00:09:48.520
The compiler speed can restrict modern developer tools from immediately responding to developer actions, which is something we need to address. We are exploring ways to make improvements while ensuring we don't compromise the language's integrity.
00:10:08.240
I want to make it clear that we will never compromise the essence of Crystal for the sake of performance. Yes, we will keep exploring ways to achieve a more efficient compiler, but we will not implement solutions that fundamentally alter Crystal's unique identity.
00:10:27.760
Ultimately, some changes can redefine your direction entirely. It is essential to remain aware of these potential shifts. You don't want to become someone else without understanding the implications of the decisions you make.
00:10:46.160
Thank you!