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.

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.

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.

Keeping the create, update, and delete code in a context still makes sense. In fact, I've been venturing out into CQRS land and enjoying the strictness and atomicity of the modules we've created lately. What seems to be contentious is that I'm advocating for single-use Ecto queries inside LVs.

This is a loosely held strong opinion, though. I want to hear how this may/will blow up in unexpected ways. Is it *always* a bad idea to write a query in the place where it's needed? #thanksforcomingtomytedtalk 😅

Hmm…nothing is *always* a bad idea necessarily, context is king. But IMO this comes from a lack of a properly structured application layer. When your app is a bag of functions, it’s extremely difficult to extend and ultimately the safest thing is to append-only. Your individual context functions

I don't think the issue is a "properly structured application layer", as the issue of "appending extra functions to an interface" is the same what happens in other ecosystems, exactly because of the "structure".

No replies yet.