Hacker News new | ask | show | jobs
by wh-uws 3801 days ago
Every bit of that "magic" is either meta programming or a dsl.

A large part of both rails and ruby is very well documented to the point where you can click on methods and see the code that makes them work.

When that fails you can debug with pry.

This stuff is not magic. Its not havening to reinvent the wheel poorly again and again.

The strongest sign someone hasnt spent much time building even a trivial app in ruby with rails is complaints of magic.

The magic straight forword once you see there is just code that generates methods (meta programming)

...

2 comments

It wasn't until after spending non-trivial amounts of time building a non-trivial app in rails that I realized I hated the magic.

It's not like I don't know that "magic" is metaprogramming and DSLs.

I hate the metaprogramming and DSLs.

  It wasn't until after spending non-trivial amounts of time 
  building a non-trivial app in rails that I realized I hated 
  the magic.
And it wasn't until after spending a non-trivial amount of time building many non-trivial apps in rails that I realized I sincerely appreciate the legwork that Rails saves me from doing. And having worked with rails for a non-trivial amount of time, nearly all of the 'magic' has been dispelled and replaced by an understanding of what Rails does and why. Giving me metaprogrammed finder methods or metaprogrammed getters and setters is wonderful. Maybe you don't like it, but I do, and this is a matter of opinions so the fact that it metaprograms is not a point of critique against the framework.

Telling us you hate metaprogramming does nothing beyond riling up more of a bickerwar.

Yet isn't the time saved by using Rails, the same thing that every other framework offers---without using large amounts of meta-programming?

I mean I like Django. I think its saves me a lot of time. I love the ecosystem, that lets me pick up someone else's apps and use it directly or use it as template to write my own.

Django makes different choices when it comes to what level of metaprogramming to afford, and how to display that to the user.

Now when I first started with MVC on the web (I'd known about it via Smalltalk, but it has a whole different feel there), I used Symfony PHP with its scaffolding and at then point active-record style generators. I liked it, and it helped me understand the core of MVC.

After that, I became opinionated and as my opinions didn't align with that of Symfony or Rails, I chose Python and Django. It was a breath of fresh air because when everything is explicitly defined, it becomes imminently simple to swap out and rewrite things for your given use case.

In fact, the only thing that's pretty difficult to change in Django is the request/response cycle since that's too deeply backed into all the middleware and top level binding to the server.

I've developed non-trivial applications with both Rails and Django and while I agree that Django is more explicit, its overuse of class inheritance made it difficult to figure out what was going on, and made reference tools like this necessary: https://ccbv.co.uk/

I know you don't have to use class-based views and can just use functions with mixins instead, and that's the approach I prefer when working with Django. But if everyone else uses CBVs I still need to understand them.

Rails controllers use inheritance too, but they mostly just inherit directly from ActionController::Base or from ApplicationController. It's not a deeply nested hierarchy.

Hmmm

When it come to their database model I didn't find their use of class-based inheritance to be too crazy. There's some meta-data hacking going on in there; but it wasn't too difficult to figure it out if you wanted to extend the Django ORM to interface with other databases.

In my case, I made an interface to read from ElasticSearch and return Django objects, and store back to ElasticSearch using regular Django objects as well. Since I wasn't creating/restoring everything to ES, my library had to create a partial model that'd look up the rest of the information in Postgres if you touched a field that hadn't been stored in ElasticSearch.

On the view side though, its not too complex when it comes to request objects, response objects, templates and middleware. Injecting new template engines is fairly straight forward, and the request/response objects are just data objects.

However, CBVs are horrible. I never used them. I begun using Django before them, and when they were introduced I tried using it for a month then dropped it entirely. I can see how they can be useful for a CRUD app, or some kind of application where there's a lot of code-reuse going on between the functions related to a particular object, but that's never been the case for me.

I just use functions with decorators for permission & object instantiation from the URL.

Django actually hides all of its ugly internals in their form classes.

Hardly anyone talks about that because for 90% of the use cases it just works, but the moment you want your form widgets to do something complex, you have to write the forms yourself---in their entirety.

I hear that Django 1.9/1.10 is going to give us templates for forms and refactor that code into something sensible. Hopefully it'll be good; but if its a debacle like CBV, I'll just continue doing form templating by hand and using Form only for validation and sanitization.

I agree with all of the above. Django's Model system is great, and function-based views work well too, but the class-based views and forms are misguided attempts to apply OOP principles where they aren't really needed. Inheritance is just not the right tool for the job, it creates more problems than it solves.
>Maybe you don't like it, but I do, and this is a matter of opinions so the fact that it metaprograms is not a point of critique against the framework.

Almost every 'critique' of a language is because people don't like the features used/not-used.

It's like saying that the syntax is not a valid critique of brainfuck because you like it.

From someone who loves RSpec along with its metaprogramming and DSLs, I agree that much of "magic" in Rails and its ecosystem is annoying. RSpec gets it right in that it implements an elegant, readable DSL for a specific use case: testing. Rails does a good job at enabling rapid application development but it does a poor job at maintainability and testability. It's a trade-off, but one that I'm less willing to make for complex, long-term applications.
it does a poor job at maintainability and testability

How do you figure?

Just look at the article:

> Progress over stability

> We have to dare occasionally break and change how things are to evolve and grow.

DHH has also revolted against TDD so it's no surprise that conventional Rails apps are hard to test.

DDH was against TDD, but not against testing.

http://david.heinemeierhansson.com/2014/tdd-is-dead-long-liv...

Please don't let Ruby's leaky dynamic action-at-a-distance shoddy excuse for metaprogramming and DSLs scare you away from real metaprogramming and DSLs.

Real metaprogramming doesn't involve action-at-a-distance and flaky dynamic interpretation. Real DSLs don't let you "peek behind the curtain" and therefore don't leak. True metaprogramming systems and DSLs don't let you flout "convention" and get into trouble as RoR does.

Introspection and a dynamic unstratified language do not make a metaprogramming system. High-level well-founded language manipulation constructs do.

Conventions and overloaded operators do not make a DSL. A well-defined grammar and interpreter do.

See OCaml's module system for an example of metaprogramming done right. It is simple to use and gives strong static guarantees. If it compiles, it will run without crashing; else the compiler will give clear error messages if it's unhappy.

See YACC, SQL, and XPath for examples of DSLs done right (albeit arguably abtrusely). They do not leak by design, since they do not let you "peek behind the curtain" which is the #1 way to get yourself (or others) in trouble with DSLs.

> Every bit of that "magic" is either meta programming or a dsl.

No it's not. The boot process hooks up a lot of things without your knowledge. It's an unbounded mass of side-effects that are caused by your code that you have zero path to understand or debug, other than pouring over docs and StackOverflow questions until you understand Rails architecture deeply enough to form a hypothesis about what part of your code might be implicated in the behavior of your app.

DSLs and meta-programming are not what people are talking about when they talk about "magic". They're talking about side effects.