I'm not wild about this article; it gives lots of "you can go from code like this, to code like this!" examples with non-equivalent functionality, which is confusing if you're skimming.<p>Totally separate from stylistic quibbles, I also think effect systems are often oversold by folks who like them (usually, in my experience, folks from a functional background).<p>Fundamentally, a lot of the code we write <i>is</i> the effectful IO plumbing. By that I mean: there are very few complicated algorithms, or really any hand-written algorithms at all, in a large amount of code written for modern systems. Instead, the complexity and value of the code is in the way it coordinates different external IO sources/sinks. This is pretty well illustrated in the article's toy directory enumeration/file handling example: with the IO/system specific stuff extracted into the effect receivers (processors? handlers?), the remaining code is not just simple, it's <i>vacuously</i> simple. The complexity and trickiness of handling IO, dealing with error conditions, etc. all remains, though, in the effect receivers. This is subjective, but that seems more akin to the "over-extracting methods to the point where all you do is increase the line count" school of refactoring than the "improving the comprehensibility/maintainability of the code" school. Generifying IO interactions behind an effect system in a codebase that is primarily occupied with gluing together external systems results in moving so much of the code into effect receivers that nothing useful remains behind.<p>Put another way: often, <i>what</i> we're doing is intimately coupled with <i>how</i>: like, sure, I'm technically "piping data from a source into a sink with a transformer in between", but they don't pay me to write "source |> transformer |> sink", they pay me to write (for example) the SELECT statement in the source, the column mapping/reformatting logic of the transformer, and the POST-to-endpoint in the sink. If those things already existed, it would be the one-liner above, but they don't for the business domain, so we make them. Once they're written, by all means, modularize them and make them easily usable in a streamable, convenient way. But most of the interesting code, once you peel back the curtain on "source" or "sink" is still going to be in its effectfulness.<p>Then there's the argument from modularity/swappability: that you can replace effect handlers with equivalent handlers for doing other things. If you're writing a system with many swappable backends, this may be useful. However, most systems don't have that property. Datastores and effect receivers change much less often than the data flow itself. And past a certain point you end up with "old Java"-style modularity: things abstracted so far away in service to unneeded pluggability that the code becomes harder to follow and maintain (especially given that the code may be primarily/near-exclusively concerned with specifics of IO flow).<p>To be sure, there are some cases where effect systems can really help. I just don't think those are as numerous as FP proponents think they are.