The Rails Doctrine
rubyonrails.org
rubyonrails.org
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.
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.
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.
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?
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.
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.
I would definitely say, though, that I find Ruby development to be amazing. And I find debugging in Python to be similarly awesome.
[1] https://pypi.python.org/pypi/ipdb [2] https://pypi.python.org/pypi/pdbpp
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).
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.
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.
'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.
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.
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.
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. :-/
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.
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!"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...
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.
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.
_____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.
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. :/
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.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.
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).
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.
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.
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.
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#
It does one thing, web applications, and does it really, really well for the type of coder / team it was designed for.
People that belittle it by saying it has too much magic or whatever have never seriously tried to maintain a huge web application all by themselves. Web apps are ridiculously, mind-bogglingly complex, Rails conventions have been baking for well over a decade now.
If you're Twitter, maybe you have the resources to maintain a serious web presence without Rails. Everyone else is just handicapping themselves.
Although it may not have every new shiny bell and whistle, the ecosystem is mature enough to be stable and to have developed accepted best practices, which means you don't need to worry about whether the tool you use is still going to be supported in 6 months time.
But the churn on gems is very painful. To be successful with Rails long term, you must make time to constantly upgrade your framework, for for too often a gem maintainer will just stop supporting older versions of the framework.
And all of a sudden the version you need won't build, or isn't compatible with something else, etc.
So Rails is great. It saves you tons of time and gives you rock solid web apps that talk to databases. As long as you don't fall behind in your gem versions. :)
That's me speaking after maintaining several apps from Rails 1 all the way to 4.2. And probably 5.
I don't here about people being bug free with TDD ( though significantly less bugful)
Obviously all about tradeoffs, but my impression is that if a third party lib needs a major version update, the time changing the version in your requirements is dwarfed by the time needed to investigate generally
(Disclaimer, some friends of mine made it)
It's still better than JavaScript, where whatever popular build tool you use today will be replaced in 6 months :D
https://stackoverflow.com/questions/16426398/active-admin-in...
Rails Admin: https://github.com/sferik/rails_admin Active Admin: https://github.com/activeadmin/activeadmin Administrate: https://github.com/thoughtbot/administrate
I agree that it nailed the needs of web applications in 2004. If you are still building web applications like they did then, perhaps it is still the best tool. In the circles I find myself in, there is a push for much more Javascript heavy applications and Rails starts to become a large hinderance more than a help in that environment, when compared to other tools.
We've built a log of great software together over the years, but I can honestly say that I'm not going to rush into using it in future projects.
Most answers say the opposite:
https://www.quora.com/Has-C-and-ASP-NET-MVC-been-replaced-by...
But I think that's just where Rails is in its lifecycle. We all learned a lot from it, and we've started to build alternatives, but nothing has really coalesced yet.
Flash forward 5 years and there will be post-Rails frameworks that have worked their kinks out and are starting to enjoy the network effects that Rails has. At that point Rails will lose a lot of its advantage.
* Using a well-known framework is favourable over new shiny toys in a commercial system
* An ecosystem that has good 'defaults' is essential. A single web framework won't do everything for you. You need stuff around that for testing, deployments, etc.
For mainly the reasons above Rails is still my primary tool of choice. Yes, it has pinpoints but the reasons above far outweigh the new and shiny.
I found Rails during the 0.9 releases. Coming from the horrific world of Java web frameworks like Spring and Tapestry, it was a revelation to see how fun and productive web programming could be again.
When I saw things like 2.times, 1.day.ago, and ActiveRecord, I knew I was done with Java web development. This isn't a knock against Java per se, but I just spent so much time in the trenches having to do busywork and configuration that isn't necessary if authors of those frameworks put programmer productivity and enjoyment first.
Thank you DHH!
So apparently .day multiplies the number of seconds in a day by the receiver, then .ago subtracts that from the current date[0].
However, not all days contain the same number of seconds. This is where "friendly" APIs like this lose me - they're vague and sometimes incorrect.
In Foundation, which I consider to have a decently designed date API, "dates" are doubles of seconds all since a reference date, and "date components" are used to express the concept of days, months, and years - which also require a time zone and a calendar to even make sense.
[0] https://stackoverflow.com/questions/21392065/how-do-you-impl...
But the fact is, in most circumstances, good enough is good enough. And making programmer's lives easier is generally more valuable than corner-case optimization that makes things really hard to implement and understand.
Rails does correctly handle `1.day.ago`, taking into account the number of seconds in a day.
`1.day.ago` is a perfect example of what DHH was saying, in that it looks beautiful, but requires a bit of work under the hood. `1.day` creates a duration. This isn't just a number of seconds, but is represented by hash, more like `{:days=>1}`. When it's time to do the actual math, Rails looks at the :days number, and actually moves the day part of the date forwards and backwards.
Source here: https://github.com/rails/rails/blob/master/activesupport/lib...
After a few strings of drama in the NodeJS land, a few chat with friends who used NodeJS in production, and seeing the pattern of BigCo who use NodeJS only for glue/front-end/gateway appserver, I'm pretty close to settle with Rails.
I admire DHH for his dedication to the framework for so long (since 2004). You don't see that type of dedication in the NodeJS land. Yes, NodeJS is still new, but a few BDFL/leaders of important NodeJS projects had left the boat already. One of the premier NodeJS vendors, StrongLoop, always mired with controversy (I happened to know a few people who worked for a company that was acquired by StrongLoop).
Building long-term side-project requires a stable platform because of the time limit (outside office hour + other responsibilities). Dealing with unstable but "sexy" technology is not a good choice.
We have been working with Elixir (the language Phoenix is built on) for over a year. It is an incredibly satisfying language and its toolset is surprising advanced for its age. Phoenix has been a very easy mental jump for our developers who were already trained on Rails.
This is in addition to our separate online guides focused more on getting up and running through the basics. Where did we lose you?
I definitely see Phoenix/Elixir in a positive light and at some point will give it a fair shake for myself.
Your docs in general are pretty good and comprehensive, I just felt like a few obvious things had been overlooked.
Might just be me though...!
Maybe I was having a bad day...
I'm a complete n00b and was just trying to get a pool of TCP client workers to monitor servers and update a DB and display the results in a Phoenix app, and I kept coming across the same 4-6 blog posts and docs, maybe 60% of which were for pre-1.0 Elixir and no longer quite worked.
I see a huge amount of promise with Elixir/Phoenix as well; currently it makes some hard things easy but also many easy things hard. With a few years of library/community growth I could see it wiping the floor with Rails for a lot of projects.
Only on the surface. Please see: https://dockyard.com/blog/2015/11/18/phoenix-is-not-rails
For the new year, I'm thinking about the programming landscape and contemplating what I want to learn next. I've tinkered with Ruby on Rails in the past and think DHH is on to something with the doctrine he has laid out. I've only scratched the surface of Rails, but it still seems pretty neat to me. A deeper dive would be fun.
On the other end of the spectrum, Dart + Angular is appealing in part because I'm a fan of some of the Google developers working on Dart. While Rails feels like it is entering a comfortable middle age (or at least adulthood), Dart feels a little like a car being assembled as it cruises down the interstate. It's new and maybe a bit dangerous.
Both projects are super-appealing to me. Unfortunately time constraints prohibit me from chasing both and I'm interested in opinions especially of Rails people. Are you still excited about it?
But why does that have an impact on what tech you use?
The only web-stuff I've worked on in a commercial settings was a long time ago using Java and Tomcat. At the time, it was the cool new thing. I think that some of the pain points of languages and frameworks from that era are what prompted DHH to develop Rails (I'm specifically thinking about convention-over-configuration and admit I could be totally wrong here).
So today, I probably wouldn't pick Java and Tomcat for a personal project just because I know it won't be as fun and I won't be as productive as I would be with different technology. Has Rails been eclipsed in a similar way?
I’m running a team of developers where we are using Rails as our first-line tool, but we are also committed to using the best tool to solve the jobs at hand. So far, we have only needed to add Lua for a small piece of what we are doing because we can reason about what our logic is supposed to be doing quickly and easily in Rails.
Less than a third of my team were Ruby or Rails developers before joining us, and we are always pushing forward on learning more so that we have a great bucket of tools available as we try to solve our business problems and we hit those things where trying to reason about the problem is difficult in Rails, or where performance matters more than readability and code clarity.
Those tools are pretty close to what Rails give you (notice the View/UI is open for anything... Rails View is slightly nicer as it has better templating capabilities but ... not a deal breaker for me).
It's not sexy, it gets the job done, and I know it'll run for at least 5-7 years with minimum hassle.
Plus it's easy to be productive on Java project...
"It's not sexy, it gets the job done, and I know it'll run for at least 5-7 years with minimum hassle."
http://blog.jaredfriedman.com/2015/09/15/why-i-wouldnt-use-r...
I have a different general philosophy:
https://www.nemil.com/musings/shinyandnew.html
My own bias is to pick the best tool for the job, and not risk hype dictating your decisions. If you're learning for fun and personal learning, that' s great - just realize that you should optimize differently.
I've used Groovy/Grails for a number of web apps, both in commercial settings and side projects. Since I had previously been doing a lot of Java, being able to leverage the existing Java ecosystem and libraries with Rails-like productivity was a huge plus.
Grails may have a small community, but it makes Java web development really sexy. And I write 50% of my Grails code with Java. Groovy is ok, but I prefer the excellent IDE support I get with Java.
Which IDE do you use? I find IntelliJ to have great Groovy support. Also, you can optionally type check Groovy, which helps even more.
1. Server-side uses Linux, installation through command-line
2. Java standard library API owns by Oracle? fine by 99% of the companies out there. I'm just using those libraries.
And yes I think you should consider to use Rails. In my opinion it is one of the best back-end frameworks out there.
Rails certainly is mature, its APIs are not stable at all. With every version,even minor, there are annoying changes that often break 3rd party plugins. It shouldn't happen. That's why JEE has specs, as heavy as they get 3rd parties can always refer to them in order to write custom code. Rails is anything but stable. Hard to complete a single tutorial online without running into API issues.
Unless the argument is that Rails has either a) accumulated damaging cruft or b) missing out on important new features/paradigms, "comfortable middle age" seems like a huge selling point, right? Battle-tested, mature, a huge amount of shared knowledge, etc?
I'm not trying to make any argument about Rails, but am very interested in your opinion. Has it accumulated cruft? Is it missing something that newer frameworks have embraced?
It's probably the best choice for a straight-up CRUD webapp (as was always the case). I wouldn't want to do a project with nontrivial business logic in an untyped language these days (having seen how little flexibility you have to sacrifice for safety in a modern typed language), but your views may differ.
A sad example of those defending static typing are the Java programmers. I point out that Java supports duck typing via reflection, even if the syntax is painful. They say they don't use reflection, they use Spring. [Head in hands]
In any case, there are many happy programmers in my wake, they don't need your sympathy! :-)
Field field = instance.getClass().getDeclaredField("secretField");
field.setAccessible(true);
System.out.println("The old private value is " + field.get(instance) + " but lets change it!");
field.set(instance, "new value");It's much harder to make changes because even something like renaming a field requires major testing. You end up writing much more code that does nothing, because the test coverage you need for everything is much longer than the type annotations that would give you the same level of confidence, and whenever you change anything you have to update all your tests by hand. Hope you get the data model right first time! Look at one of those videos of people refactoring Haskell for what a type system can get you.
> A sad example of those defending static typing are the Java programmers. I point out that Java supports duck typing via reflection, even if the syntax is painful. They say they don't use reflection, they use Spring. [Head in hands]
If Java is what you think of when you think of static typing, I don't blame you for hating it. If Java-style typing and duck typing were the only options I'd use duck typing. But there are much better options out there. When I write Scala, most of the time my code looks exactly the same as what I'd write in Python.
I've found code written in a duck-typed style brittle and hard to refactor safely - it's very easy to try to restructure something, then find out down the line that something blows up because of some incorrect assumptions in another part of the codebase. You can try to grep for all the method usages, but that is a laborious, error prone process in codebases that are sufficiently large enough.
Few reasons for that:
1. I'm extremely productive and fast at developing in Rails
2. It's much easier for the client to get an app that's develop for a Framework that's been there for a while, is stable and will continue to be there
3. Ruby is a nice language and the principles behind Rails resonate with me (so it's not like Java and Spring which I was eager to get rid of when I switched to Rails a bit over 10 years ago)
That doesn't mean that I don't use node.js for certain specific use cases on client projects... But my goto framework is Rails
If you live in the land of Oracle or other proprietary databases, I wouldn't suggest rails. It has some rough edges in my experience. Otherwise, I think you should find a project and run with it, or join a place already in the rails ecosystem. I wouldn't learn it for its own sake.
I have also recently been doing, for the first time in a long while, work which is not SQL into HTML and then user actions back into SQL. Rails was never seriously considered for that part of the project. This was the correct call, and the new stack (GoLang and React) are fun things to have in my toolbelt, but there have been a few points this year where I've said "I just spent two hours on something which would have been 4 lines in Rails and I'm not sure I'm done yet."
You've really distilled it to it's essence and that has given me a lot of clarity.
The company I work for uses an issue tracker written with Ruby on Rails (Redmine). There's a few things I'd like to change and so I think I'm going to spend the first part of this year getting comfortable with Rails and making a few changes to Redmine that I'd like to see. Then, I might transition to Dart and see if I can put together an interesting browser-based client.
I personally do Rails backend + Angular frontend and it is a very rewarding stack. I get the power of Angular, but the simplicity of Rails in the backend. DHH is wholly against that, but it works really well.
A number of my open-ended questions about picking tools/libraries have been [CLOSED]. It really bugs me. I think there's such a valuable need there; you pick a dev tool and it may have maintenance and development consequences (repercussions is perhaps a less gentle way of stating it) for years or perhaps decades. It really impacts everything. We need to find a way to evaluate tools in a dev-friendly manner, keeping in mind that no dev ever has full time to really read and digest the docs they come into contact with, at least in my experience. (Peter Norvig has some apt statements about the realities of dev time management in his Coders at Work interview, IMO, which could spawn another discussion).
Quora could have been that place, for some reason and because of some odd UX choices ( mandatory signup to browser the site ) , it isn't , which is too bad.
Because the interesting thing about the 'ask a specific question' concept is that some questions are closed because they're too specific. I pretty much abandoned SO. The anal retentive pendants moderating things have turned me off to spending any time contributing.
While I doubt it would destroy the site, it's extremely hard to moderate and clean up giant debate answers. StackOverflow was never advertised as a "programming/coding catchall" site, it's a very specific platform tuned to very specific needs, much like an equation, giving a tuned answer for the question. Open-ended questions are beyond the original scope of the site, and StackOverflow has grown to become the largest coding question platform as a result of it.
The strict moderation and categorization is what makes stack exchange useful in general. Why not use a free-form forum like Reddit for that kind of question? Because you know the answers are going to bullshit opinions and holy wars, mostly by people that are trying to solve different problems than you, or are actually less knowledgeable than you.
Given the fact that Reddit and similar forums suck for finding solutions to specific problems, why should a Q/A site that is good for finding solutions for specific problems try to emulate it?
Quora and Yahoo answers also suck because the questions are almost entirely anecdote and opinion based, and it seems to be acceptable to cite "experience" as a source for bullshit opinions. "Being a pilot with 10 years of experience" is not an adequate reference for a response to a question about the safety of using a cellphone radio on a commercial flight, nor does "being a veteran" count as original research into Iraqi popular support for the 2003 invasion.
Of the good "answers" from Quora that I've seen shared, all are basically long form blog posts that have found a "close enough" question to answer, rather than been motivated by the question, and I would have actually preferred to read them on medium or some other blog site. However interesting they are, they aren't answers.
I think projects like Rosetta code are useful for comparisons of programming languages, because they keep it concrete. You can also look at big high-quality projects on github or whatever and directly judge the subjective qualities of a language for yourself, based on how readable the code looks to you.
At my corporate job, we use Java with Spring, and a hellish mess of node packages/libraries/whatever we're calling them now. It's not good.
So when I do side projects or consulting gigs, I always run to Rails which is what got me into development. It's very refreshing.
Reminds me of the jQuery post the other day. Rails is just a little older than jQuery. Rails with some jQuery sprinkled in is as close to development perfection as I've ever seen.
Also re: "too much magic" - Why is magic a bad thing? Creating layers of abstraction to ease building is what programming is really about, right? Why would we want to go backwards to configure everything under the claim of "I need to know how EVERYTHING works!"?
But even this seems possible without committing to an SPA architecture. If I recall correctly they are using Ember for this.
But yeah, you're right.
This is actually a SPA and a bunch of strung together jQuery. But things subjectively feel "faster" compared to what the site was like before they upgraded to this model.
Ruby's philosophy is quite a bit different from Python, Smalltalk, Perl, Java, and PHP. Ruby is roughly described as "batteries included." Some people don't prefer this, as it encourages meta-programming and introspection rather than explicit instructions.
A lot of libraries and tools around Ruby use meta-magic; some libraries have been attempting to strike a middle ground with meta magic, such as Datamapper (explicit) vs ActiveRecord (implicit). But the bias is definitely towards implicit; or as what DHH calls "omakase."
There are several solutions for this, but I personally take the easy way out: quit your job and be the first developer in a new startup, or do some freelance work. Whatever you need that floats your boat
I don't think this is something to be admired in a language. Java is a bad language to work in because it's not expressive, not because it protects programmers (which it doesn't).
Thankfully, we are seeing this shift the other way with the growing popularity of languages like Rust and Swift.
Compared to C/C++, yes it does. Java protects you from out-of-bounds array access, uninitialized access, buffer overflows, use-after-free, double-free, etc etc.
God I hope Rust will shoot C++ in the backyard and put it out of its misery.
There's advantages and disadvantages to flexibility. I personally think there's tradeoffs that need to be balanced. But even if we accept the assumption that more flexibility is always a good thing, the wording is still poor.
That wording vividly and convincingly explained the exact reason why too much flexibility is a bad thing, rather than the good side of it.
If the author happens to read my comment, I recommend a rewrite saying something about trusting developers or maximizing their power instead of giving them a tool to metaphorically kill themselves.
At the end of the day, verbosity in Java is mostly due to its ecosystem. Its quite different than that of smaller languages like Python, or Go. Where there is a community wide effort to share code and make things simple. Not so in Java.
That said, I would take Java's verbosity over Ruby's lack of static types. I write Ruby in my day job, and refactoring is a pain, and the same old type errors keep popping up day after day, causing 500s in production. It seems no amount of TDD can prevent them.
Your second point really hits home. I've been battling with Python and runtime types. Its just the nature of the beast. That's why I've been focusing more on languages with solid type systems. I will happily trade verbosity for types. :)
I've never been more unhappy programming than when I touch Rails. I'll take python or Java any day of the week.
>Convention over Configuration
Discoverability is totally gone. Walking into a brand new RoR app and it's next to impossible to figure out what's going on. Not having a good IDE doesn't help.
>Exalt beautiful code
Write simple easy to read code. Don't be clever.
Try PHP
IMO what makes programmers happy is not so much a programming language in particular but rather the context surrounding the job: role in the team, age of the codebase, fun colleagues, level of "corporatism", good or bad management if any, how much code you are able to ship per day, etc.
I strongly disagree with DHH's points 2,3,4, and 6. But I think I'm going to learn the language anyway and use it for some projects because I think it's important to not get in a rut. Using different languages changes the way you think about code, and if you are not constantly updating the way you think about code, you are falling behind.
Besides, I really like the way DHH writes. His language is persuasive even when I quite certainly disagree with him.
Still going to learn a functional language first probably. But then Ruby/Rails.
Excellent lecture series on functional programming (language used is Haskell):
https://channel9.msdn.com/Series/C9-Lectures-Erik-Meijer-Fun...
When you get to trying to understand monads, DON'T look up monad tutorials, look for functor -> applicative functor -> monad tutorials, like this one:
http://adit.io/posts/2013-04-17-functors,_applicatives,_and_...
Also interested in F# these days now that Microsoft seems to be open-sourcing . . . pretty much everything.
One of the rare books I read online (completely free from http://learnyouahaskell.com/), and liked so much that I bought a hard copy to carry/read.
Both links below show how friendly the Haskell community is for people willing to learn:
https://github.com/NICTA/course/blob/master/README.markdown
https://github.com/bitemyapp/learnhaskell/blob/master/README...
Good luck on your journey!
[0] http://www.transcribed-interview.com/dhh-rails-david-heineme...
"One example I always pull out is “what you gonna call the primary key in your tables?” When I was working with PHP and Java, every single shop, almost every single application, would have its own naming scheme. Some would say they have the ‘Products’ table and then they'd have ‘productid’, others would have ‘product_id’, some people would have ‘prod_id’ or ‘p_id’ or ‘P_id’, and every time somebody made a new design decision it meant configuration. You now have to tell your models, your objects, how they're going to talk to this database table. Because it needs to know what the hell you called the freaking primary key column, and it just doesn't matter! Who cares what the primary key column is called? It just doesn't matter. It's going to have zero impact on the usefulness of your application."
and
"‘Dont repeat yourself’ is all about not having the same intentions spread out in multiple places. Don't have one configuration. If you're calling something, let's again take the example of the primary key. If you're calling that for ‘id’ you shouldn't have to configure that in three different places that all have to work together and all have to be changed together. You should just pick one authoritative place to have that information stored. And then you can make changes from there. It also goes with the the whole Ruby idiom: we don't want those Java boilerplate ten line things: that's repeating yourself. If you have the same idiom, if you have the same intentions, that should really be exceedingly a short expression. And that goes up throughout the entire framework. Just keep one place to change those things, and keep the idioms very short."
These days ORM would map member variable id to database table id.
"The model part in an MVC application is where all the business logic is kept. Those are all the classes like ‘Post’ and ‘Category’ and ‘Author’ and all those things –say if you're making a weblog– you'd keep all that stuff in the Model. And you'd have all the logic about whether the author is allowed to make a post and how the relationship between posts and comments work together. Those are all sitting in the model, so that's all the business logic, very often backed by a database in some sense, not always, but most of the time. And that's where in Rails we're using something called ‘ActiveRecord’. Which is this way of mapping database tables to objects, and then decorating those objects with logic."
> When I was working with PHP and Java, every single shop, almost every single application, ...
Would it have made much difference if I had staid with ruby/rails instead of python/django? I dunno. Many of my friends have careers with rails, and they have nice careers. I have nice career as well, as do many other friends with django. In the end they are not that different, I guess.
I want to say thanks to DHH for his way to maintain the framework simple, despite to many PRs that try to make rails more complex.
Thanks to this document, I'd like to read also some document about the standard in big rails app.
DSLs are part of the reason for this.
Naturally there is a tradeoff. People that have been working with a particular DSL in Ruby for a long time can achieve amazing things in a short amount of time. Equivalent productivity is not really possible in Go (at least not yet, in my experience).
Having said that, I think it is easier to onboard new (and newbie) programmers onto a Go project than a mature Ruby project.
The most magic thing in .NET MVC is Entity Framework, and all it's magic is either a bunch of strongly typed convention classes (of which you can create your own), or LINQ queries, which work pretty well.
If I'm building stuff for Adults with Money I'll choose static typing any day.
This is easily described with a contrast to Python. [...] Ruby accepts both exit and quit to accommodate the programmer’s obvious desire to quit its interactive console. Python, on the other hand, pedantically instructs the programmer how to properly do what’s requested, even though it obviously know what is meant (since it’s displaying the error message).
When you're trying to convince me that your programming language is great because another one is so much shitter in comparison, you're on the defensive and basically telling me you don't trust your own stuff. Especially when this is at the top of your article.By the way, python handles your example very gracefully in comparison to other REPLs (for instance, node spits out a cryptic, but expected traceback on exit/quit)
If this was a passing mention on some blog post, I'd be inclined to believe you, but this post is not like any other. It's a descriptive update of the current rails "doctrine". When I ask you "why is your X so great" and you tell me immediately "look at how bad Y does", I'm inclined to think you're not feeling very secure about X.
> Anyway, what did this mean for Rails and how does this principle continue to guide its evolution? To answer that, I think it’s instructive to look at another principle that was often used to describe Ruby in the early days: The Principle of Least Surprise. Ruby should behave how you’d expect it to. This is easily described with a contrast to Python:
> code snippet
> Ruby accepts both exit and quit to accommodate the programmer’s obvious desire to quit its interactive console. Python, on the other hand, pedantically instructs the programmer how to properly do what’s requested, even though it obviously know what is meant (since it’s displaying the error message). That’s a pretty clear-cut, albeit small, example of PoLS.
Nowhere in the above is he calling Python bad. He's using an example of how Python handles a thing to illustrate how Ruby handles that exact situation differently inline with his philosophy "Principle of Least Surprise". I'm not trying to get into a semantic argument here, just pointing out that he's making an illustration with a minor detail.
Calling Python "bad" would make no sense, because Python is wonderful. This is just a way to highlight how Ruby does things differently than others have chosen to do them.
I just don't see why DHH needs to do this - ruby has so many things that make it stand on its own.
As others explained exit is an object and just typing it's name is just calling the __repr__ method. Exiting the program on a __repr__ would be setting an horrible example in the mind of a Python programmer: it's oki to execute program ending code into the representation of an object. So no, nothing pedantic about setting reasonable expectations about a language... In python if you want things to happen you have to use parenthesis.
After a decade of me in PHP, his love for Ruby is a lovely selling point for trying out that language.
How is the Rails market these days? It seems (personal perception of outsider) that it has been replaced by Python/JS work.
Just after waxing in section 1 on how Rails is designed to his own happiness (including adding quirky methods like 'fifth'), he says "One of the early productivity mottos of Rails went: “You’re not a beautiful and unique snowflake”"
It's very interesting to see such different philosophies.
> We have to dare occasionally break and change how things are to evolve and grow.
> ...harder to swallow in practice. Especially when it’s your application that breaks from a backwards-incompatible change in a major version of Rails. It’s at those times we need to remember this value, that we cherish progress over stability...
I encountered this doctrine first hand. A division of a company I worked at had its division's website rewritten in RoR by some outside consultants. Even brand new, it was a mess of Ruby gems of conflicting dependencies which was undeployable. The build system was a train wreck as well. Some of the main web pages of their web sites like rubygems.org were not available - the web site had "progressed" and when you clicked on a link, the page explaining anything had disappeared. I mean hell, go to rubyforge.org this minute (1:15 PM EST) - it is down, of course. The blog of the author of the Ruby gem that then was the main gem that handled web serving did not inspire confidence.
As I would have to maintain it (as a sysadmin, not programmer), I refused to deploy the system, since it was an unreproducable mess of conflicting gems and gem versions and kludges. They decided to pay the RoR consultants additional money, despite them having never delivered a working system. By the time I left, it still was never deployed. The division closed dozens of offices soon after, and then the division shut down - perhaps not completely related, but probably somewhat related to this project.
Meanwhile, the company's other divisions had decent programmers programming for Java application servers, and that code and those servers were much more solid. Builds rolled out easily (and could easily be rolled back if need be). It was really night and day. It makes sense this contempt for stability is explicitly part of their doctrine.
rubyforge.org has been offline for over a year and a half, as announced over 2 years ago.
You describe a Rails application written by outside consultants that was undeployable, and compare it to apps written by internal Java developers. I believe the quality of the developers had more to do with the deployability than the languages of choice. You could just as easily have a Java application written by consultants, with undocumented JARs, magical PATHs, mystical server.xml's to make things work just right, and crazy ant scripts.
To those not drinking the RoR kool aid, this is toward my point. Two years ago rubyforge.org was a central repository of Ruby gems. Now it is a web page that says "RubyForge Could Not Connect to Database:". Of course, in the minds of some, this does not reflect poorly on RoR but me - I am supposed to know that two years ago they decided to transform this central hub of Ruby gems to a web page that says "RubyForge Could Not Connect to Database:".
This kind of thing is par for the course with Ruby. I know that the http://perl.org/cpan page I used twenty years ago is still redirecting somewhere sane, but rubyforge.org ? "RubyForge Could Not Connect to Database:" - and the fool is me for not knowing why. This is typical of the kind of thing you deal with in RoR world.
Insofar as projects - a Java project can be junk just like an RoR project can, yes. The thing though is that relatively, the core Java infrastructure, community, API etc. has been much more stable over the past twenty years.
Hearing that rubyforge.org disappeared eighteen months ago to be replaced by this cryptic message makes me more down on RoR-world than if it was just their website being down for a few hours. It's the kind of thing you deal with in RoR-world all the time.
In general, we've been happy with it. We ended up writing our own serializer system (similar to ActiveModel::Serializers) to provide legacy clients with the option to use XML without losing our minds. Rails has a lot of view-level niceties that we're not using under this scheme, but the rest of the framework is still very useful for this task.
Some people prefer the Rails way of doing things. Others prefer something else. Nobody is wrong.
No real ecosystem can be built on rails since its apis keep on breaking.
That's why in my experience, most people give up on rails.
Stop breaking apis, introduce stability and maybe the framework will be successful again. People don't give up on rails because of ruby, or because it's bloated or slow, but because it became an unmaintainable, non upgradable mess as time passed.
https://github.com/keredson/ruby-db-evolve
been using it in production for ~1y now.
It would make more sense if your gem would generate migrations from schema.rb changes.
Also, that rant at the end of README kinda shows that you're hating the tool you're trying to use. Why not use another? You are not tied to ActiveRecord.
I'm not trying to say that migrations are flawless as a tool. I've faced at least one major problem with them. But still.
(1) If your data migrations are not "occasional" (and I mean very occasional) that's a sign you're doing a poor job at modeling your data. Splitting one column into two is almost always an example of someone really f-ing up the original schema.
Think of it this way: how do you switch branches? Do you look up the most recent ancestor, check it out, migrate down to it, then back up the new branch? It's so hard I don't know any rails devs who actually do it. But with a my tool it's a one-line command. PRs w/ schema changes actually get tested now, not just eyeballed.
Also, did you even read the "rant"? Do you seriously like the proposed version control tool modeled after rail's migrations? ;)
As of occasional (or not) data migrations, it depends on project and its history. If project is live, rapidly developed and has faced couple of pivots, migration history will reflect it.
If automated deployment is not your case I strongly recommend it. Since I first time managed autodeploy to work properly I've never looked back. It is SO convenient.
I may be wrong again about your processes and configuration :)
Executing in 3...2...1...
BEGIN TRANSACTION
-- column changes for table products
ALTER TABLE "products" ADD COLUMN "dont_email_on_purchase" boolean
-- column changes for table searches
ALTER TABLE "searches" ADD COLUMN "tag_only" boolean DEFAULT 'f'
COMMIT
--==[ COMPLETED ]==--
from the one line code change that triggered it: 1 db/schema.rb
@@ -543,6 +543,7 @@
create_table "searches", :force => true do |t|
t.text "query"
+ t.boolean "tag_only", :default => false
t.datetime "searched_at"
t.integer "user_id"
t.integer "page_id"
(well, there were two commits obviously)rather than call "./manage.py syncdb", call "./manage.py evolvedb" and changes to your models will be synced to your schema non-destructively. (ie: without dropping and re-building the table)
* https://github.com/airbnb/ruby
* https://github.com/thoughtbot/guides/tree/master/style/rails
Err, yes, it does. That's precisely what success means. If you are successful at something, that means you did something right. What that something is is certainly up for debate, but you can't ignore success as an argument.
Unless you define "success" as "being rich", no, I'm sorry, it's not true. It's actually quite easy to become rich by being a complete scumbag with no consideration for other people.
Err, no, it doesn't.
> If you are successful at something, that means you did something right.
No it doesn't. It often only means you had better opportunities and knew people that someone with a better solution didn't know.
Success is a social game; not a game of correctness.