> Now, this line of code is not simple, it’s easy to write it, but the code is extremely complicated under the hood because:
Every time I hear someone complain about Rails, I ask myself if this person is really just complaining about how complex web dev is. I've never seen a complaint that passed this smell test.
Yes, Rails abstracts over a veritable shit-ton of complicated domains. The problem is, that complexity isn't going to go away if you decide not to use those abstractions. Every single one of that laundry-list of things that ActiveRecord::Base.create does will have to be implemented again, by you, badly, if you choose to roll your own.
It boggles my mind why developers don't take the web seriously as a domain, like it's not real coding or something. It's the worst instance of bike-shedding I've ever seen.
Rails isn't perfect, by any means. But Rails is not a black box, it's all free software. You are more than free to re-implement anything Rails does yourself and release it as a gem. Modularity and flexibility are built right in. It seems incredibly odd to leave Rails over this. For what, Java? Unbelievable.
I'm assuming you are not familiar with solnic's work. Because he is not just idling complaining. His rom project, and the ecosystem of supporting gems which have grown from it over years of work, are the exact opposite of "implemented again, by you, badly." It's more like "implemented for the first time, correctly, by someone who actually understands what good design is."
That's valid, and you're right, I wasn't familiar with his work.
But that doesn't diminish any of my points. So he did reimplement ActiveRecord. I'm not surprised he found it difficult to actually integrate into Rails. Rails is a framework. You don't treat a framework like a library. It's not going to play nice with your design because frameworks by their very nature impose the design on you.
With a framework, "works for me" is a perfectly valid reason to keep using it and to dismiss criticisms with. That's the whole point, to get you up and running with as little fuss as possible.
I personally hate CSS frameworks, I'd rather retain more control over the markup and selector semantics. That's a choice I make, and I'm aware of the tradeoffs. I would not make the same choice with web dev, because choosing the other side of that tradeoff involves way too much work.
But I'm a working coder, I'm not trying to make my mark on the world. I just want to get shit done and move on. Solnic obviously wants to make something bigger than just a website. He's looking for a bluer ocean to tame. Which is cool, we need all kinds of coders.
What this is really about is that Rails isn't for him. I can accept that. But his rationale is all wrong, it expects Rails to be something it isn't and never could be. Rails is absolutely the best at what it does for the kinds of coders it's intended to do it for. It tracks the state of the art of web development and boils down most of the complexity with user-friendly abstractions.
It's not terribly flexible, but Rails doesn't want to be flexible. It wants to be productive. He wants to go help build the next Rails. Godspeed. I hope he succeeds so that I can go use his framework when it's finally ready in 10 years or so.
I'm sorry but I just don't get this, in your previous comment, you mentioned:
You are more than free to re-implement anything Rails does yourself and release it as a gem. Modularity and flexibility are built right in.
And right here, you also mentioned:
I'm not surprised he found it difficult to actually integrate into Rails. Rails is a framework. You don't treat a framework like a library. It's not going to play nice with your design because frameworks by their very nature impose the design on you.
Flexibility is available in Rails. But is not a top priority. I would say that Rails gets most of its flexibility from Ruby. You have Rails Metal, which is intended to provide a modular way to extend Rails. If you know Ruby well, you can take advantage. Solnic had the capability to do so, and did, but eventually chose to leave the ecosystem. I'm fine with that. I don't expect the techs i use and love to be all things to all people. I just wish he hasn't chosen to shit on the tech that sustained him for so long.
I don't think the honest explanation of the reason he chose to leave the Results ecosystem is shitting on it; and I think that description is itself a sign of the kind of the kind of tribalism in technical communities that obstructs fruitful discussions of technical subjects.
>But that doesn't diminish any of my points. So he did reimplement ActiveRecord. I'm not surprised he found it difficult to actually integrate into Rails. Rails is a framework. You don't treat a framework like a library.
Who said that? Who carved that in stone? There are absolutely frameworks built to be perfectly OK to have all of their constituent parts used like libraries.
This is just repeating "this is how it always used to be" as an argument.
>It's not terribly flexible, but Rails doesn't want to be flexible.
> There are absolutely frameworks built to be perfectly OK to have all of their constituent parts used like libraries.
You certainly can use each individual part of Rails without having to bring in the rest of Rails. I bring in ActiveSupport all the time on non-Rails projects. For ORM I prefer Sequel, curious why solnik didn't mention Sequel, the creator of DataMapper even said that Sequel was everything he wanted DataMapper to be and I can't help but think that played a big role in the decision to not continue developing it.
You can use Sequel in Rails, I personally prefer ActiveRecord as I'm not aware of a Form Helper gem that works with Sequel, though to be honest I never really looked. Way more people use AR than Sequel, so Stack Overflow debugging goes much smoother.
I'm not saying he's wrong for leaving the Ruby / Rails ecosystem. I'm saying his stated reasons are inconsistent with his course of action. I'm fine with his real reasons, I just wish he wouldn't frame it as a slight to Rails.
> It would be unfair not to mention that Sequel showed up already around the same time and till this day it’s being used way less than ActiveRecord despite being a superior solution.
I lost interest in DM mostly because of my open-commit-access policy. I mismanaged the project horribly.
Just because something was called "Session" (ala Hibernate) instead of "Unit of Work", people would claim it wasn't "pure".
The only real compromises for purity were for performance. You saw the same thing play out with ActiveRelation. Ruby is (or was at least) just too slow for complex patterns unless you wanted to pay a huge performance penalty. The kind of slow that materializing 10,000 models in an O/R Mapper would bring your app to it's knees and use hundreds if not gigabytes of RAM.
And since a large reason for writing DM in the first place was AR's miserable performance at the time, it needed to be fast.
Most of the community wasn't that interested in closing open issues. Not that I blame them. It's not fun. But I was burnt out.
During the end, ActiveRelation started development, making many of the same mistakes early DM did in the quest for purity. By that point I just wasn't feeling it anymore. I'd spent orders of magnitude more effort on writing an O/R Mapper than I'd ever hope to recover, and I felt like some of the ideas were fundamentally flawed. So I moved on.
If I were still doing Ruby, I'd be using Sequel though.
Frameworks do not necessarily impose the complete design of the application. Spring Framework in Java, for example, is great, but the only essential part of it is DI container: you may not use persistence, presentation or security layer provided by it, if it does not fully fit your architecture. Good modularity defines quality of the framework and Rails is apparently not best on that criteria.
You mean the first version of Symfony (Symfony 1, which was monolithic like Rails), and not the current Symfony (Symfony 2/3) which has nothing to do with the old one other than the name.
The convenience methods were just wrappers. Earlier versions were even more true to the PoEAA version of a DataMapper with a Unit of Work in the Session class.
Turned out this was a bad idea if your primary motivation is performance.
The fact that it didn't bother to abstract away DataObjects was by design. Nobody would claim NHibernate (of the time, 2.x) wasn't a Data Mapper implementation just because it didn't have an adapter for treating an XML file as a database. That's a parlor trick.
The real effort is in making it work and making it fast. Porting Java designs to Ruby just didn't scale in the Ruby implementations of the time and conscious decisions were made to ensure DM would actually solve the problems it was developed to address (#1 being performance as I had a large set of data to migrate that initial experiments with AR projected to take a month(!)).
The primary concern turned out to be Ruby method dispatch performance. The shorter you could make the stack, the better. Since loading 1,000 objects might be operating on a 10,000 row set, and another order of magnitude more fields, the materialization pipeline had to be streamlined as much as possible. (AR implemented a nasty abomination of a hack for this by round-tripping to the database multiple times). When it's faster to round-trip to the database multiple times than it is to iterate a large object in memory, you've got a real problem.
The lazy loading, explicit fields, dirty tracking in the Unit of Work, (which at the time were all fairly controversial ideas in rails-core) etc were all an effort to address performance. The PoEAA was an inspiration for sure, but it turned out to be a prescription for poor performance on Ruby 1.8.x.
I can nitpick too! :) I never said he reimplemented active record, I said he reimplemented ActiveRecord. Though I suppose the better verb to use would have been 're-engineered'. Reimplementing seems to imply an algorithm or design pattern, where I meant to re-do the functionality.
I think this is more about Active Record the design pattern, than ActiveRecord the Rails component. Active Record is a really easy to use pattern and ActiveRecord is a very humane implementation. Data Mapper (the pattern) is more complex. Trying to get a Data Mapper implementation to do all of the things the ActiveRecord implementation in Rails does is really hard- it's always going to be harder when you need the object model structure to significantly deviate from the database structure.
As a counter point, are you sure web dev is the complex thing, or does it just seem complex because you're dealing with these massive gnarly frameworks that hide thousands of lines of code behind seemingly simple facades that perform incomprehensible magic?
I think the mention in the article of the User.Create(params[:name]) one liner is really instructive. Creating a user is one of the most important things you're going to do in an application! The business logic rules are incredibly important, the security implications are huge, everything. Trying to make it "easy" is ridiculous, because as a developer, you should be thinking about these things. That's the kind of thing that should contain absolutely zero magic, the logic should be upfront and visible.
I've worked as a web dev, and I've also worked outside of web development, and the number one thing that drove me insane doing web development was never knowing if any one line of code was doing some severe amount of impossible-to-debug magic. I'd rather just write javascript against the browser APIs with a lightweight http server.
As far as I can tell, the vast majority of frameworks aren't really about providing functionality, they're thought experiments in how to write software. That's fine, but they should bill it as such. I'm not going to say web development is easy, there are parts that are legitimately difficult on their own accord, but I think the web development community has made things massively harder on themselves by pretending all these abstractions are actually simplifying the task they've set out to do.
What's missing for me from this whole discussion is the allowance that both methods can be correct.
Use case: you're a solo developer and you need to build a proof of concept web application based on a fairly complex set of requirements. You probably want to use a framework like Rails and focus your time 100% on the specific project requirements, and use the framework to generate the common parts of the web app for you.
Another use case: you're on a large, multi-year project for a huge client where each developer has his/her own specialty area. Here it may well make sense to go with a Java Enterprise app and wire your own persistence layer or write your own SQL queries.
The mantra of Rails has always been "don't repeat yourself." Don't waste time rebuilding the same 90% skeleton every time you need a CRUD app with a postgres database.
Want absolute granular control over all parts of your application? Then almost by definition, you really don't need a framework. So great, don't use one and roll your own web app from the ground up. But there are many times it makes complete sense.
>because as a developer, you should be thinking about these
>things. That's the kind of thing that should contain
>absolutely zero magic, the logic should be upfront and visible
No, you shouldn't be thinking about these things. Because you'll get them wrong. Are you really going to account for all security cases?
Are you really going to account for all data coercion coming to/from the db? And even if you do, why go through the pain of those cases when there's a community of thousands of other developers, some of which have probably solved it infinitely better?
Eventually, we have to get shit done. The only code that is worth something is code that serves others. Eventually we have to pick some abstractions so that we can get on with the show.
> No, you shouldn't be thinking about these things. Because you'll get them wrong.
This attitude is really pervasive in web development, and I think it's kind of bizarre. If you're building something as a developer, you need to understand what it's doing, because at some point something will break and you will have to debug it.
When you get to the point you have to debug it, are you going to want to figure out some sort of insane meta-object protocol where you can't figure out where or why a method is dispatched, at what point inputs get santized, etc., or do you want to walk down a simple function chain?
Keep in mind I'm not advocating rolling everything yourself, I'm saying if you use a library it shouldn't be treated as a black box. I'm advocating avoiding abstractions that obscure your ability to understand what's happening (what I call magic). Use a library for user authentication, for sure, but if you can't explain how it works well enough that you could replace it, you shouldn't use it.
So do you roll your own OS? Payment processing system? Web server on your own hardware?
Just because you aren't hand-coding it doesn't make it "magic" or "lazy," it makes it efficient. I'm perfectly happy to use Bootstrap for my web application's styling because they've handled most of the exact same styling problems I will have to, and quite well. I am quite confident I could replicate a lot of that functionality every time I needed to build a web app, but why would I do that when it's already been done and I can focus on other problems?
As an aside I'm curious why you think that "magic" is good for beginners. When you don't have a clue what is going on at all, you really should spend some time learning what happens when you create a user via ActiveRecord, which can easily be done if you study the log files for a bit and read the Rails documentation. Once you are comfortable with what's going on, then you can use the framework to auto-generate code for you.
It's about reading the code, and having a good mental model of what is happening. This is the point Rich Hickey tried to drive home with his talk "Simple Made Easy".
If you are a developer and haven't watched this yet, you really, really should. Very important distinction to keep in mind any time you are writing software.
Haven't read the Active Record source code, but would be interesting to find out where it falls on the "Simple vs. Easy" continuum.
> As an aside I'm curious why you think that "magic" is good for beginners.
I was referring to absolute beginners with little prior background. To them, technical documentation is a bunch of gobbly gook. For these people it's usually better to be somewhat opinionated and just tell them "there are other ways, but this is the tried and tested way and it works". A nice side effect is that they don't suffer analysis paralysis and panic attacks.
They don't know what they don't know, so it's sometimes useful to just tell them "this is the syntax to do X" (aka "magic") and gloss over the finer details. I've found that the time to unveil the magic is when they poke around under the hood, read up, and start asking questions about how things work.
The complaints weren't about the complexity of web dev, but the degree of tight coupling and bad application architecture that the author sees baked fundamentally into Rails and the approach it is designed to favor.
And as for leaving for what, the author identified both the other Ruby-based stacks and the noon-Ruby languages and frameworks that he sees as valuable. And, no, Java is not on the list.
Your rant looks like a reflexive defense of Rails from someone who hasn't read the source article more than superficially; the article doesn't dismiss the web as a serious domain, it just sees Rails as locked into a dated approach to the domain.
Look, if solnik thinks he can do Rails better than Rails, I really hope he succeeds, because I can't wait to meet the perfectly-flexible, perfectly-succinct web development framework that has the kind of support and tooling ecosystem that I enjoy with Rails.
I get it, tight coupling and forced architecture aren't ideal. I accept those limitations so I can get Rails' productivity superpowers. I don't just accept them, I embrace them, I've learned the wonderful joy of having everything you coded 6 months ago just slide right back into your mind because it didn't try to buck the convention. I spent extra time understanding that convention and why it exists when I wrote that code, I think most Rails devs don't do that, and so overcomplicate their applications.
I've been on the other side of that tradeoff, so I can see where you're coming from. There's a lot of appeal in making and using your own abstractions that fit the domain better. But the web is a complicated domain in its own right. The right approach is to use one DSL for the web, and make your own for your domain. DHH was right, Rails is your application. To do otherwise is to over-complicate your architecture.
My guess is that you haven't actually had to deal with any large rails applications, or that the one you are dealing with is the first one you've dealt with.
The abstractions Rails uses are fine for a relatively small app (up to 10 models). Beyond that is where the complexity mushrooms and the framework starts dragging down the project.
Solnik's points about create() are very subtle. Think about coercion, validation, and all the potentially invalid or confusing states an app can end up in.
The approach Rails takes with ActiveRecord is fine for a small project, and often benefits consultants who leverage the boilerplate to show superb progress after one month of development, but it fails in the real world.
To be fair to Rails, most approaches to input validation and the creation of multiple levels of nested objects are implemented poorly. Solnik's point is just that Rails serves up a lot of these flawed approaches into one toolkit, and so the resulting ecosystem is plagued by the sum of all the flaws, and the core team is not really seeing the big picture about how to improve the overall state of the ecosystem (why would they, they are getting paid a lot from the Rails status quo).
DataMapper was superior to ActiveRecord. When Merb got merged into Rails, I was certian DM would be the ORM of choice for new projects, but when it wasn't I personally stopped using Rails on new projects. Sinatra + DataMapper is such a superior approach to full-boat Rails too, fwiw. How many thousands of developer hours are spent upgrading to the latest Rails every couple of years for no benefit. How many useful gems are nearly obsoleted, etc.
Rails has had the worst kind of cargo cult success. Most of the gems are weekend projects that lead to a blog post and a bunch of speaking engagements for the writer, and then get left to wither after the community has naively embraced them. This is not the case for all, but it happens way too often.
There are also many, many subtle bugs that are introduced by ActiveSupport. I've personally wasted at least two weeks of time dealing with them over the past 5 years.
Ruby is a great language, but I'm glad someone as talented as Solnik is branching out.
> My guess is that you haven't actually had to deal with any large rails applications,
> The abstractions Rails uses are fine for a relatively small app (up to 10 models). Beyond that is where the complexity mushrooms and the framework starts dragging down the project.
I've worked on several rails applications with a lot more models than that. Some with over 100 models. ActiveRecord has flaws, but I never felt it was a great impediment to getting things done.
A bigger issue (as you mentioned) is the large number of gems that are abandoned or sporadically maintained. I don't see that as a rails specific issue, but it seems to rear its head most often with gems that interact with rails.
Very experienced developers can create a usable codebase in Rails with over 100 models, but it is highly unlikely to happen if someone in Rails' target audience uses it.
I'd suggest Play Framework and abandoning the idea of O/R Mapping entirely.
Once you grok pattern matching you'll never want to see another Ruby case statement again. Once you compose a pipeline of functions you'll find Ruby Procs a pale shadow of true functions. There's really no such thing as functional Ruby.
You'll end up with more maintainable code, a lower LoC count, easier testing, more mature libraries, and that's just the tip of the iceberg.
Un uncached Play Framework app will probably outperform a highly tuned Rails app out of the box, even with hundreds of person-hours spent in tuning the Ruby app.
Which leaves you more time to work on actual features.
And then you have Akka. Which is a whole other paradigm to master (but with it's own rewards).
And then you have deployment. Which is a huge breath of fresh air.
Sure, you'll miss some few things in Rails. Like Inflection. Add a dependency for one of the ported versions (like: https://github.com/backchatio/scala-inflector. It's just a single file).
The learning curve isn't the smoothest (though API docs for Java/Scala libs in general and the Play Framework guide is far more complete than anything I ever experienced in Ruby-land). But the rewards.
> I'd suggest Play Framework and abandoning the idea of O/R Mapping entirely.
Then I'd have to learn Scala. I do not want to have to learn an entirely new stack. It took years for me to learn Ruby's eccentricities. Sure it would take me less time to learn Scala, but I already know Ruby. You seem like quite the masochist, spending years in one ecosystem trying to build something, then burning it all to the ground and starting all over. Just looks like so. much. effort.
> you'll never want to see another Ruby case statement again
I never write case statements in Ruby. What I do when I find myself needing a case statement is to go looking for the missing class. I'm missing a domain element and OO programming to me is all about clarifying a domain.
> Once you compose a pipeline of functions you'll find Ruby Procs a pale shadow of true functions.
I pipeline all the time in Ruby. A lot of times I'll wrap a data pipeline in a class so I can encapsulate the logic and manage it better. When you wrap a pipeline in a class, you can do things like add immutability to the instance variables. Sure, it's not true functional, but I don't want true functional.
> You'll end up with more maintainable code, a lower LoC count, easier testing, more mature libraries, and that's just the tip of the iceberg.
Let's take these in turn.
> more maintainable code
I love maintaining my code. I fail to see how learning a new stack could actually improve on this for me.
> lower LoC count
Mostly aids in maintainability. Again not at the top of the list of things to improve.
> easier testing
I've changed my approach to testing over the years. Again, this is not anywhere close to the top of the priority list.
> More mature libraries
Again, this is something I've fixed by changing my approach to the problem. Whenever I introduce a gem, I put an interfacing class between the rest of the app and the gem. That way it's easy to swap out if it becomes a problem.
> And then you have deployment.
Deployment sucks in Ruby, not gonna lie. But again, problems are indicators of overcomplication and I've tuned my workflow to drive more simplicity over time. I know Capistrano very well, seeing it evolve over time has given me a keen eye for how to keep it manageable.
On the whole, I like the idea of functional programming and am not opposed to coding in a functional style once in awhile. HtDP changed the way I thought about programming, though I eventually switched back over to OOP. I strongly disagree that there's any kind of magic to functional. Everything in programming involves tradeoffs, and OOP better fits my mind than functional does. I look at pure functional as math-heavy and harder to grok. I want stateful objects, because humans think in terms of objects and not data pipelines.
> The learning curve isn't the smoothest
That one issue outweighs all the purported benefits of all the others. I would much rather spend my time thinking about domains than learning new tricks.
There's nothing I love more than a long thread of point-by-point rebuttals, but I think I'll leave this one alone for once. ;-)
If you like what you're doing, more power to you. I picked up Ruby because I thought it showed promise as a good scripting language and web development tool (this was pre-Rails) at a time c# didn't really excel at either.
> You seem like quite the masochist
Maybe. DM was created to solve a problem. I didn't burn anything down. I just walked away. The best time to do the right thing is yesterday. The next best time is now.
After 8+ years, I realized I'd spent much of it trying to work around limitations in Ruby. It was just time to open myself up to the idea that there is more to programming than what I knew.
> It seems incredibly odd to leave Rails over this. For what, Java? Unbelievable.
Back when Java was introduced, it was partly taken up because the features it introduced made developers more productive - hardware agnostic code, network programming out of the box...
Nowadays a lot of developers have moved on from Java. Maybe the same thing will happen to Rails...
I'm not a rails dev, but I believe that you are misconstruing his argument. It is not about inevitable complexity, but about the ownership of that complexity. If you are able to control the side effects part of development, you can control how it scales and debug it much more easily.
I have a third interpretation: I think Solnic was complaining about a lack of diversity in the Ruby ecosystem. The most salient part of the post was (imo) the paragraph regarding how Merb was subsumed into Rails, instead of continuing to compete against Rails. Rails is essentially a monopoly.
> It seems incredibly odd to leave Rails over this. For what, Java? Unbelievable.
If projects such as Merb were more common, maybe Solnic could leave Rails without abandoning Ruby.
> It is not about inevitable complexity, but about the ownership of that complexity.
I've been there, done that--was part of a team that owned a java application that grew over a decade (and eventually ran the team). A year or so after I left, they retired the application.
Why? Because we owned all the complexity and couldn't support it.
Maybe that was my failing. Maybe the team's failing. But I don't think that having control of how the whole codebase fits together means you necessarily have more control over complexity.
Those who trade for buried complexity are doomed to start digging whenever they discover an edge case.
Maybe they never need to do that, in which case that's a bargain. But I tend to think that any old enough codebase continually accrues edge cases that must be solved.
I've never seen a ten year old Rails application, but from the Rails applications I have seen, I'm horrified by the thought of how it would look after that long.
I've been in a company that let their Rails applications grow for 7 years. Believe me, the oldest code was not pretty to read and almost impossible to refactor. When we finally had a real frontend team, the only way out was to reimplement the apps with a new architecture.
At one point I realized, I should not stick into one language and one framework. Ruby is good to know, but I'm better if I can also tackle Scala, Java, Rust, OCaml, Haskell, Python and so on. Also happier, I'd say... I can now choose the best tool for the job.
Having worked on systems like that, the problem is that you end up in a situation where there are literally two people in the world who can answer questions about how something works and integrating other third party libraries or solutions becomes harder and harder.
Java isn't that bad, I'd say. ;) I've been in web development for almost 20 years, and used quite a lot of stuff, including PHP, Perl, C++, Java, Ruby and even such a weirdo like Informix WebConnect. Java is still my favorite, and the reason is the true modularity. You can combine Java EE and Spring stacks (lots of XML already forgotten in distant past), you can choose any presentation layer implementation and the architectural flexibility is the real selling point for projects bigger than a homework. I can beleive if the author would switch to it and I'm surprised that you don't.
yeah i do Scala now but same deal. Where I think the OP comment really goes wrong is when he says something like "you're gonna need all that stuff and you're gonna end up re-implementing it yourself". I really don't find that to be the case... when you're developing with libs you are cognizant of your app endpoints and just add whats needed. It's better to consciously add a lib or turn a feature on than to just accept a big ball of yarn that some cowboy framework devs shat out. In the Rails app at my job it takes a ton of debugging just to figure out how many layers of decorators are firing off around every model.
I might even go so far as to say that a lot of where JVM has strength is that contexts are pretty measurable... Spring containers, Akka systems. You instantiate them and hold them basically in the palm of your hand, you understand your scopes. Any technology that allows application scope to slip out of your fingers and intermingle with everything else under the sun is something I'd be wary of.
My own anecdote: at a previous job, new development was done in Rails, while "legacy" Python applications were maintained by one (!) guy. The Python apps were about the exact opposite of the Ruby apps -- cherrypy was used for the HTTP interface; very low level (compared to Rails, at least). He used to shake his head at the stack traces that Rails would spit out. "Intermingle with everything else under the sun" sounds about right.
>
Every time I hear someone complain about Rails, I ask myself if this person is really just complaining about how complex web dev is. I've never seen a complaint that passed this smell test.
Yes, Rails abstracts over a veritable shit-ton of complicated domains.
I call this "magic" and I dislike it very much. I'm a very explicit person. I like the ability to jump into any project, regardless of language, and be able to figure out how it works. This is typically possible with Python, Node and PHP with most web frameworks. Ruby with Rails? Not at all and for precisely this reason.
I'm fine with abstracting things but only to a degree. If you're doing a laundry list of complex things with a single statement, and I'm referring to web server specific stuff not ASM instructions, then your framework is going to require more ramp-up time than any other explicit one.
Interesting point. I find I can be pretty okay jumping onto a rails project, as I know a lot of the conventions. Where to look to see how things are connected. Admittedly, it's taken me sometime to learn how a multi architecture go project using thrift is setup :)
ActiveRecord is terrible for any kind of complex database work. If your data models are simple or you decide to shoehorn your entire data model into an "object" representation then ActiveRecord will allow you to work, but if you need to run queries like "return every product that represents less than 2% of total revenue for the last year excluding products purchased by our top 10 most profitable clients" ActiveRecord is going to give you a very inefficient solution where you'll also end up writing Ruby code to accomplish what the database is already capable of.
ActiveRecord is not the right tool for a job like this. It's meant to return records needed for serving normal web traffic, not for running data analytics. This is a better job for a tool which can run queries like this outside of a latency-sensitive environment (hadoop, presto, whatever).
> you'll also end up writing Ruby code to accomplish what the database is already capable of.
This is for the best. Usually, you have only a few database servers, while you have lots and lots of web servers. If you have a computationally intensive task, it's better to perform it on those web servers, which you can scale horizontally.
In our environment, the problem is usually the opposite -- it's way too easy in ActiveRecord to ask the database to do computation like sorting for you. Also, it can be hard to predict what impact an additional clause will have on the server's use of indexes. We try to get engineers new to Rails to write the simplest, most performant queries and then use ruby to do any soft of complicated transformation or computation.
SQL is the right tool for the job! I replied to tell you that fewer and fewer people think that way....which is terrifying. "Elegant" solutions are judged as such, by their ability to avoid SQL. It's not a hard language, why is everyone trying to avoid it at the expense of their applications speed and simplicity?
When I post job adverts, a large portion of applicants balk at the SQL questions: "just use PDO, or ActiveRecord, or ADO, or SQLAlchemy". Which is fine, if they can explain the difference between inner, outer, left/right joins - and they can't. SQL will be the next COBOL at this rate, or at least I hope so for selfish and monetary reasons.
Somewhat ironically, perhaps, it goes back to one of the author's complaints: ActiveRecord is not really what you need for complex data. The idea that there is a 1:1 relationship between a table and an object is a poor one. Normally you want a datamapper to map between the model object(s) and the saved abstraction.
To make it a bit more clear, it's exactly the same separation of concerns that you want when you write a view for the UI. The controller takes one or more model objects and uses the view to generate an abstraction for the UI. When we save and fetch information from the DB (or send data out on the wire as JSON, for example) we want the exact same thing.
BTW, be very careful about doing all your computation on the ruby/rails side. It's a good idea from a certain perspective, but you are building a very nice bottleneck there if you have anything of real complexity. For example if you have a report that needs to sort through millions of records, you are going to be hanging your server for a loooong time. As you say, in those kinds of situations, you really want to query a service that has the ability to scale the requests more reasonably. Rails is incredibly poor at this kind of thing.
My own personal opinion is that there is very little that rails gives me that is worth the pain that Rails imposes. I'm much better off building something with Sinatra. What Rails does do very well (which the author also acknowledges) is reducing the number of things you need to know to get up and running quickly. But if you are going to pay the kind of salary I demand, then you will expect me to beyond that level ;-)
Agreed. And the challenge with using Rails is that when you hit a problem for which ActiveRecord is not the right tool, you have to now discard your entire process because the whole of the Rails framework is assuming state manipulation via the ActiveRecord abstraction.
"Rails" is an appropriate term for the framework; step too far off of it, and you find you're on rocky terrain.
I keep telling people to accomplish this by encapsulating the query in a DB view, and using a read only active record model in front of it. You can then query the table through the AR interface, and use has_many and friends. Unlike using execute_sql where everything is a string, type coercion works as you'd expect.
This solves the problem if you know ahead of time the format of the query, e.g. The example you gave would probably fit well. But if you're offering some kind of query building interface, well god help you.
No one has told me I'm wrong yet with this approach and it's been working great for years.
You can drop to sql if you find yourself fighting against ActiveRecord. It is simple as ActiveRecord::Base.connection.execute(sql) where you will end up working with arrays and hashes.
OK, what if you want to generate the SQL dynamically with attributes? connection.execute doesn't do sanitization for you by itself (though you can call a private method to do that). If the generation is more complicated than that, you also have to have code to concatenate together strings of SQL code. Not because Rails doesn't have a SQL generation library, just because it's tightly coupled to ActiveRecord and fuck you and the horse you rode in on if that isn't good enough for you.
I understand your general frustration, but to respond to your specific point here, AR does actually support executing generic parameterized SQL statements:
Yeah, I generally advocate for find_by_sql and select_all, but think about what that actually does. It instantiates a bunch of ActiveRecord objects that have to be of a particular model (what if the query joins tables together and returns a result set that doesn't actually neatly contain the intended columns of a given model? I can't even use ActiveRecord::Base.find_by_sql, I have to choose an actual ActiveRecord model arbitrarily), has the columns of the result set dynamically bound to it as methods during runtime (slow), also has the methods of the model itself bound to it, which may have unexpected behavior based on the query (especially if we just choose an arbitrary model), and in exchange we get to treat the result set as an array of structs rather than an array of hashes (which admittedly has its performance advantages, but not if the fields have to be dynamically bound to each object as methods!).
Oh, and if you're writing an INSERT statement you have to use connection.execute after all. Have fun!
> what if you want to generate the SQL dynamically with attributes? connection.execute doesn't do sanitization for you by itself (though you can call a private method to do that).
You just answered your own question. You sanitize the string and then you call connection.execute. Not sure I understand your other issue but it doesn't seem too compelling.
Yeah but there's no public method to sanitize the string. Having to call a private method works, and I've done it, but it's hacky and fragile and the only way it could pass code review with a clean conscience IMO is if you add an apologetic comment saying, "I know I'm using .send to call a private method and that this could break at any time if we update our Rails version because private methods aren't supported, but there's no other way to sanitize a string programmatically in this context, blame DHH". And I don't like having to put those kinds of comments in my code.
> Not sure I understand your other issue but it doesn't seem too compelling.
If you don't understand the other issue, how do you feel qualified to comment on whether it seems compelling?
Use case: I want to pull up a table of aggregated data for my user. The table is built by joining multiple tables together. The user can dynamically select which columns in the table he wants to see.
Don't do complex database work with ActiveRecord. What I like to do is these days is do backend jobs outside of Rails. (ActiveJob doesn't support RabbitMQ yet, I may change my mind about this when it does) Then use whatever toolset you want without Rails getting in your way.
> I ask myself if this person is really just complaining about how complex web dev is
A major problem with rails is it tries to "simplify" the inherent complexity of web development by using abstractions & mappings that ultimately increase incidental complexity in the entire stack.
When performance matters, Java runs circles around Ruby, Python or any other scripting language used in application development.
Having been bitten by web applications written in scripting languages (Apache + TCL like AOLServer) with an architecture very similar to Rails, but done in 1999, Rails was never that interesting to me.
Absolutely. At the end of the day you're doing some string substitutions then sending a text file over a socket. We were doing that in the early 90s! But to do it now we use these surreal Rube Goldberg contraptions with a hundred layers of abstraction.
And all programming itself is is turning strings of 1s and 0s into other strings of 1s and 0s.
Asking web dev to be less complex is like asking financial markets to be simpler. Websites are market tools, tools have to retain a competitive edge. You can't afford to ignore market trends. You can't afford to wait until everything is well-defined. You can't let craftsmanship get in the way of shipping.
You can buck the rules yourself and operate on whichever side of the tradeoff you want to operate in, but you can't expect everybody else to follow the same rules you do.
I mean, if you don't like the web, then by all means find a different domain. I personally love it, and find it absolutely fascinating. With the right tools, (Rails) the complexity is manageable.
I don't think the web's complexities are intrinsic. It's layers and layers of crap built on top of crap. Computers are so mind numbingly fast that in some respects it's impressive we've made the web as slow as it is.
Which isn't to say that the crap mountain wasn't the best choice. It may very well be the pragmatic choice. The highest net benefit choice. But I don't believe it's intrinsic. I don't believe it has to be this way. Which means it's at least worth considering alternate paths. Even if in the end we picked the same way.
I work in video games. Currently working in VR. Where you absolutely must hit 90fps and never drop a frame. A certain degree of craftsmanship is required to ship. Layers and layers of abstraction on abstraction need not apply.
Sort of unrelated, but any suggestions for experienced backend developer who wants to get into VR? I'm working on learning 3D graphics and c++, but could use a bit of direction.
What's your goal exactly? Depending on your goal there's a few routes.
If you want to produce compelling VR experiences then I'd recommend you download Unity. You should be able to start making real, valid prototypes for different types of VR interactions in under a week.
If you want to learn C++ then... that's an interesting question I've not thought of before. Maybe I'd start with "Learn C the Hard Way"? http://c.learncodethehardway.org/book/ I'm not as much of a C fanboy/C++ hater as other game devs. I quite like C++11 lambdas and move semantics. But I hate boost and it's ilk. So starting with C and later adding a dash of C++ seems like a good way to start.
Just as a side note I will add a piece of advice I wish I knew back in the day: learn C++ itself, not what I did which was to think I was doing that, but actually really only learn MFC (this applies to any framework or library, Qt etc etc). Having said that, the STL will stand you in good stead whatever you decide to do.
mean, if you don't like the web, then by all means find a different domain. I personally love it, and find it absolutely fascinating. With the right tools, (Rails) the complexity is manageable.
I built my first website in 1994. I know the right tools. Rails is not one of them.
But at the end of the day aren't all platforms complicated.
It's been a while since I did GUI programming on the desktop, but I remember it being so complex to build cross-platform applications that rolling your own cross-platform abstraction would be downright ludicrous.
I think the parent commenters point is correct. People treat the web like it should be easy, like it should just be HTML, but its not. It's full of legacy stuff, it requires working on multiple "platforms" (browsers), it runs on all kinds of device sizes and shapes, and the applications being written for it are no longer trivial.
1) Broken platforms. How much "innovation" has occurred in javascript to compensate for a broken execution model? How much caching does your average rails app do because of the poor concurrency the the Ruby platform, requiring external services for persistence across requests?
2) Looking for challenging problems. Design patterns are often a solution to a meta problem. Building a CRUD app, there aren't too many hard domain. However, code maintenance is a hard problem. It involves many people using subjective judgement. So as a somewhat bored developer, I'm going to try to solve the meta problem.
It sort of pains me to see how much engineering effort has gone into essentially making broken systems more performant and maintainable.
> It boggles my mind why developers don't take the web seriously as a domain, like it's not real coding or something.
I'm glad to hear people say this. I want to be a webdev (second career), but rather than code school I went back for an MSCS, because I really wanted to dive into the nuts and bolts down at the database implementation level.
I've done a fair amount of machine learning, ai, large-scale parallel programming, and algorithm design, and while I'm super-green, it's good to see the top comment is that the web is a serious domain.
I've written quite a few web apps over the years, sometimes in ruby, sometimes in go, sometimes python, sometimes C#, and I've actually never had to implement 'ActiveRecord::Base.create', much less poorly. I don't see what an ORM framework has to do with HTTP, honestly, the last 2 apps I worked on didn't even use a relational DB. I'd be curious how you'd finagle ActiveRecord to work with ElasticSearch - what would you do in that case?
I don't understand why web dev is so "scary" or "complex" that it needs 8 abstraction layers on top of it for my own protection. The only time I thought I needed hand-holding was when I didn't understand SQL injection and cross-site forgery/scripting (and once you do understand them, it's not difficult to protect yourself against those either).
If I found HTTP methods and headers, Javascript, CSS, Cookies and the rest of the web stack "scary" and needed hand-holding from Rails in order to get shit done, I'd be really, really worried about my skill set...
The web world is changing quickly and you have to ask yourself if you're a "web developer" or a "rails developer". I think you'd want to be the former.
He said he's been dabbling with functional programming. I saw mentions of Elixir, Clojure, Scala and Haskell. Where did he say he was going to work in Java?
How is this relevant, exactly? Ruby was written on and designed to run on *NIX OS's, as is most of the software commonly found in webapps, because it all runs on Linux servers. I'm sure it'd be a pain in the ass to get MS Paint to run on Debian, too.
It doesn't really matter anymore. It's been conventional wisdom for years to develop in a Linux VM if you have to use Windows otherwise. Unless that turns out to be more complex that the Windows Linux subsystem, I can't see VMs becoming an also-ran.
If a Linux VM is fine for deployment, well then that specific component doesn't really need or use Windows very much does it. (That all unixy things need to put in VMs on a host running Windows is a very different constraint.)
If it's important to deploy as a Windows process, then the Windows Linux subsystem is not much better than a VM. Point is, its no substitute for a (better) MSYS2/Cygwin.
I think I understand your point, and it's been a while since my MCSE expired, but unless Cygwin has improved a lot I would estimate a VM wrapped by Windows would be much easier to manage and admin.
Now if you're saying that the webapp itself would be required to be a Windows process, there's really no way around that. But as I implied elsewhere, the biggest stumbler for Rails on Windows has always been the lack of a compiler. Whether you compensate for that by installing a subsystem with that capability or by using a VM with the capability is largely a local problem to the company.
I've done that over the years and I used to answer questions on the RailsInstaller list, and yes, at times it was harder than at other times. I'm expecting it to be easier than ever thanks to Microsoft's recent announcement to support running Bash as a full-fledged citizen on Windows:
I feel like that's because someone put a lot of time and effort into making Python's core library play nice on Windows, and Pythonistas tend to interact with the OS/network only through core library functions.
To contrast, Elixir runs on Windows. However, it may be hard to get all your projects up and running due to various baked in concerns where they were written to support Unix-like systems only.
I don't know how long ago you tried it last time, but recently this has got much better. You surely could find some gotchas here and there, but it's not as much frustrating as it was before.
I did until 3.2. The only real problem was native extensions, and many gem developers provided win32 bins for those things if they support win32 at all. Granted, I personally wasn't (...) God's gift to clean code, but I could certainly work with anything other people (say, on IRC) were working with and talking about.
The rails stack isn't designed for Windows, why should they waste dev cycles trying to support it? In any case, I do a fair amount of webdev on my windows gaming computer (don't want to mix work and side projects), VMs are so easy to set up that I barely install any dev tools on base os.
If any of the frameworks glorified on HN were subject to the same scrutiny as Rails, Github would need a suicide hotline.
I've recently had the pleasure of working on a new, medium-sized node/react project. Now I was new to a lot of the technology, but I've learned a few and would think I have some experience.
It probably took me a week to get webpack running the way I wanted. The documentation is an atrocious mix of stuff that is outdated (older than 6 months) and stuff that's too new (webpack 2.0) without any indication as to the validity. There're six different ways to get hot reloading/replacement to work, with similar problems. The configuration's syntax is heavily influenced by brainfuck with a /\w/[{\[]/s thrown in for good measure. As a soothing measure, webpack doesn't complain about anything but parse errors with the configuration. The version I was using came with 12 different options to render source maps, none of which worked in chrome (since fixed).
And that's just the linker. I actually had presets to search for, i. e. ["express.js" from:<date-of-last-stable-release> to:<date-of-following-alpha/beta-release>]. node_modules once managed to consume 4TB of hd space (someone managed to create a circular dependency) and even in regular use gets to the point where I'm looking for the elasticsearch plugin for ls *<x>. If you have checkouts of several versions or projects, each one will have it's own version of left_pad & friends at around 230MB (just checked with a clean install of mxstbr/react-boilerplate) with no way of deduplication.
I enjoy playing with new technology (currently elm & swift) but I know that it's time "joyfully wasted" right now and don't try to justify it. There's no amount of type-safety bugs that could cost as much time as a new framework's kinks.
You jumped in the deep end without knowing how to swim.
You're starting a new project, with new technologies and you tried to use the most complex stack from day 1. It's a classic mistake people make with React projects. You don't need webpack, you don't need hot reloading etc (at least not to start with), you don't need a boilerplate.
Go with browserify at first. It's simple and can be migrated to webpack later. To setup browserify?
browserify in.js -o out.js -t babelify
And you're done! Add --debug flag for source maps. Want to setup a watcher with caching in dev for speedy builds? `npm install watchify` and swap out browserify.
When you need bundle splitting, async module loading, and all the other stuff you can do with webpack, then you can easily migrate from browserify.
Don't jump in the deep end without knowing how to swim.
While that's true, why don't we see this sort of stuff with Django or Flask?
Of course we see people complain about these tools, but my impression is that people who end up leaving those communities are rarely because of community issues (more like "I'm going to do some Go instead"-style things)
Surely something is different. It's not like Django is unused...
Rails is at least an order of magnitude more widespread than Django/Laravel/any of its imitators. If you take a swing at any of the follow-ons, its proponents will invariably say it's just doing what Rails does. Try to imagine a "Why Django sucks" flamepost garnering anywhere near the attention that the same does for Rails... yeah, won't happen.
I've been working on React projects lately and also spent a lot of time gluing together all the different libraries and setting up a proper build process via Webpack. I've also worked on Rails projects in the past, and I have to say that I prefer the modularity of being able to structure my projects according to the problem they're trying to solve. For instance, you wouldn't create a single-page app in Rails.
Also, with regards to Webpack, even though it's complex, it's extremely powerful, more so than anything else I've found. It includes many ways to optimize asset bundles considerably, by splitting them up into different files, removing unused code, and of course all the usual stuff like minimizing and gzipping the assets. In comparison to Rails it also compiles way faster, by only recompiling the code that you changed. It also includes many development tools, like an auto-reloading server and even updates your webpage without a refresh (HMR). All these are things that just aren't possible in Rails without much, much more effort.
Edit: I guess there's a first for everything, but I'm really confused as to why this was downvoted. If something I said is wrong or debatable, I'd be happy to hear it and discuss it.
> I prefer the modularity of being able to structure my projects according to the problem they're trying to solve. For instance, you wouldn't create a single-page app in Rails.
Those two sentences don't follow logically the way they appear. A project's structure has nothing to do with its functionality, which SPA is. I admit that rails is late to the SPA game, but if the new websockets (ActionCable) and API mode do what the docs say (haven't tried), there's no reason why it wouln't work nicely. For a given rails project, less than 5% of non-template code should change: create an API (one line for most projects) and... well, I can't think of anything else.
The rails view architecture is also almost identical to React: a bunch of nested templates. React best-practice is a bit more insistent on modularity (small & more generic components), but a 1:1 mapping of React and rails templates is possible.
What I meant to say was that I felt Rails was too rigid for some purposes, especially creating single-page applications. It's true that Rails wasn't built with that in mind originally, but it seems that it's becoming a bit easier now (I haven't been following Rails lately and had never heard of the "API mode" you mentioned).
I also know about a couple of projects using React successfully within Rails apps, but I would personally not do that if I were to start a new project today, even though I love Ruby.
There is nothing stopping from creating a single page app in rails. I have a SPA running on rails 3 using backbonejs. Some parts of which now use reactjs.
AngularJs had/has much worse and more criticism then rails and it's much younger.
Webpack, React etc... are not frameworks in the sense that Rails and AngularJs are frameworks, if you started with them and something in them is not like you like, you can use other libraries alongside them easily enough or replace them without huge sunk cost.
This isn't true for Rails (Or Django, or AngularJs) which are huge frameworks that touch every part of your development process.
Well, but that's because Angular sucked. I mean, even the developers agreed and wrote something new without thinking of a new name.
I wasn't neccessarily defending Rails as being "better than neutral" (although I think it is). I just felt the attitude at HN is negative to a degree that isn't objective any more, and that, to me, seems like it is less informational and more hurtful for a few people I have deep respect for.
Documentation of Webpack is getting better. I still use Gulp but at least the Webpack docs aren't just a bunch of 'Coming soon' pages like they used to be - take a look at the comments here: (http://webpack.github.io/docs/usage.html)
I think using Webpack still requires reading a lot of source code and examples, the docs aren't quite there yet. But it seems they're improving - the last time I checked the page you linked, it was completely empty!
Webpack is usually the biggest source of bugs and questions on any given React boilerplate. Something won't compile, circular dependencies causing the build to fail the first time, some strange bug in CSS inlining, hot reloading not reloading, etc.
I used Rails mostly for small or medium sized projects, one or two developers teams, all of us freelancers. It's the perfect tool for this kind of work. We can deliver quickly, send invoices, move on to something else or come back later to add features.
Do projects get complicated? Yes, some of then. Mainly because most customers pay for features and not for refactoring or design, which they don't understand (remember, no in house technical staff). Try to sell them a new page with attached the price of a major refactoring... good luck with that. So sometimes features get kludged together because of budget constraints. I have projects with suboptimal UX (understatement) because they rationally decide to make tradeoffs between usability and costs. It's their privilege. I bet this would happen with any language or framework. Your customers could be more long sighted than mines, I hope they are.
So, would I move away from Ruby and from Rails? Yes, when customers won't like starting a project with Rails anymore. This means that other tools don't have to cost them more. Do I care about Rails architectural shortcomings? A little, but I appreciate its shortcuts more. They work well in my projects.
This is my takeaway from Rails. Good default for your 1.0. Frankly, I would probably use Rails even if I was starting a startup. It's easy to hire, easy to talk about. Heck you will often find graphic designers who have played with Rails.
Choosing Rails will definitely lead to problems in the long run, but at least they are well understood problems. You're going to do an in-flight replacement of your 1.0 eventually anyway. You just need one grayhair on the team to steer the younglings away from the worst abuses and you'll have a stable, if clunky, platform to build on. It's the definition of mitigating risk.
Java and C# are of course equally boring, but I think the fact that Rails is culturally open source provides a huge benefit over them.
JavaScript, Go, Haskell, etc are arguably better if you really understand them, but they're research projects. Lots of great pieces of code, but the story of how to use them together is still being written. I would use one of them if my intention was to hire slow and keep my dev team fewer than ~30 people in the long term.
No. Rails just happened to be in the right time and place to attract relatively young, progressive people who tend to use social media more.
There's plenty of "drama" in many programming communities, but a lot of it is hidden, because your median Java developer is less likely to be on Twitter, Medium, or even HN.
What you're missing (at least with Node.js/Javascript) is that Node does not aim to be Rails. Node doesn't aim to have one correct way of doing one thing as Rails often does. Yes, there are best practices, but Node aims to give the developer the freedom to do things as they need to.
The result of this is that, yes, development of your standard CRUD app is probably not as fast as it would be with Rails. Also, moving from project to project is not as easy as it would be with Rails. But the advantage is that, if you have good developers who are good at architecting (a big if), you architecture will better reflect the problem at hand.
> The result of this is that, yes, development of your standard CRUD app is probably not as fast as it would be with Rails. Also, moving from project to project is not as easy as it would be with Rails. But the advantage is that, if you have good developers who are good at architecting (a big if), you architecture will better reflect the problem at hand.
And if you just want something to work quickly, Rails wins. JS encourages developers to spend days and weeks on picking each part of a framework for an MVP that may go nowhere. Rails is no longer the new shiny and it has moved into the 'get shit done' category of developer tools.
No, I'm aware of that. I love Node and npm and UNIX and I use only small single purpose modules and its amazing. But I am effectively a research engineer. And honestly, if you want your company to run on Node, you need to be a research engineer too, because "which infrastructure should we use?" is an open question in the world you describe.
Compare to Rails, where you start of with OK infrastructure by default. That's not better, it just means you can hire a random person off the street and they're on the same page as you. If you want to keep a team of 50 JavaScript developers on the same page you need a really strong culture. Or just say "Use Ember and Express, end of story". But at that point you no longer have the "developer freedom" you correctly cite as the core selling point of Node.
And by "on the same page" I mean "we both have a similar understanding of a sensible default way to transport persist text fields from an HTML form". Put 10 JavaScript programmers in a room and you'll get 8 different approaches.
> Java and C# are of course equally boring, but I think the fact that Rails is culturally open source provides a huge benefit over them.
Java is culturally open source at this point; nearly every widely-used Java library is open source and there is a huge open source ecosystem around Java (namely everything maintained by the ASF, but there are plenty of other open source projects like Gson, etc.). Bonus points for tying in to any of the bazillion proprietary software systems also built in Java.
The problem with Java is that it's so damn verbose -- it can take forever to build a moderately complex system because you just have to worry about so many things (maven, spring, jetty, etc.) just for a simple web service. This means you're spending time up front solving a lot of technical problems just to get a simple web service up and running.
Rails is great because it implements a set of sensible defaults and lets you worry about product design rather than implementing yet another database backend for a user store. Its event-routing model also makes a lot more sense for the web; in Java everything is kind of a hack to link the web stuff back to the JVM. But yeah, once your project gets complex, it might as well be Java -- complex software is just complex to write. Rails kind of sucks when the "sensible defaults" don't make sense anymore because you need heavy customization. It's a great prototyping platform, and that means a lot -- but it still won't let you escape the problems caused complexity.
One advantage of starting with Rails is that you can progress to JRuby on Rails when scaling is required. From there you can factor out services to Clojure or Scala without rewriting everything. So I'd say Rails has much more to offer than a quick starter app.
Yes, I'm talking about the consensus web development framework around Node, to the extent that there is any. Same for Go and Haskell. Obviously all three are mature languages.
The Go community is just not that big into web development. There are web frameworks (eg. Revel) but they're not seeing that much traction. I truly love Go but I just don't think it's a good building material for more than a JSON API - for which it is awesome BTW.
Can't speak about the Haskell community though. To the extent I know the language I probably wouldn't want to use it to create HTML forms, either.
Haskell has a healthy and growing web ecosystem, from larger frameworks like Yesod to leaner ones like Snap, Scotty, and Spock. Servant is also looking promising as toolkit for building both API servers and clients. And GHCJS lets you write your frontend code in Haskell as well, if you so choose.
Uh, Go is not a research project. It was written to be used, not to explore previous unexplored language features. Basically nothing in the language is new (or at least wasn't new to the creators), something that it is often criticized for.
Dropbox has stated that pretty much their entire backend is written in Go. Go is also (obviously) used in production at Google. Neither Dropbox or Google is screwing around. Once a project is run at Google or Dropbox scale, it is no longer a research project.
Go is very simple (many people say too simple) and writing a web app in it doesn't really require a very good understanding of the language. This is because very few of its more advanced features are really required for writing a normal web app. Because it isn't really a framework, it does require a good understanding of web development.
I think Haskell can be fairly described as a research project and definitely requires a good understanding.
I think what erikpukinskis means may be more that Go is still a "non-mature"/"research" ecosystem - for example, what do you use for version control of dependencies? Rails has bundler, Go has a few different approaches, none of which are the go-to thing everybody uses.
> Go is very simple (many people say too simple) and writing a web app in it doesn't really require a very good understanding of the language.
But you do have to know to how to use the standard libraries well to write anything beyond a Hello World web app in Go.
Just because the Go language itself is simple, it does not mean web development is easy in Go. Quite the opposite, you have to write a lot of boilerplate code in Go (even with Go frameworks) to do things that would seem trivial in other frameworks.
Standard Chartered is a massive multi-national bank with a £17 billion market cap and a multi-million line Haskell code base. Is that still a research project?
Do the customers know what Rails is enough to like or dislike it? Or do they like the promises of quick functionality which you translate in to lower costs?
If I may also ask, have you run in to an older rails app when someone wanted some fairly minimal additions? Have you been the "next guy?" or do you avoid those projects? Did you migrate it to a newer rails? rewrite it? Or write old rails code? I've run in to a couple of ancient apps that were running untouched for like 4 years, they want to freshen the application, maybe add some features, you have to sell them a major refactor, or you can't touch it, like they depended on some gems that were orphaned. It's not exclusive to Rails, I've seen this with node too, once the application needs to be living and breathing to stay healthy, once you put it on the shelf, it's dying. An express.js 2 to 4 migration is effectively a rewrite, it's not super terrible but it's a chunk of work that isn't adding their new features.
I've simply never heard a long term success story with rails or node when it comes to maintenance. It's maybe not a technical thing but it seems like it's the culture of both communities. Blue sky and green field code? It's a blast, fixing up or adding to someone else' existing code? I probably wouldn't touch it. Oddly, I don't feel the same way about a lot of Java stacks though.
No, those customers only know that Rails is mainstream and so it's a safe choice. If I propose Phoenix to them I bet they will look puzzled and ask me about PHP, Python, Node, Rails, maybe even Java. I'll make a test.
I've been the next guy many times. Rails makes that easy because I know where to look. The worst are custom PHP projects because I need to understand the original programmer's way of thinking. It can be a smart architecture (usually it's not) but it's time consuming and inefficient cost-wise.
I migrated every single version of Rails.
Never total rewrites, no need to do that.
I'm maintaining Rails 3, 4 and 5 beta apps right now. The customer with the 3.2 one has very little budget (we atarted and paused the upgrade to 4.2) and it's going to be EOL very soon. We'll see what happens. I was the next guy, that app started in 2011, I got it in 2012.
Orphan and incompatible gems happen. They make upgrades more difficult but I always handled them. With node it's an order of magnitude worse because of the much more rapid pace of change. It's the main reason for I would not recommend using Node.
Java just costs more to the customer. I use it only when I'm the next guy in a Java project. It's always a pain to work with it. It's like those ten lines would be one if this was Rails and I would have delivered two days ago (small new features). I just don't understand why developers want to inflict that environment to themselves.
"Java" is a big world now. A java 8 app with spring boot and jooq is just as simple to work in as any other backend software. If someone is stuck on java 6, classic spring, and hibernate...I feel your pain.
I ended up with a small nightmare with streams and collectors. That boilerplate shouldn't belong to this world, probably it's there because of the Java way to static typing.
They use Spring, don't know which versions, but it's got @RequestParam annotations to extract parameters from the request body. I think this is Spring Boot. It looks like Sinatra because of the @RequestMapping. Having @RequestParam in the action arguments looks a little like Phoenix pattern matching but I didn't have time to dig into the web and understand if it can really route requests to different actions according to the RequestParam. Overall is more or less where Ruby frameworks where ten years ago unless it's got pattern matching.
The webapp I had to work on still use ctags, which are a major PIA which slows down work and raises costs.
Queries are written in SQL, which is perfectly OK, and executed on a connection returning a java.sql.ResultSet. Not shiny but everybody can understand that. I googled jOOQ and it looks like ActiveRecord/AREL for Java. Nice but it would have cost me more time for this kind of quick hack.
Because Java is a huge chunk of the job market (at least in the Sacramento area), not because it's a "language of choice" . Actually, the JVM is a nice thing, even if the Java language is primitive and verbose.
Too bad the jFoo alternate language implementations haven't got more traction yet. (jRuby, Jython, Nashorn, et al)
Because it takes so long to start and you feel it whenever you run the tests. It gets a little better if you disable the JIT compiler and so... in dev mode, where developers spend all their life, it's not faster than RMI. Because it used to support only the syntax of older versions of Ruby. Basically devs get all the pain of the JVM and none of the gains. Guess what they want to use? A customer of mine asked me how to migrate from jRuby to MRI because devs where having problems. I explained and suggested they could try using MRI in dev and keep jRuby in production. They're a JVM shop. I'll ask them what they decided to do.
Basecamp went through a massive rewrite, and GitHub went through a long period of (perceived) low pace innovation culminating in "Dear Github".
I don't know whether Rails maintenance issues played a part in either of those things. However I do know that YAGNI and tight coupling are traditionally things than come back to haunt you 5+ years later. Front ends may change in that time but the fundamental logic of applications, especially their data structures tends to evolve much slower. Isolating the two can only be a good thing if you're not building a throwaway project.
Everything long term is going to need serious refactoring or a rewrite at some point (or just hire exponentially more developers). I don't think it has anything to do with the language or framework.
Depends if it was written well in the first place. I am maintaining a Django app, and because they have gone for "thin models fat controllers philosophy" (the opposite of Djangos best practices) it is a pain in the arse to modify stuff that should be easy.
Ok, maybe the framework doesn't have much influence, but a language with sane types will make refactoring easier. I'm not saying it will make it easy, just easier than other languages.
Yes, one of the benefits of Rails most overlooked by it's opponents is how immensely productive it is for small to medium sized apps. This comes from not only the DRY perspective but also from having strong standard ways to do things, and quite a stable API.
I don't agree on the sentiment in the article that it's hard to follow what happens in rails/activerecord. It's pretty well documented and all the quirks are thoroughly discussed on stackoverflow. Ruby has excellent tooling and it's easy to find performance bottlenecks.
On the negative side though, I find that I use other languages when I need performance or better concurrency, but that always comes at the price of lengthier development.
> Try to sell them a new page with attached the price of a major refactoring... good luck with that
Could it work to include a "technical debt" figure in your quotes (where each feature without refactoring increase the debt and the "interests" on each future invoices)? Might be useful to explain them that quick-and-dirty is not always the best solution.
I can't take his opinions too seriously because his 3 central gripes, which he wrote extensively about, boil down to:
1) Too much complexity is hidden by simple interfaces
Those simple interfaces make programming enjoyable and don't break, so...
2) Your app logic is going to be too tightly coupled to core Rails features like AR, helpers, controllers ("your app is Rails")
Yes, you are in fact using the features of Rails when you use Rails. Is this actually a problem?
3) ActiveSupport. "No actual solutions, no solid abstractions, just nasty workarounds"
ActiveSupport has saved me bajillions of hours and never broke anything for clients. I wasn't aware it was such a flawed library, if it is?
Rails is maximized for developer happiness by, among other things, making things simple (yes, which to a large extent means hiding complexity), giving you a bunch of Omikase core features that you can in fact use, and gives you a lot of sugary methods for handling things that are tedious. I understand people wanting to try other things and leave Rails, no problem with that, but his stated reasons reveal a lot more about him than about Rails.
> his stated reasons reveal a lot more about him than about Rails.
They reveal that he has tried to build sotware that didn't fit the Rails approach. They reveal that he has been frustrated trying to build tools that allow him to stray from the standard Rails approach without abandoning Rails completely. They reveal he's tired of the lack of success on that front and is going to just move on.
I think the prevailing problem people have with Rails is there narrow definition of a "Rails app" and a very wide space for "what my app will look like in a year".
Yes, this - in my experience, most web apps start out as "good Rails apps", but few remain so indefinitely. Many people over the years of Rails' popularity have experienced the transition from feeling supported by the "Rails Way" to feeling like they're fighting it, and it isn't surprising that this burns people out eventually.
I'm sure I'm wrong, but the fact that you keep using the word "simple" makes me feel that you skimmed over the article. The author disagrees that Rails makes things "simple," and argues that it attempts to mask complexity by making things easy/convenient.
Yes. But I'm not sure that argument is any more valid here than it is when talking about high level programming languages vs assembly. Of course abstraction hides complexity—that's kind of the point.
> Those simple interfaces make programming enjoyable and don't break, so...
Speak for yourself. The last time I worked on a rails project this was the part I most disliked. It made debugging annoying, I never knew what each line of code was doing in totality and and I had to practically live in the documentation to figure out the side affects of everything I did.
This is versus most other frameworks I've used for web services where most things are explicit enough that, even if you don't know the language well / at all, you can still figure out what most of everything does. Jumping into a rails project without knowing ruby and how rails works? Good luck figuring that out without studying the documentation.
Arguably the "central gripe" of the article is one level higher, in which Rails has no competition in Ruby-land, and if you don't agree the architectural preferences of a few thought leaders, your only choice is to abandon not just Rails but the entire Ruby world. At least that was my takeaway.
It depends: what does it do when? What does it do when the interpreter parses that line? What does it do when you call `save` on an object? What does it do when you call `create`? What does it do when you call `create!`? Etc. etc.
Of course, you always have to know how the tools you're using actually work, but Rails does have a tendency to make it seem like you don't, and to defaults that make it perhaps too easy to create bugs caused by mistaken intuition.
The expectation is that "validates :field, uniqueness: true" would validate that the value of the indicated field is unique among all rows in the table. However, this abstraction breaks spectacularly. Any web application, even a Rails app, is usually run over multiple processes, often on multiple different hosts. Uniqueness validation does a non-atomic check and set, which is a known race condition in this kind of environment. The guide does say:
> ...it may happen that two different database connections create two records with the same value for a column that you intend to be unique. To avoid that, you must create a unique index on both columns in your database.
But what actually happens when we do this? The race condition where you would otherwise get non-unique values inserted into a column of unique values is instead a race condition where a database adapter throws a generic exception for "the DB complained" with an error message about a failed constraint, and your site throws a 500. Your only recourse is to capture an overly generic class of exception that's thrown by e.g. the MySQL adapter, pattern-match the exception text for a magic string like "uniqueness constraint failed" depending upon which DB you're using, and write your own custom code to recover from that.
That's right: Rails has adapters for MySQL, PostgreSQL, etc, but "adapting" different SQL variants to ActiveRecord doesn't go as far as turning constraint failures, lock wait timeouts, etc. into generic, application-intelligible exception classes. The entire point of ActiveRecord is that your application code should be portable between SQL variants--hell, it shouldn't even have to know what SQL variant it runs on!--but between having to write your own SQL for any use case other than "let's deal with a result set as an array of ActiveRecord objects" and this nonsense, no real-world Rails application achieves this.
In other words, something that Rails pretends happens in one line of code does not actually happen at all, and to make it actually happen, you have to write a whole bunch of code that has to resort to string-matching a bucket exception class for "the DB complained" for the specific exception text that your particular DB engine throws. This is probably the worst example, but it's illustrative. Rails provides the illusion of simple interfaces and enjoyable programming. After working in Rails for just a few years, though, the illusion has vanished for me and I spend far too much time asking questions like "how the fuck did THAT get set to nil?" and "what does does it take to turn this multiline string of raw SQL into objects I can actually use?".
Honestly, I don't want to come across as too harsh. The sad truth is that nothing is perfect, and if you focus on the imperfections, all software pretty much just sucks. But Rails actually tries to convince you that it doesn't suck, that it abstracts away the complexity for you, and that you don't have to worry about it yourself, leaving you ill-prepared for the reality that it's still there and you do have to worry about it.
Ah gotcha - yes this is a flaw in Rails - from the first version, Rails aimed to be "database-agnostic," which isn't actually a valuable property in practice. And DHH disregards when he feels like it, eg. nonsense like https://github.com/rails/rails/commit/9f6e82ee4783e491c20f52... .
There are some ORM's where you define the schema in the application code and it alters the DB schema on the fly, but that seems dangerous, too.
What I would do, given Rails' existing framework of "programmatically discover the table schema and magically generate logic from it", is set it up so that it observes uniqueness constraints and programmatically adds the validation when found. Also, the adapters should interpret server error messages, throw a custom exception class for "uniqueness constraint failed", and ActiveRecord should catch this exception class and turn it into a failed validation when you attempt to save a record.
If that's too much work, just be fucking honest, remove the uniqueness validation (because it's completely useless), and be upfront with us that we have to roll our own solution for it.
I think you've either not read the article completely, or failed to understand the central point that the author tried to illustrate.
The issue is with culture. There is no problem if rails wants to go one way, and the author wants to go another. The issue at hand is that Rails is stymieing growth, not just in its own ecosystem but in the ruby ecosystem as a whole.
I think this is a very good point, and in contract I can imagine that if Django had total and utter dominance in the python world, python would be in a similar position.
> Yes, you are in fact using the features of Rails when you use Rails. Is this actually a problem?
A lot of people would argue that you should structure your application in such a way that as little of the behavior as possible is entangled with the Web framework you choose, making it easier to understand and easier to (for example) develop a different application reusing that code. DHH thinks that's "wankery," apparently, which I have to say strikes me as an odd opinion.
You see a simple line of code, and you can immediately say (assuming you know User is an AR model) what it’s doing. The problem here is that people confuse simplicity with convenience. It’s convenient (aka “easy”) to write this in your controller and get the job done, right?
Now, this line of code is not simple, it’s easy to write it, but the code is extremely complicated under the hood because:
- params must often go through db-specific coercions
- params must be validated
- params might be changed through callbacks, including external systems causing side-effects
- invalid state results in setting error messages, which depends on external system (i.e. I18n)
- valid params must be set as object’s state, potentially setting up associated objects too
- a single object or an entire object graph must be stored in the database
This lacks basic separation of concerns, which is always damaging for any complex project. It increases coupling and makes it harder to change and extend code.
This feels like the core of the argument of the whole post. It does not seem correct. In isolation, the call to User#create seems magical. But there's not enough context here to criticize it. We don't know enough to say whether there's inadequate separation of concerns.
No matter how we handle "users", we are going to need to do all 6 things in the list the author presented. No matter how we structure those 6 things, there is going to be a single entrypoint function that kicks them off --- end users won't be pushing 6 different buttons to drive them. So: what's the better design here?
The point I made is that this is all happening in your ORM layer, in ActiveRecord these concerns are not separated. Recent addition of Attributes API at least isolated coercion logic, but it's still part of the ORM, which for me is a mistake.
This might no be the the best example, but this is not a Medium blogspam, the guy has wrote several widely used gems and we should not stop at this technical example to invalidate the whole points he is trying to make (and I don't consider this code to be the core argument of the post.)
> This feels like the core of the argument of the whole post. It does not seem correct. In isolation, the call to User#create seems magical. But there's not enough context here to criticize it. We don't know enough to say whether there's inadequate separation of concerns.
There's enough context for me to start putting up the horns and cheering, because AR is one of the more persistent boils on my ass when I'm building things in Ruby (because I use Ruby for Ruby, rather than Rails, my frontends are all JavaScript and my services are all Grape). His last point is sufficient to me to demonstrate inadequate separation of concerns--the better design is the one that doesn't require an active database connection to know what fields the object has in it. Answering "how do I build an SOA without every service having a line to every database?" inevitably becomes "don't use ActiveRecord, ever".
What solnic has done with Virtus (which I use in all my projects, it's awesome, he's one of my favorite current Ruby people because of it and I'm sad that he may be leaving) is to return to the novel notion that an object knows what's in it. Dumb data objects are in almost every case a better long-term strategy, and solnic's frustration, if not expressed perfectly, is one that inevitably burns even Rails projects that grow to scale. And while this is a single example of Rails's monolithic nature choking out a lot of the Ruby ecosystem, it's not the only one (see his comments on ActiveSupport).
That's a totally valid point, but is 100% orthogonal to what's being discussed. Invoking a single command to validate, run callbacks, persist to the database, etc, etc. a model (and the larger argument of whether conflating DB access and persistence logic is a good thing) has nothing to do with whether the object is aware of it's own properties.
They are both critcisms of ActiveRecord, for sure, but quite a bit different in content. One (AR objects not knowing their own properties) feels, at least to me, like an unfortunate early design decision, while the other (encapsulating everything involved with saving a model in a single statement, "magic avoidance" be damned) is very much in line with the core philosophy of ActiveRecord and Rails.
> a single object or an entire object graph must be stored in the database
Hence "the last point" (though you might have caught me mid-edit). I view these as functionally the same problem: not only are you instantiating the object, but it must immediately go to live in the database or it's useless.
But you're right in that it is a philosophical problem. Rails is wrong. =)
There are always pros/cons to any approach one can as easily argue that without AR your code is less DRY as you need to keep your models in sync with your DB schema manually. (I am not a fan of AR either)
That's not really a unit test and not really a good idea to do it this way. You'll still have to keep model in sync with schema you'll just know when they diverge.
I agree with the author that abstractions should be optional, whenever possible.
However, just because something is heavily abstracted doesn't mean it's a bad approach, at least from a productivity standpoint. Without certain things being heavily abstracted, we'd go insane.
Just as
User.create(params[:user])
gets translated to thousands of lines of Ruby, so also
CoolClass.new('foo', 3)
gets translated to thousands of lines of C, and
printf("It's %d degrees today in %s.\n", temperature, city);
gets translated to thousands of lines of assembly.
Are they all heavy abstractions? Yes. Is it oftentimes very nice to be able to use heavy abstractions? Also yes.
To me the point isn't so much separation of concerns as it is separation of side-effects.
printf has a well design side effect (printing to stdout). Coolclass.new has an expectation of an instantiation of object in memory. If Coolclass.new also called an external service, then that would be a violation in my opinion. Thankfully, we generally don't do that.
User.create is not only capable of tons of side effects (just like Coolclass.new) but it is encouraged to do so (via callbacks and such).
There was a recent article about Julia that discussed how a printf in C translate to very few instructions in assembler.
Also I would like to point that "translates" is a little misleading word. There are two ways of implementing an abstraction from a higher level system to a lower level one.
You can generate code or you can write a runtime framework that does the work dynamically. Although from the higher place both may seem the same, there's a huge difference between them that has consequences.
The link to that article is below. printf in C tranlates to a few lines of assembly in preparation for a call to sprintf. That in turn will have a lot more instructions in assembler.
And most important, a call is not the same as the implementation of the called function, my point to begin with, please see my comment in the context of yours.
Per cloc it's actually 1093 lines of C (plus some more in the printf.c file), and generally speaking hundreds of lines of C is the equivalent of thousands of lines of assembly.
In any case, the complexity of the called function is exactly what we're discussing — it's why the author objects to "User.create(params[:user])"
My problem is whenever something spooky doesn't work, I never know which part of the source to read through. You need to understand the architecture to even know where to look. Which means you have to go through a huge up front process (like reading a webseries on the subject) to even get started. This front loading is the kind of thing that keeps more people from getting into programming, and is one of the primary ways we keep our salaries high.
I agree that this is not a good example of simplicity vs ease, but I think his core argument is still correct about what Rails is. (Whether you or I may like/dislike "What Rails Is" is, of course, another matter.)
The other way to look at Rails is that, as a framework, it has made a decision to have the model carry most of the weight for domain logic. In a "fat model skinny controller" framework, you're not surprised to see single lines of "magical" code like this in the controller, any more than you're surprised that each line of the route table masks thousands of lines of code that execute when a URL is matched.
This is very much not Merb's design. But that doesn't make it an invalid design; it just means that understanding a Rails app might best start with the models, not the controllers.
(There's a lot not to like about Rails! It's been years since I worked in it full time and I don't miss it.)
In 2016, with systems regularly decomposing into services for both perf and code management purposes, I'm trying really hard to find a reason to say this isn't an invalid approach except for what amount to toy problems (the kind where "if you don't know where you're trying to go, any road will get you there"). ActiveRecord being a mudball of "what X is" and "how to get X" is a really, really big problem, and my view of it as an observer--heavy in Ruby, heavy in avoiding Rails at all costs--is that it seems to be sourced from an unwillingness of the Rails community to consider that not everything is Rails. Services become intractable, as I note in my reply to your first post--and I don't even mean "microservice all the things", just the profoundly unsexy and unbloggable "SOA".
That DHH might even believe with a straight face enough of that essay to write its contents like an English major who just discovered the adjective doesn't really change that the universe is continuing to shrink the place in which his viewpoint can make sense. And, with it, goes Ruby's relevance, because of the heavy weight of Rails on the Ruby world as a whole.
> No matter how we handle "users", we are going to need to do all 6 things in the list the author presented.
I think maybe your broader thesis is we almost always need all 6 things. And if that's true for you then Rails is a good tool for you.
If we only ever need one out of the 6 things at a time then ActiveRecord is only adding extra complexity for us.
I think OP is basically saying I usually only need one or two and that they'd rather not have the extra layer of indirection... "save(andValidate)" is fine for them. They don't need the orchestration abilities that the declarative "afterSave(validate)" step affords.
DHH's suppress really is a good example. If you are calling save(andValidate) everywhere, you can't really do something like suppress(), because your validation logic is disbursed.
My opinion, and I think maybe OP would agree, is that there's usually a nice, composeable way to get the same problem solved, without resorting to a giant engine that understands all the different parts. But that's just an empirical assertion on our part. Obviously your mileage will vary.
In Django, the validation & type coercion would typically happen in a Form object (or, if you're using Django REST Framework, a Serializer). That step at least is outside of the ORM and seems much more explicit to me.
Also, in Django models are explicitly defined. There's no ActiveRecord magic of reading the database to define the model. Which is not to say that AR's approach is bad or wrong, but it is pretty significantly different from Django.
I haven't worked with Rails, but have worked extensively with Django and this doesn't seem to be the case. Even though Django is very similar to Rails in some ways, to pretty big differences is that Django seems to be much more explicit in general and (I might be wrong about this) Django seems to be easier to use in a SOA since your controllers (views in Django) are not as tightly coupled to your models.
That's correct. Around the time that Rails became popular, Django was undergoing a major refactoring to remove "magic" and make its underlying logic more explicit.
Further smaller changes have been made since then for the same purpose: explicit over implicit, code or configuration over convention is part of Django's philosophy.
IMO that also makes it easier to graduate from a beginning to an intermediate level use of the framework because while there are sane defaults in many places, in others you're required to define your specific implementation explicitly from the start. It's a tiny bit more code up front, but all the details are exposed and it's obvious how to override default behavior. And at the same time the framework supports keeping your code reasonably DRY and takes care of much of the tedious, repetitive stuff.
There's still tight coupling in some places (ModelForms, for instance, are arguably part of the controller layer and are tightly coupled to the ORM). But they're reasonably optional (you can use plain Django Forms instead of ModelForms in your views or not use the Forms library at all.)
This argument often comes up and I'm genuinely curious why people think Django is less "magic" than Rails, in my experience it has been the opposite.
My experience with Django (for instance: class-based views and admin parts) is actually that you have dozens of magical classes or methods and if you don't know them all, you're screwed. Often when I try to do something, many aswers on StackOverflow boil down to "just override a_method_that_is_hidden_somewhere()" or "just use ListButWithSpecificBehaviorView(), easy you see?".
Are there any specific example you have in mind where Rails do something magical that requires more code in Django but where Django is more explicit?
PS: not trying to start a flamewar, both are OK-frameworks, bla bla bla ;-)
I had a hard time understand how Rails works under the hood by reading the source. No such issue when reading Django source code. Rails magic is really powerful and I got overwhelmed. Maybe its just my Ruby-fu is not strong.
I get the feeling its not your Ruby-fu, but Rails is a lot like trying to jump into the show Supernatural in Season 10. I did some Rails sites early, and now have very little clue what's going on when I read new code. I'm sure I could get it, but its going to be a time investment. This seems to be the way of opinionated frameworks.
It's been awhile since I looked at either but I remember as a beginner I had trouble parsing both the Django source and the Rails source. The rails source was the hardest because I didn't understand ruby and the Django source was hard because I didn't understand python.
I feel like people really forget what it's like to be a beginner when they say "read the source".
Better design? In all seriousness Django - they get this right. It seems to hurt rails developers that it means typing a bit more, or is a little less 'magic', but then python did always attract software engineers, whereas Rails always seemed to attract code "ninjas" at best.
I can't grasp the hostile attitude towards rails at HN. Even agreeing with (some) of the criticism, I'm deeply thankful to Rails, DHH and everyone else involved.
Because before rails 1.0, I worked in php.
Many people may actually be too young to remember, but the jump from php and anything else that was state-of-the-art at the time to rails was without doubt the biggest leap web development ever took.
The most meaningful advances actually weren't just technical but social. It would've been possible to write an excellent webapp before rails, but just about nobody ever did. The opinionated nature of Rails many are complaining about today was a revolution because it taught everyone using it good architecture. You can nitpick about any one of those opinions, sure. But back then it was common to join a project with >100kloc with directories containing password.php, passwprds.php, pass.v3-old.inc, large_image.head.2002-v1.jpg & employees.xls. The quality of almost any rails project I have seen is, in comparison, excellent. It'd say a new team member on a rails project was productive in less than a third of the time it took in non-rails projects at the time.
So, to anyone complaining: I'm pretty sure that looking into any of your strongest held believes on web dev, you'll discover that rails had significant influence in creating them in the first place. To do something like that, pretty much as just one guy on the beginning, should afford someone a certain amount of respect.
I whole-heartedly agree with everything you said, but I also felt stifled and stymied by Rails for years, and am happy to be doing other things at the moment. It is possible (and I think fairly common) to both deeply appreciate Rails while finding fault with it, and to respect the validity of its approach while preferring other tools.
I see it more as he wants Data Mapper to be as easy as Active Record. Just from a pure patterns perspective, it never will be, because Data Mapper has one additional level of complexity.
This is my initial response as well. I came from the land of Java web dev and Rails was the best thing to ever happen. But it's been 10+ years since it really took the world by storm and things have changed. This "I will never use Rails again" saber rattling is just linkbait crap but well reasoned critiques of tools and patterns are always a good thing.
I would argue that is was perfectly possible before rails, many projects never left PHP and are doing just fine with it. Wordpress for instance, i think Facebook also?
I think rails has plateaud in terms of improvements. The article is pointing out the tight coupling of activerecord with business logic which is the consequence of a belief that I strongly disagree with in the rails community. 'fat models, skinny controllers' has caused a lot of mayhem as minor database updates (or update intention) triggers a cascade of actions.
This behaviour is counter to the model2 MVC implementation that rails is using as controllers should really be in charge of coordinating (helped by specialized classes if need be).
The author correctly points out that the way rails deals with views is painful however rails views are not tied to the model at all, they are tied to controllers and this can be modified if need be.
I personally maintain an approach of tying dedicated ruby classes to view files (e.g. SidebarComponent) and compose the view in the controller using a chain of these classes. This approach is much more object-oriented and avoids the weird pass-along view-hierarchies that many rails projects have.
There are much things to improve about rails but the project doesn't seem to absorb more object-oriented approaches over time and is tilted heavily towards DSL's for everything and doesn't value creating a more specialized class hierarchy to encapsulate more complexity.
I don't see a need to move away from Rails yet though as you can easily work inside the framework in a more Object-oriented approach. I guess you can characterize my approach as skinny models, skinny controllers, fat business logic objects and every partial is powered by a view object.
I too have stopped using Rails. To other Rails refugees, I highly recommend the up-and-coming Phoenix Framework for the Elixir language: http://www.phoenixframework.org/.
Simple as in simple, fast, productive, beautiful Ruby-like syntax. Favors a functional and immutable workflow over object-oriented and mutable spaghetti code.
Spun up my first Phoenix toy project 6 months ago and fell in love. You can really tell that a number of the core contributors are/were rails contributors, it carries over a lot of its strengths and tries to learn from its failings. Could really see Phoenix replacing Rails some day.
The creator of Elixir is in the Rails core team and helped (wrote?) write Rack. The creator of Phoenix built Rails apps for quite a while before finding Elixir—their experience definitely helps because they take what is good about Rails but know which "pain points" to improve on.
I've been trying out Phoenix, and it seems like the top contender for a Rails successor. It's not quite as fluent as Rails, but it's close. But I'm curious: since it is so much like Rails, won't it suffer from all the same complaints as in the article? It is still a monolithic, "Phoenix is your app" kind of framework, isn't it? Isn't the Devise-but-for-Phoenix library going to require Ecto? I think of Phoenix as just "Rails but faster." How is it different from Rails in ways the article author would appreciate?
(Edit: Btw I happily accept Rails' monolithic nature for all its conveniences, and I don't really identify with this author, but I'm curious to hear your opinion whether Phoenix would be a good fit for him.)
> A new phoenix application is not a monolith. The `phoenix.new` generator generates a regular Elixir application for you that sets up a default Endpoint worker in your supervision tree, as well as a web directory to put phoenix related files (routers, controllers, etc). wrt to collective process, we add `worker(MyApp.Endpoint, [])` into your supervision tree, so we do exactly what you are wanting. Building a Phoenix application is building an Elixir application, not the other way around. Your phoenix dependency and related workers are just one component to your larger Elixir/OTP infrastructure. Note: Lance Halvorsen, who gave the "Phoenix is not your App" talk, is on the Phoenix core team. We have been pushing these ideas since the beginning and as Lance I and laid out in our ElixirConfEU talks, we're taking a stronger stance on isolation with upcoming changes to guides and phoenix resource generators.
I think it's really quite a testament to Phoenix that so many people think it too is monolithic. A client can request a Phoenix application and I can get productive immediately without worrying about creating an unmaintainable, unperformant mess. No wasting 2 days on configuration hell. I can even jump into an existing project and be productive.
Another point is that the libraries around Elixir aren't (in my experience) Phoenix-focused or obsessed with magical Phoenix integration. In most cases, things work well together. Just call functions.
Monkey-patching, thread-unsafe operations, and uncontrolled shared global state are all non-problems in Phoenix. Decent code architecture and testability aren't usually a problem either because proper separation is enforced. Functional/immutable programming makes a huge difference here too.
Ecto 2.0 is really what ActiveRecord should've been. It's incredibly well thought-out. I suspect the author would be really pleased with Ecto.
Finally, Phoenix favors simplicity over ease in most cases. Complexity is not hidden in 100 layers of abstraction and callbacks.
The author also mentioned DHH's... colorful personality. So I'll take this opportunity to mention how much more welcoming and humble Jose Valim and Chris McCord are.
How's the community and library ecosystem looking in Elixir/Phoenix?
It sounds great in principle. I'd love to move from Rails toward something more functionally-inspired, but I worry that lack of libraries and google results is going to be a net productivity killer over the Rails + evolving into micro-services approach.
Nostalgia warning: I also grew frustrated with Rails / ActiveRecord and jumped to Merb / DataMapper with excitement. Perhaps it will sound like a small thing, but I remember feeling especially frustrated that every ActiveRecord model became such via inheritance. This drove me crazy:
class User < ActiveRecord::Base
Why should my `User` extend from `ActiveRecord::Base`? Is a User of my app also an ActiveRecord::Base? What is an ActiveRecord::Base anyway?
So, when DataMapper came along and favored composition over inheritance I was sold.
However, my experience with DataMapper was that it didn't have the stability of ActiveRecord, nor did it reach feature parity.
And, then Rails killed Merb. At the time I thought it was a tragedy. The competition Merb provided did improve Rails, it would have been nice if that competition had been longer term, though. On the flipside, I wonder if there would have been enough community to support two large Ruby web frameworks.
In the end I made peace with Rails and ActiveRecord (and, believe it or not, even ActiveSupport!). I don't have great love for Rails, but it is a powerful tool, so I accept it for what it is.
That said, I think the author's criticisms are well stated and hopefully there will be some influence on the future direction of Rails, etc, and the way devs approach Rails.
Having used many different ORMs that let you think that your business models could just gain persistence with a little sprinking of automagic, I far prefer the non-object-orientation of ActiveRecord.
Databases aren't object-oriented. Thinking of them with an is-a, LSP etc. mindset is a recipe for pain down the road. Databases are containers for facts: a means of storing, finding, synthesizing and manipulating facts. Your User class isn't a user of your application; IMO it's wrong to think of it as an object, because it could just be a slice of the User's facts (e.g. a subset of the columns).
I'm not a big fan of object orientation any more, and I like my databases to be stores of facts. The data in the database is primary; code in the application is secondary. Persistence isn't something I add to my benighted objects to let them be reanimated by query; persistence is what lets me briefly get a handy representation of a tuple locally.
To my mind, ActiveRecord models are little more than hashes with a nicer syntax. I don't need them to be much more; I don't want them to be much more. You can try and add methods and make them smaller, but coordinating the manipulation of facts is problematic in a transactional world, and the responsibilities aren't clear either. Object orientation is predicated on the idea of message sends and hidden state; tables have explicit state and no behaviour. Not a good match.
Have you tried Sequel? Sequel has, for me, filled the void left by DataMapper. Most folks I know that have used both ActiveRecord and Sequel vastly prefer Sequel.
Something to consider for people interested in Sequel. Sequel is great and all, but it still follows the Active Record pattern (Sequel::Model), not Data Mapper. Also expect to run into some problems with gems that interact with ActiveModel (Devise, CarrierWave, etc.). It's all solvable of course but it might require some hacking. Most popular gems have sequel versions or ship with sequel support, but it's not as well tested and maintained, we had to contribute several patches. Also, if you plan on using Sequel with Rails, don't use any of it's plugins that make it behave closer to ActiveRecord. Stuff like nested_attributes, delay_add_association, association_proxies, instance_hooks. They seem really nice at first, but I guarantee they will cause all sorts of unpredictable problems down the road. I would recommend looking into something like Reform which decouples form logic from your models because working with complex forms is going to be harder without all of the AR magic.
Sequel::Model's quite optional - it doesn't force you to use the AR pattern. It's built on top of Sequel::Dataset, which is entirely usable all on its own.
It doesn't force you, but you lose all of it's ORM features. Sequel::Dataset is basically just a query builder so ROM would probably be a better choice then yeah.
As a thought exercise, suppose I have my User class and now I would like to write it as json. Do you think it would be strange if the established solution were this?
class User < JSON::Base
Where by extending JSON::Base, I now have access to helpful methods like to_json?
Instead we have JSON.dump(user). And, if I need to customize the way the User json is written, I can opt in by defining a method. Thanks to Ruby's open classes, I can make the definition of such methods optional, suppose a separate file includes something like:
class User
def as_json
end
end
Requiring this file will bring in the extra json behavior without littering my actual user.rb with the details of how a User is written to json. Whether this is worthwhile or a bad idea is debatable, but I like that it is possible.
Now imagine if persisting a model to the database were similarly flexible? What if we could do this?
ActiveRecord.save(user)
Maybe it would be a good thing, maybe not.
As it is, I've come to accept the ActiveRecord approach, but when I create a model that extends ActiveRecord::Base, I think of it, not as a User, but an ActiveRecordPersistedUser. Where it makes sense, I separate my BusinessModel's from my ActiveRecordPersistedBusinessModel's for clarity.
The inheritance approach, used in both ActiveRecord and ActionController is sort of like the original sin of Rails. It affects everything from semantics, to performance, to testability. It is often the reason things eventually seem hard, but also the reason many things initially seem easy.
I'm somewhat split on the author's opinion here. I also picked up Rails back in the day (I think the first version I installed was 0.8), and I have a bit of a love/hate relationship with it.
As a framework for building comventional HTML templated database backed websites I still think it's near unbeatable, especially with the addition of a few common gems. However it so often gets shoehorned into other places - API backends, rich client apps, and massive systems. Places where the Rails conventions rapidly go from everything falling into place to getting in the way and needing to be worked around, or heavily tuned.
I completely agree that ActiveRecord is the core of why big Rails applications are complex to work with and often exhibit disproportionally poor performance. It doesn't lend itself well to composition, and results in data persistence being intertwined with business logic. That's fine for early prototypes, and in all honesty will get you to market quickly, but it makes extracting the concepts you discover during development into a coherant API much more complex than I'd like.
These days I still use Rails for the aforementioned HTML generating web applications, but it's often acting as an API client to systems built on top of a Grape based backend, with an API built around service objects and a simple data access later.
Interesting you bring up the point about API backends. I'm the author of Nodal [1], with the goal of bringing the best design patterns and practices from Rails and Django to the world of Node, focused completely on building a decoupled API layer. There is no view / template logic at all.
The project is very lightweight right now (benefits of being a young project with a sole full-time contributor), but I'd be interested to hear your feedback as to what you think is or isn't necessary for continued development. :)
Interesting, I think I came across Nodal while evaluating options for a side project a while back. Having just taken another look the big thing that seemed to be missing was something to serialize objects to JSON, although that may be because serializing objects is so trivial on JavaScript anyway. There also didn't seem to be much documentation about the operational side of things, most glaring was nothing being said about how the scheduler actually schedules jobs and ensures they get run.
Scheduler is actually still a WIP. I've changed the core around significantly in the last few releases, which has changed how the scheduler operates. That's why there's not much around it. ;)
We serialize models to JSON automatically in the response layer, and all models have a `.toObject()` method that takes an optional interface (which keys to actually serialize).
There is full API documentation but I still have a lot of work to do creating more fleshed-out tutorials. :)
The issue I have with just having a toObject or to_json method is that context is everything when serialising. Different access levels, different client types, and just different parts of an API call for different ways of sending data to end users.
Which is why you very clearly specify the interface whenever .toObject is called (which fields are exposed). By default, everything is included, but you have complete granular control. It's what allows us to do things like have full GraphQL support. :)
I read this with a lot of head-nodding but also a great sense of sadness.
I agree with pretty much every brickbat hurled at Rails in this article, except for one thing:
> Both projects were ultimately killed by Rails as Merb was “merged” into Rails, what turned out to be a major Rails refactor for its 3.0 version. DataMapper lost its community attention and without much support, it never evolved as it could if Merb was not “merged” into Rails.
DataMapper wasn't killed by Rails absorbing Merb. DataMapper was killed by "Things You Should Never Do, Part I":
> "They did it by making the single worst strategic mistake that any software company can make: They decided to rewrite the code from scratch."
DataMapper 2 was insanely ambitious, and true enough, it was never finished. A core subset was salvaged as ROM (Ruby Object Mapper), which has a certain artisan purity but is a long way from hitting the readable/understandable sweet spot that DataMapper originally had. But DataMapper 1 was abandoned by its developers. Pull requests languished and there weren't even any maintenance releases. I idled in the DataMapper IRC channel for a while and pretty much every query was answered with "don't bother, wait for DM 2". Unsurprisingly, people switched to ActiveRecord instead.
I still use DataMapper. I use it in my own framework, which is plaintively simple compared to Rails and no doubt makes a load of mistakes, but they're the mistakes I've chosen to make (which, as per DHH, is "opinionated" software). I would love DataMapper to be, if not revived, at least slightly maintained. There is life outside Rails, but you have to want it.
I dare to disagree. My point about DM being killed by Merb/Rails merge was about what happened back in 2008 with its consequences through all the years. I'm talking about DM1 specifically, if Merb survived and DM could grow with it we would be in a different place now already.
As far as our DM2 efforts go, this really didn't end so bad. rom-rb is growing very fast and we're already in the process of making it easy to use for typical CRUD stuff. Hanami integration will help here a lot too.
You nailed it. HABTM just never worked, and there was little interest in making it work. Since I handed out commit-access like candy, the majority of contributions were to endlessly refactor. Or do things like letting you treat a CSV file as a database. And HABTM still didn't work.
I didn't know how to put the genie back in the bottle. I didn't have the same problems that prompted me to create DM in the first place anymore (and by that point, I wasn't sure that porting a large Java Pattern to Ruby was even a good idea considering what I'd learned in the process about method dispatch performance in Ruby) and I was burned out on maintenance. So I handed over the keys and the rest is history.
I messed up. :-)
Today I'm happily writing apps with akka-http and think O/R Mappers are a fundamentally flawed idea. It's like trying to build a truck to move a few yards of dirt 100 feet. It'll never pay off. And I think even "users" would probably find that the hours they put into learning and using the tool will never get ahead of the performance, simplicity and linear scaling of effort they'd have had with a simpler solution.
So these days I'm much more likely to write this in Scala:
val limit = 10.0
sql"SELECT name FROM coffees WHERE price < $limit".as[String]
Than anything else. You will never find an O/RM that's faster, simpler or easier to write and maintain than that.
Plus Contextual Validations in the O/RM is just a bad idea. Even if they do appear in the PoEAA. First-class-Form objects and deserialization/validation at the app boundaries may not be a new idea, but it's the right one. (IMO)
Hey Sam, great to see you commenting on this :) I started contributing to DM when Dan was already in charge but I was a DM user when you were still working on it.
Anyhow, you made really good points here. I've worked on ORMs for a couple of years before I concluded the same - NOT WORTH THE EFFORT.
My approach with rom-rb is functional, as in this project works more like persistence libs in functional languages, rather than an O/R mapper. I removed the whole idea of mutable objects and managing their state using UoW etc. This simplified the stack a lot, and despite a complete lack of any performance-related tweaks rom-rb is already faster than ActiveRecord.
I also agree with your opinion re validations. I removed this concept from rom-rb as well and built a standalone validation library instead. This works very well.
That sounds like the pain I went through when I tried to write my own ORM. You want to go nuts with refactoring, chasing an ideal design that just doesn't exist.
> So these days I'm much more likely to write this in Scala:
I do this sort of thing a lot in ActiveRecord. I'll write a class method with ".where('price is null or price < ?', argument)". I use ActiveRecord a lot like I use Sequel, drilling into the underlying database layer. It occasionally bites me, but when it does, it's a good reminder to simplify my database architecture while nothing else is relying on it.
This way I can get the benefits of an object that behaves the way I want it to behave, but also respects the data layer. I don't want to give up either.
I do feel like Rails, in an effort to make things easy, encourages devs to overcomplicate their apps.
It astounds me that people are still citing that Spolsky article when its central example of what not to do is the writing of Firefox, which turned out to be a huge success.
Not that rewriting from scratch is always a good move. Evidently, DataMapper proves that!
The Spolsky article is about Netscape 6. That rewrite took 3 years, during which time (1997-2000) they lost ~80% of their users to competing browsers? It may have been amazing software, but not a success. Firefox/Netscape 8 was 2005ish.
Phoenix is very Rails like in the way it makes developers work and very un-Erlang. I mean: Phoenix apps are monoliths and not loose collectives of processes with an explicit http process.
It starts with the right claim but it ends with workers inside Phoenix. Instead the router and the http server should be at the same level of the other workers. Actually, they shoul be much less important, an implementation detail.
A new phoenix application is not a monolith. The `phoenix.new` generator generates a regular Elixir application for you that sets up a default Endpoint worker in your supervision tree, as well as a web directory to put phoenix related files (routers, controllers, etc). wrt to collective process, we add `worker(MyApp.Endpoint, [])` into your supervision tree, so we do exactly what you are wanting. Building a Phoenix application is building an Elixir application, not the other way around. Your phoenix dependency and related workers are just one component to your larger Elixir/OTP infrastructure. Note: Lance Halvorsen, who gave the "Phoenix is not your App" talk, is on the Phoenix core team. We have been pushing these ideas since the beginning and as Lance I and laid out in our ElixirConfEU talks, we're taking a stronger stance on isolation with upcoming changes to guides and phoenix resource generators.
Understood but to make me clear: I'd like to see Phoenix as part of an umbrella application and not it starting other applications as its workers. It should be a peer among peers and not the boss. However, as Rails demonstrated, the current approach is very convenient so I can hardly criticize it too much at this stage of Phoenix adoption. I think it helps the onboarding to the platform.
Phoenix v1.3 is adding an `--umbrella` flag to the `phoenix.new` generator for first-class umbrella support out of the box. In the Phoenix book we also have the reader breakout their application in an umbrella for the domain bits and a web app for the phoenix bits. Umbrellas have been a little underserved in the community so far, but stay tuned for future improvements around this.
I said this before: phoenix is the new Rails, and that is not a good thing. Phoenix will end up bogged down with the same great "ideas", hex will end up chock full of crap like gems.
Elixir ok, phoenix not so much.
askyourmother, while you're busy putting down other communities and folks' hardwork, we'll continue building the future. Comments like these aren't welcome and add zero value to the conversation.
If you want to rebuild Rails in elixir, go for it. Seems like a wasted opportunity though - to break away from all things Rails.
And yes, phoenix will end up bogged down like Rails, and hex will end up chock full of crap, it is the Rails developer mentality I'm afraid, they just can't help themselves.
Have you tried Phoenix?
I can see some similarities with Rails, but Phoenix's components are way more decoupled. In my current app Phoenix is handling the websocket messaging stuff. All the real logic is handled by Elixir modules and apps that have nothing to do with Phoenix.
I like to think of Phoenix as an interface to my app. It's less intrusive than Rails.
You don't have to use Ecto (the "ORM" thingy that is actually not an ORM) to get get the full power of Phoenix, it's also decoupled.
Regarding Hex, it's like every package managers out there. Sure you can publish anything. Rubygem is full of crap, npm is full of crap etc.. But I can also find some very small and focused libraries that wouldn't have been published, had a quality filter been setup to publish anything.
I have 2 main concerns going forward with any Rails alternative (ie. Trailblazer and the like): community support and jobs.
I have no idea how big the community behind each library/framework is and honestly I don't have the time to properly test-drive multiple and research the health of their respective ecosystems. With Rails I can rely on 10-15 gems that can help me with 80% of my projects. Perhaps I overestimate my reliance on 3rd party code, but that leaves me with my second issue.
Ruby jobs are de facto Rails jobs. I have weekly email newsletters set up for Ruby jobs and in the last 3+ years only a handful were Sinatra/Rack based. It would be interesting to see a reliable source of non-Rails Ruby jobs out there.
At some point you'll be in a position to decide which tech stack a company should use. I suspect you'll find there's a bit of a chicken and egg problem here - you'll want access to the largest pool of good candidates possible so you will also be disincentived from straying from the well worn path.
Even if you grant that good programmers can pick up new languages or frameworks easily (which I'm not entirely convinced of - there is a wide gulf between "can follow the tutorial" and "successfully used in anger"), you'll incur a penalty in velocity while all your new hires learn Framework X.
Anecdotal example of the perils of going off the beaten path: I often see a job advert on StackO for a company looking for Python/Django guys. When you click through to the job description, they are actually using Perl/Dancer. Not that there's anything wrong with that, but for me personally that's a deal breaker. I have no interest in investing the time to become proficient on that particular stack.
> Even if you grant that good programmers can pick up new languages or frameworks easily (which I'm not entirely convinced of - there is a wide gulf between "can follow the tutorial" and "successfully used in anger"), you'll incur a penalty in velocity while all your new hires learn Framework X.
I think the question is more "Does what we're doing require good programmers, or can we get by with shitty ones?" More often than not, you're not doing anything special, and you want to pick a platform that the cheapest, most common programmers out there can add features in a non-disastrous amount of time (different depending on industry + your competition), and not generate enough technical debt to collapse everything before the next rewrite/upgrade cycle.
I'm a full-time Rails developer, and I've run into the exact pains that he's talking about. By and large, I've fought with ridiculous things as projects grew, and run into extremely 'magical' bugs. It's frustrating as hell. But I've found the way through them is actually to lean into ActiveRecord, not away from it.
When it really boils down to it, ActiveRecord is a perfect pattern to deal with the "submit a form, validate it, run some logic, return the results" round-trip that's the core experience of web applications. Do you have validated data you need to do really complex logic on? Sweet. Send it on over to some PORO's. Have a complex query that isn't easy to cache? Nice! ActiveRecord will get out of your way. What's really hard is figuring out how to frame the problem in a way that makes Rails a great solution for it. This part is really really hard, I think in a lot of ways akin to art (and by 'art' I don't mean some deeper honor or aesthetic - just that there's no guidance), since the principles and patterns actually come from your domain and not somewhere else. And the developers I know who really hate the way Rails does something, especially ActiveRecord, are huge on applying patterns.
When I've taken the time to think through how to structure, really deeply, the applications are a pleasure to change and modify even when I come back much later. And for me, the proof is in the pudding: those aforementioned other developers who hate ActiveRecord don't complain! They'll see it, give a small 'huh,' then go do what they need to do just fine. But when I don't, they turn into the twisted spaghetti nightmares. I see a massive sub-current of dissatisfaction with Rails, and I think the reason for this is just a subtle but markedly different priority of thought. I can't articulate it yet, I just know what it looks like when I see it.
Anyway, I love Rails as it is now. Soon I hope I can deploy a single application across web and mobile platforms natively, along with supporting them all, as one guy. That's insane. Really like this blog post because I've got some things I'd like to be able to do with the ActiveRecord API, but I'm not really sure how. I don't know why the thought never occurred to me to just ask!
I'm not surprised by this development. I'm familiar with Piotr's code and it's hard to miss the fact that he's writing Ruby as if it was a functional language. Sharing inspiration between languages and paradigms is an awesome thing but if you're going to try hard writing Ruby like if you wrote Haskell you'd probably be much better off writing Haskell in the first place. Back to the original article I think it says more about Piotr's personal path as a developer than Rails and Ruby community at large.
That's not true, although there's a lot I took from FP. Like avoiding mutable state, and functional composition for data transformations.
This doesn't change the fact my code is OO - I use objects, composition, decoration, delegation and many other OO techniques, and in general try to avoid heavy inheritance-based patterns.
I can understand how people may think I'm trying to use ruby in an awkward way, but this is really not the case.
I find your Ruby code super awkward. Like you're trying to turn it into a language that it is not. At least it is not in my book but then again I'm just some random dude on the internet, a sample of one ;)
Reminds me of Zed Shaw's critique of Rails[0] which explains many of the short comings of Rails. Zed wrote the mongrel server for rails. Assume this article is massively politically incorrect & vulgar as hell, just as a heads up. Really good read though, and does explain some of the interior politics of rails and how it evolved.
This article is nothing like "Rails is a Ghetto". Zed's rant is 90% personal feuds, drama that is practically completely irrelevant today. The article being discussed is 90% technical critique.
> This article is nothing like "Rails is a Ghetto". Zed's rant is 90% personal feuds, drama that is practically completely irrelevant today. The article being discussed is 90% technical critique.
True. And yet, it reminded me of that article Zed wrote, which I summarized as a vulgar critique of the internal politics of the rails community.
Having little experience with Rails, it's the tone of that "Crazy, Heretical" article [1] that really strikes me. That tone where you're laboring to describe something that really truly does make sense when you're in the company of a bunch of people that just don't want to hear it.
There's too much purism in those kinds of arguments, arguments that really are more about spectrums. It sounds like Rails is really great for learning the shallowest 40% of a wide variety of programming concerns, and a lot of web solutions for small clients aren't ever going to dip below that 40%. And as soon as you get beyond that 40%, asking questions like "but what if it doesn't make sense to do it that way?" and "what is that weird runtime bug that doesn't happen in my development environment?" and "why can't I refactor without being scared I'll introduce a weird regression bug?" then it's totally fine to be attracted to the idea of static typing, compilation, and libraries/frameworks that are more explicit.
I was quite happy to walk away from the Ruby on Rails world 4 or 5 years ago. I basically escaped before the onslaught of Rails 3.0 and what came next. I think somewhere around the adoption of coffee script I got pretty concerned.
While at Google I became aware of Go and what that looked like at scale. I would highly recommend trying out Go. I think the simplicity will be a refreshing change but there will also be some familiarity coming from the Ruby/C world, can't quite pinpoint why but just feels that way.
I usually find "I am stop using XXX" type articles to be a bit negative. That said, I stopped using Rails years ago myself, so the linked article resonates with me. My goto web frameworks are Ruby+Sintra and Clojure+ring+compojure. Sometimes I also use meteor.js but it is more like Rails in that it is a complete package of everything you are likely to need, pre-configured.
Now I never use dynamic languages and never thought Rails was a good idea. But I'm glad I read as through as the "Convenience-Oriented Design" and the simple vs easy quote. I've seen many designs which have sacrificed consistency or orthogonality to make the common case as tiny as possible, and struggled to articulate what was wrong when I was counter with "how simple the tool is to use". Hopefully this will give me some better language.
I feel like the very world "simple" is part of the problem. Orthogonality/Consistency is much more important. Also don't treat odd use-cases as gratuitous features to be someday supports. No, a use-case is not a feature, but that hacks that will be added to accommodate those are. And features are bad: "[things] should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary."
Secondly, avoiding mutable state is a general, good advice,
which you can apply in your Ruby code. Ditching global state
and isolating it when you can’t avoid is also a really good
general advice.
As an Erlang programmer I agree with the general sentiment here, but wouldn't doing this in Ruby really lean hard on one of the pathologically nasty Ruby runtime issues? Which is that it doesn't release memory back to the system?
When every new operation on a data-structure starts by producing a copy of the previous version it seems like you'd really want a runtime which is efficient and intelligent about how it manages memory?
Unless that idiosyncrasy of Ruby has changed since I last used it several years ago. In which case. Nevermind. :-)
Ruby's MRI never returns RAM to the kernel, yes. But if you use immutable data structures and release them relatively quickly, the GC will have much easier time releasing their memory back to the pool that MRI is using for allocating new ones. So the inevitable RAM bloat that MRI accumulates over time is still there, but is slowed down.
As far as my not-so-big experience with them goes, the immutability programming techniques in Ruby actually help a lot with its sticky RAM problem. Complex object hierarchies of mutable objects and references to them are a nightmare for the GC. Having structures/objects that are used and [quickly] thrown away without (or rarely) being attached to complex object graphs is making the GC work more reliably, and faster.
I like rails. A lot. The syntax is amazing. Period. If you can get a gem or get what you need from rails. It is simply close to amazing.
But dare you. You just go down one simple level. (first level is what you get with rails and for example extending active record.) it becomes a horrible mess of dependencies and magic / structures.
I never found a framework so hard to modify. ( for example writing your own multi category / multi tag gem)
That's when i stopped web dev. It was just mind boggling. This is several years ago. I think around version 3 or even 2? And every version broke the active record stuff...
I really thought rails would catch on in germany. But if you look on indeed there are literally like five jobs in Germany... Maybe I'm not alone with that problem...
Rails is great. And of course it isn't and will never be perfect. Obviously the author would love some alternative frameworks, mainly so he can use some more and some less exotic code patterns. Maybe after almost a decade of writing CRUD apps in Rails he is a bit bored? I can't blame him and seeing the Ruby community so focused on basically one framework is a tiny bit sad.
So I definitely see where he is coming from with all this, but truth be told it was never Rails' indent to be a precision instrument. It has been a reliable framework that makes a lot of Developers very happy. A great reliable car for the masses so to speak. But not a Ferrari.
Although I may not agree with your perspective entirely, but I respect it.
I think everyone has different needs, and you have your personal needs which Rails no longer satisfies, so you are moving on.
Rails still solves a lot of problems for a lot of people I believe. I work as a consultant for a few companies and in some cases I see people losing time and money on what would be resolved immediately if they had just made the right call by using Rails.
Good luck on your journey, and remember the rails community will always have its door open for you :). Your projects on github look exciting, I will take a look at them. Very cool stuff!
I've also seen the writing on the wall for leaving Rails/Ruby. I think a lot is down to Ruby the language simply not being well-suited for an increasingly multi-core/concurrent future. That said, a more reasonable approach is to begin transitioning a few projects at a time, and make sure you've solidified on your new tools of choice before chucking the old ones.
I remember a few years ago I teased with ditching ruby for node.js. I'm glad I dipped my toes in the water and waited for Elixir.
Things aren't always the best fit for a person and they have to decide to move on.
Solnic has contributed a lot to the Ruby community and I'm not surprised to see him leave.
Within the the web domain of Ruby there has very much been a Highlander attitude of "there can be only one". That one has always been Rails. For someone that wants to create better pieces or have more choices other languages are more accepting.
On much of what he said in the article he is on point. Personally I've never been a big DataMapper fan (sorry dude, I just prefer Sequel), but I do agree ActiveRecord isn't great.
I've considered leaving the Ruby eco-system, but I look around and don't like the alternatives I see either. One of the great things about learning Ruby on Rails is job skill relevance. If you want to make a move and you know Rails then pretty much all job search matches are a green light. If you know Java and you are working with Play then nobody wants you because they want experience with Stripes, Spark, or god forbid Struts; now you have to relearn the whole framework and rinse repeat each time.
Personally I stick mostly to Ruby on Rails (and JavaScript) for my professional work, and then on personal projects I work in various obscure technologies that I just enjoy because I enjoy and I don't need to worry about if it will help bring in the bacon.
Sounds like he wants Arachne. Which isn't written yet. He even mentions learning Clojure. Linked article stops just short of mentioning it, but there are some themes that are common between the linked article and the story of what Arachne should fix.
The concept of the zeitgeist is interesting. A lot of general dislike of Rails is in the air and the only question seems to be what the replacement will be, not if there will be a replacement. Naturally the ruby guy thinks it'll be a new OO ruby framework which has always done the impossible before and the Clojure people think it'll be the usual immutable functional magic which has always done the impossible before. Best plan for the future is wish them all luck and wait and see. I don't see any other useful strategy at this instant?
My money is quite literally on the Clojure guys, I was one of the backers of the Arachne kickstarter, but best of luck to Hanami and rom.rb and all the new wave ruby stuff. One of you revolutionaries had better succeed, or else...
Some of it may be the natural result of success and age. A near decade of continually having to revamp my rails code "because the guys at hulu really need it" or "this is very helpful for github" is inevitably going to eventually make me say (if you'll excuse the profanity) F them I'm sick of rails and authoritarian monoculture in general and hulu is very nice but it can just go help itself, I have work to do that isn't "I have to chase latest fad that someone else needs". It may be a natural state for the lifespan of a framework to enter a stage where staying on the bus is more expensive than hopping off, maybe even hopping off anywhere. I tried some Play framework projects and I felt the sirens pull of static typing, but, after a few years, unless you keep up with changes, the technical debt just accumulates each framework revision until I'm sick of seeing releases instead of pumped.
I'm talking about projects that last many years not a semester or so. I'm not sure the chronological nut has been cracked of heres a magic solution for long lived projects. Assuming there is a magic solution. Perl CGI I suppose (only slightly tongue in cheek kidding)
Is it uncommon to use other patterns within rails like service objects? I like using Draper, Pundit, and other gems which provide decorator and policy objects.
I prefer to not use Helpers and AR callbacks (generally Concerns too) as I don’t think they encourage good OO even though they are officially part of rails.
Ultimately it comes down to what your goal is. Is it to deliver some business value fast to end users? Build a new product with a small team? Then I think rails is a great tool to achieve that.
We fixed in in Firefox 47, but the fix was deemed too risky to be uplifted to Firefox 46. That was probably a mistake. Anyway, Firefox 47 is going to be released in two weeks on June 7th. In the meantime you can remove the box-shadow from .widewrapper.main using the devtools, or you can use Firefox Beta (47) or Firefox Developer Edition (48), which you can get here: https://www.mozilla.org/en-US/firefox/channel/#developer
I noticed that too. But it renders and scrolls perfectly on Chrome. I wonder what's the difference?
Firefox is typically a lot slower than Chrome, but the performance difference this time is amazingly large.
Was bad in Firefox on Windows too (even to the point of me googling to find tab profiling tools for firefox out of curiosity, didn't find anything useful that's still active, so I've no clue what it is doing it)
What I don't understand is why people feel the need to proclaim that they're leaving xyz? Why not just focus on the positive and focus your energy on the new stuff you'll be doing. It sounds like someone who just broke up and keeps claiming they're totally over it but just can't stop talking about what a bitch their ex is. If you're planning to do haskell, elixir, clojure and scala, write about that.
> What I don't understand is why people feel the need to proclaim that they're leaving xyz?
Often, such proclamations are not noteworthy. However, if the speaker has been a long time user of xyz and a contributor to it, then the proclamation is noteworthy.
my two cents on Rails (as someone who's worked with Rails/Ruby, Node, Scala, Golang in some depth)
- ORM is bad at any sort of scale/complexity.
- Net IO that looks like property access makes it too easy for devs to do bad things, N+1 queries etc.
- ORM abstraction is not helpful when you know the exact efficient query you want.
- ActiveRecord Models + the Ruby module system encourage OO bloat.
- ActiveRecord database drivers are too numerous and not well implemented. Default schema generation includes many SQL anti-patterns.
- ActiveRecord has too many public interfaces, too much meta-programming. Hard to understand scope, Hard to analyze and improve performance.
- ActiveSupport monkey patches too much of Ruby. Need an very deep understanding of language to understand what's going on at a non-superficial level.
- Rails/Ruby community places too much emphasis on "clever" DSLs / APIs
- If your stack/framework choices limited to dynamic languages, Rails is a lot less efficient than Node and for web apps you need JS developers anyway.
However if you've run into the same problem where you feel like you need to either make fat model or fat controller in Rails, here's a simple solution:
A simple formula to take a lot of AR's bloat away is to use it mainly as a read library (AR's great for generating complex queries in a simple & readable manner).
For write operations (aka user interaction) I use a combination of solnic gem (Virtus) with ActiveModel that way I remove a s*t load of responsibilities from AR and the controller :
- params management (and strong params)
- validations
- nested associations
- callbacks
- And all the context management (like user vs admin...)
That way I only mildly part from the rails way and yet have a good separation of concern. Actually ActiveModel is used by ActiveRecord so having a form object relying on it is still very much rails compliant. The refactoring is minor (no hexagonal stuff) and the level of indirection very low.
This should come at no surprise, although I don't see anyone criticizing Rails anywhere.
I've never written a line of Ruby, but trying to read Rails code evokes me all this: it seems like a framework created with the sole purpose of hiding everything possible from the programmer.
Rails has plenty of critics. You just aren't looking hard enough.
The most common criticisms are: it's slow and it has too much "magic."
At the end of the day, it comes down to this: every framework has its pros and cons. When you use a framework, you gain certain benefits but sacrifice certain things and have to conform to the framework's opinions. In the case of Rails, the primary benefit is extremely fast prototyping. But that's only possible because the framework hides a lot of complexity from you, which can bite you in the ass if you try to go outside its conventions.
This. One fine example is Gitlab: It's full of features and does many nifty things. But it's painfully slow and the developers now have a hard time trying to fix this.
The slowness is not due to Rails. It is mainly due to us not scaling up the infrastructure team fast enough and now having problems with the file serving backend. We're working on it in https://gitlab.com/gitlab-com/operations/issues/42
Conventions is something I try to avoid at all costs. Conventions are usually things that are hard to find in documentation. Conventions are things that every experienced user says that "oh, this is common knowledge" and conventions are the reason why things seem to work magically.
Obviously if you follow a framework from day 0 you don't even notice it. For newcomers, it's a source of frustration.
That's not really what convention refers to here. Rails' motto "convention over configuration" simply means that boilerplate should be avoided, and that code should use sensible defaults whenever there isn't information.
For example, ActiveRecord class names map to table names through a simple pluralizer (UserProfile -> user_profiles). That's a convention, no configuration needed. Just write a class and off you go. You can override this behaviour, but you can also write huge apps that just follow the convention. Other frameworks would typically make this mapping explicit.
You do need to read the documentation to see what the conventional behaviour is, but it's not very deep knowledge. It's not much worse than other frameworks, where you need to find how things are configured.
My experience is that programmers migrating to Rails are thoroughly confused by these conventions like "UserProfile -> user_profiles". Although it's only the second-biggest source of confusion after ActiveSupport, e.g. "10.hours.ago" even though the integer class does not have an hours method according to the Ruby documentation.
But is that any different from any other system, where you have to learn how things are put together? For example, Java projects frequently use Maven. You need to download and learn Maven to understand how it's put together.
You can explain those two things you mention in a few seconds ("Ruby allows adding new methods to anything; the 'hours' method is defined by ActiveSupport"), and then the confusion has been eliminated. That leads to an increased understanding of Ruby.
FWIW, I've had a whole bunch of junior colleages learn Ruby, and those things were never a point of confusion. If anything, I have the opposite experience; Ruby and Rails are superb for newbies because of all the sane (convention over config) defaults.
Unfortunately, one segment of the Rails developer culture has perpetrated a lot of ugly overdesign (mini-frameworks such as Devise, ActiveMerchant, etc. that inject themselves into Rails in brittle ways) that certainly will confuse newbies. But that's not Rails' fault.
Explicit configuration may teach a new developer about a codebase, but it also means that there's more upfront work when developing. If the conventions are already there, in the form of good developer habits and good workflow, it's more pragmatic to encode them as explicit conventions, rather than introduce lots of un-DRY boilerplate.
Yes 1.+(5), 5.-(1), 1.*(2). Ruby is probably the most object oriented language out there, besides Scala(which borrows from Ruby. Which borrowed form Smalltalk). Keeps syntax rules to a minimum. Where is something like Java 1 + 1 is a special syntax case on primitive types(primitive types in hindsight were a terrible decision). In Ruby methods can be called with spaces and without parenthesis. So 1.+(5) is the same as 1 + 5.
It's definitely a issue, but I think it's far from the biggest issue. If you're going to use ruby, you're going to have to come grips with the culture, which for better or worse involves more "magic" and meta-programming than, say, Python where the same power exists but is avoided on principle.
It takes a little getting used to, but once you are, then the tooling is there to help you make sense of these things:
1.method(:year).source_location
The bigger issues with Rails I see are the monoculture issue raised in the article, plus the intractable issues with ruby around performance, memory bloat, concurrency, and last but not least, the multi-paradigm nature giving you functional features, but without any of the usual immutability guarantees (unless you follow a constrained and unconventional coding style which no one does in the ruby community).
I can call methods on objects in most frameworks/libraries. The fact that I don't know if .trim() is a core Javascript function or part of jQuery isn't a weakness of jQuery. If a "developer" can't be bothered to consult documentation when they work on a slightly different project than they're used to, then they're in the wrong industry.
Is there a problem? If they don't know, there's not much harm. But surely this is part of the learning process. Understanding leads to enlightenment. There's certainly evidence that tons of developers using JavaScript don't know how classes work.
Frameworks should be designed for experts as well as newcomers. I was a Ruby-only developer and, after starting a full time Rails job, picked it up quickly enough.
Your complaint is more about implicit vs. explicit. Implicit behavior is bad when it's surprising. When it's what you would have done anyway, then making it explicit creates an unthinking, tedious ceremony that you repeat daily.
Some of my favorite Rails devs are former Python devs. They appreciate conventions and the freedom they give you.
And if conventions don't change :) If a team can follow conventions it's a good thing, but I personally favor explicit code that does nor les nor more than it says. I do use frameworks, but I always pick the minimalist ones where I can see the chance understanding what goes on under the hood.
I personally can't wait for Rails to be a distant past. So many start-ups got burnt badly by using Rails -- easy to start, hard to scale, maintain, and extend. Rails is too opinionated and if your use-cases don't fit into "Rails way" your screwed.
I've always heard people blast Rails b/c of Twitter's experience but Twitter did survive it and scale. Maybe Twitter would have never gotten to the level of success they did without using Rails? Also, I'm not convinced that the original developers at Twitter did a great job implementing the first Twitter infrastructure. It is possible to write bad code using Rails that would be bad no matter what language or framework was used. It's a huge unknown in that story that entirely changes how to judge the outcome.
But at least it got them started and they could understand if there is a market for their product. My bet: if twitter started with Java Struts (it was 2006) they would have had to spend so much money and have needed so much time to launch that we would be using something else now. Not necessarily a system bootstrapped with Ruby, but you got the idea.
> if your use-cases don't fit into "Rails way" your screwed
Of course.
If a startup service doesn't fit Rails, they should have picked something else. I'm not using Rails for everything.
Startups usually try on a bunch of use-cases (features, ideas, workflows) before they gain traction or die. Your saying that startups should know all the use-cases they plan on building before they even start -- that simply impossible. Maybe your point is that startups shouldn't use Rails and its more suited for dev projects with a clear spec.
Not really. Rails is good for quickly hacking things together across a very wide range of the domains that startups usually play in, which makes it as good as anything out there when upfront productivity is the priority and you have rapidly evolving specs.
The only really common startup use case it's decidedly bad at is realtime/sockets/streaming data, where Node takes its place as the hack-it-together tool of choice--at a significant productivity penalty compared to Rails.
It's also, of course, pretty bad at all kinds of tasks unrelated to web development or REST apis. You wouldn't want to write machine learning algorithms or do statistical analysis in Rails, just like you wouldn't want to do 3d game development in Rails. And while you do occasionally see startups who have bolted some heavy data processing or pseudo-ML monstrosity onto their Rails apps, I've never seen anyone in the Rails community claim that was a good idea. The vanilla recommendation there is to keep your main server stack in Rails and then write services in something more appropriate for those needs.
Your also implying that easy to get started and ( scale, maintain, and extend) are mutually exclusive. I am saying they are not and don't have to be. Moreover, this kind of thinking just proves the point of why we need to move of from Rails.
Move from Rails into what? Nobody is disagreeing that Rails has problems, but until there's a battle-tested replacement out there with a similarly strong community and range of libraries it's all just theorizing.
Back up what you're saying. Rails built a lot of extremely successful companies. It is not hard to scale or maintain if you are competent. If you scale beyond the capacity of Rails, you are Twitter and it's ok to move on.
I am seeing good amount of comments saying "Twitter did it", this is simply a logical error (survival bias). Moreover, I think Twitter would of been successfully even without using RoR.
The things that suck in rails are the views, the asset pipeline and the stupid helper methods for routes that are so complicated for nested routes it's a joke. The database part is actually the good part if you do it right.
Another point that was subtly made, but needs highlighting.
If you are programming in ruby you are ONLY doing a front facing webapp. There are lots of servers out there that run headless. The ruby ecosystem is completely dominated and controlled by rails. As a result, ORM mappings and gems are completely focused on a web-response centric world.
As monolithic ruby apps are broken into microservices, ruby as a language will also be abandoned for those microservice back-ends - simply because the ruby ecosystem has only one way of viewing the world.
I have seen posts like this time after time of experienced developer eventually hating (opinionated and/or coupling) framework.
I too eventually came to a similar conclusion albeit on different platforms. Frameworks get you started quickly but you will eventually hate them. And I do mean framework and not library (there is a subtle but massive difference... yes the oxymoron was intentional).
Its even worse in Javascript land. You could rewrite this post and just insert one of the many Javascript frameworks like Angular.
I'm not going to pretend it's better than Rails, but I implement most of my projects as Sinatra psuedo-frameworks, with Sequel for the ORM. Sequel is a solid ORM that has a reputation of being stable and reliable. Sinatra is just simple (vs easy sometimes) and I like the way it integrates routing directly. It's good enough to power Neocities anyways, and I've baked in some of the niceties you'd expect from a larger framework (such as testing).
I wonder if the author of the article above has looked into Sinatra? It seems to be the solution he is looking for, in a sense.
I have used Padrino (http://www.padrinorb.com) a lot recently, which is really a framework on top of Sinatra that make things like testing, ORMs and renderers easier to integrate into a raw Sinatra base.
I especially love that I can use 95% of gems written for Rails in it - about the only ones I can't use are the ActiveRecord specific ones. (Note: I use DataMapper in most of my projects, but looking at Sequel as the ORM for my current app).
I've been doing a lot of the same recently. Super light in terms of code and very readable. When appropriate, easy to gemify and then mount in a Rails app
I've been developing apps with Rails since it was announced. It's been an amazing tool/toolchain, providing a very useful level of abstraction that allows rapid development.
Recently, I've been doing a lot of Go (Golang) development. For me, it's sort of the anti-Ruby-Rails. I really like the fact that it requires me to "roll my own" in so many situations. I need to understand what's happening under the hood to make things work.
But, the abstraction/magic of Rails is useful. Speed to market with trustable, battle tested magic is a profitable proposition.
I want to introduce Golang into my current project, but I haven't quite found the right place for it yet. Rails makes it so much easier and faster to add functionality at our scale.
It might be a better sell if you try to introduce Elixir, and I am guessing its Phoenix library/framework as well.
I've tinkered a bit with Golang and I love it but IMO it's too much extra work in the Web development part. It's exciting and very educational to pop the hood and understand how many things fit together, especially if you're coming from Rails, but you should be aware that after a while the novelty wears off and sooner or later you'll start looking for the quicker paths to introduce trivial Web cruft.
I am yet to experiment with Elixir + Phoenix but the community feedback so far has been fantastic.
> First of all, it worries me that many people react like that. We’re discussing a tool, not a person, no need to get emotional.
Laughably, no.
Code is written by people; it's essentially a set of ideas that execute and do things in accordance with the vision of the creators. The creators poured themselves into the tool. Code is an extension of the self.
(If it isn't, it should be; people take the best responsibility for code when it's like that, and it's probably the main essence that separates OSS from most proprietary work. People don't fully invest themselves into creations that can completely disappear out of their lives forever upon the next organization restructuring.)
This article formulates well why I strongly prefer libraries to frameworks.
A framework dictates you the structure of what you are doing. Libraries can be combined, replaced, and used in various ways, fitting more the task at hand than the mist common case.
You don't want to know. I inherited and am currently tech-leading a large e-commerce project powering an e-shop doing $10k+ sales a day. Even a small bugfix or a very minor UI addition is taking days because outdated tests are breaking, because there are dozens of tight integrations directly in the code, because there's zero separation of concerns, and awfully inefficient ActiveRecord queries everywhere. Making a cart checkout with ONE item takes 50+ ActiveRecord queries. Yep...
It is extremely challenging and very educational for me, and I appreciate the experience. I've always been a fan of repairing and improving things -- but truth be told, it gets tiresome and annoying VERY quickly.
I am currently working hard to stabilize the entire process of small refactorings for the sake of the new features/bugfixes, streamlining deployment, making full separate QA/Staging environment (yes, even that wasn't addressed by the previous team) so we can test with confidence and without fearing we'll break Prod, and to reduce the 3rd party API dependencies -- right now they are 20+.
I am hopeful that after I stabilize the project and make the process of introducing new code easier and quicker, I could then make the case for gradual exodus to Elixir/Phoenix. Realistically, I am not seeing that Rails abomination I inherited to be a sustainable job for even one year. Inevitably I'll burn out, the customers will lose patience, and my employer will be unhappy both with me and the customers. Not cool for anyone involved.
So I'll try to gradually run away from Rails. As pointed by numerous smart people here, it's suited for medium-sized projects at best. Even Sinatra/Padrino and 50+ attached libraries would have been much easier to maintain.
Ive got a similar problem, dealing with a rails app i inhereted that collects telemetry data from thousands of remote units traveling out in the field.
Basically there is no separation at all of active record and buisness logic. You end up with connections to ftp servers and other application layer adapters down in active record models.
With all of the application layer in the AR models its only a matter of time before the developers end up weaveing a thick carpet of spaghetti dependency through everything.
On top of that changing the database becomes a royal nightmare because the database is what defines this AR model that all of your buisness logic and application layer spaghetti dependency relies on. The databases usually end up full of garbage because without complex validations and lots and lots of tests which by the way were never written ruby and rails will dump any trash into your db whenever. So you end up with columns with like 10 variations of the definition of NULL or FALSE.
Usually around this point your app just slips into a state of quantum uncertainty. It essentially ceases to behave deterministically at least when viewed from within the bounds of human perception.
Its hard for experienced developers to bend rails in away so that things don't become overly dependent on each other and neigh impossible for average or beginner rails developers to manage.
Im just really not impressed with rails at all especially coming off of 6 years of development time on huge enterprise apps written with the c# .net libraries. I mean really they are light years ahead using IOC dependency injection for injecting service apis into controllers while using mapping patterns for keeping buisness and database logic separate. Its the only way to break up large apps and keep them sane and maintainable. Additionally static typing is the only thing that keeps things sane in really large applications doing complex business logic through many layers of interfaces.
Hey and sorry for replying with so much delay. I keep forgetting HN won't send me mobile notifications for replies.
Truth be told, I am not sure how well will I cope. I am good, I have experience, I have been doing lots of quality repairs in my life before. But you know what? At certain point you don't think it's worth your time and energy. That's the real enemy here -- demotivation.
I spent humongous amounts of time in the object-oriented land. I think I'll just hop to the functional programming world -- isolated functions, functions as first-class citizens, immutability (hell yes!), no shared shate (oh God please, I want that!), and goodbye side effects. At least I hope so. It might just be another shiny thing I'll be pursuing and won't be much better. We'll see.
But you know what? I prefer working hard to build things from the ground up in a new and much better language and ecosystem than to spend my life trying to demystify somebody's strongly opinionated framework which doesn't cover even 40% of what I need in my project.
Alternatively: Rails doesn’t believe in doing anything that would make it anything resembling modular so people who don't agree on everything can still work together easily.
This is simply why I've never liked Laravel.
Don't get me wrong, I love the packages esp. Eloquent and Blade (validaton and translation not far behind) and I reuse them in all my projects now.
I simply hate the "magic". I don't touch anything with too much magic going on and even avoid some features of Eloquent because of that.
He mentions it at the end, but I'd strongly agree that Clojure addresses the issues he mentions. I see a lot of discussion in this thread about Elixir and Phoenix, but I'd take another look at Clojure.
It's got a strong, friendly ecosystem that encourages small, composable libraries. For every level of your application, there's competition - http servers, sql abstractions, front end libraries. And there's great resources to help you choose what works best for your use case - the Luminus docs, books, blogs, and several active forums for discussion with library owners and just regular developers.
Couple that with a community that really took Rich Hickey's "Simple made easy" talk to heart and the default immutability and functional paradigm and the abstractions that Clojure itself has to offer, not to mention the performance the JVM brings to the table, and I think it's a great language to hang your hat on in the long haul.
I'm going Clojure route and in it for the long run. Being able to eval any single piece of your code in a REPL direct from your IDE in the context of your app is just insane. Also having one single language for JavaScript and JVM is super useful.
Also after programming for 4 years a bit I've felt the core of programming beyond CRUD/consuming APIs is about manipulating data structures. Having powerful utilities for this and not having to shove everything into classes and objects makes it really easy to get stuff done. Going back to Ruby feels like I'm working with a kludge in comparison. Everything that doesn't need to be a class is one, then you get caught up in naming things. Then you try to debug things to end up with an object that has 500 methods on it and you don't know where half of them came from because they were metaprogrammed in through 10 layers of indirection. Yesterday I tried upgrading to Rails 5 and gave up because I couldn't debug an outdated library in 6 hours without realizing I have to figure out what this library and ActiveSupport/Model is doing in order to make headway. Ain't nobody got time for that.
There is no good alternative without specifying the use case. In the main article he is looking into Elixir, Clojure and Haskell, because it fits what his working on.
I have the same sentiment with Rails. I built a big warehouse/delivery system (routing, etc) on 2006 with Rails 1.2.3. still being used up to this day. After that, I never looked at rails again. All of my web apps small and medium were made with Sinatra. After reading this article, I'll give a look to hanami.
I found it a bit strange, but not that strange. First, a "thesis" isn't too uncommon at the BA level. I majored in math at UCSC where this is an option. Can't say if this is something people do in CS, but I wouldn't be surprised.
Funny, his complaint about Ruby completely owning your app and the creators wanting it that way are the same that James Shore gives for Ember (also made by the Rails people) on TDJS.
This isn't a Rails gripe. He only seems to know Ruby/Rails and lashes out at it. Frameworks = Lots of abstraction. At least the abstractions in Rails aren't leaky.
solnic wrote the majority of DataMapper, its successor rom-rb, and the Virtus object modeling library. He knows much more than Rails and understands its problems.
Not to take away from solnic's many valuable contributions to open source, but I think it would be more accurate to say he was a heavy contributor to DataMapper rather than that he wrote the majority of it
Yes, I was on the core team between 2010-20#{hard-to-tell}. DataMapper was created by Sam Smoot and quickly taken over by Dan Kubb who did a crazy amount of work, practically rewriting it and introducing all the crucial features, and then maintained it for a couple of years with the help from a small group of people.
This is correct. It's probably hard to measure a person's total contribution to DataMapper because the gems are spread out across 20 to 30 repositories, not just dm-core.
I did maintain DM for a few years, but burnt out as there wasn't enough time to keep up with the community demands and work a full time job. There were a couple of years I effectively worked 40-60 hours a week on DM and only 5-10 on work; this wasn't tenable long term and burned me out.
The small dev team, of which solnic was a core member, are an amazing group and there's no way I could've maintained DM for even a fraction of the time I did without their support.
Rails developers are spending more time fighting Rails these days than improving it. I have the feeling that good coders have left the ROR ship and that Rails is now the framework for code-schools and learn-to-code bootcamps. It's a bit sad, but as long as Rails is tied to Basecamp I don't see any solutions.
The author is right, competition is important, the Rails/Merb scenario is the open-source version of Microsoft E.E.E
Really, even if it weren't tied to Basecamp I think if DHH remains as Rails' BDFL, we won't see the type of changes a lot of developers want to see. Which just means we need to highlight other frameworks like Hanami, Trailblazer, et al. in Ruby user groups.
The main difference is that Django does not rely on monkeypatching or magic methods, and for me the separation of concerns feels just natural in Django.
When I started with Rails it felt like magic, you didn't know why things worked.
...but these are the same people who made what Rails what it is today. What is concerning is their occupation of top seats on other hot projects (Rust, Elixir etc.).
Great article, and only 391 posts. Clearly I need to show up 24 hours after the fact and put in my two cents ;)
From what I've read here, it really doesn't sound like his time with rails is quite "up". It sounds like he has read the writing on the wall about rails, after a very long time with the framework (certainly longer and more involved than I've been, though I have used Rails quite a bit). This is different from realizing that a technology won't last "forever", it's a more distinct understanding that you see where things are going and how your current tools don't quite match up anymore.
But when my time with Rails is "up", that will mean that I have largely stopped using it. I'm mot counting maintenance, or perhaps the occasional one-off, I mean that if my time with a technology is "up", that means I don't use it anymore for day to day work.
I'd be interested in reading more from Piotr Solnica on this topic, because I'm in a similar spot. I don't see Rails as the ideal match for much of what I'm doing on the web, but I'm not anywhere near ready to give it up. I increasingly need much more interaction between the client and server than I get from the MVC approach, but I'm not sold on javascript front ends with a web service backend, at least not the way it's been presented now. For starters, I personally (yes, this is very much a personal trait) don't relish the idea of giving up Ruby to write most of my app in Javascript.
It's not just that I like ruby, I don't really like the idea of giving up the very rich set of languages I can choose from on the server side, or minimizing their role, in order to allow javascript to take over most of my programming work. I also feel that javascript front end frameworks are still a moving target, and I have a suspicion (like I said, I'm trying to sort this out) that when the dust settles, elaborate javascript front ends communicating with a web service written in something else won't be where I go next. I've read about some exciting new possible directions in this blog post, and I've read interesting things elsewhere (Volt, specifically, non-js languages transpiled to isomorphic javascript, more generally). It is all very exciting and promising, but is this the moment to give up on Rails, which works though I find myself increasingly shoehorning things into it? For me (again, just for me, everyone has a different set of interests and tasks), no, not yet.
Drawing on my past experience - the last time I felt this way was when web programming in java moved from the jdbc/servlets/html with libraries to struts, struts2, spring mvc, pico, spring di, jpa, hibernate, ibatis, wicket, tapestry and so forth. Looking back, I wish I'd had the conviction to stick with the old way of doing things even though I knew its days were numbered. Keep an eye on things, keep learning.
It sounds to me, from the end of this article, that this is what Piotr is doing. There are some good suggestions of where to go next, but I guess my question for the author is this: where are you going now? Is your time with rails "up" in the sense that you no longer have a substantial day to day use for it, that there is a new technology that you'll be working with now the way you worked with rails for 9+ years? Or is this more a situation where you see that your time with rails is ending - if not today, then certainly before long?
> Is your time with rails "up" in the sense that you no longer have a substantial day to day use for it
It means that I'm no longer interested in supporting Rails in my gems and I accept the fact it may hurt adoption of these gems. It also means that I will be actively working on an alternative stack that can be used instead of Rails. That's why I support Hanami project and experiment with dry-web project too (which is more like a toolkit for building your own stacks, already supports Roda, and we'll add support for Hanami too).
Apart from that I'll be spending less time on OSS and instead I'll be learning new languages. That's pretty much it.
Yes, that makes sense. I'm not sure I'd read anything by you until this post, but it sounds like you're talking more about where you are putting your framework development efforts, rather than what you'd use as a framework for the time being.
Framework development is pretty far from what I do (I rely on the efforts of people like you, honestly), but like I said, I can see the need. I'll probably be using something like what you're working on in the not too distant future. Best of luck with your efforts, I hope good things come of it.
What I'm trying to understand is why all these coding academy students are learning ruby on rails:
To make them have to go back to coding academy school in two years?
So that they maintain legacy codebases and don't touch the new shiny features the experienced engineers are working on until they get their training wheels off?
Because there is actual demand for ruby on rails despite all the hate and sunsetting of rails I see on HN?
You're making the mistake of assuming that what people talk about on HN/etc. is correlated with the state of the industry. Tech forums are always going to be focused on news and up-and-coming things, whether or not those up-and-coming things actually succeed at displacing the technologies they're aimed at displacing.
Also, and I'd love to see actual demographics on this but I know it's impossible, while lots of posters on HN/proggit/whatever are professionals, a lot of them are also high school or college students that are still coming at it from a hobbyist perspective (i.e., focused on what's new and exciting rather than engaged in the relatively boring world of getting paid to solve other people's problems). For that matter, a lot of the professionals approach their work from a hobbyist perspective (not necessarily a good thing for their customers).
I don't mean to sound like I'm down on hobbyists or students at all, just that different people care about different things, and just because most HN posters know a lot about the technologies they post about doesn't mean they know or care about the actual state of the industry (just their corner of it)(that applies to me too of course, we're all like the blind men and the elephant).
I can't speak for other cities because I haven't watched their job markets enough, but anecdotally in Chicago I've seen it break down mostly like this:
Big companies use enterprise Java unless they're stuck with a legacy VB/ASP/Coldfusion stack, with C# less commonly.
Fintech companies use a mix of C# and C++.
Small companies started before ~2010 use PHP, with Rails less commonly.
Small companies started after ~2010 use Rails, with hipster Java (Scala/Groovy/et al) less commonly.
I can only remember offhand seeing one job ad for a company using Sinatra instead of Rails for their Ruby stack.
HN is a place where people who are on or fancy themselves on the bleeding edge of tech congregate. It shouldn't be surprising that the opinion of that group, with the selection pressure it experiences, is dismissive of anything that's closer to "stable, mature project" than "hot new thing".
I can't speak for others, but I run a very small 'academy' alongside my business and I picked Rails for them to learn for the following reasons:
1. it's easy to get something up and working, which for a lot of students helps keep them motivated
2. Hartl's Ruby On Rails Tutorial. So far, it's the best book/course on how to get from knowing pretty much nothing to being able to work in a 'modern' dev setting (good editor, git, bitbucket, testing, backend, front-end, etc.).
3. if they want to actually get a job as a junior dev somewhere else, I've found that joining a startup or company that uses Rails is pretty easy. Much easier than jumping into a front-end React/Redux shop, for example.
I do not necessarily intend to use Rails actively with them in their first projects, and for those who can and want to I'll probably have to introduce them to the complexity and horrors of front-end javascript development, but at least with the Rails Tutorial they can get started by themselves and learn some degree of 'best practices'.
Ruby on Rails is mature, widely adopted, and reasonably stable. Just like the then-dominant Java web stack was when Rails was getting going. There can be expected to be Rails demand for some time; that doesn't mean its not losing currency, just that that isn't an instantaneous process.
Any decent coding school should teach the basics, so that learning a new framework or language is, if not trivial, then at least something you can pick up on your own.
A few years ago if you said anything negative about Rails, you were either pure evil or unbearably stupid; or both.
If you didn't fully embrace tableless design with CSS, despite the latter's glaring defeciencies for that task, it was the same treatment.
I also recall great pressure to adopt EJB with its deeply flawed architecture, etc.
I could go on, but the point is that there seems to come a time when all of these things face a moment of truth, wherein sober minds feel a little freer to speak aloud on their shortcomings. This frequently snowballs into all out backlash against the tech in favor of The Latest Shiny Thing.
The enforcers of what's hip and smart for everyone now move on to browbeating Developer Land with the new tech, and we all allow it to happen again. Why do we keep repeating this process when we've all seen the movie so many times?
Reminds me of "The programming language lifecycle"[1] (written in 2006), which essentially implies that the reason programmers continually search for new languages is simply out of a desire to 'distinguish' themselves from their peers, and have little to do with the actual merits of the languages in question.
QED. My hypothesis was confirmed, up to this point I was pretty sure he's been living under a rock possibly for decades complaining about how hard programming can sometimes be until I realized he is an IE user.
Show us a better solution without sacrificing everything that rails has given us and maybe we will listen.
Every time I hear someone complain about Rails, I ask myself if this person is really just complaining about how complex web dev is. I've never seen a complaint that passed this smell test.
Yes, Rails abstracts over a veritable shit-ton of complicated domains. The problem is, that complexity isn't going to go away if you decide not to use those abstractions. Every single one of that laundry-list of things that ActiveRecord::Base.create does will have to be implemented again, by you, badly, if you choose to roll your own.
It boggles my mind why developers don't take the web seriously as a domain, like it's not real coding or something. It's the worst instance of bike-shedding I've ever seen.
Rails isn't perfect, by any means. But Rails is not a black box, it's all free software. You are more than free to re-implement anything Rails does yourself and release it as a gem. Modularity and flexibility are built right in. It seems incredibly odd to leave Rails over this. For what, Java? Unbelievable.