00:00:09.650
My name is Brad Urani, and I work at Procore. This talk is about object-relational mappers (ORMs), specifically comparing and contrasting Ecto and Active Record. Ecto is an ORM for Phoenix.
00:00:16.230
Phoenix is a web framework for Elixir, which is a relatively new programming language created by José Valim. José was a long-time core member of Rails, and he split off to start his own programming language.
00:00:24.269
Elixir is an interesting language; it's very fast, functional, and it has Ruby-like syntax. It's designed for very high concurrency and does that exceptionally well.
00:00:30.570
Elixir compiles to Erlang bytecode. Erlang was originally developed for massively scalable soft real-time systems, which require high availability.
00:00:36.570
Erlang was created by Joe Armstrong back in the '80s for telephone systems while he was working at Ericsson. He wrote software for a telephone switch that ran a million landlines with 99.9999999% availability.
00:00:42.750
This technology was used to design systems that could serve the entire continent of Europe. Although it was groundbreaking, it fell out of popularity when the Internet emerged in the '90s.
00:00:54.449
During this time, languages like Perl and Java became the de facto languages of the Internet, and Erlang was somewhat forgotten.
00:01:00.660
However, it's made a comeback recently as people realize there are still use cases for high-concurrency real-time systems on the Internet.
00:01:06.720
One of the neat things about Elixir and Erlang is that you can run thousands of processes concurrently, allowing for remarkable inter-process communication.
00:01:13.530
Imagine a telecom technology that routes thousands of phone calls in real time with servers that automatically cluster to create real-time distributed systems.
00:01:19.439
Erlang is like an ugly Ferrari—it's incredibly fast but has a somewhat difficult syntax that isn't very user-friendly.
00:01:25.890
José Valim came along and created Elixir, which runs on Erlang but has a more aesthetically pleasing Ruby-like syntax.
00:01:31.049
Although the similarity to Ruby is somewhat superficial, Elixir is a functional language, and how you use it differs significantly.
00:01:36.299
Now, it's sort of like a pretty Ferrari, combining amazing speed with a visually appealing interface.
00:01:42.830
Phoenix, built with Elixir, is an MVC framework that emphasizes productivity without sacrificing speed or maintainability.
00:01:48.000
Developed by Chris McCord, it shares many similarities with Rails. Phoenix has its own MVC architecture, routing, and generators.
00:01:54.449
It employs a package manager called Hex, which takes the best aspects of both Ruby's Gem and Bundler. Additionally, it features Mix, akin to Ruby's Rake.
00:02:03.899
Today, I will be discussing Ecto, the ORM that shares a feature set with Active Record, including queries, migrations, and validations.
00:02:10.229
Many people say that Phoenix represents the next evolution of Rails, which we will explore.
00:02:17.060
Phoenix is also many times faster than Ruby on Rails, which can sometimes make Rails feel slow.
00:02:22.430
Elixir and Phoenix can be particularly advantageous for real-time communication systems.
00:02:28.190
For instance, when sending messages from one phone to another in a mobile app built with Elixir, the message goes directly between servers without going through Redis.
00:02:35.540
In contrast, Rails 5's Action Cable requires messages to go through Redis. Ecto's architecture allows for more efficient real-time message transfer between servers.
00:02:42.830
This difference in architecture signifies a fundamentally faster model.
00:02:48.000
Using this technology, applications such as video conferencing systems and MMORPGs can be built more seamlessly.
00:02:54.780
An example is League of Legends, a popular game whose backend was built using Erlang.
00:03:01.010
Ecto, as an ORM, operates within an MVC framework built on telecommunications technology, somewhat like Rails but with additional capabilities.
00:03:07.170
Today, however, my focus is specifically on ORMs and how the designs of Ecto and Active Record contrast.
00:03:13.520
Throughout my experience, I've worked with various ORMs, primarily in Java and C#. I recently transitioned to working with Active Record and Ecto.
00:03:22.120
When I look at this list of ORMs, Active Record stands out due to its unique design.
00:03:28.190
Before diving deeper into ORMs, I want to touch upon functional programming.
00:03:36.930
Elixir is characterized as a functional language, which emphasizes avoiding state and mutable data.
00:03:41.430
This might not seem intuitive right away, so I'll explain that Elixir does not have traditional objects like Ruby. Instead, it has modules.
00:03:48.270
This means that there are no instance methods; it uses functions instead of methods and data.
00:03:54.170
It also does not allow mutations. For instance, if you modify a struct, you receive a new struct, leaving the old one unchanged.
00:04:00.650
This use of immutable persistent data structures causes a fundamental shift in how the language operates.
00:04:08.210
With that in mind, allow me to begin discussing Active Record.
00:04:14.080
You may have encountered Active Record before, so I'll provide an overview and set a foundation for our discussion on Ecto.
00:04:20.370
It's essential to understand what drives the design philosophies of Active Record and Ecto.
00:04:25.620
I created a demo app called Hallway Track, which I'll reference throughout this talk.
00:04:32.050
The premise revolves around attendees at conferences and the informal chats people have in the hallways.
00:04:37.560
So, how do we define the relationships here? A conference has many parties, and each party has several users.
00:04:42.590
Now, let's set up Active Record. We have our Party class, which includes scopes for conference dates.
00:04:49.710
Scopes are reusable query fragments, allowing us to create reusable bits of queries.
00:04:55.960
We can combine these scopes for specific queries. For example, we create a scope for conferences that started after a specific date.
00:05:02.200
With Active Record, the syntax is very readable, making it easy to understand at a glance.
00:05:09.610
As we go further into the code, we see our controllers and views all integrating smoothly.
00:05:16.790
However, a common issue that can arise is the N+1 query problem.
00:05:20.289
This happens when queries aren't preloaded, leading to additional database hits, which can degrade performance.
00:05:27.980
To address this, you'd add a preload method to your queries, but it complicates the initially readable syntax.
00:05:34.590
The result is that the elegant and simple Active Record syntax gets cluttered.
00:05:40.900
This leakiness often requires developers to remember implicit database interactions while using Active Record.
00:05:47.700
This can lead to confusion as developers try to abstract away the database details.
00:05:54.560
As I mentioned earlier, our frameworks can lead to complex debugging processes when it comes to understanding SQL queries.
00:06:01.820
In Active Record, the abstraction can limit your understanding of what's happening under the hood.
00:06:08.060
From my experiences, the SQL often becomes a background consideration rather than a primary focus.
00:06:14.230
Joe Armstrong once stated that, regarding objects, you may want a banana, but you'll get a gorilla holding it.
00:06:20.490
In this case, the active record model serves as the gorilla, complicating matters.
00:06:27.770
You've lost track of where the queries are scattered in the codebase.
00:06:34.420
The design allows for convenience but often sacrifices explicitness, which can impact performance.
00:06:39.360
Active Record does favor English-like syntax for the sake of readability.
00:06:45.380
While this may expedite developer productivity, it can lead to performance pitfalls.
00:06:51.890
As I mentioned earlier, convenience may often come at the cost of explicitness in these cases.
00:06:57.140
Now, let’s transition to Ecto to explore its approach.
00:07:03.230
Phoenix and Rails have a lot in common, particularly for CRUD applications, but Ecto delivers real-time communication capabilities that set it apart.
00:07:11.680
Ecto is not just a simple model. It's more comprehensive, comprising a repo, schema, changeset, and query.
00:07:17.420
First, we need to define the schema in the model file. In Active Record, fields are dynamic, but Ecto requires them to be explicitly defined.
00:07:23.440
In Ecto, this explicitness aids in clarity, ensuring we define relationships clearly between models.
00:07:29.270
Once the schema is defined, we can proceed to the controller, which maintains its own structure.
00:07:36.960
For instance, in the index action, we retrieve the request and response and handle them without relying on global state.
00:07:42.590
The repo module represents our database, and we access queries through it.
00:07:48.090
This structure separates responsibilities, allowing us to have both repo and query parts in our design.
00:07:55.140
The repository pattern separates the concerns defined in Martin Fowler's design patterns.
00:08:01.650
Active Record merges several models, leading to a somewhat confusing amalgamation of patterns.
00:08:07.290
What’s interesting is that Ecto has no save method, which deviates from the Active Record pattern.
00:08:14.420
In Ecto, you can't just modify and save an object directly. Instead, data is returned without methods.
00:08:19.540
Structs in Ecto are immutable, meaning that once a struct is created, it cannot be altered.
00:08:25.090
This absence of mutability fosters a different design philosophy compared to Active Record.
00:08:30.220
When we create queries in Ecto, we define them clearly, allowing for greater control and visibility.
00:08:38.370
The queries resemble SQL syntax, which enhances readability and manages interactions with the database.
00:08:45.860
We can also define our queries in a way that includes specific fields while avoiding the sometimes chaotic select star problem.
00:08:54.090
When we need to jump into complex queries or groupings, Ecto retains structured reasoning in defining relationships.
00:09:01.230
This clearer structure allows for tracking queries easier within the codebase without losing track.
00:09:08.510
If we examine the test performance of Ecto, we notice that tests are concurrent, running multiple at once.
00:09:15.780
This is due in part to how the Erlang VM manages concurrent processes, enhancing the overall performance during testing.
00:09:23.170
The use of Ecto also aligns with contemporary tools such as PostgreSQL, allowing the implementation of JSON types.
00:09:30.650
Adapting Ecto for nontraditional databases adds flexibility, making it possible to interact with different data sources.
00:09:38.920
As we explore these tools, it’s clear that Ecto and Active Record illustrate different paths through similar challenges.
00:09:45.420
In summary, there are trade-offs associated with each ORM. One is not necessarily superior, but they cater to various needs.
00:09:51.460
Ecto encourages explicitness in its structure, while Active Record focuses more on developer convenience.
00:09:57.470
Finally, I’d like to discuss considerations for choosing the ORM that suits your project best.
00:10:02.240
Resources such as the Bike Shed Podcast explore these topics in-depth. For anyone interested in immutability, I gave a talk at RubyConf titled "Change the Unchangeable."
00:10:08.020
If you’re curious about the distinctions between Ecto and Active Record, or interested in relating back to service architectures, there are exploration opportunities available.
00:10:16.470
Moreover, Procore is actively seeking developers and architects, so if interested, be sure to connect!