Existential crisis at Railsconf
railsbird.tumblr.com
railsbird.tumblr.com
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.
- I agree that most rails programmers will not move to clojure.
- For monorail apps, rails is still king.
That said, for us, when comparing clojure and ruby REST API services we've built, clojure has had the following benefits:
- Less code
- Less tests needed
- Better concurrency
- Less developer hours
- Less maintenance
- About 33% of the servers for same performance
- Easier/faster debugging
It's been far more then a 10x improvement overall, and if people are looking to move out of the monorail style of app, it's definitely worth a look.
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.
Cheers!
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 :)
And here's an attempt to objectively rank programming languages by expressiveness, measured as lines of code changed per commit: http://redmonk.com/dberkholz/2013/03/25/programming-language...
Just take run of the mill Ruby code and convert it to Clojure. Especially anything that looks like functional programming.
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.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).
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.
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...
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).
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.
let add a b = a+b
is more expressive than func add(a:IAddition, b:IAddition) -> IAddition {
return a + b;
}
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.Also the empty list can be expressed as a type...
class EmptyList
def empty?
true
end
endBut 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 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.
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.
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.
TL;DR: I believe 10x frameworks are out there.
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?
> typed is 10x better than dynamic
10x what? Rails' community is many-x larger then Yesod's, in that case dynamic wins.
:)
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.
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?
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.
> 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.
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).
There have been lots of things that do something like this: SOAP and the associated WS-* standards are probably the best known.
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 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)`.
[0] https://github.com/playframework/playframework/ [1] https://github.com/scala-js/scala-js [2] https://github.com/japgolly/scalacss
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?
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.
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.
Main hometaker: it's like in Haskell I have to do more work up-front, to enjoy much better productivity down the road.
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.
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.
Ruby is strongly typed.
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.
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.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.
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 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)
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. :-)
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.
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.
(defn [items] [:ul.items (for [item items] [:li.item (:display-name item)]])])
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.
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.
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.
> 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.
These are not good reasons, but they are my reasons.
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.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.
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.
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 ;))
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.
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.
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.
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 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 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 ;)
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.
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.
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.
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.
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.
No it has not. In fact there has been more elaborate work done inside of rails (and django/python) than ever before.
Actually 'Rails is dying' rant has been going on for years! Almost like cold war propaganda. The only thing that will cease to exist is the war.
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.
http://www.indeed.com/jobtrends?q=php%2C+javascript%2C+ruby%...
http://www.indeed.com/jobtrends?q=php%2C+node.js%2C+ruby%2C+...
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.
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.
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.
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.
Neither Chrome nor Firefox has any interest in fixing this.
https://code.google.com/p/chromium/issues/detail?id=275955 https://bugzilla.mozilla.org/show_bug.cgi?id=906896
IE doesn't support Server Sent Events at all.
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.
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.
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.
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?
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.
Oh how I love that! I would rather build my business on something old and well testet then something new and shiny.
Or Perl.
Or COBOL.
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.
http://www.cvedetails.com/product/18211/Djangoproject-Django...
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.
DHH uses Rails for Basecamp, so it makes sense that he'll lead the project towards the goals of BC.
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 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'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.
https://github.com/eventmachine/eventmachine/blob/master/CHA...
IT seems to have much more fix and features in recent months then its entire life span.
And as DHH pointed out on twitter
Clearing up misconception re: Action Cable: EventMachine only used for connection handling, threads for channel code. No block restrictions.
Is that really the case? Clojure and Elixir?
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.
If I wanted a "There's Only One Way To Do It(TM)" world, I'd be programming in Python, not Ruby.
Highrise was a palatable "cheap and cheerful" CRM system but they decided to stop investing in it.
The appeal of Basecamp is that it is a simple product and there isn't anything 40 developers can do to make it more simple.
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.