LOL at the idea that every Rails programmer will be switching to Clojure or Elixir! While they might be interesting languages (particularly Elixir) I don't see any 10x advantages their web stacks have over Rails for the typical "majestic monolith" use case.
Re. EventMachine: As I understood DHH's speech, the idea is that ActionCable abstracts all the messiness around EventMachine, Websockets, Rack and threads. We won't know until some ActionCable code is released but it sure didn't look complicated.
It does seem odd that -api takes years to get in, but ActionCable gets a go-straight-to-core pass without any community review first. It certainly seems like a weakness in the process, which should be addressed, although I'd agree with the eventual result & priorities. -api probably isn't something I'd ever use: even if I eventually created an API-only app, I'd probably have started from a regular Rails app and gradually optimised things out.
Edited to add: I'm actually quite bullish on TurboLinks 3 if it can help me to avoid ever having to write a Javascript MVC app again. It's not so much that these apps are hard to write, it's that they're freaking hard to debug, particularly in the hands of users.
> the idea that every Rails programmer will be switching to Clojure or Elixir! [...] I don't see any 10x advantages [...]
I do. While I cannot speak for Clojure and Elixir, I can speak for Haskell, which I have moved to from Rails.
10x for me is:
1. A 70MB all-in binary to deploy, using 1-3MB of memory when running (has a build in HTTP(S) server), responding in 2-10ms to my requests. Compare that to 700-1500MB of gems, using hundreds of MB while running, serving requests in 50-200ms... More then 10x! And my framework of choice (Yesod) consists of 23kLOC, where Rails has 210kLOC (source: openhub.net)... Another 10x!
2. Less bugs when growing the codebase; "strong compile time guarantees" is now my main weapon when fighting maintenance curve.
Back in my Rails days I'd say "typing is a very narrow form of automated testing", which given my exposure to C++/Java was defendable opinion.
Now I say "strong typing is a wonderful test suite you get for free and automatically stays up to date". Not that it replaces tests; but it literally a wonder how Haskell's HM-typesystem it rejects broken code at compile time.
I'm not sure that reduction in code size or better performance is necessarily the 10x metric you want to go for. Maybe in some cases, of course, but 'my framework has fewer lines of code' is absolutely irrelevant to the delivered value of a service, for example.
Does using Yesod mean that you can deliver code that better meets your goals? In a business environment, that might mean easier maintenance, or better performance. Equally, it might mean faster development times, where maintenance is less of a priority. If it meets your goals then awesome! If it doesn't, then there are lots of other things you can use – including Rails.
Often goals are: crank out X with programmers Y on deadline Z. I assume the client has no language/framework preference.
If X is a greenfield webapp and Y are not Haskellists yet (language has a steeper learning curve then, for instance, Ruby), and Z is very soon then I will probably choose Rails (given that programmers have some experience with dynamic languages and/MVC framework, and I'm fluent with Rails).
Notice that maintenance costs are not a factor. This is often not accounted for, but a large part of a webapp's costs are maintenance: and this is where Haskell shines: maintenance and refactoring.
Let's say I'm starting up, then low maintenance costs are of PRIME importance. You want to be able to keep adding/improving with a small team, not being bogged down by an endless stream of bugs only found on production -- nothing ruins flow like that.
Strong typing on the web has been an intractable problem for me so far. Sure, I can have strong typing in my server-side code. But so many errors result from the interaction between the server, CSS, HTML, and JS. For example, you define a route at the path `/apples` but send an AJAX request to `/oranges` instead. Or you write `<div class="apples">` but query it with `div.oranges` instead. These are very much like type errors or name errors, except they occur at the boundaries of languages and processes.
Have you worked out a way to catch these sorts of things at compile time? If not, do you think it's possible in the framework of the future?
The examples you give don't seem to be typing problems, they seem to be wrong-value problems. They might incidentally also involve typing issues (e.g., "/oranges" might not exist or might be an endpoint with a different signature than "/apples"), but that doesn't seem to be the central problem in any of the examples.
> Have you worked out a way to catch these sorts of things at compile time? If not, do you think it's possible in the framework of the future?
To the extent that they are typing problems, it would seem conceptually possible to catch them through a strongly typed language and framework that abstracts all the underlying technologies and compiles to a combination of backend executable(s), and front-end HTML, JS, and CSS, and includes all the routing for both ends.
Actually building such a beast would seem to be a non-trivial engineering challenge.
> The examples you give don't seem to be typing problems, they seem to be wrong-value problems.
They're like type or name errors because the "apple" and "orange" here are like identifiers, not data. Sure, to the browser, they're data. But in terms of the structure of the web application, they're identifiers like variables, function names, or types.
For example, the HTTP endpoint "/apples?count=5" is like a function "apples(int count)."
> Actually building such a beast would seem to be a non-trivial engineering challenge.
It certainly would. That's why I'm wondering if you consider it possible.
"[I]t would seem conceptually possible to catch them through a strongly typed language and framework that abstracts all the underlying technologies and compiles to a combination of backend executable(s), and front-end HTML, JS, and CSS, and includes all the routing for both ends"
That would certainly do it, but I think all you need is some definition of interface that you can check your code against on both sides. This could be generated by one side and consumed by the other, or produced directly by the programmer(s) and consumed by both. You would need some means of actually checking your code against the specification on the consuming side(s), but they needn't be part of some broader framework (beyond the trivial sense in which they already are).
Sure, you can do that; but the problem is that you then have to worry about type system mismatches between the interface definition language, and the back- and front-end application languages.
There have been lots of things that do something like this: SOAP and the associated WS-* standards are probably the best known.
Haskell has some typesafe template languages. I'm not a huge fan of them, tbh, as they're kind of rough at the moment.
More promising in my opinion is the fact that Javascript is becoming an increasingly popular backend for Haskell via GHCjs which will give a great space for building type-checked front ends which have all the guarantees you like. For instance, type checked routes already exist which prevent you from writing the wrong endpoints or sending invalid typed data to them... these can be transparently extended to the frontend without much more difficulty.
While a bit rough around the edges, the full type safe server-client stack can be done in Scala with Play[0] + Scala.js[1] + ScalaCSS[2]
I say rough because despite Scala.js' fantastic performance characteristics, you're looking at 100kb file size off the bat; from there generated code size is reasonable, but that's a pretty big hit, particularly for cache challenged mobile clients.
Otherwise, being able to tie Play's type safe reverse routing into the client is a big win. Previously with GruntJS + Coffeescript approach I'd get small file size, but complete lack of safety; just winging it with `routes.user.maybeNotExist(id)`.
> errors result from the interaction between the server, CSS, HTML, and JS
this may be true, but I'm not sure spending resources trying to solve those problems, are the best use of resources?
I would rather be happy with a strict separation between the front-end and the server than try and deal with such an impedance mismatch and the framework cruft that generates.
I guess it just seems overly ambitious to me.. finding the right abstraction for the server is difficult enough without polluting it with the front-end.
It seems to me people are very productive in other languages that don't tightly bind the front-end code to the server; why spend time solving problems are are more incidental than essential?
> I guess it just seems overly ambitious to me.. finding the right abstraction for the server is difficult enough without polluting it with the front-end.
Certainly. That's why I'm skeptical that this will ever happen.
> why spend time solving problems are are more incidental than essential?
I wouldn't characterize these kinds of errors as incidental, inasmuch as they account for a very high percentage of the web app bugs I've encountered.
Designers of languages like Rust and Haskell noted that null pointer dereferences were the single largest class of errors in other languages. Thus, the designers chose to make null pointer dereferences impossible at the language level. With that choice, they turned a huge number of run-time errors, which developers often miss, into compile-time errors, which developers cannot ignore. This has proven itself beneficial to productivity and software quality.
So too here: If I'm correct that client-side type and name errors constitute a large fraction of all web app errors, then catching them at compile time will be a big win.
But again, I don't know how feasible this is. Nor do I know whether it would involve compiling from a type-safe language to HTML/CSS/JS or just static analysis of raw HTML/CSS/JS.
the logic of your analysis is sound. I suppose I'm just not sure that client-side type and name errors constitute a large fraction of all web app errors.
Anecdotally, the team I am on doesn't have these issues (we certainly have other issues), but I could see them being important to prevent on certain projects.
When using Haskell it feels like I more clearly have to deal with those not-strongly-types-environment issues. I have to write some interface code (which surely takes some "extra" time) to pull un-strong into Haskell; but then the unstronglyness is represented strongly in Haskell types and has to be dealt with accordingly. This reduces funny bugs that may otherwise arise when overseeing corner cases.
Main hometaker: it's like in Haskell I have to do more work up-front, to enjoy much better productivity down the road.
But isn't that like saying a healthy person can run 10x faster than someone with a limp?
For context, my background has been predominantly in a dynamic language, but now I've drank all the typed kool-aid, so I'm sold, as it seems you are as well.
So we're essentially saying typed is 10x better than dynamic, but was dynamic ever really a good place to start with?
Dynamic has a nice exploratory quality. It pushes off the moment of reckoning, but sometimes you need that if you're sketching an idea in code. It was good for me when I first learned, and I think that's still true now. For "in the large" systems it's basically required that stuff gets a bit more gooshy and dynamic-y and interact in an indirect, protocol-driven fashion.
But when you actually have a specific piece of engineering in mind, it's nowhere near as helpful - it tends to solve things that could probably be solved more soundly with compile-time constructs. But there's a process of building up your understanding to where you can actually have confidence in what you're building, which isn't reached so easily. Having the compiler fail your code before it can run is very "magical" in that sense.
As a Haskell programmer who has also come from Rails -- I'm a Rails developer now -- and who is also interested in writing a web app in Haskell, I'm very interested in your experiences. Are you on any forums or online communities that have helped you in developing a Haskell web app?
No, just started to use Yesod to do simple things. Then moved on to hard things. Sure I'm on relevant mailinglists and /r/haskell; but apart form that no special community forum helped me.
Well, I haven't started my web app yet. Right now I'm finishing up a Haskell app that plays Connect Four: maybe that could be the backend for a web app.
It looks like you're using Yesod. What resources did you use to learn it -- I think there's a Yesod book, was that helpful? Did you consider any other Haskell frameworks? What did you find hard about writing an app using Yesod? Do you think it took less time to write the app than it would have given a similar level of knowledge about Ruby/Rails?
Although I'm way faster writing Haskell than I was, say, six months ago, I feel I'm still really slow compared to how fast I can code in Ruby. Having said that, when I write a Haskell program, the only errors are usually logic errors, not process errors. NoMethodError (an unexpected nil) must be one of the most common Ruby/Rails errors. It's really great to just not get that anymore. :-)
> Now I say "strong typing is a wonderful test suite you get for free and automatically stays up to date". Not that it replaces tests; but it literally a wonder how Haskell's HM-typesystem it rejects broken code at compile time.
But in practice I've come to the idea it's a meaningless distinction if you're not going to bother to declare the types on your methods/functions.
Instances may be Strongly typed in Ruby. Methods are not. So you get almost none of the benefit. It's like Types only exist in Ruby to support Mixins and inheritance chains.
Prefer Composition over Inheritance right? But what if through Composition you effectively lost all your Type information? That's the issue Ruby presents.
> Instances may be Strongly typed in Ruby. Methods are not.
Sure they are, just not all of them:
[].first('wat') # => TypeError: no implicit conversion of String into Integer
What Ruby lacks is _static typing_ and compile time checks of these types.
Instead we have runtime checks in a few places.
> Prefer Composition over Inheritance right? But what if through Composition you
> effectively lost all your Type information? That's the issue Ruby presents.
This is mainly advocated because subclassing core classes (e.g. Array) can lead
to weird behaviour. For example:
class MyArray < Array
end
m = MyArray.new([10, 20, 30])
p m.map { |number| number * 2 }.class # => Array
Here one would probably expect an instance of MyArray to be returned, but
instead we get a vanilla Array.
> This is mainly advocated because subclassing core classes (e.g. Array) can lead to weird behaviour
No. It is advocated because it produces simpler code in the long term in most cases. It is a quite different question to inheritance from core classes.
Using introspection in Ruby is generally against convention. There's no reason to care about the class name if it #responds_to? the method you care about calling.
That's not an example of a strongly typed method in Ruby. That's an example of an assertion (most likely implemented in C).
Though in hindsight you're right anyways. Methods define an implicit type for the arguments they operate over. It's just you don't know what it is without reading the whole method. Which I think gets to "expressiveness".
I agree with the push to get people on the same page with regards to terminology. However, this comment would be far more useful if it suggested an alternate term for the real difference the parent was intending to indicate, or made explicit a claim that the difference was in fact not real.
I think one has to bend backward in order to defend that claim; but you probably have some ground somewhere since the term "strongly" is weakly defined :)
By strong _I_ meant HM-typesystem strong, or stronger... (for instance I dont think the NullPointerException-king Java is strongly types either -- though it is strictly typed -- again a matter of personal definition)
Interestingly, we had a couple of Clojure experiments.
Takeaway was that there were some benefits in terms of performance and maintenance, but they weren't worth the tradeoff in expressivity and increased developer time.
There's no reason that Rails should be restricted to 'monorail' or monolithic apps. We've had great success writing what are essentially microservices in Rails. Code is easy to read, easy to maintain, and performs well. It's hard to find any compelling reason to use another toolset under those circumstances!
I guess just another example of different strokes for different folks. For us developer time decreased, and expressivity increased.
I wasn't suggesting that rails shouldn't be used for microservices, we actually have a number of rails microservices in production as well.
I was more stating that I agree with OP in that if I were to write a monorail style application today, I would use ruby/rails over clojure. I was also pointing out that if you are moving to more of a SOA/microservices framework that we've had great experience with clojure, and that it's worth looking at.
I'm a huge fan of rails, and have been using it since pre-1.0. I think as we look back on this period in time, we're only going to appreciate rails more and more for really making self / low funded startups viable.
A great point, of course. That's why we had a crack at Clojure in the first place!
Basically, it's great to have a diversity of freely-available, open-source tools that can be used for such a wide variety of different tasks. I expect the 'my toolset is better than your toolset' nonsense will always be with us, and while it's useful to discuss some of the pros and cons, we should all bear in mind that most tools are awesome :)
If you feel Clojure is less expressive than Ruby, you're not good enough at Clojure yet. I'm not saying you have to prefer Clojure's syntax, and Ruby probably has more libraries for a lot of things you want to do. Going from Ruby to Clojure may be a productivity tradeoff for you and your team, but objectively it's not an expressivity tradeoff. Clojure has a bit more expressive power than Ruby.
In Ruby you can't express the concept of an empty List through a Type.
When comparing statically typed languages to non, that's generally what "expressiveness" means to me. Any idea can be expressed through expressions in a turing complete language right? That's not a useful metric.
In Ruby a method's type-signature expresses almost nothing for example.
def f(a,b)
Does the method side-effect? What types are a or b? Are they the same type? Does the method mutate the arguments? Return a new value? What sort of values might it possibly return?
In Ruby you can't express any of these things outside of naming conventions (that are entirely useless for answering any of these questions to any tooling).
Compare that to Scala:
def f(a: Int, b: Int): Int
Does the method side-effect? Almost certainly not (but it would typically depend on the containing Type). What are the types of a and b? Integers. What does it return? An Integer. Does it mutate the arguments? No; they're immutable. Is it possible for the method to return anything else? Throw an exception perhaps? That would be unexpected. Otherwise you'd write it to return a Try[Int], so you can assume more about the author's intent here.
Well now you're getting into statically vs dynamically typed, which doesn't apply to this conversation because both Ruby and Clojure are dynamically typed.
But in a statically typed language like Scala or Haskell, you can use the typechecker to express proofs about program correctness. That is a form of "expressiveness" that doesn't really exist in Ruby or Clojure (unless you use core.typed).
There's nothing about dynamic typing that prevents declaring types right? Because in Ruby you while you can extend an instance, you can not taketh away Types from it.
IOW, Ruby could use the Scala syntax I wrote, and still be just as Dynamic. You're already constrained by how you use that type within your method. You're just not expressing it concisely since you have to read the method to understand the implicit Type it's operating on.
In practice a lot of this gets naturally conflated though. Which I think you were getting at.
But if we're going to limit ourselves to functions with undeclared types, I guess I'd point to Clojure's partial as something you can't really express with Ruby. Or Pattern Matching in Elixer.
Well, Ruby is duck-typed with dynamic/late dispatch, so method receivers are not known ahead of time. When I call `foo.bar`, it does a dynamic lookup in the class hierarchy at runtime to see which class implements the `bar` method, and the result can be changed at runtime. So although you could theoretically declare types in Ruby, it would just be documentation. You'll still get the type errors at runtime because there's no ahead-of-time typechecking happening.
With Clojure you can actually compile your modules while developing them and discover certain classes of type errors ahead of time, so something like core.typed actually makes sense because you can run the typechecker over your code instead of having to run a separate test suite.
The main type error you always have to worry about in both languages, though, is accidentally calling functions/methods on nil at runtime. Of course that applies to null in Java too...
> You'll still get the type errors at runtime because there's no ahead-of-time typechecking happening.
That doesn't mean it's just documentation though. It could tell you that something is happening you didn't expect. Like passing a Role where you expected a User. (And if you wanted to operate on both interchangeably you shoulda put an interface on it.)
> The main type error you always have to worry about in both languages, though, is accidentally calling functions/methods on nil at runtime.
Agreed. Option/Maybe types FTW. The ?-operators sometimes presented as a solution feel very half-baked in comparison (they don't return a new type so just because you remembered to use it on line 10 doesn't mean anything to lines 20, 37 and 82).
Expressivity to me is generally about code size, for a given problem does the language allow a concise solution to be expressed?
The more concise the solution the more expressive the language.
A language that supports 4*4 is more expressive than a language that only supports 4+4+4+4, languages that require more type information to be expressed are in general less expressive.
where IAddition is an interface requiring the infix + operator to be defined, and the subsequent definition of said interface, where as a more expressive language will deduce the interface from the function.
An empty List would have to be a List first. So an Instance. But at that point you'd be facing a significant challenge to ensure it's both Immutable and still a List (or Array, whatever).
But your definition of "expressive" is (IMO) backwards. Because the first example only actually expresses a label that only has meaning because you give it. It doesn't tell you if the method prints to STDOUT, concats a String, adds an Int, adds a Float to a Decimal (and how that would be achieved), etc.
All that, and Ruby is (IME) more verbose than Scala (and I suspect Elixir, Erlang, Clojure, etc) for any real non-trivial example.
I think the biggest reason would be Clojure's macro system. The code itself is an abstract syntax tree that you can rewrite in arbitrary fashion at macro expansion time. There's a good example here of how Clojure's macros are more powerful/expressive than Ruby's instance_eval and class_eval: http://daveyarwood.github.io/2014/07/09/whys-guide-to-ruby-i...
Not sure what examples the author was thinking of but functional lisps tend to be extremely expressive just because of their nature. If there is expressiveness you are missing the language can be molded in ways that are simply not possible in non-homoiconic languages.
> LOL at the idea that every Rails programmer will be switching to Clojure or Elixir!
I meant those as examples based on what I see around me. That's exactly my agony, I don't know what is next and, if I did, I would be learning it already. At this point, I just feel it is not Rails.
> Re. EventMachine: As I understood DHH's speech, the idea is that ActionCable abstracts all the messiness around EventMachine, Websockets, Rack and threads
If you are using Event Machine you can't abstract away from it. You need to do all I/O using Event Machine aware mechanisms. You can get rid of callbacks by using fibers but you are still required to use an API specific to Event Machine. For example, you can't use File.read to read a file as that will block your event loop.
Nginx HTTP Push Module seems to much better solution than EventMachine. So Nginx keeps opened sockets and a Rails app sends messages via ordinary HTTP.
I'm also wary of handling websockets from Ruby, which is demonstrably ill suited for any kind of high concurrency networking (been there, got the t-shirt).
Since most people already run nginx in their stack anyway I don't see the advantage of sticking with a Ruby-based solution that is almost guaranteed to be inferior on every metric.
You are confusing the real need to use EM aware mechanisms with a not-real inability to use abstractions over EM itself. Those are two different issues.
As a general comparison, when it comes to building server-side web apps Rails is preferable to Clojure. But for the web stacks / ecosystems as a whole Clojure wins by about 10x. The main reason for this is ClojureScript. For those who aren't familiar ClojureScript is a Clojure->Javascript compiler that lets you write your UI code in Clojure and drastically simplifies Javascript codebases. Given how much time is consumed writing UI code in modern web app development, the benefits that ClojureScript gives you over the turbolinks/js framework of your choice approach that Rails emphasizes cannot be overstated.
I've found that writing web-apps/api's in Clojure, using ClojureScript on the front-end, then using Rails to write small services where you want to take advantage of some of the great Ruby libraries is the way to go. You get the best of both worlds.
> As a general comparison, when it comes to building
> server-side web apps Rails is preferable to Clojure.
Do you generally prefer a Rails-style framework over microframeworks?
I went from full-time Rails to full-time Clojure, and I would use Clojure over Rails these days for the same reason I'd use Express/Koa (Node) or Flask (Python) over Rails.
I'm curious (as someone who's only dabbled in Clojure): could you write an Ember app in ClojureScript (or Angular/React/Knockout)? Is it like Coffeescript---i.e. just a compiler? If you wanted to build a SPA in ClojureScript, how would you approach it?
You can write Ember/Angular/Knockout etc... in ClojureScript (I've done it before) but it comes out feeling weird and unnatural. You always feel like you're trying to fit a square peg into a round hole.
The preferred solution is to use a ClojureScript wrapper around ReactJS and write your own event handling logic. I'm a big fan of the Reagent library which wraps React with a dead simple API. I believe it's the best UI library ever created and I wish more people knew about it.
The big idea is that you store your UI state as one single Clojure data structure. A Reagent component is just a Clojure function that takes the necessary sub-section of the UI state as an argument and returns a Clojure data structure that represents the HTML code that it wants to render. An example of this would be the following component that displays a list of items.
Then whenever you change the state of 'items', the component will automatically re-render and inject the new DOM as necessary using React's diffing algorithm for high performance. The key thing here is that there is no Javascript framework to learn. All you do is manipulate Clojure data with Clojure functions and use React to render it. There's no 'Ember.component.extend' or 'ng-repeat' to worry about. You spend very little time looking through documentation. The Clojure langauge IS your framework, it's really incredible.
This is the strongest argument for Clojure in web programming. HTML (and all XML-based UI frameworks) are just tree data structures, so it's trivial to represent them as s-expressions and manipulate them using normal Clojure code, then render them to HTML at the last moment, instead of having to use different syntax to inject code into templates. Lisp/Scheme languages are uniquely well-suited to the problem domain.
But lisp/Clojure actually holds no real advantage in this area. Javascript, Ruby, Perl, Python, etc. all have built in lists and list-of-lists (ie, trees). They all have map, filter, etc. to manipulate their native lists and hashes/objects/maps in similar ways to lisp/Clojure.
http://jsml.org is just one example (Javascript). I know similar things exist in Perl and I'm sure Ruby and Python have them as well. If not, it's literally something you can write in a couple hours.
Thanks for the link, that is interesting. While I don't doubt that it's possible to create something similar to https://github.com/weavejester/hiccup in Ruby and Python as well, I am not aware of existing libraries for it and it's definitely not considered the "idiomatic" way to generate HTML in those languages. They both skew heavily toward template languages that are some variation on <div>{{foo.bar}}</div> and require special syntax, which in turn requires editor support for syntax highlighting and such. And Javascript has been the same way until recently--Angular and Ember are template-based by default. And while JSML looks pretty good, I think the other alternative Javascript is trending toward is the JSX approach taken by React, which is basically just backwards templating, and requires a precompiler pass.
Meanwhile with Clojure, because it's homoiconic (code is data and data is code), all you need to implement a DSL for generating HTML is basic functions and macros (which are just functions that process your source code), no special new syntax is necessary. In fact if browsers used Clojure (or any other Lisp/Scheme dialect) as their native scripting language, there'd be no reason for HTML, XML, JSON, or CSS to exist at all in the first place. They could all just be code.
You'd use a React wrapper such as Om[1] or Reagent[2]. These take advantage of React's DOM diffing and pair it with ClojureScript's immutable data structures.
Eventmachine itself is in kinda unmaintained state. Newer projects are starting with Celluloid and stuff, which arguably offers much easier way to reason about concurrency. I am not sure why they would pick EM as base for ActionCable.
I always wondered why Rails programmers prefer Clojure/Elixir over Scala, Scala syntax and concept seems to me much more translatable to Ruby than Clojure. In Scala, just like in Ruby 1 + 1 is 1.+(1), you have a scala version of method_missing, duck typing, pimp my library etc... Is there a reason why Rubists prefer a completely different paradigm such as Clojure?
I dove into Scala before Clojure because lisp was so alien to me. After a couple months of Scala, I still felt like I didn't know where to begin with a blank slate, though I was eventually productive.
When I finally gave Clojure a shot, I was building things my first week. Kinda like my first experience with Ruby.
Clojure felt like a better Ruby to me. The aesthetics that drew me to Ruby were improved in Clojure.
> Is there a reason why Rubists prefer a completely different
> paradigm such as Clojure?
The leap from Ruby to Scala is a larger gulf than Ruby to Clojure, though it's not obvious at a glance.
For me, Scala is a great language that continues to present me with good surprises (i.e. literal curry syntax). The only issue for me is the JVM and the package/namespace system (not to mention mvn, sbt).
In this way, Erlang/Elixir is more enjoyable for me. I much prefer the Erlang module system (Python and Node.js get a special mention here as well) vs. what you get with Ruby, PHP, Java, etc.
I got interested in Clojure because I felt I needed to learn something LISPy. Similarly, I got interested in Elixir because I felt I needed to learn Erlang. I have yet to have any kind of similar motivation for Scala.
These are not good reasons, but they are my reasons.
Having moved to Elixir from Ruby (among other languages), I can say that Elixir's syntax is pretty natural coming from the Ruby world. That's probably no coincidence, considering that its creator (Jose Valim) is a Rails contributor.
Elixir/Erlang/OTP has a lot of useful stuff to say about testing, deployment, reliability, maintenance, and code quality. Ruby does too, but is constrained in various ways.
Honestly, websockets-as-first-class-citizen plus the E/E/O process model is a huge win, and one that Rails just won't have going for it.
That doesn't make Rails obsolete, but it's outside of its comfort zone compared to the new/old tech.
> Unfortunately, we don’t have better options in Ruby for working with websockets.
We do! Celluloid (the actor model) is vastly superior to EventMachine in my opinion. It fits much better to Ruby's OOP style and I suspect would integrate into Rails very cleanly. I am positive that bringing any EventMachine technology into the Rails stack would be a mistake.
I am saying that with a bit of a bias as I have written my own celluloid-websocket[0] gem that comes with a Rack adapter. But I wrote it because I put a project using EventMachine websockets into production and was not happy with it. Now in a new project I can just hook up the celluloid-websockets Rack app and run it using `passenger start` or any of the Rack application servers.
Even though so many people seem to flock to Node.JS for these kinds of servers, the fact that as a language Ruby is superior to Javascript remains, even if Javascript VMs are a hundred times as fast. As long as Node.JS is run on standards compliant VM's things like promises are just lipstick on the callback hell pig. You can write clean and understandable Ruby to solve any problem, including Websocket servers. We as the Ruby community were just late to the asynchronous I/O party. Now Celluloid is production ready, there's really no reason (except for performance of course) for a Ruby developer to write Javascript on the server side.
(sorry for my extreme opinions, if you want a more nuanced deliberation on a point just ask ;))
A year ago we benchmarked Celluloid and Event Machine. Celluloid was much better... on JRuby. Event Machine was better on CRuby based on our tests and, since we couldn't migrate to the JVM due to other factors, we ended-up stuck with CRuby and Event Machine.
>> the fact that as a language Ruby is superior to Javascript remains, even if Javascript VMs are a hundred times as fast.
As someone who frequently switches between Ruby/Rails and NodeJS (sometimes in the same day), I wonder about this statement (err, fact).
You mentioned that the Ruby language is superior and that this is a "fact". What about the Ruby (I know Node isn't really a language, but for the sake of discussion, Node,JS,npm) is substantially better that the speed trade-off is worth it (besides familiarity)?
In my case, I'm familiar with both, and I prefer Node,JS,npm. Node,JS,npm are definitely not perfect, yet still, I like it over Rails,Ruby,Gems/Bundler.
I'm not looking to "win" here; I'm just very curious now given your assertion.
> What about the Ruby (I know Node isn't really a language, but for the sake of discussion, Node,JS,npm) is substantially better that the speed trade-off is worth it (besides familiarity)?
It's a bit stupid, it's hard for me to even consider the idea of Javascript being in the same category as Ruby. Of course, with Node.JS existing it's totally fair to bunch them in the same category, they're both server side scripting languages.
Ruby was designed from scratch to be a perfect generic scripting language, merging the OO concepts of Smalltalk with the power and unix-friendliness of Perl. No constraints, just an implementation of a programmers dream.
Javascript on the other hand was designed to be a language ran in the browser, with a tightly controlled I/O system a very domain specific standard library and a very short schedule. It's got warts and plain mistakes, it took decades for people to see past them and value Javascript for its redeeming qualities. The redeeming qualities being first class functions and the unexpectedly useful asynchronous I/O model.
You state that you like Node.JS over Rails. I would hesitantly agree. Rails isn't of this time anymore, they made the mistake of not embracing JSON APIs as the future of web development, and are foolishly continuing work on serving HTML. That both Rails-API and ActionCable were not in Rails 4 demonstrates they are simply behind the times. At the time that it became clear JSON APIs and Push protocols would become important people looked around and saw the Ruby ecosystem simply had nothing to offer. Rails wasn't serving them, and all other Ruby projects were either small, not production ready and in either case had no community following. It was a perfect moment for Node.JS which put the modern web right up front. At least, that's how I view that history.
Of course, 90% of web applications being developed today are not 100% single page apps with JSON and websocket backends, so Rails isn't quite dead yet. But perhaps if you're to looking to build such a modern app the Ruby ecosystem isn't the ideal place to look for it anymore. That doesn't mean it's not viable anymore. I wrote celluloid-websocket in a few dozen lines, it basically connects Faye's websocket protocol implementation with Arcieri's Celluloid and Rack.
I really want to write half a book more about why I think Ruby is so much better than Javascript, but it's getting late so you'll have to excuse me.
>> ...it's hard for me to even consider the idea of Javascript being in the same category as Ruby.
Indeed. I think anyone would agree...they were not built for the same purpose; however, let's set some expectations here. As it relates to backend JSON APIs, what is better about Ruby/Bundler?
>> Ruby was designed from scratch to be a perfect...dream
OK, that's fine. Though, I've never heard of a proven perfect language/platform, regardless of intention.
>> I really want to write half a book more about why I think Ruby is so much better than Javascript...
Please, no book, but I would be happy to read one concrete example of why Ruby/Bundler is substantially better hands down. Of course, you are free to argue that you just don't like JS. I'd be fine with reading that, but I'm still curious to see a real example. I'm willing to accept that I may be wrong, but without proof, we can't get there.
Yes, Ruby is a nice looking language; still, I have not come across any proof that writing, maintaining, and deploying Ruby/Bundler is substantially better than writing, maintaining, and deploying Node/npm for backend JSON APIs especially given the gratis performance benefit and ease-of-use of Node/npm.
The same or better result with lower overhead and better performance. Before I ever wrote a line of JS intended to be executed via Node.JS, I actually thought Ruby was better as well :)
*
NOTE: I am quite aware that some Haskell lover is probably laughing and sticking their nose up at this entire conversation. That is perfectly fine because I'm willing to bet they can actually provide the concrete example I am looking for.
> Please, no book, but I would be happy to read one concrete example of why Ruby/Bundler is substantially better hands down.
One illustrative example might be the existance of Celluloid. The idea that you as a developer of Ruby apps can swap out the I/O system to something that's arguable better than what what the default style is. The reason Javascript can't do that is because it doesn't have synchronous I/O, nor multithreading, it's simply lacking those primitives.
I don't like the callback style, and I'm not entirely sold on promises.
In any case both those 'issues' might be close to fundamental differences between Ruby and Javascript but if I'm honest, this is going to sound like I'm back pedalling, but in real measurable terms they won't affect the quality of your codebase. I don't think porting a library from Javascript to Ruby would solve any real problem (as Haskell would), and it would result in your library being slower.
The dozens of little things that make Ruby a more pleasant language, they are what keeps me on the Ruby side for most projects.
> I am quite aware that some Haskell lover is probably laughing and sticking their nose up at this entire conversation.
Haha, I'm actually also a Haskell programmer. My top 3 is Ruby, Haskell, C# ;) I do Ruby and CoffeeScript for a living, build games in C# as a hobby and am building a C compiler in Haskell as my secret plot to take over the world. I have a sideproject that's a REST API in Haskell as well, but I'm not 100% convinced yet that Haskell is right for that.
Easy proofs for Haskell superiority: You can compile into a static executable. You can make the typesystem enforce the correctness of your user input parsing (this is crazy effective in JSON Apis, so effective that I now use Grape in Ruby to do sort of the same thing). Its lack of OO and focus on processing data leads to very clean architecture. Its level of abstraction is so crazy that they can actually swap out their entire I/O system for another one without changing any application interfaces, this one blew my mind, it's the change that makes GHC 7.8 run the Warp webserver twice as fast. They actually changed it so the 'fork' system call does not actually spawn a new thread, it spawns a fiber that's run in an event loop type system, and changed all the I/O functions to use asynchronous I/O on that event loop. All of this without changing a line in Warp, they just transparently made every traditional Haskell use modern I/O principles. Academics man, they're smart ;)
C# is cool because it manages to stay clean, fast and structured even though it's super powerful and implements almost every paradigm known to man. It's a statically typed compiled language with near native performance, yet code in it is nearly as succinct as Ruby. If I'd jump ship from Ruby because of performance reasons, it'd be to C#, not Node.js. Provided it runs smoothly on linux of course ;)
> Haha, I'm actually also a Haskell programmer...building a C compiler in Haskell as my secret plot to take over the world.
Haha; I got a kick out of reading that. Nice!
> I have a sideproject that's a REST API in Haskell as well, but I'm not 100% convinced yet that Haskell is right for that.
I'd be interested in what you are finding there. I have been wondering if I should start moving toward Haskell or Erlang/Elixir. So far, I've spend much more time with Erlang and Elixir and I'm liking it.
What has given you grief on the Haskell side?
> Easy proofs for Haskell superiority...
Wow! I had no idea Haskell was so flexible. Perhaps I really should spend a bit more time there. I've never read anywhere else about this level of flexibility in Haskell.
If nothing else, this conversation was well worth it just for that...thanks :)
> I have been wondering if I should start moving toward Haskell or Erlang/Elixir. So far, I've spend much more time with Erlang and Elixir and I'm liking it.
I wouldn't know about that, I only took a glance at Erlang, didn't really like the syntax but Elixir seems really pretty (Rubyist speaking of course ;)). I'm also a bit put off by how Erlang has distributedness integrated in its language, I didn't really try it out so take this with a grain of salt, but I have the feeling that it makes it more of a domain specific language, and it perhaps would be in the way of generic programming. I also had to deal a lot with a misbehaving RabbitMQ at work, so I might have channeled my incompetence into a opinion of Erlang :P
> What has given you grief on the Haskell side?
Well, both web projects I did using the Scotty framework, which I adore. The first was a web adaptation of a school project, you can take a look here[0], I like that a lot. But the second project was a docker container provisioning tool, and it had to do a bunch of stream processing and such. It's not that the libraries are bad, but there's a lot of research being done and there's 5 different popular I/O stream libraries, with various amounts of super high level abstractions, it just slowed me down a lot having to research all of it and dealing with some really high level Haskell.
That's one down side of Haskell. There's an easy way to do things, with nice pure functions and a I/O monad here and there. And there's the hard way of Haskell with monad transformers and generic type classes and what have you. You can easily avoid the hard stuff, but if you get sucked in you'll feel like a total dumbass and it'll cost you time and motivation :P
> If nothing else, this conversation was well worth it just for that...thanks :)
No problem, thanks for making me back up my ludicrous opinions ;)
As someone who's done the bulk of the work for Action Cable, I wanted to clear the confusion re: cable and eventmachine. Cable is currently using EventMachine because it uses faye-websocket for dealing with websockets. And Faye is one of the very few well maintained ruby library dealing with websockets.
And in fact, Action Cable uses Celluloid threadpool to run all the application code in threads. So the model is a combination of EventMachine + Threads.
There's absolutely no reason it can't use Threads + Celluloid all the way. But building on top of Faye was the simplest way to get things up and running.
As someone who's tried to use Faye and EventMachine (separately) back in the Ruby 1.9.3 days: Have they stabilized enough to be used for anything?
My memory of them is rather horrible.
Memory leaks, segmentation faults(!) and obscure deadlocks eventually made me scratch EventMachine from the list of things I'd ever want to touch again.
And Faye, well, I don't think I even got it fully running at the time. I still re-call my astonishment when I realized that neither of their two different server-impls at the time would pass even most basic tests (e.g. browser connect/disconnect, redis start/stop) without crashing, locking up or losing messages.
Admittedly it's been a while... Is anyone running Faye in production and can comment?
Edit: Thanks for the feedback. I guess it's time to give Faye a second chance.
I wrote http://firehose.io/ that runs on a separate fleet of servers to handle pub/sub that uses Faye. For the most part it runs without putting up a fuss.
Lost messages aren't a concern because it's assumed the protocol won't handle lost or dropped messages, so Firehose messages have a sequence that counts up per channel that the client keeps track of.
You can't use Faye without eventmachine. Cable only uses faye-websocket though - https://github.com/faye/faye-websocket-ruby . Do let me know if you had any negative experiences with that. I don't know about the state of the things in the 1.9.3 days, but faye-websocket has always "just worked" for me.
When I was building live relation system faye server has problem to accept more that 1k simultaneous connections. For nodejs it can accept about 30k simultaneous connections. Did you do some stress test with more that 1k connections?
Is this just a really polite, introspective take on (Rails|Ruby) is a Ghetto? I can't point out one really valid critique in this entire rant. While I imagine that you've had enough kool-aid to actually believe the things you said, I think you should probably do a few google searches to find out how many shops are hiring Rails devs versus Clojure or Elixir. You can do more experimenting by seeing who else is actually working those jobs, what kind of professional experience they have, and if you're really lucky figure out what they get paid.
Rails needs websockets, just like years ago when it needed a better way to handle organizing and deploying assets. The modern application demands it, and if you've ever had the pleasure of trying to build a websocket application in Ruby you'd understand why it's actually really exciting that we're going to get the Rails community to build this for all of us.
If you want to be disenchanted about some aspect of Rails then pick the fact that the need for diversity at RailsConf this year has yielded some of the worst presentations I've ever seen (like, literally, the presenter spoke poor/broken english and the Docker oriented talks were about 6 months behind).
Rails moves the way it does and absorbs the ideas it does because they become popular. It's much easier to add a feature that everyone wants, instead of inventing a feature that makes a solved problem that much easier/faster/what-have-you. DHH seems to have to explain this every few years, but go back in time when Rails adopted sprockets and you'll see posts not unlike the one you just wrote.
Realistically, Ruby and Rails jobs are still among the highest paying in the industry. Startups and other more established companies still choose Rails as their platform, and not just for bullshit brochure sites. Certainly there remains a "best tool for the job" mentality but, right now, the alternatives are to: build it yourself, hop on a less "mature" framework -- Pheonix? I don't even know what you pick when you adopt Elixir as your platform language and need to build an API or front end apps but Pheonix won the google -- or choose from one of the popular technologies like Express.js, Laravel(?), or Django. That part of building technology (and business) didn't change, and there are still hundreds of thousands of Ruby and Rails engineers out there.
The main competitive alternatives to Rails are single page application frontend frameworks combined with light API focused backend frameworks. Not a single web application framework.
The static assets are actually served by nginx. In cases where some page data is dynamically generated by Rails, it's nice to keep both pieces of code together in a mono-repo. That said, when I recently extracted a Backbone app from the Rails codebase (retrofitted Grunt.js), I decided to ditch the public/symlink approach and split the app over 2 subdomains. What I find now is that I like the mono-repo approach, and would be fine with cramming both codebases together, while having granular and global deployment scripts.
I actually do this: I ended up leveraging sprockets to get some environment interpolation (like API locations) and easy preprocessing languages (e.g. coffeescript). Also, by doing this, I don't have to make everything single-page. I can build one off pages if I want to (not that it happens much, but, still). Also I get some nice bits for logging, metric agents integrate easily, etc. I realize I didn't need it, but, there really wasn't a down side to using it, except for that some views ended up a little fragmented when using angular templates in public/ versus actual views... Even then, it was a decent learning experience and I'd probably do it again just for the interpolation and sprockets asset building.
> Startups and other more established companies still choose Rails as their platform
As far as I can tell, this process has come to a grinding halt in the past few years.
I certainly see established companies ditching Ruby, not so much because of the language or framework itself, but because of the community that only seems to be able to solve problems "the Rails way", even if that's far from the most appropriate architectural solution.
It's shocking how many Ruby developers are architecturally ignorant about anything not applied by Rails, and it's biting many companies in the ass.
Frankly, I'm surprised anyone would still make comments like yours after all these years. Comments like this probably peaked in 2008-2009 ("Rails can't scale" was even earlier) after the zed shaw article and there was a bunch of hype about everyone supposedly moving to Django and how Rails was supposedly dead, yet that didn't happen then, or any of the other times.
The reality is that lots of companies have been and continue to be created around Rails applications. An AngelList job search focused on server-side technologies currently returns 1267 startup results for "rails" while "node.js" returns 832, "node" returns 854, "django" 434, "python" 1461, "flask" 69, "go" 441, "php" 1192, and "Java" 3163.
JavaScript has become bigger, and it hasn't killed Rails on the server. Java remains huge, and it hasn't killed Rails. Python, Django, and Rails have roughly the same relationship as they did back in 2009.
A lot of very smart people who have extensive experience with many technologies choose Rails for new projects for very good reasons, this has been the case for the 10 years people like you have been making the same FUD-filled comments, and it will likely continue to the be the case for some time.
That's what everyone predicted half a decade ago, yet it hasn't happened, not even the PHP death part. The relationships between these technologies have not really changed dramatically for the past 10 years. For example:
As a brand new Rails developer/web developer altogether, I'm an outsider looking. But it feels to me the chants of "Rails is doomed" mirror that of "PHP is doomed". Yet as you state (and show in your links) PHP is still very healthy and nowhere near death. Sure it might not be the hottest thing on the block, but really JS won't remain the hottest thing on the block in 20 years either, but JS won't die. Neither will Rails. Rails might not the new scorching hotness that it was in 2006, but it's still plenty hot. Rails has quite a bit of life left in it.
Despite languages and the FLOSS projects around them being passions and/or hobbies for so many professionals, at the end of the day I kind of need to get paid for knowledge and opinion. This also sort of requires that individuals and organizations who employe people for their opinion/expertise give two shits about, for example, Elixir.
As long as there are (tens of?) thousands of new job postings for Rails every month I think that indicates devs who prefer Ruby aren't "biting asses", and that companies aren't passing over Ruby/Rails.
>> That's what everyone predicted half a decade ago, yet it hasn't happened, not even the PHP death part.
Indeed. I don't think it will happen...at least not the way people are predicting it to happen. There are plenty of dev jobs that ultimately, you can pick any of the mentioned technologies and if it makes you happy, you'll find a job that will allow you to apply that skill while paying you a great salary (or hourly fee).
These debates are good fun for sure, but ultimately, it doesn't matter in most cases.
> It's shocking how many Ruby developers are architecturally ignorant about anything not applied by Rails, and it's biting many companies in the ass.
On the contrary, I started in web development by learning Rails, and it's simple, streamlined way of responding to an HTTP request has allowed me to pick up other architectures quite quickly. By being so simple, it gives me an easy point of comparison, and then I can appreciate other architectures differences.
Websockets isn't really HTTP and so it doesn't really conform to the request/response model in HTTP that is centered around retrieving document objects.
Most web service implementations, including Rails, are built around that paradigm - they get a request for a document, they return it, then they can forget about it (stateless) and move on to serving subsequent document requests, which are likely to be entirely unrelated to the first request. The Rack framework that connects Rails to webservers like Unicorn is just a thin (pun not intended) abstraction on top of that.
Websockets, on the other hand, is a clever way to upgrade (or rather downgrade) an HTTP connection to its lower-layer communication channel, the TCP socket. Once you escape the document-oriented confines of HTTP, the kind of server you need changes because the concurrency model could be entirely different. If you expect a long-running communication channel with a client, a forking webserver like Unicorn is going to have scalability limits (as you'll need a process per connection), and you're going to have a lot of Rails code in memory that has no use whatsoever.
So I wouldn't expect that Rails would be very useful for a websocket service. And I wouldn't fret about it either :) Different protocols often require different services.
You don't need to go as far as websocket to leave the stateless world: Server-Sent Events and all its cousings (Comet, chunked transfer encoding, even long polling ...) all need to keep a connection open for an unknown amount of time and then send data back to the client. Is Rails discouraged for such use cases ?
Server Sent Events sounds like a great idea until someone opens your app in a few separate tabs. Then you quickly hit the limit of 6 simultaneous HTTP connections, and it looks to the user like your application is frozen or crashed.
Neither Chrome nor Firefox has any interest in fixing this.
You could hack around this with wildcard subdomains as some Comet solutions did, but that's so so ugly.
The ecosystem around websockets is much more mature, the browser support is better, and the connection limits are more sane (Firefox will make up to 200 websocket connections, last I looked). I don't consider Server Sent Events a viable option.
If you could run Rails in an event-driven webserver, it might be usable with persistent connections. Otherwise you'll need a whole lotta memory for all those workers that'll be sitting around doing nothing most of the time.
I used Phoenix for a small project last September, not much more than a toy but anyway...
Pros: websocket support is good, the developers are friendly and answer questions, the app is faster than what I'm used to with Rails.
Neutral: Elixir looks like Ruby but it's very different. Be prepared to learn everything from scratch. You need also to know a little Erlang and the OTP framework to be able to use some useful library functions. OTP is a world on its own.
Cons: the tooling is very immature, probably like the one for Rails at the time of the 1.x releases. Be prepared to write many things by hand instead of requiring gem_x and automagically get functionality for free. This is going to slow down developement, increase costs and possibly get you outbid from competitors. Nevertheless it could be OK for internal projects used to get familiar with the framework.
We've come a long way since September, so please check again. I am outlining our 1.0 remaining milestones Friday at ElixirConfEU. We should see 1.0 in a few months
The websocket support in Phoenix is amazing. And it's not a huge jump to at least get an app up and running if you are a Ruby developer. Most of the really hard things from elixir/erlang have been tucked away nice and neat.
And since we're plugging Elixir/Erlang web frameworks, might as well drop a mention of Sugar (disclaimer: I'm one of its contributors): http://sugar-framework.github.io
No, Rails isn't great for web socket kinds of things, but if it were me, I'd just use something else for that, and Rails for the main site. It's still one of the best things out there for quickly iterating, and yet still maintaining some structure and discipline, from what I've seen.
> No, Rails isn't great for web socket kinds of things
You're doing the "best tool for the job" thing. But if Rails is not a good tool for the job of web socket programming... then ya kinda have to wonder why they're rolling a web socket thing into Rails core, no?
What I've done a few times in the past is had a Rails server for the main app, and a node-based socket.io server for the websockets. All the socket.io server does is listen to a redis server and emit events to the right listeners.
Agreed. I was fine with Railsconf focus last year of being "rock solid". Rails is still the best at what it does thanks to its community.
However, Rails 5 is moving to a direction that goes against the abstractions and platform it runs on. If I don't care about this, now I have even more code and dependencies in my Rails apps. On the other hand, if that is becoming the sanctioned way of building apps, I would rather do it elsewhere. To me it is a lose-lose situation.
My last startup used Node.js + Angular + Postgres, which was great for supporting multiple single page applications and websockets.
With my current startup (a healthcare marketplace where we have to support older browsers), we chose Rails as the best and most mature way to provide server-rendered pages.
I think it's great to try to extend Rails to provide a credible websockets approach, but it will always be difficult because the biggest strength of Rails is the incredible ecosystem of gems. However, all of that existing code is written as blocking, rather than asynchronously like Node and some newer frameworks.
Nevertheless, the Rails ecosystem remains a hotbed of innovation as well as a very warm and welcoming place for both new and experienced programmers.
Rails has not been the new hotness since at least the time Node rolled around. But that's a long way from an existential crisis.
A slight tangent, but as a lover of rails and a user of websockets, I can't recommend Tubesock[0] highly enough. I think regardless of your opinion on event machine, Tubesock is a better engineering match for rails, than websocket-rails. Hopefully, the websocket support will be a standard in the future, as opposed to an afterthought for rails, but until that point, I'll keep recommending Tubesock!
In web framework terms, Rails is old. When it was created single-page applications weren't on anyone's radar, APIs were extremely uncommon, and websockets hadn't been invented. It's natural to expect some pain try to adapt new paradigms into the old model. Whether this pain is worth it is up to the individual to decide. My web applications are almost always pure client-side these days, so Rails is not something I often turn to.
Not quite sure I'm understanding the point of your snark. The fact that vulnerabilities exist mean that it's not well tested? Take a look at the tests directory.
No matter how many tests you have, security vulnerabilities exist in your code, I assure you. Their frequency of discovery says more about the popularity of a codebase than it does about the thoroughness of testing.
I have to say that sort of stuff put me off Rails a bit. If you compare to Django for example for code execution vulnerabilities it's Django 0, Rails 11. Though Django has maybe 1/3 to 1/2 as many users as Rails it's still enough for it to be pretty well tested out.
I understand that there's not quite the same consistent 'theme' this year, but I'm not sure that's concordant with developers who are using Rails 'abandoning' it or anything like that.
It's true that real-time operations like websockets are a total pain in the arse with Rails. Nobody's yet figured out an optimal solution for that sort of thing, and maybe ActionCable is a good solution.
The thing is that while some demands on the web stack have changed, a lot of it is still pretty similar. We have HTTP requests, and HTML, and assets, and databases. It might turn out that Rails can also perform some other tasks that require realtime operation. Or maybe it won't be able to, and we'll be able to use some other tools.
Ultimately, we're still using Rails for all of our new web apps. We've tried loads of different toolsets, but haven't found an alternative that's compelling enough to bother. So YMMV, but the fact that Rails is maybe a bit less exciting that newer frameworks doesn't mean it's not great to use any more.
The Rails team, including DHH, owes us nothing. They aren't required to give us a framework of our choosing, they're the ones building it! Just like we don't owe anything to Rails!
DHH uses Rails for Basecamp, so it makes sense that he'll lead the project towards the goals of BC.
After trying Clojure(and Luminus) several times over the past year I don't think it would be my go to for things that Rails is tackling. On a side note writing Clojure gave me a little anxiety so I'm trying to hold back on it for now.
After working in this stuff for a while I just use the right tool for the right job. Most of the time Rails is that tool and it allows you to just get stuff done. Sometimes Node is the right tool, or Python.
I think the new Turbolinks stuff is pretty interesting(and useful) although it doesn't help me with forms, and that's the thing I'm usually using React or Angular for these days. Angular may get crap but it's actually really good at forms.
I believe the right balance with turbolinks is a mix of React for interactive animated stuffs, graphs, etc, and turbolinks to render stuff that is better generated server side, or to push json data (and then bind it to your react component)
The OP is talking about Elixir/Clojure as alternatives. I really liked Elixir's built in Actor like system, Ruby like syntax and the fact it runs on the Erlang VM is very interesting.
I was always wondering why Ruby developers who looked for an alternative didn't move to Scala / Play ecosystem, Scala always seemed to me more like "typed Ruby" than a "better java" or "mediocre Haskell".
But after skimming elixir's getting started docs, I think I know why. Elixir seems to have much more "Ruby like" syntax, it's not running on the JVM, and it's dynamic.
But still I wonder how much the Ruby / Rails community is aware of Scala / Play framework / Akka / Akka-http (formerly spary) as a possible comfortable alternatives to Ruby / Rails / Elixir's actor system / Ruby API?
Play framework knowingly (and admittedly, giving all due credit) borrows a lot from Rails. and I am amazed how Ruby and Scala have more similarities than Scala and Java, yet people still link Scala with Java much more than with anything else.
I think the Scala ecosystem will benefit a lot if there was even a small stream of Rails contributors that also do Scala on the side. I think what makes Rails and Ruby so great is the amazing community and open source culture behind it. As a Scala fan, I can't be but a little gelous...
I somehow got stuck upgrading from Rails 3 to Rails 4. Nightmare...
I've been through 5 Rails upgrades. Rails 2 to Rails 3 was a nightmare...
Rails does not scale well with complexity & is a pain to maintain...
There are a number of reasons for that. Rails started off favoring syntactic sugar over architectural integrity. They are gradually iterating toward a solid architecture. However, that required some significant api changes, which causes upgrade pain.
Also, the prevalence of monkey-patching (largely due to an unsound & overly complicated architecture), exasperated these issues.
Rails architecture is still overly complicated & misses the mark, IMO.
DHH's infamous "golden path" direction put the blame on the developers, when Rails itself had some major architectural flaws.
Rails Routes + Controllers are horrible. Why do we want an extra level of indirection? Sinatra/Express.js are easier to reason about RESTfully.
Asset Pipeline is horrible. The Node.js ecosystem (i.e. browserify) is much better. Client/Server separation of architecture scales in complexity more readily than the Rails monolith monstrosity.
I'm kindof bummed that Rails became so big. The "Rails Way", while being a step forward from what was there before, became too prevalent; sucking up too much mindshare; inhibiting further evolution of the broader ecosystem.
It's time we let Rails slowly die. There are many better libraries & frameworks out there.
I never hear any production app with elixir in Berlin, some noise with clojure, but some people move from node.js to Golang. As for rails, people are happy.
Sometines I think is super cool to rant rails :)
As a ruby/js dev moving to Berlin in September, that's good to hear. I'm interested in talking to folks who might be more familiar with the scene there. If you know anyone who'd be good to reach out to, let me know!
This is interesting. I hear most about Elixir, with Clojure coming second. As I said above though, those are just examples, if I knew for a certain what is next, I would be learning it already.
In Berlin, Munchen people chat about elixir when they compare some pharma, alcohol industry. As for clojure, only small projects. as for the hype, let's say go. But, majority choose, php :)
The almost complete dominance of the Rails in the Ruby ecosystem seems incredibly unhealthy to me.
IMO, Rails should do what Rails is good at and was designed for (simple, monolithic, server-side heavy web applications), and there should be dozens of other successful Ruby frameworks with other philosophies.
Rails was supposed to be the breakthrough for Ruby, but instead the near monopoly of Rails is suffocating it.
It's especially jarring when the Ruby world - which originally revolved around "Matz is nice so we are nice", emphasizing developer happiness, being a more readable Perl, etc. - now revolves around the "Rails way" as if all other ways are wrong.
If I wanted a "There's Only One Way To Do It(TM)" world, I'd be programming in Python, not Ruby.
Not really the same architecture. It has it own differences and has much less magic involved. The project direction and the community is determined more by the community and not by a BDFL.
I don't buy this, having written and dealt with a lot of concurrent Django apps - I think people read something about the GIL often, and don't understand what the articles are really meaning.
Basically Django is usually fronted with mod_wsgi and you use celery for backend tasks. The multiple requests part are dealt with because the web server pre-forks, and it's just fine with it.
I think Django's problem is it moves very slowly, and mostly just that. The ORM isn't awesome, but it's workable. You can also choose to not use parts of it, like templates, and that's common in single-page apps.
It is not very difficult to plug in gevent/tornado/twisted with Django and deal with it in a pretty effective way. Also, most the resource memory intensive tasks are delegated to celery anyways.
Re. EventMachine: As I understood DHH's speech, the idea is that ActionCable abstracts all the messiness around EventMachine, Websockets, Rack and threads. We won't know until some ActionCable code is released but it sure didn't look complicated.
It does seem odd that -api takes years to get in, but ActionCable gets a go-straight-to-core pass without any community review first. It certainly seems like a weakness in the process, which should be addressed, although I'd agree with the eventual result & priorities. -api probably isn't something I'd ever use: even if I eventually created an API-only app, I'd probably have started from a regular Rails app and gradually optimised things out.
Edited to add: I'm actually quite bullish on TurboLinks 3 if it can help me to avoid ever having to write a Javascript MVC app again. It's not so much that these apps are hard to write, it's that they're freaking hard to debug, particularly in the hands of users.