Remix.run Logo
supermdguy 9 hours ago

That's a good point, thinking about it some more, I think the business logic feels so trivial that it would make the code harder to reason about if it were separated from the effects. Currently, I have one giant function that pulls data, filters it, conditionally pulls more data, and then maybe has one line of effectful code.

I could have one function that pulls the wallet balance for all users, and then passes it to a pure function that returns an object with flags for each user indicating what action to take. Then another function would execute the effects based on the returned flags (kind of like the example you gave of processing a pending charges table).

The value of that level of abstraction is less clear though. Maybe better testability? But it's hard to justify what would essentially be tripling the lines of code (one function to pull the data, one pure function to compute actions, one function to execute actions).

Additionally, there's a performance cost to pulling all relevant data, instead of being able to progressively filter the data in different ways depending on partial results (example: computing charges for all users at once and then passing it to a pure function that only bills customers whose billing date is today).

Would be great to see some more complex examples of "functional core imperative shell" to see what it looks like in real-world applications, since I'm guessing the refactoring I have in my head is a naive way to do it.

grayhatter 8 hours ago | parent [-]

> The value of that level of abstraction is less clear though. Maybe better testability?

You wouldn't do it to make it easier to test; you would do it to make it easier to reason about. E.g. There's some bug where some users aren't getting charged. You already know where the bug is, or rather, you know it's not in the code that calculates what the price would be. But now, as a bonus, you also can freely modify the code that collects the people to charge, and don't have to worry if modifying that code will change how much other people get charged, (because these two code blocks can't interact with each other).

You know the joke/meme, 99 bugs in the code, take one down, patch it around, 104 bugs in the code? Yeah, that's talking about code like you're describing where everything is in one function, and everything depends on everything else as an intractable web somehow.

> But it's hard to justify what would essentially be tripling the lines of code (one function to pull the data, one pure function to compute actions, one function to execute actions).

This sounds like you're charging per line of source code. Not all code is equal. If you have 3x the amount of code, but it's written in a way that turns something difficult, or complex to understand and reason about, into something trivial to reason about, what you have is strictly better code.

The other examples or counter points you mention are merely implementation details, that only make sense in the context of your specific example/code base that I haven't read. So I'm gonna skip trying to reasoning about the solutions to them given the point of the style recommendations is to write code in a way that is 1) easier to reason about, or 2) impossible to get wrong ...but those really are the same thing