Post

Fully agree. I would also consider converting the 2 boolean functions to those that return :ok | {:error, reason}: is_email_address? => validate_email_address is_available => check_availability It's also future-proof if additional error reasons pop up. You may say I generally dislike booleans :)

I also think the approach I proposed gets to the point more quickly. In your example you produce the error in one shape (e.g. `{:is_email, false}`), and then later convert that into another shape (`{error, reason}`). I find this extra conversion needless and confusing.

Was going to argue with you, but then I realized you're right 😂I was going to say something along the lines of "I might not be in control of those functions being called", but nothing stops you from writing a wrapper function for each step.

😂 Yeah, the generic `validate` helper shown here can reduce the amount of micro functions. It converts true/false into ok/error_reason. I typically also add validate/1 which produces error without reason. But if the check is more complicated/longer then I definitely move it to a separate priv fun.

I'm aware of this pattern but never needed it, as I prefer functions that return :ok | {:error, reason} as opposed to a boolean. Booleans are simply not informative enough, I don't like them :)

My bad for showing a wrong example, it’s not really about a function returning a bool instead of tuples, it’s the idea that every chained member in a with condition will by tagged with an atom describing the operation, so that we avoid collisions in the « else » block!

It's fine IMO, but I've seen it abused to a point of code being completely unreadable. I'd only use it for simple cases like this - short function names with 1-2 arguments. But I really like what @sasajuric.bsky.social proposed here as the alternative: bsky.app/profile/sasa... It's way better.

Saša Jurić@sasajuric.bsky.social

Hard pass. I dislike how things which are strongly related (validation and the corresponding error) are separated so far apart. This is what I do instead 👇

If I need to know which statement failed then I find `with` to be trying to fit square peg into round hole. You either need to know (and then you probably should use `case` or separate function) or you do not care, and then you do not need hops like that.

Hmm idk about this one. I really feel that we should be able to do both: 1. focus on the success path 2. being able to handle the specifics error One would say that the saga pattern is here for that but feels like a bit much to implement for that (sending a follow up skeet)

Fine when used sparingly. Definitely less readable than if you can get away without the tagged tuples, but sometimes you legitimately do need different error handling for different failure cases, and the alternative of 6 levels of nested case statements or single-use private functions is worse.