Hacker News new | ask | show | jobs
by cies 4638 days ago
Play is not "beyond" Rails, it is merely an other community (Java/Scala) that catches up with Rails.

Node.js is a joke, I see more and more people "get it". It sure serves a purpose, but the language not being for general purpose, the syntactical problems of JS and the single-trick concurrency model don't make it fit for true disruption.

Meteor might be a contender for "next level" (currently it is build on Node i think, but that might change one day), I also consider Yesod (Haskell) and some of the web stuff on Clojure to be good contenders.

I think it will not be merely a new FW that changes the scene, I expect it to be a new language along with that.

5 comments

WARNING: A lot of Play/Scala cheerleading from a former Ruby developer. I can't help it. I love my job. Feel free to summarily disregard. ;-)

Play is an evolution for sure. But I'd consider it "beyond". Validation concerns are where they should be: At input. Not the Models. Comet, Websockets, etc are all trivial. Chunked Responses FTW. You don't need different responders. Render _anything_ by having a Writable in-scope.

Our API calls to render our models as JSON look like this:

  api.photos.get(id) map(Ok(_))
The plugin universe isn't there yet, but I tend to think most apps out-grow most framework plugins pretty quickly.

Honestly, I find Play/Scala _more_ productive than Ruby MVC in general. Fewer bugs. Much better performance and memory usage, so fewer constraints (that one is huge). Rework is much easier, but also much less necessary. The language itself is a joy (IMO) to work with.

The Java ecosystem is a huge enabler. You can have complete control over resizing images in ImgScalr, faster, with no external dependencies, in less code and a flatter learning curve than anything I've ever used in Ruby. Scala itself presents a lot of new things to learn and get comfortable with language-wise until you feel you're back in the groove, but once you've got it, I've found that the ecosystem makes the complex things much easier, and the language itself makes the easy things engaging as well.

Ruby doesn't really help much trying to tackle hard problems IME. Image Resizing? Better shell out to ImageMagick. Dubbing a video? Hello shell my old friend. Cache coherency across a cluster? Fire up another external service (maybe Redis) to manage and start working through failure modes and failover scripts if you care about availability. Compare that to Hazelcast. Need to serve static assets? Better setup an NGinx proxy. In-memory near-caching? You don't have the memory for it, and the GC can't handle it anyways, stick to Redis.

Put a crew of experienced Play developers head-to-head with experienced Rails developers, give them the same goals (and non-goals), and you'll have a faster, more maintainable solution from the Play team in the same or less time for anything but the most trivial apps.

IMO. :-)

Most of these seem pretty silly to me, as the tasks you say Rails are bad at happen to be the same that SOA tells us should be separate services anyhow.

I really don't want to handle the side effects of dubbing videos in my web app. That kind of stuff belongs in a dedicated service anyhow - big monoliths are really the killer of maintainability.

"Most" seems a bit harsh. Cache coherency is a hard problem for sure, but if you can handle memory efficiently, local-in-memory near-caches are awesome things to have access to.

Just because it's popular to farm that out to another service (and another operations bill) in Ruby because, lets face it, there's not much alternative, doesn't mean it's the best solution. It's just the practical one given the constraints. Lift the constraints, expand your options and there you go.

Some of my others might seem silly to you. Fair enough. There's just at the top of my head.

Dubbing is an IO problem mostly, and pretty cheap. Unless you're doing a lot of it, adding complexity and (really large) performance hits by having to integrate with external services is not a "better" or "easier" solution if you can just say:

  val dubbedVideo = Dub(inputVideo, newAudioSource)
Same for simple image resizing. You have to be pushing a lot of resize operations to make that something you'd want to farm out as opposed to just tossing 'em over to an actor system. And then you should probably be trying to bypass your application server entirely so you don't trade a CPU spike for a lot of IO. Again, more complex.

I've worked in a number of very large Ruby apps. Did a lot of dumb things. Maintainability issues though? That hasn't come from ImageMagick, FFMpeg, Redis, etc. Those things are (mostly) just big up-front expenses. Would Zencoder have made any of our apps more maintainable? No. Absolutely, Definitely, Unequivocally not easier to maintain than the already simple internal API calls that haven't been touched much in years. Zencoder's API has changed more than our own I'm sure.

I would use Zencoder today as opposed to doing the same again. The up-front cost just can't be justified. But even so, maintainability isn't the issue there.

You write a dozen lines of code to do a thing. That code lives in-process. You don't touch it for years. You never have to worry about system dependencies. You never spend an additional dime on operations costs for it. You never had to develop a contingency plan for failover. You never have to worry about it suddenly breaking or a change in it's behavior that isn't directly related to a commit you made you can find with nothing more than "git blame". That's maintainability.

Using external services over bundled libraries is a decision you make on either 1. Cost or 2. Performance. If you don't have performance constraints, and you have access to a simple library someone else has developed you never choose the external service on the basis of maintainability for a given application. It's more expensive in every way.

I guess it's just hard to convey what an enabler solid, mature libraries that don't break can be if all you've experienced is the churn of Ruby and the limitations of having to farm out work to third parties because your system simply can't handle it without worrying about tying up 1 of your limited pool of 16 processes able to service requests under Unicorn for the duration of the operation. Or you're worried about scaling and cache cohernecy so you have to build a cluster of Redis servers, with custom failover scripts, additional system monitoring services to ensure it's both available and that you have a peek into it's behavior. Or you have to talk to a service to get even basic thumbnails and now you're spending 5 seconds to do what could have been done with just a few lines of code in in one second locally with no additional concerns for availability, another bill to pay, or it breaking some day because the service made "improvements".

90% of the "maintenance" problems I've seen with Ruby code can be categorized as: Scaling, Typos, or simply doing the wrong thing and talking to code or services you shouldn't have (i.e.: A SQL update to bypass validations in an offline batch processing scenario, but later on critical business logic is added and now events to trigger those side-effects are also inadvertently bypassed).

Don't validate your models beyond very basic database integrity. Don't worry about farming out services unless it's an actual organizational goal for internally developed services or it becomes a scaling or cost issue. Always favor libraries over services. Your entire stack is libraries. 99% of the code that runs your business is libraries. Services are important, but they solve a niche problem. Don't prematurely optimize for services and commit to the maintenance overhead they bring if you can't justify that with improved time-to-market or scaling because the alternative would be to roll your own. I'm not suggesting you roll your own. I'm suggesting you look on Github first unless you actually have a scaling concern.

So that was a tangent… ;-) But yeah. Maintainability is my current cause-du-jour. Because IME, the Ruby ecosystem has one of the worst maintainability track-records for time and cost of any platform I've ever worked with (and I think I'm fairly qualified to make that claim. I started with Rails v0.7, written some pretty massive open source Ruby projects, have dozens of Gems to my name and have been paid to write and maintain applications in Ruby going on 7 years now).

I can second the thought about Yesod - in terms of how it feels it rather comparable with Rails, but is more concise with less boilerplate and stable in the sense that it's hard to accidentally break something; if your change compiles, then it generally works correctly and safely. Tracing /debugging can be a pain sometimes, though.
Play is not "beyond" Rails, it is merely an other community (Java/Scala) that catches up with Rails.

In many ways, it is beyond Rails. For instance, it offers type-safe URLs and builds upon the Akka actor framework (allowing you to schedule asynchronous tasks, make reactive web applications, etc.).

> builds upon the Akka actor framework

This is really where Play shines. I wouldn't bother with Play for a basic CRUD app, it makes you do too much grunt work yourself (e.g., authentication). But when you have a backend built on Akka and want to build a reactive, event-driven front-end Play makes it trivial.

Akka is the key. Its actor model just makes reasoning about concurrency so easy because of how it deals with state. Add in remoting and clustering and you've got a highly scalable, event-driven clustered backend without too much extra work on your part. Play fits into that sort of ecosystem quite nicely.

Worse might be Better in the case of Node, though. It's also benefiting from a great package manager. NPM already has 2/3 as many packages as RubyGems and 20% more than PyPI.
I think Rust with a new framework might get some momentum in coming years.
That's my hope. I have one or two ideas that I haven't seen elsewhere and various other ideas that I hadn't seen elsewhere until I looked at certain esoteric frameworks like Yesod (plus a couple of other Haskell ones and Ur/Web), as well as all the normal ideas. Three of my key goals are speed, safety and correctness, all things that are simply lacking (and often drive people away from them in the end) in frameworks like Ruby on Rails and Django (which, incidentally, has been my preferred framework with Python as my preferred language).

However, before I can build the web framework I want in Rust, I'm having to write the HTTP library I want in Rust (with similar goals), and that's the stage I'm currently at: http://github.com/chris-morgan/rust-http.

I am aware of your work and I really appreciate it.