sheharyarn

sheharyarn

Need code review

I’m writing (my first) hex package to introduce “Ecto shortcuts” in an elixir/phoenix app. I was getting really tired of doing this all the time:

PhoenixApp.Repo.all(User)
# and
PhoenixApp.Repo.get(User, 2)

It should allow you to simply do:

User.all
User.get(2)
# etc...

I have a few concerns with this project, especially if I might be going against Elixir patterns. I would really appreciate if I could get some feedback on the code before I publish it.

See the Code here


Currently, my main concerns are:

  1. Is the naming scheme correct? (i.e. is Ecto.Shortcuts a good name?)
  2. Is doing this a good idea?
  3. Are there any anti-patterns in the code?
  4. Am I using macros correctly?
  5. What should I keep in mind while publishing this as a hex package?

Marked As Solved

Qqwy

Qqwy

TypeCheck Core Team

Welcome! Great that you’re creating a Hex package.

Let’s try to answer your questions:

  1. Your naming scheme is correct. While any names for packages are of course allowed, the advised convention is to indeed use Foo.Bar if you wrote a package Bar that extends the more general package Foo. In cases there exists both a Bar and a Foo and you wrote some kind of compatibility-layer between them, the order doesn’t matter (so you could go for e.g. alphabetical order there). So the name Ecto.Shortcuts is great!

Arguably. Some people will agree, others won’t. I myself would say that it is nice to be able to shorten Repo-based things inside your Controllers, (and saying that you basically should never talk to the Repo anywhere else). If Ecto.Shortcuts is the nicest way of doing so, is again very much a matter of taste.

It does mean that your ‘model’ is again directly connected with the repository, which is something that Ecto itself explicitly didn’t do. If you’re for instance dealing with multiple repositories that you want to switch between (a common example of this is Sharding), this is a problem.

The most important thing that might be considered an ‘antipattern’ is that your code is still missing documentation. In Elixir, documentation is a first-class member of the language, and most people try to add documentation to their functions.

I don’t see any other obvious anti-patterns at first glance. A really helpful tool to increase the quality of your code is Credo, which tries to point out some anti-patterns and inconsistencies in your code.

  1. The way you are using __using__/1 is correct :slight_smile: .

Besides the fact that documentation is important, be sure to use Semantic Versioning for your package, because this means that when other people list a certain version as dependency requirement, their code will not break if you decide update your package.

:smiley:

Also Liked

josevalim

josevalim

Creator of Elixir

The issue with the approach above is that you are coupling your schema with one particular database and the schema is designed to represent any data source, which may not even be a database in the first place. We explore some of those things here: Ecto’s insert_all and schemaless queries « Plataformatec Blog

My concern with using something such as shortcuts is that people will forget those basic tenets schemas and repositories were built on. So I would rather define modules such as MyApp.Accounts.get_user(id), which is the direction Phoenix is taking, without a need to tie repositories directly into schemas.

Misha

Misha

Those sound eerily familiar… is it from the README of my own project you seem to have ripped off and claimed as your own?

Anyways, I don’t want to get petty on this forum, but I had to call out what seems like plagiarism to me. Ironically, this thread was a good run down of the issues to address in own project since it was reviewing a proxy of it.

Before I knew about this, I was already in the process of adding complete test coverage and updating to support the new Phoenix idiom that Jose pointed out. Though I am slightly annoyed, it is good validation that I was working on the right upgrades.

Sorry to introduce myself to this community in such a negative light, but I hope to have a lot of positive things to contribute in the future.

sheharyarn

sheharyarn

Awesome! Thank you for your feedback!

Once I get all of the functionality working, I’ll start working on the documentation. One more question, how would the tests look like for it? I have a very limited experience with TDD, and I’m not exactly sure how would I go about writing tests for macros.

Qqwy

Qqwy

TypeCheck Core Team

You’re very welcome! :smiley:

Test Driven Development means that you first write tests and then fill in your code so they pass, which is not what you’re doing here. (Which is, of course, also a fine approach. :stuck_out_tongue_winking_eye: Each way has its own advantages and drawbacks.)

The thing you probably want to test here, and also the way you can test the macro, is by simply creating a few modules that include the using Ecto.Shortcuts line. You could then test if the commands are properly passed on to the actual Repo when you call them on your test modules.

Another possible test is to test what happens if using Ecto.Shortcuts is added to a module that actually does not contain an Ecto schema.

If you need inspiration, feel free to pop open any of Elixir’s core libraries, such as for instance Ecto itself to see how they write tests there. Most of them are very understandable and of (at least in my opinion) a high quality.

And, especially when your modules start getting more complex, it might be worthwhile to check out José Valim’s post on using Mocks during testing.

Where Next?

Popular in Questions Top

lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
gonzofish
I’m currently trying to understand how to join three tables using Ecto. All the examples I’ve seen use 2, so maybe I’m just missing somet...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
Codball
Mix format works fine if run from the cmd. I’ve followed this to facilitate the implementation into VSC which involves downloading an ext...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
srinivasu
How to handle excepions in elixir? Suppose i have A, B, C ,D, E modules. and each module has get() function. A.get() method will call th...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 35421 110
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 42633 214
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New

We're in Beta

About us Mission Statement