Thinking in Ecto – ElixirConf 2017

Updated slides here: https://drive.google.com/file/d/0B3_AFNqIYFlHZHk5WnF2UXF5b00/view

(Repo)sitory

Ecto uses the repository pattern instead of the active record pattern:

With Repo you have an abstraction over your data, this abstraction can be a centralized class or module (in elixir) that connects to your database, and external APIs, etc. For your business application this module is where you get the data from, it doesn’t matter where it comes from.

On the other hand the active record pattern ties every business object to a database table, coupling your data related operations to the database, violating the single responsibility principle.

What are the drawbacks to the ActiveRecord pattern?
The biggest drawback to active record is that your domain usually becomes tightly coupled to a particular persistence…softwareengineering.stackexchange.com

Active record pattern – Wikipedia
In software engineering, the active record pattern is an architectural pattern found in software that stores in-memory…en.wikipedia.org

 Explicitness

All database related operations are explicit since we always have to talk to the repo module.

 “…as a general rule elixir doesn’t make a lot of decisions on our behalf. ”

so there’s no magic, or hidden behavior behind the scenes, instead is preferred to write code that is explicit in its intention.

Schema definition

“schemas are maps between db relations and your elixir structs”

On Ecto you have to make the schemas yourself, instead having a program do them for you(why? flexibility)

Associations

“Associations are connections between different db tables, and their associated structs.”

In other querying languages we have lazy loading, which can lead to the N + 1 Query problem.

In Ecto this isn’t the default behavior if you want to do this you have to write code specifically for this action.

Operations as data structures

  • Query
  • Changeset
  • Multi

All of these are data structures, which allows us to manipulate them and modify them before we send anything to the database.

Queries are composable, so we can build queries from previous ones:

Here what’s happening is that we’re adding constraints before the final query reaches the database, each query builds on the previous one.

Changesets do:

  • filter and cast
  • Validation
  • receive {:error, …} or {:ok, …}

“Validation isn’t set in the schema instead it is done in the changeset because validation can change depending on how we’re updating. ”

On his example there are tracks that are part of an album and tracks that are released as singles so they could be two different paths for adding a track as part of an album or as a single. These require different validation and therefore a different changeset. This gives you the flexibility to handle data from different sources for example and apply validation depending on the source.

(Multi)ple operations

If you want to do multiple operations on the database you can do something like:

this way these operations act as a database transaction either they all fail or they all succeed. if you want to execute code after they have succeeded you can use Multi.run() after it.

Flexible schemas

You don’t actually need schemas, you can perform queries without shemas

When doing queries without schemas you have to select which fields do you need.

 “schemas are supposed to make your life easier if you’re having trouble writing queries with schemas consider if the query can be done without one”

Bending schemas

On the initial phase of an application we tend to design our data as database tables, and then create data structures that mirror our db tables, and then we need to show these data structures in our view layers, so we end up with a User interface that looks like a database table. Additional to this it is really easy to make forms in Phoenix from Ecto changesets, which accommodates this workflow. If we could decouple the way the data is designed(how it looks in the UI) from the actual database tables we would be able to present the data in the best way for the user.

Ecto has a solution to make our schemas look more natural, we have virtual fields and embedded schemas for this.

A virtual field won’t be added to the database table it will just be used for creating and validating the changeset initially and later on converted to how we want it to be saved in the database.

The same thing with embedded_schema, we can use it just as any schema validate it and such and later get its fields and values to add it to a real schema which is going to be persisted in the database.

Ecto is a set of tools, not a framework

  • use schemas (or don’t)
  • use changets (or use Repo.update_all)

 As Ecto is not a framework you can decide which parts you use and which parts you don’t, it’s your choice and that’s good.

Special Thanks

The content and the code here were from the talk given by Darin Wilson on ElixirConf 2017.

Learn more from him and Ecto on his book: Programming in Ecto from the Pragmatic Bookshelf.


Leave a Reply

Your email address will not be published. Required fields are marked *