Earlier quoted context omitted.
"Words are allowed to have contextual meanings" Sure, but this discussion is about FCIS, that's the context, and the GP should consider that. " think I need a more precise meaning of "business logic" before I can answer this question" Well, some examples. A tax application - the tax calculation according to the law. A word processor - layouting and rendering engine. A video game - something that calculates the state…
> Take the tax calculation for example. That cannot be decomposed into pieces that are generic, and potentially reusable elsewhere. It's just a list of rules and exceptions that need to be implemented as stated. You can decompose it into "1st part of calculation" and "2nd part of calculation", but that's meaningless (unhelpful). (Similarly for the game example above, the rules only exist in the context of other rules…
Simplify your code: Functional core, imperative shell
191–200 of 219 posts
Re: Simplify your code: Functional core, imperative shell
#192Earlier quoted context omitted.
> I think using Date.now() is perfectly ok. This is why we have tests which we need to update every 3 months, because somebody said this. This is of course, after a ton of research went into finding out why the heck our tests broke suddenly.
I would call those badly-written tests. The current date/time exists outside the system and ought to be acceptable for mocks, and in python we have things like freezegun that make it easy to control without the usual pitfalls of mocks.
Re: Simplify your code: Functional core, imperative shell
#193Earlier quoted context omitted.
Making a distinction between pure and effectful functions doesnt require any kind of effect system though. Having a language where "func" defines a pure function and "proc" defines a procedure that can performed arbitrary side effects (as in any imperative language really) would still be really useful, I think
> Having a language where "func" defines a pure function and "proc" defines a procedure that can performed arbitrary side effects (as in any imperative language really) would still be really useful, I think Rust tried that in the early days, the problem is no-one can agree on exactly what side effects make a function non-pure. You pay almost all the costs of a full effect system (and even have to add an extra languag…
Re: Simplify your code: Functional core, imperative shell
#194Bertrand Meyer suggested another way to consider this that ends up in a similar place. For concerns of code complexity and verification, code that asks a question and code that acts on the answers should be separated. Asking can be done as pure code, and if done as such, only ever needs unit tests. The doing is the imperative part, and it requires much slower tests that are much more expensive to evolve with your cha…
https://hemath.dev/blog/command-query-separation/
Down at the bottom it gets into composition to make utility functions that compose several operations. Any OO system has to be careful not to expose methods that should have been private, so that’s not specific to CQS. It’s just that the opportunities to get it wrong increase and the consequences are higher.
Re: Simplify your code: Functional core, imperative shell
#195Earlier quoted context omitted.
I would call those badly-written tests. The current date/time exists outside the system and ought to be acceptable for mocks, and in python we have things like freezegun that make it easy to control without the usual pitfalls of mocks.
What are those mock pitfalls, which are avoided by freezegun which is a mock according even to them? IoC and Clocks solve the same problem. So what are the pitfalls of using those instead of this other mock?
Re: Simplify your code: Functional core, imperative shell
#196Earlier quoted context omitted.
> Take the tax calculation for example. That cannot be decomposed into pieces that are generic, and potentially reusable elsewhere. It's just a list of rules and exceptions that need to be implemented as stated. You can decompose it into "1st part of calculation" and "2nd part of calculation", but that's meaningless (unhelpful). (Similarly for the game example above, the rules only exist in the context of other rules…
Well you can claim that the core is the programming language, in which we write those tax rules, but that's not a very useful distinction IMHO (for how to write programs in the language).
The example on the homepage is the "specific shell" - simple and easy to use, and by far the most common usage, but if you scroll down the table of contents on the API page (https://requests.readthedocs.io/en/latest/api/) you'll see sections titled "Lower-Level Classes" and "Lower-Lower-Level Classes" - that's the generic core, which the upper level is implemented in terms of.
Re: Simplify your code: Functional core, imperative shell
#197I like the general idea, but unless you're assuming some very clever language or even more clever ORM that fixes things implicitly, wouldn't email.bulkSend(generateReminderEmails(getExpiredUsers(db.getUsers(), fiveDaysFromNow))); get all users and then filter out the few that will expire in 5 days, on a code level? That doesn't sound like it would scale
Irrelevant. The "bad" code does it too. It's talking about something specific and not "let's fix all the problems with this code".
If you pick and recommend a pattern where filtering should happen separately from retrieving, all your code will be bad
Give a man a fish / teach a man to fish, but bad.
Re: Simplify your code: Functional core, imperative shell
#198I like the general idea, but unless you're assuming some very clever language or even more clever ORM that fixes things implicitly, wouldn't email.bulkSend(generateReminderEmails(getExpiredUsers(db.getUsers(), fiveDaysFromNow))); get all users and then filter out the few that will expire in 5 days, on a code level? That doesn't sound like it would scale
Often the answer to "some very clever language" is a lazy functional language like Haskell, where it's quite common to express problems naturally on infinite or near-infinite lists (of numbers, users, whatever...) in this way - and the language's lazy evaluation semantics effectively turning it into an efficient streaming data pipeline of sorts. But even if not, the example from the article is just hypothetical. `db.…
I fixed a performance issue at some point where a missing index meant a scan of millions of rows every login. It worked, and could log in 3 people per second or so. It was still terrible code.
Re: Simplify your code: Functional core, imperative shell
#199Earlier quoted context omitted.
Right, I think a better way of stating my main assertion here is that you have to be able to partially work in a transaction. If your "shell" pretends that you can always complete the full transaction, either successfully or with a failure, then it is a brittle shell. Sometimes, you can simply make progress on an presumed open transaction.
It doesn’t have to pretend anything you don’t want. If you don’t want this kind of problem/failure possibility, then you have to encode those states in the type system. Functional programming can do the same things you can do in imperative, but you gotta make it when it’s not there. Just like in any other paradigm.
Re: Simplify your code: Functional core, imperative shell
#200Earlier quoted context omitted.
I disagree that these two pieces of advice are opposed. I think they are orthogonal at worst, and in agreement at best. "Functional core, imperative shell" (FCIS) is a matter of implementing individual software components that need to engage with side-effects --- that is, they have some impact on some external resources. Rather than threading representations of the external resources throughout the implementation, FC…
>GCSS tells us we shouldn't simply solve the one and only problem in front of us; we should use our eyes and ears and human brains to understand the context in which that problem exists This violates KISS and YAGNI and potentially leads to overengineering code and excessive abstraction