Summarized using AI

Sometimes you need to change to stay the same

Martin Verzilli • April 25, 2025 • Sofia, Bulgaria • Talk

In his talk at the Balkan Ruby 2025 conference, Martin Verzilli discusses the evolution of the Crystal programming language over the past 13 years, exploring the necessary adaptations that have ensured its longevity and relevance. The central theme of the talk revolves around the relationship between change and identity, particularly how embracing change can be essential for maintaining relevance in an ever-evolving technological landscape.

Key Points Discussed:

- Embrace of Long-term Change: Verzilli expresses his excitement about change as an essential element for long-term projects, emphasizing that adapting is crucial for survival.
- Crystal's Origin Story: He recounts the origins of Crystal, a Ruby-inspired language developed to address the limitations faced by their applications written in Ruby when they were subjected to high stress. The focus was on creating a compiled language that maintains Ruby’s expressiveness while improving performance.
- Experiments with Development: Initially created as a fun project, Crystal gained traction through community involvement after its announcement on Hacker News. Despite the initial lack of seriousness, the community's excitement turned the project into a serious endeavor.
- Changes to Language Requirements: To improve compilation speed, Crystal's developers proposed changes requiring developers to annotate instance variables. This proposal met with significant backlash from the community, raising questions about the project’s identity, its core values, and whether Crystal would still be considered Crystal after these changes.
- Community Dynamics: Verzilli discusses the mixed reactions from the community post-change, noting that while some were disappointed, others appreciated the shift and recognized its necessity. He explains how this change allowed Crystal to mature into a production-ready language and reach version 1.0.
- Future Challenges: Despite its success, there are ongoing challenges, like the need for a faster compiler and the balance between maintaining the language's core identity and improving developer experience with tools.

Conclusions:

- The essence of a programming language can be impacted by the changes it undergoes. Understanding the implications of decisions to adapt is crucial for any project’s survival. By balancing core values with the need for changes, Crystal has managed to evolve without losing its identity completely. Verzilli emphasizes that some changes can redefine a project, which necessitates careful consideration of their impact on the community and the project’s future.

Sometimes you need to change to stay the same
Martin Verzilli • Sofia, Bulgaria • Talk

Date: April 25, 2025
Published: May 02, 2025
Announced: unknown

Next September, the Crystal programming language will turn 13 years old. I was there when it was born as a fun experiment, and I'm still there 13 years later, as it continues to develop into a proud descendant of our beloved Ruby. I'm going to share a handful of stories of key decisions we had to made along these years to guarantee its continued existence. I want us all to smile at the sweet irony that, often times, embracing change is our best chance at building somewhat permanent things in a fundamentally impermanent world.

Balkan Ruby 2025

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!
Explore all talks recorded at Balkan Ruby 2025
+5