|
> The languages that truly let you do anything you want flexibly invariably lead to incomprehensible ivory towers. It is why managers hate Lisp, it's why Perl is joked as write-once read-never. I've yet to see that happen in a Lisp project. On the other hand, inflexible languages like Java lead to abominations like the Spring framework, where tons metaprogramming happens at runtime via reflection. The thing about compile-time macros (e.g. Lisp macros) is that they can be debugged at compile time. For example, if you see a macro invocation, and you don't know what it does, you can just expand that macro right in your editor, and look at what code was generated. People are always worried about DSLs, but most projects end up with their own DSLs. They're just often built out of functions, methods, objects, etc. I think the real issue with understanding a project is learning the concepts, architecture, and abstractions they use. Knowing e.g. Go really well doesn't save you from having to wade through the giant pile of code used to express the program's intent. Abstraction is a way to get that complexity filtered down as close to the problem's inherent complexity as possible. Yes, you'll have to learn the abstractions, but if done reasonably well, that will still be much easier than trying to understand the non-abstracted version. |
I wish there was a kind of super-upvoting that added one to the font-size of the comment you're upvoting, because I would absolutely super-upvote this comment.
> Abstraction is a way to get that complexity filtered down as close to the problem's inherent complexity as possible. Yes, you'll have to learn the abstractions, but if done reasonably well, that will still be much easier than trying to understand the non-abstracted version.
Absolutely. It's possible (arguably, too easy) to build a bad DSL, but the point of a DSL is to surface the inherent complexity of your domain so you can grapple with it on its own terms. Not using a DSL doesn't mean that complexity goes away; it just means you have to grapple with that complexity using coarser tools. You usually end up with a DSL-lite of types and functions that work in your domain, often with warts due to poor interactions with the host language's feature set.
For a lot of reasons, I'm a big fan of eDSLs, which aren't too much different from the DSLs-lite we usually end up with. But overcoming that impedance mismatch with the host is not easy. (That's one of the benefits of Lisp, I think -- very low impedance mismatch to overcome!)
I've gotten somewhat good at doing eDSLs in Java(!), where you want to keep things mostly idiomatic, unconstrained Java while still adding the novel behaviors you need for your domain solutions. But you're always going to have to wrangle the complexity of your domain, whether or not you involve a DSL in that effort.