only because we reserve the use of the word "magic" for the times we find it bad/unsuccesful.
When it's good/successful, we call it "powerful, mature, and robust high-level abstractions and APIs".
That "magic" is always bad is just a syllogism because a value judgement on the success of the abstractions or APIs is built into the term as used. Abstractions that are confusing, or unexpected, or inconsistent internally or with the platform they live on, or especially leaky or buggy, or in practice hard for beginner developer-users to develop proper mental models to guide use around and to understand how to debug the use of -- get called "magic". But nobody set out to provide such abstractions, they set out to provide nice, polished, predictable, simple to understand, consistent, powerful tools at the right level of abstraction for the domain -- when someone thinks they've failed, with abstractions at a fairly high level or higher than the speaker thinks is appropriate for the domain -- they call it 'magic'.
"Magic" is not something the developer doesn't understand, it's something the developer cannot possibly understand, because you didn't document it properly (or at all).
Nope. "magic" is poor execution of something, one way or another. It's a category of something done unsuccesfully, not some kind of difference in kind of thing.
This matters for how we talk about 'magic', like, you shouldn't have put all that magic in there, did you think we want magic? No, nobody wants something poorly documented and nobody thinks they do. Nobody sets out to make something unsuccessful, "magic" is a failure.
Is it magic when it does something convenient for you based on conventions without you writing the steps? As long as 'magic' is clearly explained in the docs I don't see how it's different from a layer of abstraction like a compiler or a car.
There is no line; that's the definition. (I'm agreeing with you here, btw) It's a blub issue; if one doesn't understand it, it's derisively called "magic". So you don't get this argument because it's totally based on the observer.
I use Django at work and I hate it because it's magic all over the place. And I recognize that me saying it is simply I haven't had the time or impetus to go figure out the stuff I don't have figured out yet, so I can bucketize all that as "magic".
I've had a similar experience in Ruby where metaprogramming was used in favor of objects with functions. When I had issues, it was very hard to debug.
Maybe it comes down to the quality of the abstraction. I think the point of a good abstraction is you don't have to go down to the layer below.
Or maybe this is a board full of programmers who love to fret over unimportant minutia.
The idea has a well understood meaning, just use that meaning. Yes, maybe somewhere on the edges it's fuzzy, learn to live with fuzzy.
If we are debating an API design and a colleague says "it's too much magic", is that bad thing? If I write deliverEmail(email) and the e-mail "magically" gets sent, what's wrong with that?
On the other hand, if we debate the abstraction itself--for example behavior doesn't match user expectations--then we can do better at improving the API design.
A car is not magic. It does exactly what it purports to do and nothing else. David Blaine levitating is magic. It works in a very limited set of circumstances and no more. It works to amuse some spectators. It doesn't work to, for example, cross the Hudson River, despite outward appearances.
Similarly, in programming we use "magic" to describe something that seems to defy what the underpinning (language, framework, etc.) would allow. We know that it's using some trick to pull off what it's doing, and that trick likely has constraints that won't allow the magic to ever become a true abstraction.
Note that I'm not calling Phoenix magic as I haven't used it enough to know
For example, I actually do understand http, but doing anything not explicitly designed for by the framework of choice can be painful. It's not that I don't understand the underlying tech, it's that the "magic" is expecting a specific use case that I don't want to do.
Also applies to scenarios where a developer does not understand something not because they don't want to, but because the vendor has actively tried to obscure how it works and is asking you to take it as a given that it will always just work "by magic" for every use case, which invariably nothing ever does.
When do you learn about the JVM in a Java environment? At what point should you dig into be Ruby source code?
At some point you have to treat the abstraction below you as a black box.
I've personally found it helpful to accept the black box and only dig in after I've gained more experience or at the point I feel like a lack of understanding is getting in my way.
When the abstraction can be considered 100% leak-proof in practical terms. Also, if you have alternative tools when you encounter a case where "X" doesn't fit, you do not need to learn about "X" as long as you have "Y".
But when a solution is presented as "this must always be used", the solution should have been around for a long time with a track record of never breaking. If that's where the abstraction is, it's usually solid enough to not go any deeper.
In my experience, most developers don't talk about "magic" as if it's the same thing as "abstraction". "Magic" usually means an abstraction that leaks under non-trivial conditions.
The only thing I couldn't figure out how to override was streaming uploads.
But this describes all manner of legitimately useful features. Garbage-collection, for instance, or dynamic-dispatch, or closures, or await/async.
As technicolorwhat and vendiddy already said, it's also poorly defined. In languages like Haskell, or SMT-solving languages, the programmer might know very little about how the language is implemented.
> you inevitably end up with edge cases and bugs in your application that simply can’t be resolved without that understanding
You can run into trouble if you have an incomplete understanding of your programming language, but this isn't particular to 'magic' abstractions.
It makes for great demos but it basically means “this just works so you don’t need to know how it works”.
The problem is you always need to know how your tools work, often sooner rather than later, as you inevitably end up with edge cases and bugs in your application that simply can’t be resolved without that understanding.