Post

My thinking on this one has evolved after working on some medium to large-scale code repos. When I started writing code professionally, I had absorbed some of the best practices common in MVC frameworks, DDD, and other programming patterns. btw, thread length != rage 😜

In my first coding gigs, I experienced first-hand the impact of poorly organized code. SQL queries were scattered throughout template code, everything was mutable, and debugging was painfully tedious. I scoffed and rolled my eyes.

Later, I followed the patterns laid out by the Phoenix code generators. Where contexts contained CRUD code, controllers and LiveViews called those context functions. One of the biggest pain points that has grown out of this pattern, though, is query code - specifically *reading* data from a Repo.

0 reposts1 like

While I can imagine some applications that have identical queries used across multiple call sites, this hasn't been my experience. Instead, I've seen hastily added functions in contexts which serve a single call site elsewhere in the codebase. These functions often have hilariously long names.

This reminds me of the bad old days of CSS before utility classes came along. Each time a new feature is requested, someone has to look for existing code that serves the purpose. This becomes less practical over time, and devs are often nervous about breaking things, so we *just* add to the pile.

Really interesting comparison. Do you see an overlap between the ways the SPA world tackles CSS issues and this ecto query question? Abstractly they feel a little similar to me. In addition to CSS I also often find SPA data queries living close to calling UI component code with some utility helpers.

I don’t live in SPA land, so I can’t say for sure that you’re describing a similar pattern. The last sentence sounds like what I do in LiveView modules, though. 👍

Years ago, I heard a hot take on a podcast that stuck with me and I've been taking it more seriously in the past few months. Something along the lines of "just write the query in the controller/LV and move on with your life." IIRC, this was a classic Chris Keathley hot take.

Now, this probably feels like heresy. I didn't start writing queries in my LVs until I was exhausted from the ritual of managing queries in contexts. When I'm in a LV, I know what data I need for its specific use case. I only need to name a local variable and a socket assign. No abstraction needed.

it’s a fine rule of thumb but once you’ve gone from “i run an http api” to “http, coap, mqtt” then it helps to have functions in their own space. however the contours of that space are irrelevant. just write your functions

I personally find it very frustrating to look at code in the eg Phoenix auth generator style where there are contexts and then you look at the function and it’s like a “Repo.all”. I find queries to be the easiest thing to read, and often as short, so when I have to trace a function call to