Granted, it might look "beautiful" in the eyes of a experienced RoR developer, but personally i find it just makes code very hard to read. Just my 2 cents.
Granted, it might look "beautiful" in the eyes of a experienced RoR developer, but personally i find it just makes code very hard to read. Just my 2 cents.
Rails took me about a year of full time work before I could reliably fix bugs in a 1-day timeframe. Before that there were frequent unpredictable week-long goose chases through the Rails stack... usually just to learn I was Doing It Wrong and there was some convention you just really can't break without everything falling apart.
I had the same experience with Ember.js, another convention-over-configuration framework. A year of full time development before I could bang stuff out without being afraid I'd get totally lost and have a feature balloon up from two days to a month. And this is with a computer science degree and 10 years of web development experience.
Once you get past that first year, it's great. Or, if you're on a team of people, you just get help.
I taught RailsBridge a few times, and it's kind of crazy how many concepts you have to teach someone just to get to the point of a simple web form on Rails. It's probably at least 100 totally disconnected ideas, from routers to HTML to templating engines to MVC.
We're just not doing a good job paving a path from PHP's functional, minimalist, "copy/paste this snippet of code into your template" architecture to things like Rails/Ember which provide ergonomic toolkits for modern apps.
I just don't know what could really bridge that gap. So many terrible php and <insert language you like to make fun of> codebases come from exactly
> "copy/paste this snippet of code into your template"
programming.
Which is how most beginners learn (myself included. cobbling together myspace and wordpress templates) and it takes a while before you've done enough of it to see how deep the holes you dig with it can be but in the mean time your stuff "works" but is a nightmare to maintain and understand long term.
I had a lot of hope for the node community (because at least then newbies only have to learn the quirks of one scripting language) solving this with express/ sails or something else but they've stalled.
I guess its just a hard problem. No idea how to solve it
That right there is the problem: too many people are after quick wins and instant gratification and aren't willing to make an effort to learn something the proper way and appreciate its complexity, even if they are not exposed to it directly.
I learned Rails via the Rails Tutorial[1], and finished it in three weeks of evening and weekend sessions. When I started, I knew a little JavaScript, but not much else. By the end of the tutorial, I had a fully functioning app (parts of it I had customized, even!) and was ready to start building my own stuff. It was very empowering and I was blown away by how incredibly smooth and easy the Rails framework was.
That said, if I had taken the approach that lazy PHP beginners take and tried to learn by copy/pasting stuff (or relied on Rails scaffolds from the get-go), I would have stumbled over and over and probably given up.
[1]https://www.railstutorial.org/book
edit: not sure why people are downvoting -- did I say something controversial?
While I kinda agree with you to a certain degree, I think instant gratification is crucially important, at least in the first "play" phase. A lot of people don't want to know something before they even attempt to play with it. That's what playing is there for, it gives you a small insight of what to expect.
You don't really have a play phase with Rails... or Ruby for that matter, a lot of my front-end or PHP developer friends can't even install Ruby on Windows because it requires you to know certain things about the OS, the language and some very basic things from how linking, compiling and C works (most developers don't).
To even get started with Rails you either need to be a experienced Ruby developer, or dedicate time to learning Rails before you even begin to use it (and even then, I am not sure you could grasp some concepts without knowing Ruby's rich syntax).
Not to mention, you need to know how to use bundler, setup a database, a web server, etc. Compared to most PHP frameworks, where it's just download X, visit /, "voila," edit file something.php, visit `/something` and "voila," again.
Also, as someone who works for a hosting company, most of our PHP developer clients don't RTFM, they prefer blog posts, or YouTube tutorials (this isn't even a joke) because they don't have time for getting started guides. :|
Its basic, but that should be the point. You can fluidly graduate from Bottle to Flask + extensions or to Django depending on which you prefer. Or just start in Flask - the base API is pretty much the same, its just it has a ton of extensions to implement all the server functionality you could want.
Every tool can't be everything to everybody.
At the beginning of my career, there's no way I could do Rails, but nowadays, I'm just not interested in anything but.
All those vague concepts kept me away from learning rails because it always felt it was hacked together.
There are also a lot of PHP frameworks that have this pro status because they are hard to learn. But using comments as programming features doesn't sound pro to me.
Some time ago I jumpt fresh into C# and .NET MVC. Now that is what I call a pro framework. It was very easy to learn but so powerfull.
Ofcourse I'm biased now because I fell a little in love with C#
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)
...
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.
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 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.
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.
How great would this be?
name = BooleanField(template='switch_not_radio_boxes.html')
Your template file spits out HTML for flip switches instead of radio boxes (e.g. Https://proto.io/freebies/onoff/), and the template can add javascript/css to be bundled into a singular location with the rest of the Form fields static assets.
It'd be simple.
But nope, instead BooleanFields use a widget that creates HTML & sprinkles error messages upon it through some byzantine means.
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.
How do you figure?
> 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.
http://david.heinemeierhansson.com/2014/tdd-is-dead-long-liv...
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.
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.
Couldn't agree more on this. Magic is good if you understand the underlying stuff but if you don't and you are once offtrack you are lost. Maybe it's also a matter of taste. However the hype and traction DHH could build when RoR started was quite impressive.
The issue is when do each of us, as individuals and/or teams, really need to understand more. And perhaps more importantly, when does it make business sense to leverage magic to get to market faster, build cheaper, or find market fit before worrying about building the most robust thing possible.
Ruby's freewheeling philosophy however means that even when you are the author of the code some other code might have reached in and changed something out from under you. Not only do you not know there is another layer somewhere doing stuff that impacts you you can't even reliably follow a path to find that layer and debug it. As long as everyone does everything perfectly this is a wonderful world to live in. But the first time someone breaks the rules and impacts you and you lose a week or more unnecessarily you'll understand the distaste that ruby fosters in some people.
It's more about being able to discover what you need to know that it is possessing full knowledge of everything you need to know.
I'm not entirely sure how a filesystem works under the hood (let alone the physical media it's on), despite interacting heavily with one every day. A bug involving a hard disk would be incredibly opaque to debug, from my perspective. I suspect that you find it easy, because you've spent the time developing an understanding of the system.
> Not only do you not know there is another layer somewhere doing stuff that impacts you you can't even reliably follow a path to find that layer and debug it.
And this is where our roles are reversed! I would have little trouble following that path, all the way down into C if needed- because I've spent plenty of time understanding the system.
The problems you describe are problems anyone would have with an unfamiliar system, and it's not Ruby's fault.
Way to reduce what he's saying into the classic, "He can't be depressed! There's starving kids in Africa dying!". You've taken his /observations/, misplaced the usefulness of those observations, and then reduced them into some absurd argument that he's not actually making.
Accessibility to the unfamiliar access goes wonders and reduces the "magic" feel. If ruby doesn't have that sort of accessibility, then it IS Ruby's fault. If that's what Ruby actually wants, that's fine - but holy crap, it's this sort of mentality that completely fucks over usability.
I actually like Ruby, but hate RoR, because of a very lacking sense of control, unless you are very deep into it. You have absolutely zero feeling for what it OK and what's not OK to do with so much implicit magic behind the scenes. And that's debilitating.
My interaction with RoR can be boiled down to this exaggerated dialog:
- Here, write your code in this pattern and it will work.
- And if I change it like this?
- No it won't work.
- But why?
- It's an opinionated framework. It's the opinion of some Very Smart People(tm).
- But this is my work. Why can't I do it the way I want?
- Because you are dumb. And your dog is dumb. You haven't grokked it. You aren't a hacker. Neither is your dog. Where are your hoodie and Nike Airs?
I think the key difference is that you don't need to know how that works. I think there's a question of how leaky the abstraction is and how often you need to look behind the curtain.
There's probably a SE paper somewhere stating this formally, but I figure well done implementations on top of abstractions only need to reference one layer down. It might be okay to inspect the state the layer below for performance reasons, but no further.
That means that a well done Rails app might want to inquire about the state of HTTP, but shouldn't inquire about IP addresses. And it might want to know about indexes on its databases, but not disk caching policies or i/o schedulers.
So the case of "too much magic" is not to become used to the discomfort of not understanding how underlying abstractions work, nor is it to stop using them. Instead you want to choose dependencies with well documented abstractions, implemented such that you can inspect if you need to.
This has nothing to do with Rails specifically. I see plenty of coworkers who dislike Django's large set of features, as too much bloat, or too much magic they don't understand. Instead of reading documentation, and becoming expert in Django's abstractions, they spin up Flask apps, slowly reinventing the wheels, but maybe not quite as round.
You can even search for "rails typo in migration" and the first result is a stack overflow post suggesting and explaining how to roll back the migration so you can edit it
That's a little extreme, surely this must be hyperbole.
That said, I don't have a problem with frameworks that are larger. Hell, I'm a .Net dev by day myself and that certainly doesn't meet that requirement. I just don't find it elegant.
Deleted comment
How about electrons? Can you draw me a graph of the electrons currently residing in your computer case/laptop? Can you explain to me exactly how your PHP code will look in binary?
Sorry to be snippy, but you're making a pretty audacious claim there. I don't think any reasonable software engineer/developer can claim to fully understand every underlying principle.
I mean, you can have an abstract, high-level idea of how things work, but do you really think you know the intimate details of every single piece of hardware/software involved in writing your code?
it's the difference between being able to wire up a logic gate from transistors with a basic understanding of how they work and to be able to wire up a cpu, ram and some io from logic gates, being able to wire up a computer from cpu chips, ram chips and IO chips.
Even if you don't know the exact details of the latter in principle you understand that whole device that you just built.
So the claim is not so crazy as it might sound initially.
I think this is a false claim because.
1. Rails is easier to learn than most of the things mentioned above, so not magic
2. It's perfectly reasonable, and good, to build on top of and leverage things that you haven't taken the time to learn intimately.
No, that wasn't the claim.
> 1. Rails is easier to learn than most of the things mentioned above, so not magic
Ignoring the strawman component: that's a matter of opinion, for some those electronic bits and pieces are actually simpler to understand than software.
> 2. It's perfectly reasonable, and good, to build on top of and leverage things that you haven't taken the time to learn intimately.
Yes, absolutely. Just like we don't require everybody that uses the highways to be car mechanics or road construction workers. Society would grind to a very rapid halt if we had to have an intimate understanding of everything we use everyday.
I did a dual-major in CS and EE, and then an MSc in CS. While I'm a little fuzzy on the specific details of the current transistor geometries (14nm?! that's wild!), I do pretty much understand the entire stack upwards from there. I could design a fully-functional computer from the logic gate level, although it likely would be slow as hell and be exceptionally boring. It's not my strong point, but I understand enough about what's going on.
Honestly, most of my electronic design work these days is analog circuits slung onto the side of a microcontroller, with code written in C. I'll do schematic design and capture, and board layout without too much difficulty.
Going up from there, I've written my own (toy) operating system from scratch. I've written Linux kernel drivers for both off-the-shelf devices and for custom devices implemented in FPGAs. High-bandwidth/low-latency TCP servers written in C. My own (toy) programming language. I've written C extensions for PHP and Python, and have done pretty intense profiling work on them; this requires a pretty deep understanding of how the internals of the interpreter work (part of my MSc coursework). And I've done web apps in PHP, Python, Ruby, and Elixir.
The whole point of this is that I'm totally comfortable going as deep into the stack of abstractions as necessary to solve whatever problem I'm facing. When I started learning Rails, I was mystified by all of the "magic". I'd never even really used Ruby, let alone all the extra stuff Rails does. But I set up the emacs-bundler library (https://github.com/tobiassvn/bundler.el) and started diving in. I'd work through a tutorial, and every time I encountered something I didn't understand, I'd dive into the guts of Rails (bundle-open activerecord) and read the code until I understood it.
As an example of going a layer deeper, I once encountered a bug in a Python script that used PySerial. There were multiple threads, and the script would hang sometimes. I read through my code and couldn't find any problems, so I dug deeper into the PySerial code. Nothing obvious in the .py file for PySerial, so I dug deeper into the C extension. In the C code, I discovered that there was one case where the GIL wasn't being properly released before doing a (sometimes) blocking call! Tada! The script worked great if the call didn't block, but hung if it did.
I think we should all aspire to this level of having enough of a mental model for all the layers underneath us that we can go dig into them when needed. But it takes a lot of effort to get to the point you're at, so it's a pretty big ask. (Also, most of us probably can't go back to a university to learn the EE side, and it's not easy to self-learn it.)
Having said all that, for Rails specifically, it's pretty easy to do exactly what you did and just open up Rails and other library code. It's almost entirely simple method definitions, and the parts that aren't can be understood if you go read about how `define_method`, `method_missing`, and `const_get` work. The "Rails is magic" meme seems to either scare people off from reading the code, or give people permission to be lazy about it.
Install pry, pry-rails. Something weird occurs? binding.pry, `show-method` or `show-source` and it dumps you to the exact line and filepath of the method, be it the original or a monkeypatched method (use -a to show them). Keep digging like that and you'll eventually hit the C implementation code.
[18] pry(String):1> show-method length
From: string.c (C Method):
Owner: String
Visibility: public
Number of lines: 5
VALUE
rb_str_length(VALUE str)
{
return LONG2NUM(str_strlen(str, NULL));
}Sure, I can concede that code that tries to do too much for you to the point where you didn't actually want it is annoying. It's just that, in the context of what Ruby CAN look like, Rails isn't that arcane.
For example, entirely for fun (it was a lot like a game - I couldn't stop seeing how far I could push it), I gradually built up a small library (less than 100 lines of code) that eventually yet radically transformed Ruby into what looked like a badly designed yet different (functional) language. Functions could be conveniently composed, partially applied, juxtaposed, etc by monkey-patching the symbol class with overloaded operators. I also had fun getting all this working for instance method calls so they could be treated the same way (few caveats with that though).
Not to say that this is a production-worthy effort, it's simply not. It's just the experience that has ultimately taught me the extent of Ruby's (perhaps dangerous) power and that Rails doesn't actually call upon that much of it in the grand scheme of things.
Truly knowing Ruby for Ruby and what it's features can really do, you only need to look at the so-called magic that Rails demos to understand intuitively how it does what it does.
Another subtle thing with it is that, while I'm writing code in whatever scripting language I do think about what's going to be happening under the hood non-stop. For example, every time I write a line of activerecord, I'm thinking of what kind of SQL is likely to be emitted, and whether or not it'd even be possible for the database to have an index for the query. Sometimes a table scan is the best you can do without denormalizing and its awesome to notice that right away instead of down the road when it's slow.
But this all is both a blessing and a curse. Often it ends up meaning that I spend more time thinking about a problem than I need to.
Another fun example from some recent work: a client calls me up and has a machine that they can't access. More probing reveals that the machine is buried under a frozen highway! (I'd love to go into way more detail but... NDA) Anyway, we do still have an RS485 link to it, with getty running. The goal was to determine whether it was a software problem (fixable without needing a backhoe in 4 months when the earth thaws), a hardware problem, or a cabling problem. How do you know for sure? Jump into the bootloader and configure the ethernet phy to tell you what it sees by directly writing registers over MDIO! Turns out the PHY is alive and well, but can't seem to see the 100MBit sync pulses. Plus it is still successfully doing PoE negotiation. The cable is still connected but either the switch, the cable or the magnetics are bad. Field guy is going to try a new switch before we abandon all hope, but at least we know that no amount of software fixes will solve the problem
Complexity/perceived burdenwise, I think java is to rails as rails is to sinatra (or a similiarly small framework).
There may be a point where you want your functionality bundled and presented as a framework (if you, like me, think of frameworks as bundled and groomed libraries/functionality), but if you're not sure you're at that point (or don't know what that point is), try to start smaller (like sinatra) and go bigger, rather than the other way around (starting with the biggest tool you could find, trying to find the smallest).
I strive not to become a good developer on X platform (for Y language) but rather just a good developer who's proficient with Y language (and happens to be able to use X lib).
At this point I think I'd only choose rails where I knew from the start that it was going to be a big, complex, semi-monolithic service. I can definitely see value in rails for doing that kind of thing.. But for everything else Sinatra is a pretty good default position.
Then I started using and looking into Sinatra, and it's way more basic and Ruby instead of Magic.
If I had a dollar for every minute I wasted rewriting things that I could have for nearly-free with (for example) Rails and CanCan and a quick call to load_and_authorize_resource in my ApplicationController, or a lame hacked substitute Rake task for ActiveMigration... that'd be a distressingly accurate description of way too much of my career.
Of course if you really are just building just the one microservice and don't have any complexity to manage, then yes, Sinatra all the way, 100%.
Also, OO inheritance has some well-documented flaws as a code-reuse mechanism. I couldn't point exactly to what favoring composition over inheritance would look like in ruby (I've seen some approaches, but have an unhealthy dislike for the word "Factory" so they didn't seem great), but maybe there's a better way to share that code you're trying to share? Also, I don't think the solution is mixins because once you have too many of them how they interact becomes very hairy -- but regardless, I think a ruby solution exists to that problem as well. There is also the "has a" vs "is a" distinction but I digress.
Of course, there is a point where you shouldn't rebuild the wheel, but I don't think "shared functionality", or "access to persistent objects across requests" is that point.
To expand on what I mean, if these are the things you want to do:
- Respond to requests like an API server
- Serve static files
- Serve templated files
- Shared information across request
- Share application-relevant objects across requests (ex. marshallers, keystores)
- MORE STUFF
- ...
I think the point where rails makes sense is at/after "MORE STUFF", and possibly in "..." range.
The company's architectural model dictated that the new version should take the form of a (non-micro) RESTful service layer handling the data in its own database (also facilitating the application of the problem to new lines of business for different varieties of marketplace item under different brands, improving visibility to the review process to sellers, and leaving open an avenue to outsource or automate certain parts of the problem.) We would migrate the legacy code over to use this layer instead, then we would write new frontend code with better workflows, then we'd coordinate with other teams to review new classes of marketplace item with different review criteria, then some year we'd have room for the pie-in-the-sky machine-learning-assisted review (assuming that something more important didn't come up instead.)
The result of this was a modestly complex set of abstract business-data objects, including marketplace items, all the metadata associated with them (editable by reviewers in this system), owners of items, reviewers, reviews, internally visible comments associated with the reviews, feedback associated with the reviews, review escalation, reviewer-supervisors, and a variety of other things which I forget right now.
I say RESTful: while not as pure as it could be, it actually did a half-decent job of being hypermedia-y and not merely "throw some JSON around over HTTP". Things had URLs instead of just IDs. Lists of objects were paginated with consistent ways to get links to the next/previous page.
Sinatra left us with uncomfortable choices between having excessive code duplication and the quality/maintainability issues it would bring, or writing our own logic to ferry Sinatra's various handles to the request / response / templating engine. We chose the latter, and I don't regret it - I regret that we sunk as much time as we did into that piece of code instead of building it on top of something with richer abstractions. It was the wrong choice for this particular application.
Rails is the only environment in which I've routinely found myself utterly stumped. Not because it's hard, because it isn't. But the thick layer of "magic" makes it awfully hard to debug sometimes.
It's also dangerous because Rails fits a specific niche, like he mentions--building (potentially) many web systems quickly. We chose to migrate large legacy systems to rails, which meant lots of the nice convention just. doesn't. work. Day 1, you're already digging in to figure out how to get around the magic!
That's why I'm excited about Sean Griffin's work on the [Attributes API](http://edgeapi.rubyonrails.org/classes/ActiveRecord/Attribut...). To do it, he's had to refactor out a lot of internal monkey patching so that (in Rails 5) there is only one source of type information for an AR model. This means gems can extend AR, I can extend AR, new requirements can walk into my door that I can deliver on without monkey patching or opening Pandora's box of a patch of crappy Rails internals. The magic is still there, but it's done it a way so the magic doesn't fall apart in unexpected, unmanageable ways. That's what matters to me.
We all adopt certain amount of implicit choices in our lives because if we had to be explicit about everything, we'd be bogged down in choice-making and not really get anything done.
Why care about choosing the right ORM, Logger, templating engine when there's real business problems to solve? If there's a true business advantage to choosing an alternative, then substitute, but eventually you have to get on with the show and make something meaningful.
Strong defaults and conventions are a feature and Rails nails it better than any other framework out there.
https://www.djangoproject.com/weblog/2006/may/01/magicremova...
By now, it's hard to tell what you had in mind – something like contrib.admin or the global settings file?
class Model(models.Model):
field = models.SomeField()
rather than.. class Model(models.Model):
def __init__(self, *args, **kwargs):
field = models.SomeField()
super(*args, **kwargs)
Django is most certainly the framework that bundles a whole lot of choices together (similar to Rails), but the magic it performs on behalf of the user is extremely minimal.I would definitely say, though, that I find Ruby development to be amazing. And I find debugging in Python to be similarly awesome.
http://werkzeug.pocoo.org/docs/dev/debug/
eg...
For Pyramid: http://docs.pylonsproject.org/projects/pyramid-debugtoolbar/...
For Flask: http://flask-debugtoolbar.readthedocs.org/en/latest/
For Django: https://github.com/django-debug-toolbar/django-debug-toolbar
I have no idea how well they compare to equivalent Rails tools though.
Here's a brief overview of PyCharm debugging functionality:
http://pedrokroger.net/python-debugger/
I really like the ease of use for remote debugging. It's essential in helping to maintain a Linux development environment that closely resembles production while actually coding on a work laptop that runs Windows. Beyond that, I often use the remote functionality to run one-off scripts to retrieve and process data from a production Django system (though, generally this is restricted to 'read' operations unless it's been tested in dev).
[1] https://pypi.python.org/pypi/ipdb [2] https://pypi.python.org/pypi/pdbpp
'exit' is an object. Expressions typed at the REPL are stringified. Thus, when you type 'exit', it gets stringified, and thus you get that message.
'exit' is also a callable, so if you type 'exit()', the REPL will exit.
The same goes for 'help', 'copyright', 'credits', and 'license': they're just objects that get stringified.
Having the REPL work the way you want would mean building magic into it, and magic avoidance is part of the language's culture, so that's not going to happen. Having it print that message is a compromise between keeping things friendly and building magic into the REPL, if you consider printing the result of expressions automatically to be magic.
The Python REPL isn't being a dick, it's being parsimonious and predictable in its behaviour.
This is what Ruby developers mean when they say they optimize for developer happiness over bowing to the will of the computer.
/uses Python regularly and enjoys it.
It's best to design an API that makes what's happening clear without being overly verbose or esoteric, and without making assumptions, especially not dangerous assumptions that may cause you to lose data (exit may close the REPL and cause you to lose your session when you forget that exit is a special word in REPL mode). My personal feelings are that Python has done a better job at this than any other major language. I have major projects in both Ruby and Python and I enjoy the Python ones 100x more because of this.
This document partially explains why; DHH is normalizing shortcuts because it helps him gain new users, even though working around those same shortcuts becomes a major PITA when you need to go a little bit off the beaten path, which happens in one way or another in most real software. There is a way to make these things explicit with only marginally more typing/"effort" (for example, requiring parens to call functions with no arguments, making it explicit and obvious when someone is referencing a variable vs. when they're calling a function), thus avoiding the complexity down the road.
I find statements like this a bit condescending. It's like when Java developers say 'Oh, that's nice, but I work on big applications." "Obviously you don't get it because you're not experienced. Experienced developers get it."
I'm sure that wasn't your intent. But it still irks me a bit.
I've been writing software for a very long time, in many languages and paradigms over the years. I believe that qualifies me as an experienced developer. My years of experience tell me that if I only experience pain 5% of the time, then the 95% of the time I don't experience the tools I use making me do extra work more than makes up for it. :)
Correct. I meant it inclusively, like most of the Python community is either experienced developers who've worked in a lot of languages and have sought refuge in the sanity of Python or the apprentices of such developers. Python doesn't have a figure like DHH to give it sex appeal, so not many new people use it.
There are definitely experienced developers who have not yet had occasion to seriously enjoy and appreciate Python.
>My years of experience tell me that if I only experience pain 5% of the time, then the 95% of the time I don't experience the tools I use making me do extra work more than makes up for it. :)
I meant this as a count of the number of issues, not the amount of time it takes to resolve them. That 5% of problems caused by non-obvious implicit magical behavior usually take an inordinate amount of time to debug and solve, and then the workarounds are usually disgustingly ugly because the framework had never conceived that someone might have a valid reason to circumvent their magic. Even worse, this locked-down, "looking inside will void your warranty" attitude (which Rails often calls "convention over configuration") frequently means that the workaround must be somewhat pervasive and ugly up your code not just in one place, but in several places to really resolve the problem.
Experienced developers may not encounter this often if they don't use a lot of magical APIs that promote the systemic ambiguity of "do what I mean".
In 2005, when nobody used Rails, as a complete beginner to Ruby, I was able to write a patch to improve the Oracle database adapter. Somehow, despite all the magic, it took me very little time to find what to change and submit a patch. As a complete newbie to the language and platform.
Rails 2 and below revolved around a lot of hacks. Rails 3 removed many of those. Rails 4 even more so. Check out the book "Crafting Rails 4 Applications" to see how easy it is to hook into places in the framework to get what you need. (Disclosure: I'm the editor of that book.)
The argument you make about "voiding the warranty" is an argument I hear from people who have touched Rails for a project and hated it for one reason or another. It's not a sensible argument.
Remember, for centuries, people used "magic" to explain away something they didn't understand. :)
One part of the system not being obfuscated doesn't mean that many other important parts aren't.
>Rails 2 and below revolved around a lot of hacks. Rails 3 removed many of those. Rails 4 even more so. Check out the book "Crafting Rails 4 Applications" to see how easy it is to hook into places in the framework to get what you need. (Disclosure: I'm the editor of that book.)
I currently maintain both Rail 2.3 and Rails 4 applications. I totally agree that Rails 4 is a much smoother experience. There are still hacks around the magic that I've had to implement. The one most immediately on the top of my head is one of the form generators ignoring the method argument in some circumstances because it knows better and forcing me to jury rig them into obeying the command anyway (with a bit of JavaScript that alters the method on-page IIRC).
>The argument you make about "voiding the warranty" is an argument I hear from people who have touched Rails for a project and hated it for one reason or another. It's not a sensible argument.
Of course it's a sensible argument. Frameworks shouldn't be causing those feelings in people -- the magic isn't magical if it's getting in the way. If people are coming away with the impression that the system will blow up or otherwise misbehave when they try to peel back the covers, it's ignorance to just blame them for feeling wrong. One should try to at least understand the problem; then, you can decide if it's a problem that needs correction or if you're just OK with people who want some flexibility and cooperation from the framework not using your stuff and be honest about that so that they don't have to waste their time.
>Remember, for centuries, people used "magic" to explain away something they didn't understand. :)
And, also for centuries, people used "magic" to hoodwink gullible people.
Not really – all the code knows is to stringify objects, and it saw the object called `exit`, for which the stringified version is that error message. But nowhere in that flow does the code know how call anything that could exit the REPL.
/doesn't use Python regularly and thinks the smart move would be to make the REPL understand certain things as commands instead of normal Python code.
It's not really magic at that point. It's not really 'magic' at that point to me.
Granted some people might say its surprising for stringifying an object to call sys.exit() or throw an error that'll cause exiting.... But within the context of the REPL its not surprising.
With Ruby, this isn't a big deal because if `exit` is a function, then typing `exit` will call it, and you need to use the unary `&` to bypass this and have the callable treated the same way that Python does (which is roughly equivalent to a Ruby Proc).
Ruby doesn't require the hack, but Python would, for better or worse.
First/early impressions do matter, however.
But also, how is bundling that explanation into the stringified version of the "exit" object not as magicky as Ruby putting an "exit" method on Kernel which is in the root namespace of the REPL and exits the current process (with an optional exit code)?
That said, technically correct is best correct, so here is your upvote!
That is a critical difference that needs to be kept in mind.
Edit: grammar fixes. I didn't reread by comment before posting. :-/
Python 2.7.10 (default, Sep 8 2015, 17:20:17)
[GCC 5.1.1 20150618 (Red Hat 5.1.1-4)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> exit = "I'd like to assign a value to this non-reserved word!"
>>> exit
"I'd like to assign a value to this non-reserved word!"Couple of points though:
1. It also says you can use Ctrl-Z (though you still have to hit Enter after that, which is a bit of a pain).
2. You can just use Ctrl-D. Works on both Windows and Linux, no need for Enter. Smooth and quick.
1) Did they fix the thing where you had to use __self__ practically everywhere? Double underscored variable names also look like crap, especially when they're everywhere. It looks like a really shitty design flaw, having to use __self__ this and __self__ that everywhere. (This situation may have been ameliorated since I last looked at the language.)
2) Not everyone likes significant whitespace. But moreover...
3) If you code for long enough, you'll eventually realize that Ruby, Python, C++, etc. etc. are all fundamentally flawed due to OO making it too easy to write spaghetti-dependency code with mutable state everywhere, which means EVERY OO CODEBASE NO MATTER WHAT eventually becomes an unmanageable bugridden long-test-runtime complexity tarpit.
They should stop calling it "technical debt" and start calling it "object-oriented debt" ;)
So you eventually convert to the Functional Programming™ religion. ;) And that is the real reason not to use Python (or Ruby or Java or C), IMHO. But don't take my word for it, here's John Carmack basically saying that everyone should use functional paradigms (even in OO languages) if at all humanly possible: http://gamasutra.com/view/news/169296/Indepth_Functional_pro...
2) That is a reasonable choice. I like expressing myself once, instead of repeating myself in both whitespace and brackets or whatever, but I get the argument for autoformatting after copy/paste. Of course, lua does this the best, by having neither significant whitespace nor semicolons, and just figuring out where statements end from the grammar.
3) Objects are wholly optional, and can mostly be avoided. the functools and itertools libraries go a long way to bring the functional religion to python.
Both come with tradeoffs, but Rust's borrow checker seems, anecdotally, to be easier for people to understand than the category-theory word salad that litters most strictly-immutable FP language discussions.
A simple example of a single threaded mutability bug is passing an object by reference to a method which then (either intentionally or unintentionally) mutates the object, to the complete ignorance of the caller up in the call stack. The only thing stopping that is literally, programmer skill. No language constructs. At least in all the OO langs I ever worked with.
I really, really want to like Python, but I just can't seem to stay with it long enough to work through all of the "weird" stuff. :/
_____this is so offputting______
But otherwise language seems cool
So called "magic" methods, which are called by Python in various circumstances, are surrounded by double underscores. One of such methods is __init__, which works as an initializer for newly created objects.
The other thing is that all methods, unless otherwise specified, take a pointer to the current object as a first argument. So when defining an initializer that takes no arguments from the user you write:
def __init__(self): # etc.
I think only __init__ and __name__ are widely used in Python, all the other such methods are very special purpose and very rarely used outside of deep library code.BTW: Being "ugly" or not is not the best characteristic you can base your opinion of a language on.
Possible non-code-altering solutions to the problems include: 1) limiting educational material on Rails to only use a subset of the built-in methods so that newcomers aren't overwhelmed by feeling they need to learn the entire std library before being able to make progress, 2) Using more explicit versions of code vs the more terse but harder to understand versions enabled by syncretic sugar to ensure that people coming from other languages first understand what is going on, then are blown away when they discover you can write it in an even cooler way, 3) a deeper explanation of what is going on under the hood to make the magic seem "OK".
And I guess the word 'critique' connotes a somewhat more detailed, analytical assessment - at least to me.