DEV Community

Cover image for Where do you stand on "magic" within languages and frameworks?

Where do you stand on "magic" within languages and frameworks?

Ben Halpern on July 20, 2022

Let's discuss the concept of magic — what are your opinions? Magic (programming) In the context of computer programming, magic...
Collapse
 
jmfayard profile image
Jean-Michel 🕵🏻‍♂️ Fayard • Edited

My view is that abstractions are a good thing, the bread and butter of programming. You don't generate your HTML in C with printf(), do you? But we also need to be aware that they can be leaky.

Twenty years ago: The Law of Leaky Abstractions

Collapse
 
ravavyr profile image
Ravavyr • Edited

I'd say you shouldn't be using C to build websites at all, that there are much simpler ways to write your html these days :)

But you're right, abstractions are good thing, but not when someone creates an abstraction layer for HTML tags to where your write _br() instead of < br > literally typing more characters to use an abstraction because some old timey dev was utterly insane. [true story, old tag library i had to use years ago]

Collapse
 
besworks profile image
Besworks

I like to use the term automagically especially when describing things like Web Components to people. It's not really automatic which I feel implies no effort, but rather it's so advanced as to seem like magic to someone who doesn't get the how the abstraction works.

Image description

Collapse
 
tbroyer profile image
Thomas Broyer • Edited

The way I use the term "magic" is whenever there's implicit behavior (generally based on naming rules, but sometimes on introspection/reflection, scanning, etc.) that generally cause "action at a distance"; it can probably be generalized as "too much abstractions, more than you can comprehend". "Convention over configuration" is different from "magic"… until there are too many such conventions.

As long as it works, "magic" feels great, boosts your productivity, etc. The moment it breaks, good luck finding why it broke and then how to make it work the way you want/expect. And of course, just like a framework, the moment you need to do differently and "escape the magic", you're likely going to hack around and start depending on internals/implementation details ; a bit like any kind of framework.

That's one reason I don't like frameworks: you built a blog in 10 minutes and 30 lines of code? great, but did you realize you're using a gazillion lines of code you didn't write? Yet you're liable for them once you push them to production. Write a bit more code you fully understand, to glue together fewer dependencies (easier to debug, easier to update, smaller, probably faster too), and always be explicit (don't write "magic" yourself).

Collapse
 
mordechairoth profile image
mordechairoth

Well said.

Collapse
 
manuartero profile image
Manuel Artero Anguita 🟨

can't agree more actually

Collapse
 
cerchie profile image
Lucia Cerchie

I don't like the term. Reducing complexity is hard work, not magic. It also removes all the developers from the idea that they can control the outcomes.

Collapse
 
jeremyf profile image
Jeremy Friesen

I find that the most important feature of "magic" is that the tool needs powerful introspection. Emacs. has bonkers amount of magic available, and the introspection tools are top-notch. Similarly, Ruby has the ability to craft powerful magic (see Rails). Ruby also has powerful introspection.

So, if the tool uses magic, understand how to navigate the incantations. Those "magic macros" will save a lot of time.

Collapse
 
jmfayard profile image
Jean-Michel 🕵🏻‍♂️ Fayard

A possible issue is that the "magic macros" can confuse the hell out of the developer tools from the IDE.

For example Scala is more powerful than Java or Kotlin, but its IDE support is worse because of that.

TL:DR developer tooling matters

Collapse
 
brunoj profile image
Bruno

I hate it when I'm new to a framework and love it when I'm experienced with it. 😅

Collapse
 
katafrakt profile image
Paweł Świątkowski

Interestingly, I could say exact opposite. When I'm new, I just love all the things being done that I don't have to do myself. When I start to work in larger codebases, it causes a lot of problems with refactoring and general headache that I'm not in control.

Collapse
 
gklijs profile image
Gerard Klijs

It's an double edged sword. With Spring Boot in the Java ecosysteem, a lot can be auto configured. Just add a dependency, and a lot of classes wil be created and started for you. Once you need to change something, it can be hard to know where to change it. And when something goes wrong on startup it might not always be obvious.

There are a lot more types of magic, like macros or synthetic sugar, for which more or less the same counts. It's easy when it works, but it can be hard when it doesn't.

Collapse
 
fish1 profile image
Jacob Enders

I tried using .NET core MVC, (for a day). The framework is able to detect the classes you defined, link them to the HTML, magically create routes, and probably much more that I never was exposed to.

Coming from a C/C++ and NodeJS background, this level of abstraction is just uncomfortable to me. I like defining my Classes, instantiating my Object and then passing it to the framework to be used.

Just being able to define a class and have a website popup feels like I'm creating configuration files, not programming.

But too be fair, I do tend to write a lot of the same boiler plate setup code on every Node application I build.

Collapse
 
manuartero profile image
Manuel Artero Anguita 🟨

it's like salt in food. A touch of magic/salt is needed. It makes our meal more tasty. But too much.... turns food inedible.

Reaching the point of "no idea who/when/why is executing this" would be the equivalent to too salty meals.

Thing is, the more you use it, the more you get to it right? (until the doctor warns you about using salt in excess)

Collapse
 
armousness profile image
Sean Williams

I only like magic when it's fully expressible within the language itself. For example, Rust has a println! macro that lets you put terms in the format string, and the terms are typechecked. However, Rust's macro system is available to the programmer, so you could reimplement println! if you were so inclined.

I guess the broader point here is, languages should focus more on allowing robust metaprogramming. Nearly all magic is metaprogramming, but this means in most languages you're stuck with the magic the language developers/maintainers thought you deserve.

Collapse
 
rgfaber profile image
R.G. Lefever • Edited

If you want to achieve software manufacturing -as in a repeatable and scalable industrial process- relying on relatively unskilled workers (aka juniors) to cut the cost, while still achieving high velocity or even some automation through code scaffolding, some "magic" is unavoidable. If you prefer artisan software development, resulting in an inconsistent code base, only understandable by the magicians themselves, by all means go ahead, but watch "The Sorcerer's Apprentice" first....

Collapse
 
stephen_tran profile image
Stephen Tran

If your application or website rely a lot on frameworks or libraries then perhaps low code or no code would be the safer and faster way to go. Something such as WordPress allows user to use boilerplate templates and customize them.

Collapse
 
rgfaber profile image
R.G. Lefever

Thank you for your feedback. As architects, we have a number of responsibilities: guarding non functional requirements, offering guarantees in the quality level of the output, providing tools that turn software development into software manufacturing, just to name a few. This is not limited to the front-end. In fact, the front-end is often the least of our concerns (cutting corners here, i know) and sure why not pick the path of least resistance there. But as for back-ends that handle huge amounts of events/data and/or need serious concurrency, core code that is tested through and through with minimal specific implementation is probably preferable.

Collapse
 
stephen_tran profile image
Stephen Tran

This is the dilemma of software engineering.

Collapse
 
mistval profile image
Randall

This kind of magic can offer us a lot in terms of productivity gains, but we should never be dependent on it, and should always use low-magic solutions until we understand the underlying technologies well.

What I mean for example is that you shouldn't try to use React before learning how to build a site with plain HTML, CSS, and JS.

You shouldn't use Nest.js before learning Express (or maybe even the raw http library).

You shouldn't use ORMs without learning SQL.

If you skip learning the fundamentals, and depend on magic, you'll be in trouble when the going gets tough.

Of course, I'm not saying we have to dig silicon out of the ground and build CPUs with our bare hands before learning to program (though I'm sure that would be pretty enlightening).

But any time we use a framework or library, we should try to sense when it might be obscuring the fundamentals and preventing us from learning something important. Not always easy, but I think it's something you can get a sense for.

Collapse
 
bugmagnet profile image
Bruce Axtens

As the team works through putting COBOL onto Exercism I'm reminded about some of the declarative magic that COBOL provides. The thing I'm thinking about is 88 levels which can simplify code dramatically.

Collapse
 
polterguy profile image
Thomas Hansen • Edited

The less you need to know about the code's internals the better encapsulation you've got. More encapsulation is a good thing since it allows us to move further up and do more with less. I think it was Paul Graham who said; "Always use the highest possible level of abstraction, since it allows you to deliver more with less". I insanely agree with this thinking, to the point where I arguably built my entire career around it, in implementing Magic - Literally ...

Magic is a good thing, always, think about it - All the best languages have high levels of magic at its core; SQL, HTLML, CSS, etc. The reason why these languages are great, is because you don't need to understand how they do what they do, you can just trust them to always doing it ...

Collapse
 
jzombie profile image
jzombie

It's hard to put a lot of faith in something that doesn't provide unit tests and code coverage. What may work right now may not work tomorrow after it gets hacked on.

Collapse
 
baenencalin profile image
Calin Baenen

It's fine because it can enable really cool behavior.
Þink Rust's interior mutability pattern Rc/RefCell.

Collapse
 
wjplatformer profile image
Wj

thorn!

Collapse
 
baenencalin profile image
Calin Baenen

Correct.
I also you ðe highly underrated eð. (Ðough it doesn't look good wiþ ðe low resolution of ðe font DEV uses.)

Collapse
 
amiamigo profile image
Ami Amigo

To me...Magic is like having prebuilt functions like Sort. As opposed to manually have to come up with an algorithm to sort things myself. Abstraction is good...But you can't convince me that frameworks like React makes since easier...they become so complex that they defeat the whole purpose.

Collapse
 
raibtoffoletto profile image
Raí B. Toffoletto

Abstractions are great! In 2022 we don't boot our computers and literally have to type our program before running it... we came a long way from punch cards.
But any abstraction should be clearly documented and with the possibility to extend / customize. I hear a lot of complains from the folks using swift ui, so not a good example for that.

Collapse
 
amiamigo profile image
Ami Amigo

To me...Magic is like having pre-built functions like Sort. As opposed to manually have to come up with an algorithm to sort things myself. Abstraction is good...But you can't convince me that frameworks like React makes since easier...they become so complex that they defeat the whole purpose.

Collapse
 
htho profile image
Hauke T.

There is a word by the German Author/Poet Rainer Maria Rilke "There is magic in every beginning" ("Jedem Anfang wohnt ein Zauber inne").

When you start to learn a new Framework everything seems to be magic. It took me a long moment understand how module mocking works in jest. (the moment is not over yet).

I don't like magic if I am not able to understand whats behind it. I am glad that I first learned JS Promises and then async/await. New JS Programmers need to learn Promises but will not use them much. It will always feel awkward for them. For me async/await actually felt like "syntactical sugar". For them its a language feature, that will feel as magic once they want to understand why something happens when.

Frameworks take this to a whole new level, where you apply some attributes to your html code and you have half an SPA - and a hard time to understand how it works.

I like VanillaJS because there is no magic (as long as you dont do it).

Collapse
 
qm3ster profile image
Mihail Malo

Hating magic is a form of Survivorship/Availability bias.
Yeah you remember all the abstractions that got in your way, either by not letting you know the underlying details or requiring a lot of upfront reading to grok.
But you are forgetting all the good ones that you understood intuitively and/or saved you lifetimes of work.

Collapse
 
henryong92 profile image
Dumb Down Demistifying Dev

What are you talking about?
We perform "magic" all the time when we meet managers with unrealistic timelines 🤷🤷‍♀️🤷‍♂️

Collapse
 
n1ckdm profile image
Nick

Is magic not just misdirection? Which is kind of what you're trying to do when creating an API that encapsulates a bunch of complex logic, but presents a simple interface to a user.

I don't see a problem with using the term.

Collapse
 
hackape profile image
hackape

Magic/abstraction is a spectrum. There’s good magic and there’s bad one.

My criteria is, if a magic feels nature, almost close to language primitives, and doesn’t come with easy footgun, it’s good magic.

So the two points for good magic are:

  1. Ergonomic API
  2. No/rare funny unexpected behavior.

Bad magic often goes wrong easily, and is always difficult to debug. The ones that stand in the middle, I have mix feeling and would approach with caution.

Like for example, MobX’s reactivity is very powerful. But when they allow implicit circular dependency, one can get into a dead loop. Upside is they’re aware of the problem and make it relatively easy to debug.

I would personally use MobX, avoid circular dep with caution (cus that’s usually a sign of bad code structure on your part). But I wouldn’t feel comfy to use it in production codebase maintained by a team of devs of varied levels.

Collapse
 
gnsp profile image
Ganesh Prasad

I go full Vernon Dursley in this context.

Collapse
 
fjones profile image
FJones

Couple of weeks ago, we had an old toplink-then-eclipselink-then-custom magic inferrence that caused all of our enum values to be offset by 1, so __I'll remain firmly in the "magic is bad" camp.

Collapse
 
kspeakman profile image
Kasey Speakman

Magic is great. Until it doesn't work for your new use case. Then the "abstraction" rapidly becomes technical debt.

Collapse
 
stephen_tran profile image
Stephen Tran

I remember when Microsoft first created Excel, their motto was something like "Kill all the dependencies".

Collapse
 
ifarmgolems profile image
Patrik Jajcay

Magic without documentation = good luck, have fun

Collapse
 
progrium profile image
Jeff Lindsay

Magic is ok if you aren't building on it. Magic is less ok if it's infrastructure. Magic is for sprinkling on top, as a treat.