Hacker News new | comments | ask | show | jobs | submit login
After reading “Rails is yesterday’s software”, I need to reply (codethinked.com)
259 points by D_Guidi on May 11, 2016 | hide | past | web | favorite | 209 comments

Moving on from Rails sounds great until you try to build a serious web app with one of the alternatives. While I think that many of the architectural criticisms are valid, Rails demonstrates the primacy of ecosystem and strong conventions over language design and cs theory.

'Tomorrow's' languages and frameworks would do well to take heed. Winning this war has as much to do with culture and marketing as algorithms and data structures.

Clojure, for example, is a much stronger programming language than Ruby on paper, but for a straightforward web app, you'll likely spend at least twice as long to get something working--and while it will be based on better engineering principles, it will also take new engineers much longer to grok since it doesn't follow any universal set of conventions.

With Rails, you end up in the weeds in the long run, but the alternatives put you in the weeds right off the bat (with the promise of eventual salvation). The reality of most product development (ymmv) is that the former is highly preferable to the latter.

It's all about how you prioritize the problems you need to solve.

At my current job we primarily use Wordpress. Why Wordpress? Because we have a large and non-technical content team, 260+ websites and several tens of thousands of pages of content that need to go up quickly.

We're just 4 developers - about 1 for every 8 content & marketing people we have. We spend very little of our time on frontend. Tell me that you're going to get that kind of leverage with another tool.

Wordpress is just about the last thing that you would pick as a developer or ops person to base your tech stack, but in our case it is the right choice.

Aside: Coming from Rails and having spent six months deep in Wordpress core, it's actually kind of awesome. Seemingly every problem is solvable.

Comparing Rails and Wordpress seems like apples and oranges to me. Rails is a framework that lets you build anything web-app-ish, while Wordpress has its well defined, rather limited use cases. If it works for you, great, but the scenarios are different.

That's not the point of what I was saying.

I'm making a point that Wordpress is also "yesterday's software" and there's nothing wrong with making that choice.

WordPress is a pretty crazy codebase, yet, it seems sane compared to Rails. Interesting that WordPress as a service are moving to a node.js backend from PHP - even they chase shiny too

Is it not an advantage for average users to be able to do both the front end and back end knowing only a single language?

The same advantage as just using a screwdriver to handle nails and screws? No. Right tool on the server (hint: it's not JS nor node), right tool on the client (JS if needs must)

Do you know of any decent (modern stack) WPaaS besides Pantheon?

> With Rails, you end up in the weeds in the long run, but the alternatives put you in the weeds right off the bat (with the promise of eventual salvation). The reality of most product development (ymmv) is that the former is highly preferable to the latter.

You're absolutely right.

And yes, Rails has quirks and I agree with most of the criticism of the other article

Option 1: Twitter is built on RoR, have growing pains and lots of whales when it has an established product (when it gets the investors and the money to invest in a rebuild)

Option 2: Twitter is built on Clojure, product takes more time, iteration gets slower, hiring is slower, some other competitor gets ahead. Ooops

These things depends a lot on how you build an app, too.

All our webapps these days are thin React apps (with server-side rendering) that don't have a dedicated backend. Instead, they talk to a group of generic microservices. We've been doing this style of development since around 2010.

With this methodology, a lot of Rails' ergonomic concerns (templating, the split between rendering HTML vs. data, etc.) just melt away. Front-ends become formally isolated clients of microservices, forcing you to engineer better internal APIs and get things like security correct from the start.

Not OP, but my guess is that would count as "in the weeds right off the bat"; the impression I get is that a lot of Rails's value proposition revolves around being able to start using it without actually needing to know or understand very much. (Which is not a bad thing, exactly! Its power as a rapid prototyping tool comes in large part from this trait. Unfortunately, so does its strong tendency to produce unmaintainable code.)

Each approach comes with its benefits and challenges. I would never suggest anyone jump right to a microservice architecture if they haven't come to appreciate the problems posed by a Rails-type design.

One aspect I keep hammering on about with regard to microservices is reusability. If you're developing just one user-facing product, nevermind. But if you have a bunch of products, reusability across microservices is a huge boon compared to monoliths. Reuse all your job processing, notifications, data storage, login/auth/group/role/permission management, identity verification, image processing, NLP processing, feed processing, etc. etc. etc. across your entire stack.

With monoliths, the only other option is to build these as libraries, and unless you want to write bindings or write code more than once, you're now chaining yourself to a specific language.

I'd love to know more about your webapp methodology. It sounds wonderful.

The current implementation is nothing special. However, I'm quite happy with our methodology itself.

We use a simple microservice design: All our microservices talk using JSON over HTTP. They share nothing. Everything is done by communicating. There's also an event bus so they can listen to each other's events. All our microservices are multitenant by design, so that they can support any product with no data spillover.

We have a bunch of general-purpose microservices built out to service our particular needs. User-facing webapps are built entirely out of these building blocks. They don't need to deal with login or OAuth; there's a microservice for that. Similarly, almost all data is stored in a single document-oriented data store (which we've heavily rearchitecting in Go and will soon release as open source — email me if you want to be notified) on top Postgres and Elasticsearch. For anything that we need from a webapp, we build a microservice. (We have a lot of older Ruby and Node stuff, but all our new microservices are written in Go, which has been a very pleasant experience.)

One key component of our development workflow is the use of a Linux virtual machine that each developer runs locally. It hosts the exact same stack (and uses the same deployment system) as our real production and staging environments. This lets the developer focus on work and not on how the microservices are run. It's not pain-free, but we have made it quite comfortable, among other things through a seamless system of mounting, where the code running on the VM for a particular app is using the developer's own project folder on the host machine. Hot code reloading is also enabled where possible. So a React app will automatically bundle with Babel and so on when you reload a page.

There are challenges to using microservices in this way. One is deployment and hosting. We currently have our own homegrown system for this that works fine, but hope to migrate to Kubernetes soon. Another challenge is documentation. In the end, the code (and project readmes) is the authority on how a particular microservice works and what APIs it implements; we did automatically generate API docs at one point, but it hasn't kept up with our Go projects. These days we just refer to the code. The most painful aspect of this, and onboarding, is documenting the cross-cutting, "big picture" concerns.

I'd be happy to answer any other questions you might have.

That's much appreciated - lots to think about!

Edit: how do you scale? For example, do you just have lots of nodes running your authentication microservice for all of your active apps?

Yes, we run every microservice on multiple nodes. How many depends on how much traffic a microservice needs. Some receive tens of thousands of reqs/sec through frontends, whereas some are only invoked for daily processing jobs etc.

Elixir/Phoenix gets this right. Working on a side project right now and so far it's a very enjoyable experience.

I find the abstractions much more intuitive. The framework as a whole is just as "magical" for fast prototyping, but it's composed of much simpler individual modules that are easy to wrap one's head around.

It's surprising how mature the whole ecosystem feels considering it's still quite niche. It helps to have decades of battle-tested Erlang libraries at your disposal.

Wait till hex is filled with crap like gems are today. The Rails programmers are coming to elixir as it had already been called the new Rails, and they will follow the pragprog book to it the new promised land.

If you enjoyed early adopter status in elixir phoenix, wait till it is Rails mk 2. It will suck big time.

You have a point there, but I do wonder if this is inevitable, or if (1) the language does make a difference in that regard and (2) the community can help steer newcomers in the right direction and establish best practices, standards of quality, etc. etc. (cf. Clojure?)

As a side note, I feel like this has happened to some degree to the React ecosystem. I can no longer count on packages to be of decent quality.

I agree that Rails' strong opinions are still a strength. I like Clojure a lot, but for someone new to the language trying to get a Clojure web app started is like pulling teeth. Elixir and Phoenix, with their connections to the Ruby community, really get this, and I think they provide a much better introductory experience.

I've been doing Clojure for the better part of 3 years now and I'm not sure I get why people feel doing web development in Clojure is hard. Our first foray in Clojure was/is an API to manage our users that was built by 2 developers who were new to the language and has been running largely unmodified since being released.

I actually believe the opposite. Jumping into and doing Clojure web development is extremely simple at the core. The issue with frameworks like Rails (and I'm not against Rails as I have used it on multiple successful projects and still think it's great) is that you get so much for free and don't have to understand how all the pieces fit and work together (at least initially). Soon enough you have to have more knowledge of that and that's were the complexity comes in.

> The issue with frameworks like Rails <... snip ...> is that you get so much for free and don't have to understand how all the pieces fit and work together

Having used both Ruby/Rails and Clojure, I think Clojure swings too far in the opposite direction, where absolutely everything is foisted on the developer and they must hold the entire codebase in their head at once or drown.

We even see this in luminus, the closest thing Clojure has to a web framework. It's just a leiningen template which spits files out on disk and says "there you go, it's your problem now". Of course there are upsides to this approach, but personally I've come to find developing web servers in Clojure a withering, joyless experience. Elixir and Phoenix show much more promise and seem to strike the right balance between featureful-ness and cleanliness.

> where absolutely everything is foisted on the developer and they must hold the entire codebase in their head at once or drown.

I don't get that, and if that's how you feel I'd say you are doing functional programming wrong!

That being said, I do agree about Luminous and I think it's a terrible way for a new web developer to Clojure to get started. Instead build your way up for what your app needs pulling in the libs as you need them and understanding how they fit and work together. Chances are you don't need that many at all.

Is it fair to ding Rails for that, though? Regardless of what framework you're working with, eventually you're going to be peeking under the hood. Of either the framework, the language, or both. Whether that's front-loaded or not, it's still there. So the question becomes which framework eases you into the deep end of the pool, rather than which is the least complex.

I've seen plenty of Rails apps that could have written better initially. But I haven't really seen any where it was impossible to refactor and improve them as a developer learns more.

I'm not dinging Rails for that. Like I said I've done some successful applications with Rails.

The difference I'd say between Clojure is you learn those from the bottom up, whereas with Rails you learn from the top down. Either way, you are going to have to learn them!

Where exactly does it say that you can't start by actually learning how Rails works, before you build things with it?

I think the biases of people who were experienced big system developers before they moved to Rails, are very different from those who started with it, potentially not understanding web app development very well, and then produced something challenging to maintain

No, I realize that. I was thinking more about complaints along those lines in general rather than anything you said specifically. Maybe it's just a case of setting unreasonable expectations as a consequence of how Rails in particular is recommended to newbies.

Have you tried luminus[0]? I found it to be quite straightforward to get started. What I didn't like about clojure is that it smells like java a tiny bit too much and there's too much to choose from be it language abstractions or libraries I guess that's what you refer to as "pulling teeth".

I'm gonna try Phoenix for my next project, even though I really like Django and I have never been too much into rails or ruby. My other option would be Django + socket.io, and I think that would be the more mature stack, but as much as I like javascript and python I think that would lead to more complexity and thus make the project harder to maintain. I may be stabbing myself in the foot, but let's hope not :D


I suggest checking out Pushpin (https://github.com/fanout/pushpin). It works great with Django, and no need for multiple languages.

Django 1.10 with Channels (which you can start using right now)... is very exciting...

> With Rails, you end up in the weeds in the long run, but the alternatives put you in the weeds right off the bat (with the promise of eventual salvation). The reality of most product development (ymmv) is that the former is highly preferable to the latter.

As one of our product managers put it: Often, you want something you can sell well fast enough to buy time to make it good.

Overall, in this tool/framework/language debate, I'm growing more and more convinced two things matter the most:

- Pick something the weakest 40% of your team are comfortable using. Especially with support, I'd trust myself to figure out enough of Elixir/React/Whatever to be decently productive within a week or two on the go. But that's the thing - that's why I advocate to pick something the weaker team members are fine with. They will struggle, not the stronger team members.

- Smash problems with standard solutions. Don't be smart. Pick the right tools, throw hardware at them. A decent combination of load balancing, language+ORM, an SQL persistence layer and possibly a message queue can handle _a lot_ of traffic. And it's easy to hire for and to get new people on board because there are no smart things going on.

Note that the language and web framework are not part of this consideration at all. My approach would prefer more established frameworks like rails or something in java though.

I think this is a strong point. If rails is yesterday's technology, then what is today's?

To be clear, by no means am I trying to claim that Rails is the clear winner over other technology choices, or that a good answer to this question needs to be one single, unambiguous answer. I've learned a lot about other possibilities. Node of course, but it's still relatively new, and you need to prefer (or at least be ok with) javascript instead of ruby. Pheonix and Elixir sound promising. My own personal prediction (probably better to call it a suspicion, since I'm wary of predictions) is that an "isometric" approach like Volt will become more common (the approach, not necessarily that specific implementation, though it is of course a possibility as well).

But for now? Some will do this, but I wouldn't use Volt, though that has more to do with the requirements of my job than anything wrong with Volt (there really is no need for me to go so bleeding edge in what I do). I personally am hesitant to invest too much in Javascript, even on the client side, since there is still a great deal of churn. Again, this may simply not be a possibility for everyone, it depends on the kind of app you're writing.

So it's not so much that I don't see good, perhaps preferable alternatives to Rails. I just don't see a sufficiently unambiguous case that Rails is out of date to be calling it yesterday's technology - yet.

And lastly, as I mentioned in he other thread about this, when Rails isn't working for me, either because of code clarity or performance, I tend to go to older, more established technologies, not newer ones. For very elaborate sql, I use… sql, not contortions in ActiveRecord that I think are much harder to read and understand than a sql statement. I also often go to raw sql for performance reasons (mass inserts, queries that result in very large result sets that need to be optimized for speed). Unix, networking, specialized languages and environments for scientific computing, machine learning, stats, or other specialized tasks. That tends to be where I go.

I came to Node after four years on Rails and about 10 years of PHP before that.

It definitely felt like a step back from Rails, but that's partly because Node wasn't meant just to be a web framework.

I've gotten pretty comfortable with it, but I feel like the original decision to use it (which predates my joining the company) was primarily driven by how shiny and cool it is. The vast majority of what we do is standard CRUD stuff.

On a personal level I've enjoyed learning it, and from a career perspective it's nice to have it on my CV, but had I been on board when the original decision was made I would definitely have chosen Rails.

(Plus they also chose to use MySQL for no good reason. We've managed with it just fine, but in literally the last three weeks we ran into some limitations that would not be a problem in Postgres. The CEO, not being technical, doesn't quite understand why changing the database midstream is not something you do without really compelling reasons.)

Why compare Rails with Clojure (a framework vs. a language)?

I think if you more fairly compare Rails with Django, Flask, Laravel, etc. you might find the differences aren't so great.

Just curious, but what do you consider a serious web app?

I have had great success with Python across a variety of different applications.

A lot of people seem to end up comparing/picking between Python and Ruby so I am curious for my own knowledge what type of serious application does Ruby make easy where Python makes difficult?

I also think the overall gravitation towards microservice architecture generally makes language choice less important on the whole...but that's just me.

> for a straightforward web app, you'll likely spend at least twice as long to get something working

For a straightforward web app, Rails is probably a fine fit. For something less straightforward, it can shackle you down the road. The alternatives are an up-front investment that can save you time and effort down the road, but also give you enough leeway to make mistakes.

> (ymmv)

This is probably the most important to remember. Every problem is different. Every situation is different. Good engineering isn't just the implementation, but also the design process.

For most problems, there is rarely a single "correct" solution. This means decisions about which tools to use should should include maintenance costs, familiarity, and other non-technical criteria. For example, it's probably a better idea to be consistent with tooling even if a side project is a great fit for another language/framework. Or maybe it's worth the cost in your particular situation.

In CS we often talk about trade=offs. Should we use the normal trig functions or trade memory for speed and use a lookup table? Should the data be stored in an array or linked list? Should the math be done using int16, int32, int64, or a bignum library? Good design happens when you take the time to consider all of your options, including which tools you will use.

> Winning this war has as much to do with culture and marketing as algorithms and data structures.

This is true enough. I'd go farther and say that winning depends almost entirely on culture and marketing. The annals of computing are littered with the forgotten remains of technically amazing projects that suffered from poor or non-existent marketing execution. Rails is so popular mainly due to marketing tactics that won developer mindshare, rather than due to any technical merit.

The larger question is not a mutually exclusive either-or situation. A good framework should be easy to use for the most common cases initially and well thought out enough that it's easily extensible in the future.

When Rails first came out, I loved it. It made common stuff easy! Sure, it became intractable if you needed to deviate in any way from the planned normal cases, but that was fine for now. I thought it was a great V1 of the Ultimate Web Framework, and in time they'd build it out to have better and more flexible extensibility. I thought it was fine starting point to build upon, and that eventually they'd redo and flesh out the various badly designed subsystems.

As the years went by, I realized that it was not a V1 of that mythical Ultimate Web Framework. Not at all.

Its developers were quite content to feed on the low end of the market that just needed a quick way to shuttle data between a database and web forms. They had no intentions of updating its design to accomodate any other use cases. The few concessions that were made to other use cases were generally bolt-on hacks rather than integrated elements of the framework. They were focusing their time on flying around the world giving talks at conferences, writing books, giving training seminars, and otherwise monetizing their brand.

Actual engineering work on Rails itself slowed to a near-halt, and it was then usually reactive in the sense that Rails had to be dragged forward kicking and screaming. Rails was no longer an innovator, but that was fine because they were making plenty of cash off of what Rails was. Indeed, they now had a strong disincentive to make any radical design changes, since they would have to redo all of their books and course curricula around the new design.

There is no reason in principle why one couldn't build a framework that's both easy to get started with and easy to extend. It's just that nobody's bothered to do it yet.

So django gets it right. Laravel and symfony seem to get it right, yesod for Haskell gets it right - basically Rails is pretty awful, always was, but the crowd got caught up in five minute blogs and shiny magic to question the questionable insecure code, the rather suspect architecture.

Seems to me you don't actually remember what the web framework landscape was like in 2004.

Can you be more specific? What do Django, Laravel, or Symfony do right that Rails does so awfully? I have had to use Symfony and everything about it was an inferior/weird Rails.

This is the old "use the right tool for the job" cop-out. The original post went deeper than that. I would summarize it like this: can modern complex, large-scale web apps be built with the tools we have today, be they Python, Ruby or Javascript?

Or do we need an entire new class of tools which have traditionally been used to build large scale systems in the past?

It's a multi-faceted question of type systems, tooling, packaging, dependency resolution and others. And as web apps continue to evolve, my guess is that the current tools will be considered lacking.

It used to be that picking "the right tool" meant choosing between Ruby, Python, PHP, JS. In the future it might mean using (gulp) Java + WebAssembly or a combination of other unusual tools. This would be quite game-changing for most web developers. ;)

> The original post went deeper than that.

If there was depth, I missed it. The only two points I got from it were 'I prefer static typing over duck typing' and 'avoid dependency hell'. The original post didn't add anything new to either argument and both have existed and been rehashed over and over again for decades.

And he didn't point out how any of his "todays languages" are any better at avoiding dependency hell.

Go statically compiles everything into a single binary. I'm not sure what is meant by "dependency hell", but this at least simplifies the runtime story.

> simplifies the runtime

That has been a solved problem in ruby for a long time. Bundler[1] (or similar tools) does the equivalent of static compilation by copying[2] all of the dependencies into the project and statically loading[3] them.

[1] http://bundler.io/rationale.html

[2] http://bundler.io/v1.12/bundle_package.html

[3] http://bundler.io/v1.12/man/bundle-exec.1.html#ENVIRONMENT-M...

I'm sure it helps, but you still have a runtime dependency on Ruby as well as something to unbundle the bundle. Maybe this isn't a big deal, but it's not as easy as a single static binary.

Fair enough. He would have done well to explain that. Java does the same. Is it considered tomorrows language? At the end of the day its another trade off between compiled and interpreted languages, and one thats been around for years.

Java doesn't do this. There are tools that let you bundle all of your jar files, but even then, you typically have the JVM as a runtime dependency.

also, the image of a pig's face as electric socket while hilarious, shows how much the original author mis understood duck typing. It's not just look like duck, but also quack like a duck. Since when does a pig's nose behave like an electric socket? The idea behind duck typing is about concentrating on behavior instead of identities. He completed missed it.

It was just a funny picture. And besides, duck typing doesn't rely on things behaving the same. It relies on them appearing the same (in terms of method names). A pigs nose appears like an electrical socket in that it has holes in the same places. So actually it is a pretty accurate picture.

That said, I don't think duck typing is Python's biggest problem. Go sort-of has duck typing, in that you can make a type implement an interface just by giving it methods of the right names. It's a bit safer because you have to specify the 'ducks' though. It's kind of static duck typing.

Rust gets it totally right. But anyway the dynamic typing is a far worse issue than duck typing.

A language with more strictly enforced interface inheritance would probably require a more, uh, deliberate intent to stick an electrical outlet into pig's snout, but you could probably still go ahead and do this if you were really hellbent on it.

I will concede that duck typing allows you to do this sort of thing more casually, though.

The trick is to ignore everything until the "duck typing" picture including the picture. Then to pay attention to the last four paragraps.

There still isn't much there, and some of it is just unfounded.

For example, while the author claims there are 'crazy levels of duck typing' in Ruby / Rails he provides no such evidence of it and as noted by recent work from Aaron Patterson the vast majority of calls sites even in a very large rails app are actually monomorhpic (https://www.youtube.com/watch?v=6Dkjus07d9Y).

But more important than this cherry picked example is the complete lack of this type of technical discussion, which is why I find the post very shallow.

Is Java really that unusual of tool? Java 8 + Spring boot + Jooq is a simple and powerful tool to build backend services. There is already great tooling, libraries, and a wealth of information around solved problems. Dare I say, it is almost boring to build backend services with the above stack because it is so straight forward. Maybe that is why it is not used, I mean talked about :)

Has Rails ever been for "complex, large-scale web apps" though?

My understanding of it has always been that it was for the vast majority of web apps, which are neither particularly complex nor particularly large-scale. Rails was there to help those projects get started easily and iterate rapidly. If your Rails app turned out to be a hit you'd probably need to rewrite it, but that was OK because (1) very few apps qualify as "hits" and (2) only apps that actually get written can become hits, and with Rails it was much easier to turn ideas into functioning code.

Large-scale web apps have their own unique types of problems. New tools may be needed to cope with them, but that's a whole different thing than the problems Rails was created to solve.

can modern complex, large-scale web apps be built with the tools we have today, be they Python, Ruby or Javascript?

They absolutely can be built using just Rails (or python) and HTML.

I won't shill any harder about how, but it's not only possible, it's enjoyable and easy. I've done it.

Why not? I would be curious to see how people tackle large, complex web software in an efficient way - that is with tools support, not by fighting against them and working around inadequacies.

Example: if the unit tests represent 50%+ of the code base, one is probably working around dynamic typing.

And here's some examples of complex software for comparison: image editor, digital audio workstation, CAD, video conferencing, computer vision & imaging, office suite, large games (think DeusEx, not minesweeper).

Not complex: almost anything CRUD

> Example: if the unit tests represent 50%+ of the code base, one is probably working around dynamic typing

Unit tests are checking a lot more than argument type.. I have no idea what environment you worked in, but the comment comes across as rather clueless.

The 50% heuristic comes from a story I read once about a company claiming they were able to build a ~200 kloc app in a dynamic-typed language.

The secret was their ~200 kloc unit test suite. :)

It has nothing to do with argument types per se, just that one must have very high coverage in order to be able to be reasonably sure that their app won't crash after minor code changes.

In my current project we can get away with having integration tests cover a lot of ground and only unit test what makes sense thanks to static typing. High coverage is good to have, but should be balanced with test development and maintenance effort.

Unit tests check a lot more than whether the argument is Int or String, but so do good type systems. I'd say your comment comes across as more clueless.

A huge portion of unit tests are doing exactly that. Many people simply don't realize how many problems are actually type problems. Like null/nil/whatever as the most trivial example. It is more likely that your comment is made out of ignorance than the one you replied to.

Mmm. By that definition, I would not define the software I built as "complex". But I also wouldn't define Facebook, GMail or Stripe's web app as "complex" either, and I see folks using very complicated client-side technology to build those "simple" apps.

I use intercooler.js, which I built, and which I shill heavily because I'm quixotically trying to fight the Facebook/Google 80's-style-thick-clients-in-javascript zeitgeist.

Claiming it is easy is probably bit of a stretch. I can't imagine any large-scale web app or native desktop app being easy to implement, regardless of the tools.

The original post (not this OP) was clearly a response to Rich Hickey's talk "Simplicity Matters," which was given at a Ruby conference.[0] Particularly the part about "1,000 gems," which Hickey calls "hairballs" in the talk. I've started calling all packages hairballs since watching that.

[1] https://www.youtube.com/watch?v=rI8tNMsozo0&t=15m39s

To be fair, given the quality of the code from most Rails developers, the gems are more like turds than hairballs.

Actually I would put Ruby, Python and PHP and server side JS into the same category. Need something more performant, look at C or Java. JS has it's own niche on the front end, so you don't really have a choice there. Need concurrency, look at Erlang or GO.

This. For backend applications the difference between ruby/pyhon/php is negligible. Maybe node.js is a bit different.

Don't forget about .NET along Java.

> The original post went deeper than that. I would summarize it like this: can modern complex, large-scale web apps be built with the tools we have today, be they Python, Ruby or Javascript?

Well, clearly they can, because lots of people are doing it. Maybe some other tools would make it easier than it is now but it is certainly possible now.

With a wide interpretation of "can", the answer will be yes. But that's not a particularly interesting question to ask, as you've said it yourself. If X makes it 50% easier to create a complex product than LAMP, that's a huge difference.

> In the future it might mean using (gulp) Java + WebAssembly

You know, after being out of the Java world for about ten years now, I'm starting to get the itch to use it again. I was one of those people that used to joke about programming in XML, but that's really just a layer of indirection which is often a good solution to a problem.

It's a very nice language, is fast, and has so far not been destroyed by Oracle. Plus JavaFX may be ugly, gut it is a cross platform GUI toolkit that works.

Let me take the opportunity to plug Scala, which gives you (better than) the expressiveness of Python or Ruby but with (better than) the safety of Java. (OCaml, F# or Haskell are other options in a similar quadrant).

Scala + Play Framework, which incidentally was inspired by Rails, however in my opinion is much more consistent amongst other things.

I'd like to add that ScalaJS on top of Scala + Play is really a pleasure to work with for web applications. The integration with existing Javascript libraries is very smooth and Play/SBT transparently handles the transpiling when you reload a page.

I don't actually like Play (its routing in particular is very ad-hoc and doesn't make good use of Scala's capabilities). I use Spray for JSON APIs and Wicket for HTML UIs.

> (better than) the expressiveness

You should say more rather than better, because better is very debatable when it comes to expressiveness. That expressiveness can often come at the expense of accessibility/readability, and IMHO that's the case with Scala.

A lot of the popularity of Go comes from its explicit lack of expressiveness. I barely use the language, but the one thing I remember most from my time learning it is that I could easily understand every Go source file I found. From Hello, World! all the way up to distributed applications/libraries, Go code was long/verbose, but explicit and easy to understand.

Meanwhile, I've never found Scala code to be very readable. It almost requires that the code be written with the same coding conventions that you're accustomed to using. Even when common conventions are used, we found Scala to be counterproductive in larger teams. Code reviews were significantly less thorough for Scala projects than either Java or Node projects were.

> That expressiveness can often come at the expense of accessibility/readability, and IMHO that's the case with Scala.

I don't think there's inherently a tradeoff. E.g. in Python you have to write "(lambda x: x + 1)" where in Scala you can write "(_ + 1)"; I think the latter is both more expressive and more readable, because naming "x" isn't adding any clarity for the reader, it's just ceremony that you have to skip over when reading. Similarly Python's verbose, repetitive constructors don't clarify anything (worse, they obscure the rare cases where your constructor does something different from "self.x = x; self.y = y; ...", making it too easy for a reader to be surprised/confused by those cases).

> A lot of the popularity of Go comes from its explicit lack of expressiveness. I barely use the language, but the one thing I remember most from my time learning it is that I could easily understand every Go source file I found. From Hello, World! all the way up to distributed applications/libraries, Go code was long/verbose, but explicit and easy to understand.

I think people overestimate the importance of understanding a line in isolation and underestimate the importance of understanding a whole component or system. A one-screen class where you have to spend a couple of seconds understanding each line feels harder to read than a three-screen class where each line is simple, but (IME) ends up being more maintainable.

> Meanwhile, I've never found Scala code to be very readable. It almost requires that the code be written with the same coding conventions that you're accustomed to using. Even when common conventions are used, we found Scala to be counterproductive in larger teams.

All I can say is that's not my experience.

> Code reviews were significantly less thorough for Scala projects than either Java or Node projects were.

I don't follow. Surely if people find it harder to read they should codereview more carefully (or simply reject on grounds of unreadability)? That's what reviews are for, no?

> E.g. in Python you have to write "(lambda x: x + 1)" where in Scala you can write "(_ + 1)";

Can you give the lambda variable a name in Scala? In Python you can write "lambda city_name: add_state_suffix(city_name)"

Yes, you can write (x => x + 1) as well, and there are certainly cases where you want to. (Some people argue it's confusing to have two ways of writing the same thing, but it's a very mechanical transformation, just syntax, not a conceptually different way of doing things).

Scala and Clojure are both on my list of things to investigate.

It certainly doesn't give the readability of Python or many other languages

It absolutely does, if you stay away from bad libraries. Most of the time you can translate Python directly 1:1 into Scala, or do better (e.g. none of the junk repetitive "self.x = x" constructors you get in Python).

Add Groovy to that, and you have the dynamic typing and flexibility you see in Python and Ruby with Java. JDBC with Groovy SQL or JSON parsing with Groovy's JsonSlurper is a joy to work with.

I still have PTSD from trying to write correct concurrent code in Java. Everything I used to do in Java I now use either Scala/Akka or Go.

> can modern complex, large-scale web apps be built with the tools we have today, be they Python, Ruby or Javascript?

For me, after the experience working on a startup that used TCL using an approach similar to AOLserver back in the first .com wave, web apps are always built with JVM, .NET or any other JIT/AOT enabled language toolchain with JavaScript kept for its indisputable place on the browser.

Rails codebases do not age well, and are always unpleasant to work on. I never saw the same issue with django codebases of a similar age. Nor even ones from Perl or PHP frameworks either.

No. It is a special combination of the shiny insecure magic of Rails, mixed with the happy meal mentality and abilities of most Rails developers.

The last two codebases I have inherited in Python have been fairly poor. And the Java ones before that. I don't think its a language specific thing.

You've never seen a Perl or PHP codebase age poorly?

That's unbelievable.

Oh, you again. Never mind my earlier question. I see that you have some special, irrational vendetta against Rails.

Recently I upgraded a project from Rails 3.2.x to 4.0.x... 4.0.x -> 4.1.x... 4.1.x -> 4.2.x

It was, and still is, a nightmare.

Technically speaking Rails itself upgraded in a reasonably straight-forward way, just follow the documentation (well and a few blog posts here and there for the things missed in the official docs). But all the additional Gems, and dependencies of those Gems (and so on) made the process excruciating. Many things broke in subtle ways at runtime (no compilation, so no compiler errors) and there was no clear path to upgrade; because whilst Rails' upgrade path is documented, there's a plethora of Gems that also needed to be upgraded separately (some in contradictory manners).

You might wonder why I was so out of date in the first place. Two reasons:

1. I inherited this code-base.

2. I've attempted this (or a similar) upgrade about 5 other times in the past; spending hours upon hours debugging crashes (or just weird behaviour) with enormous stack-traces where my application's own code often doesn't even appear in the stack trace. It's only now after making several failed (or rather overly time consuming) attempts I was able to come up with a "workable" upgrade path.

Gems dynamically generating methods left, right and centre, Gems replacing methods of seemingly unrelated classes (when they definitely do not need to), and crazy "conventions" that hide all the actual logic make debugging any sizeable Rails project a complete disaster. Don't even get me started on the poor performance, much of which is to do with poorly designed Gems and not even the Ruby interpreter's fault.

That said... I still turn to Rails when I want to get a new project (with users, database, login, admin etc.) up and running quickly. It's a shame, but in terms of development speed, it's hard to beat Ruby (and Rails). For small projects Sinatra is very solid, and Padrino is interesting - but honestly I can't wait for the day I can move to a compiled language and still achieve this sort of development speed.

The main problem I see in the ruby community, in this regard, is the willingness to make breaking changes and justify it via Semantic Versioning. While on the surface this seems ok the underlying problem, as I see it, is the old version isn't maintained, so essentially the only maintained version now has breaking API changes.

There are few ways this could be addressed, e.g. separate branches for old gems, and some developers do actually do this but in the end I've noticed these legacy branches and gems just bitrot while the developer devotes their time to the new branch. So essentially to use the gem you have to make the SemVer API jump which then begins the dependency failure cascade dance you mention.

I'm close to starting another new Rails job and I'm not looking forward to the inevitable rails rescue work on legacy codebases, yet this is the reality of a modern Rails developer.

Also I think this upgrade work needs to be factored into "development time" and when you do I'm not convinced Rails is actually faster.

I think this is the source of the early focus on unit testing in the Ruby community.

The problem is a lot of Ruby developers have not felt this pain yet and eschew testing because they work in startups that are in a state of permanent death-march.

A little (okay, a lot) of unit testing goes a long way to ease this pain. The people making breaking changes in their gems usually/hopefully have good testing in place and the return output of their methods are documented.

I went through the same upgrade process that the OP mentioned at scale. The company had 5 or 6 microservices that needed to be upgraded from Rails 3.1. While having 10,000+ unit tests was very helpful for reducing regressions, we still had several huge problems:

1) We couldn't be sure that we hadn't broken something because we knew we didn't have 100% test coverage.

2) Some of the gems we depended on conflicted so severely that we had to rip them out and implement the solution ourselves or pick a different gem.

3) Our tests themselves of course contained code with breaking API changes. That means we had to maintain the tests as well as the production code through the upgrade, and had to make changes to many of those tests.

All of this uncertainty means that this was not your typical test-driven confident refactor. QA still had to do massive regression testing, and we're pretty sure we introduced at least a new bug or two. It took a pair of devs 4 months of non-stop work to get these services up to Rails 4.1. The upgrade was absolutely necessary as the Rails core team had already stopped fixing major security holes in 3.1 long ago. The company incurred a tremendous cost during this upgrade process. If they would have kept things up to date all along they could've saved money, but of course that would have eaten into the supposed time-savings of Rails.

I believe it and know that sucked, but unfortunately in Rails 3 we got caught with our collective pants down in terms of security. Nobody competent was really auditing it (as was demonstrated against Github) to match the amount of momentum that it had. I see that as more of a Black Swan event than any inherent problem with the framework (yes, I'm basically blaming its users). This wasn't typical of the Rails 2 to 3 upgrade path and doesn't look like it'll be the 4 to 5 path either...and certainly not for incremental updates.

I think your memory of the 2 -> 2.1 -> 2.2 -> 2.3 (if you were lucky to get bundler running) to 3 to almost immediate 3.1 with massive changes (asset pipeline) upgrade is a little fuzzy. It was the suck. A lot of companies I know of are still running Rails 2 because of this change.

Which companies? _trollface_

This problem isn't specific to Rails 3.1. At some point, your frameworks need to be upgraded, because at some point the developers stop supporting your version. Django announced recently that 1.7 would no longer be getting security fixes. The question is: how much will it cost to upgrade when the day comes? Frameworks and communities that encourage less magic and less dependencies will always be less costly to maintain.

true but even staying current across small SemVer changes can be a relatively large burden


Fair points all. But the breaking changes I'm referring to are items like changing method names, most likely because OCD, and helper methods, etc. While good/great tests will catch this type of stuff in your code, it will still be a lot of chasing your tail refactoring code because someone didn't like the way something was named. I see this a lot in the ruby community. Its like some sort of crazy insanity that ruby devs exercise when changing publicly exposed API methods just because _____. smh

Yeah changing your method names around in a publicly-exposed API that has users on an incremental release is more than a little bit belligerent.

I have upgraded a very large Rails 3.2 app to 4.2 recently. It was about 2 weeks solid of work for my team. It was a project I inherited and when I got it the test suite took an hour to run.

The biggest problem which I had was dealing with the dependencies. This project used just under 300 gems, many of them unmaintained and a few of them I had to fork to get to work with rails 3.

I am very fast making things in Rails, for the most part I find it just works. When projects get to a certain size, very roughly around 50k loc, they become very slow to work on. Slow test suites and dependency hell become problems.

  $ find -iname '*.rb' | xargs cat | wc -l
No real problems working with this codebase. ~190 gem dependencies.

Mind, most of the code is tests:

  $ find -iname '*.rb' | grep /spec/ | xargs cat | wc -l

I've found upgrade hell can apply to C#/dotnet stuff too. I work on a project that has attempted to upgrade Entity framework versions multiple times and keeps pushing it off because we get buried in compile time errors. It's a case where Microsoft supported several different paths to architect an app and then quietly deprecated half of them - database first vs. code first, POCOs vs. ObjectContext, etc. and we happened to be on the losing side of history. Compile-time errors are definitely easier to find, but the path to fixing them can be just as bad. What I really long for is good documentation and a clear path forward for each breaking change.

Indeed, Microsoft's lack of commitment to APIs is what inspired Joel's famous essay: http://www.joelonsoftware.com/articles/APIWar.html

IMHO .net has lost some stability with the recent packaging systems like NuGet and chocolatey; they don't really encourage stability.

Never much liked EF... Linq-to-SQL may be dead/stable, but we're still using it, and it's pretty slick - course it is only for SQL server.

The problem is not C# or .NET. The issue is Entity framework. Either stop being scared of using SQL and use something like PetaPoco or stop trying to turn objects into records and use Mongodb and just store the damn objects.

I hear horror stories like this, and I have one of my own.

1. Absolutely no tests of any kind

2. Over 100 gem dependencies

Upgrade from 3.2.x to 4.2.x took one developer (me) three weeks of work. I don't know if that's a lot or not, given the major version upgrade and all of the gems (which were a huge pain). I've not had any problems in production reported via Honeybadger or by end users, so I think the upgrade was a success. I did end up writing about 200 unit and integration specs during the process.

I'm thinking back to my days in the .Net world at BigCorp. Unfortunately I have nothing to compare it to, because we never upgraded anything from one major version of ASP.NET MVC to another. Is that a better situation?

A huge upgrade on code with no tests and a bunch of magical dependencies?

The problem wasn't Rails there.

There's an argument to be made that Rails, by not actually enforcing conventions like TDD, gives an amateur/impatient developer a very high calibre footgun.

Unfortunately, of course, that gun doesn't usually go off until it's handed to someone else.

Not enforcing TDD? Rails' own creator bemoaned the culture of test cargo culting in the Rails community. This is pretty well documented. If there's something Rails falls down on it's certainly not testing.

Is there anything that actually "enforces" TDD? Because if there is I want to stay away from it.

Yes. Being forced to push changes to production with zero test coverage, and hence zero confidence in your code on a Friday night. (true story)

After that you always make sure test exist before even pondering a push of potentially breaking changes! :P

Oh yeah, I mean I always write tests for anything for work. I don't do TDD all the time though, sometimes I write the tests after the code. A language/framework that forced me to do TDD would just piss me off, which was my original point.

I was being tongue in cheek on that one, sorry if it didn't come across that way. Although I've been a Rails dev for 6 years now, I've come to hate the TDD approach and am a convert of FP and types, & compilers a la Haskell. Because there really is no such thing as a massive change in FP IMO. Unfortunately I'm not competent enough in it yet so Rails still pays the bills.

My "enforcing TDD" point was rather tongue in cheek. Really, I was just saying that a rails app of even moderate complexity with no tests is a very dangerous beast, and something I would not wish upon my worst enemies.

You can remove the word "rails" from that, and it's still 100% true.

True, but I think that with rails and a few dozen gems one can bolt together a terribly architected app that on the surface seems to work but is in fact a bunch of spaghetti and lasagna code bolted together with duct tape, teetering on the edge of a cliff like a house of cards; checkmate.

(sorry, couldn't help the futurama/zap branigan reference once I start mixing metaphors).


When people are forced to write tests, they merely write lousy tests. It doesn't change anything.

In cases like this when I ask why TDD isn't done the answer is usually some variant of "its working" to which I usually reply "how do you know?". :P

The only library I've felt absolutely safe doing upgrades with is Wicket, because it makes extensive use of the type system to ensure that you only use it in supported ways: many classes are final, and even those that aren't have a lot of final methods. It can be frustrating to have to copy-paste a Wicket class when you want similar behaviour, but it works beautifully.

I've felt like any project horribly out of date is a pain to get current, Rails is no exception to that. Sure, many Rails projects have a lot of dependencies, but so do other frameworks. Sure, part of your argument is static vs dynamic, but I'm not going to join you in that argument.<grin>

This is exactly the past problem I've had with every Rails app I've been involved with (none of them have been from scratch) -- even during the setup process there's an immediate reckoning with gem snarls and other version issues.

"makes it easy to install 1,000 gems into your project without a single line of configuration, is exactly why it’s hard to debug".

This "let someone else do the work, get it from a gem" mindset is what kills long lived projects. It has nothing to do with the tools and everything to do with experience.

You don't need 1000 gems. Managing anything more than core dependancies in a project can easily create exponential bugs and consume all your resources to fix. Remember left-pad?

This is true in any language and ecosystem and has nothing to do with rails/gems/ruby. The same is with Python, JS, PHP.

Senior/Lead devs need to carefully curate what a projects foundation is. A strong, well designed foundation means you have something solid to build on. If you don't understand what's in your deps, haven't read their code, see how often it's updated and how many people actively use it, and can say you are using 80% or more of the code in it then don't use it.

Writing your own code is often the best route since it fixes your exact use case, no matter the language, libraries or frameworks being used.

I work on some really big projects in the wild for various clients in ruby on rails and they have so many gems that often I find unused gems they are afraid to remove them in case it actually is being used, but you know what? They were moving forward with features - their user base was happy and their product worked for the most part.

You know what kinds of projects I see fail? The ones who try to architect everything using a core set of libraries and build everything themselves. I've seen hugely funded projects with years of development burn for that very reason.

I know I'm just a single datapoint, but it's worth mentioning that there exists projects that absolutely will do better in the long run with just installing all the gems.

> often I find unused gems they are afraid to remove them in case it actually is being used,

I've worked on code-bases of small to medium size where people were afraid to remove self-written code because nobody knew if the code is actually called somewhere. It's not actually the gem that's the problem - it's being diligent. If you need a gem's function add it as top level dependency, don't rely on some other gem depending on it. require the code explicitly everywhere you use it. That way you can at least search your code base for it. Be equally diligent when removing code: Remove all code that only this code depended on. Other than that: Don't be afraid to break stuff.

> This "let someone else do the work, get it from a gem" mindset is what kills long lived projects

If you replace "gem" with "library", this actually makes a lot of sense. It saves time to reuse existing (high quality) software.

Plenty of ecosystems do just fine with this mindset, starting with the JVM and .net.

The problem is specifically Ruby and the gems system.

More specifically, the problem is the combination of Ruby making it very easy to monkey-patch and apply magic, and a community which more or less ubiquitously encourages gem authors to use those facilities as promiscuously as they like. Either in isolation would be dangerous; the combination is lethal.

> Senior/Lead devs need to carefully curate what a projects foundation is. A strong, well designed foundation means you have something solid to build on. If you don't understand what's in your deps, haven't read their code, see how often it's updated and how many people actively use it, and can say you are using 80% or more of the code in it then don't use it.

Having to deal with my share of poorly supported components in Django/DjangoCMS, I can confirm your observation for Python. But betting on the wrong opensource component is often better from betting on the wrong proprietary technology. It comes with the territory.

> Writing your own code is often the best route since it fixes your exact use case, no matter the language, libraries or frameworks being used.

The problem is not you supporting your own code versus you supporting the code of a random dude from Internet, the problem is when you move on to the next job and some poor guy has to support and fix bugs in your code from 3 years ago. In my experience the average quality of community components and components developed in-house are not that different.

Personally I wish project managers starting caring more for life-cycle planing.

This kind of thinking is how you end up with 8 zillion job-securing lines of custom frameworks-within-frameworks and stuff like:

  def isTrue(x):
    if x:
      return true
      return false
Code is debt: https://blog.codinghorror.com/the-best-code-is-no-code-at-al...

Reviewing vendor libraries always a good idea, but you aren't going to make it very far as a "Senior/Lead dev" if you are constantly using someone's money to reinvent the wheel.

  $ tree node_modules

Author is being nice, but I'm happy to point out that author of replied-to post is revealing they are a frustrated novice. All the focus on "Rails made programming cool" tells me "I do things for dumb reasons." Clear case of chasing the dragon.


Your comment comes across as narrow-minded and frankly, a bit arrogant. It is just so dismissive. Rails's original popularity came from developers fleeing the excessive ceremony and boilerplate code of enterprise Java – and .NET to some extent.

Sure, there are some inexperienced (or simply bad) developers in the Rails community, just as there are in every community. But most of the Rails developers I've met also have experience in at least one other major web stack. They're not chasing "shiny magic features". They're chasing productivity.

For me personally, Rails offers greater productivity than any other web framework I've used. The truth is Ruby has little to do with that, as much as I happen to like the language. I could go on for quite a while about why I feel Rails offers the best productivity, but it boils down to two main points: the entire Rails community is focused on building web applications, and the Rails core team is mostly comprised of people actually building web applications. Features get added because they're needed. Common frictions get ironed out.

Rails isn't about "magic". Rails is about getting shit done, quickly and mostly-cleanly.


I'm curious to see examples of the shiny magic you're talking about. Honestly. I can think of some conventions that seemed a little magical at first but make more sense once you understand what's really happening under the hood.

Have you worked much in Rails? I'm asking, because it sounds like your exposure is mostly from demos and blog posts, which are obviously going to use the five-minute, "happy meal" examples. A complex, real-world application is very different from a presentation where somebody whips together a blog engine in 15 minutes. For example, I can't remember the last time I saw somebody use the scaffold generator for production functionality, other than maybe for temporarily mocking up some functionality for stakeholder feedback.

I'm wondering if some of our difference in opinion is just based on Rails appearing easy to use. Take ActiveRecord for example. Sure, you don't need to understand SQL and database engines to get started using it, but if you're going to build anything serious, you better understand how to drop down to raw SQL when necessary, how indexing works in a RDBMS, etc. I personally think ActiveRecord, while a bit bloated, is a great mix of making the simple stuff extremely easy and getting out of my way when I need to do something more sophisticated.

And I think that applies to Rails overall. It makes the simple, routine stuff very easy, and it lets me do more sophisticated things with minimum complexity overhead.

All of that said, my opinion is based on my experiences. It sounds like you've seen/had other experiences with Rails, maybe systems built by less mature developers. I've inherited some bad Rails systems, but I've inherited just-as-bad systems built in Java, .NET, PHP, Javascript, etc.

Haha perhaps.

/me is a Rails programmer, a lot of the time.

Reposting a reply I put on the original submission, but pertinent here as well:

Use whatever tools/framework you want. Whatever it is you use, you will eventually become [the original] OP. The reality is that every language/framework has warts. As you use it and get deeper into it, you will uncover these warts. Eventually, all you can see is the warts.

It's important to take a minute every once in a while and look at the thing you built from a user's perspective. See what problem you've solved for people, or just what cool new thing you've built. Staring at a bug backlog and a mountain of tech debt will always get you down about your project, but that's the reality of programming...bugs and tech debt.

I feel like this is a terribly lacking reply. I'm not a trend-person by any mean: I'm a deep-backend developer, and my main language right now is Java[1]. However, when I have to maintain rails apps, even well-written ones, I find myself frustrated. I think ceding the advantages of a compiler is a fundamental mistake. Compilers and static checkers make for better software more easily; they don't replace tests, but they complement them and constitute compilable documentation for your code, enhancing its maintainability considerably.

[1] I write in Java because I work for a Java shop, but even if I had my choice of languages, I'd probably be using either Swift or a compile-to-JVM language.

Many of the complaints against Rails in this HN discussion are around code base maintainability, gem proliferation, and amateurs.

Any tool that allows the rapid (almost effortless) accretion of complexity will suffer these problems. It goes with the territory.

I think that's a good point. JavaScript with Node is arguably worse than Rails for exactly that reason.

The author leaves the business needs completely off the table, even though it would help his case. If you have a limited amount of time to launch your product in your current round of funding, and you want a framework that helps a small number of tech employees build working first generation critical features reasonably quickly, handle a large number of tasks not critical to the company's value proposition reasonably well, can be maintained and scaled on a variety of PaaS options well long enough until the company is profitable enough to move to the next phase of tech infrastructure, is Rails attractive software? I'm not an expert with it, and I don't even enjoy using it, but I believe it is.

I considered speaking to that, but then I felt like I was delving into religious arguments. My framework is more efficient than your framework! I felt it would have drawn people away from my main point, which is to think deeply about the tools you choose, and everyone needs different tools.

Some software does become "yesterday's software." I'm looking at you Cold Fusion, Flash, COBOL, the Abacus. I don't think Rails belongs in this group. I recognize that it's a good framework even if I don't personally like.

Interesting comment; I believe if you are going to implicate Cold Fusion, you also need to rope in PHP.

My first exposure to web programming was HTMLScript at my university in the mid 90s (now called MivaScript and is the language used to build the MivaMerchant product). Soon after, I switched to PHP 3, but I found that I preferred Miva.

I have not touched Miva in years after spending some time as a freelancer in the late 90s, but because it is tied to a successful niche e-commerce platform, the language survives. It is very similar to Cold Fusion minus the enterprise level database support.

I worked with CF for a time in the late 90s/00s (when it was still a product of Allaire) along side of ASP (pre .net), and I actually preferred it to both ASP and PHP - mainly because the mixing of mark up and DSL blocks seemed really unscalable.

PHP may have been seen as an evolution in web programming since it abstracted the mixing of logic and presentation a bit more than Miva or CF, but in retrospect I believe PHP was not an improvement. It made general web programming easier, but software maintenance is easier in languages like CF and Miva that embrace embedded mark up/logic.

The frameworks provided by Ruby, Python, Perl, and even TCL (among others) seem to have reached a point where only blurring the lines between client and server seem like the only logical paradigm change - and that's not to say it's an improvement.

This isn't really the case. There are modern web frameworks for PHP -- https://laravel.com/ is the best example

Also PHP still powers much of the web and has taken a step forward with PHP 7 which seems to run a good bit faster than Ruby and the like.

Mostly because of one application (Wordpress).

It runs a bit faster because of wordpress? :)

Assuming you were answering to your GP, modern PHP is a totally fine language to program in with a lot of upsides (that would take too muh to enumerate here).

Some transaction you perform today will touch a system running on COBOL. I've come across finance and retail systems that have been running for almost as long as I've been alive, some of it on original hardware [0]. The reason we don't develop anything new in it isn't because it's awful (though it is awful), it's because most of the important things we wrote in it are still working.

[0] Sometimes this is better than the 'N layers of crufty consultant supplied virtualisation' model. Sometimes it is not.

It's the same empty argument that started being thrown at PHP six or seven years ago. Because it's not the hot new thing, it's yesterday's software, regardless of whether it's still fully up to the task. Rails will still be going strong ten years from now without question, and there will be frequent articles proclaiming that it's terrible that whole time.

I personally love ruby and rails and still find it to be extremely effective and adaptable to most web development tasks.

As people flee the platform a huge amount of opportunities are going to open up for that still enjoy the platform. I can't wait.

The problem I feel with Ruby and RoR apps is that people bang gems together without knowing how those gems do what they promise to do, what those gems depend upon, what those gems monkey patch, what they change.

Further down the road, maintenance drowns you.

I've rallied against this mindset before, e.g. regards security http://williamedwardscoder.tumblr.com/post/43394068341/rubys...

I find large Python apps fairly unmaintainable too, but to a much lesser degree.

There is, perhaps, a law, such that any project with a strong tendency to pile up more crap instead of reducing it to "just right, when nothing else could be removed" (a-la 9P2000 protocol, and few foundation libs of Plan9) will end up in a J2EE-like pile of collective stupidity.

At least, everything in nature tends to get reduced to a local optimum by a straightforward optimization process of trial and error. There is no way to make a reliable and efficient complex system by piling up more and more crap.

And, funny enough, JavaScript will be even worse - it already makes J2EE look not that bad.)

This should be studied in comp sci. Instead of building compilers and interpreters in the abstract, there should be a serious study of how languages/frameworks are created and developed in the wild.

I suspect there are easily visible patterns and trends, and they tend to repeat over and over.

The corollary is that specific languages can't fix cultural issues unless they're designed to do that.

I've got my problems with Rails: routing is overly complicated, the asset pipeline can be tricky, and so on.

But Rails is very good at producing HTML and, in particular, partial chunks of HTML. As the current thick-clients-in-javascript trend cools off (it's happening, this was at the top of /r/webdev yesterday: https://www.reddit.com/r/webdev/comments/4iphv4/12_year_of_p...) people are going to migrate back to HTML as a transport for web apps, using libraries like http://intercoolerjs.org. (Disclosure: I developed it)

Rails is well positioned for that.

The assets pipeline can be tricky, sure, but it's tackling an issue that is really hard to get right. Routing in Rails on the other hand, I don't really see what's so complicated about it. You define resources, you have namespaces, constraints, the DSL is extremely nice and straightforward, I think it's actually one of the huge successes of Rails as a framework.

IMO the asset pipeline is not worth the complexity. CDNs + caching do a good enough job of getting stuff to clients, so the complexity (and distinction between dev mode and production mode) isn't worth it.

My problem with routing is that the default is an implicit semi-REST pattern, and that routing a lot of verbs to the same controller method is tedious. I prefer Sinatra's "ground up" model instead, although you can certainly write a rails router that way (and sinatra has the same verb problem.)

But I concede that's a matter of taste.

What makes you think that being able to produce HTML is such an important piece, and that Raila delivers better than most other frameworks?

HTML gives you HATEOAS without thinking about it:


and is the minimum level of complexity necessary for a human web interface.

Rails isn't necessarily better than other platforms at producing HTML: it does support rendering partials which is nice: http://guides.rubyonrails.org/layouts_and_rendering.html. So, rails is pretty good at it, but I can imagine other tools being perfectly competent at the problem as well.

> HTML gives you HATEOAS without thinking about it

No, it doesn't, though it certainly makes it simpler (than something not designed as a hypermedia format) to do HATEOAS if you think about it.

> As the current thick-clients-in-javascript trend cools off

...thinks like WebAssembly will be ramping up, spurring a trend of thick-clients-in-other-than-JavaScript.

Rails is still page-oriented, no? I've found Wicket is head and shoulders above anything else for actually producing HTML, and it can already do lightweight partial ajax updates to the UI if that's the style you're suggesting.

Rails lets you render partials directly.

I've never used wicket, but it looks pretty good at this sort of thing.

> As the current thick-clients-in-javascript trend cools off

I think that's wishful thinking.

The drawing you link is great though.

Maybe. I've been through three JavaScript hype cycles now, though, so it isn't as unlikely as a lot of folks think.

Dynamic languages reduce the formal overhead required to develop new ideas.

I can't imagine that an "eliminate boilerplate via convention at the cost of explicitness" mentality would have evolved independently in a world where assurances are earned by proving extra properties to the compiler.

However mordern compiled languages now formalise the shortcuts afforded by dynamic languages, e.g. type inference, generics, implicit conversions, typesafe macros, type classes, etc.

Similarily conventions popularised by rails-esqe frameworks are being formalised using the tools listed above.

I fall into the scala camp, but have used rails at a previous job. My guess is I need 1.5x scala lines vs Ruby which I believe is a justified cost. Opinions of course vary.

At the moment, the alternatives mentioned to Rails aren't actually alternatives. You are still going to make major trade offs in productivity compared to Rails...

Unless he's talking about Elixir and Phoenix, which IMHO is the future of web development.

As someone who has never heard of Elixir/Phoenix, why do you think it's the future. What does it do better than Rails? I'm looking to start a new web application, and I'm open to new technologies.

Elixir is a nicer to work with language that Erlang that compiles down to the Erlang VM. That gives it a better concurrency model and fault tolerance than Go.

Rails core team members have been building Phoenix. It's syntax is built to be extremely familiar to Rails but it's been built from the ground up to correct a lot of core issues that come up long term with Rails. It's basically fast Rails.

You get a very equivalent level of productivity with performance and fault tolerance of Erlang. Benchmarks show performance on par with Go.

It's really fascinating. I've been programming professionally for about 17 years now and it's the first time I've been truly excited about a language for a long time.

First, thanks for taking the time to answer my question, I'm at my day job (I program at night) so I can't do much research

>correct a lot of core issues that come up long term with Rails.

I've never gotten to this point, what are some of these issues? From reading comments here, it seems like dependency hell could be one, but what do you think? I've had issues in my short time with outdated gems, but I don't know if this is necessarily an issue with the framework/language.

For me personally, one of the coolest features of Phoenix is that it natively supports concurrency. Communicating with a front-end via websockets is really easy to do with Phoenix, whereas in Rails it's basically unheard of. I know that Rails 5 is going to introduce ActionCable and that it's possible to write event-based apps with EventMachine, but these are ultimately poor solutions compared to what's capable in languages that take concurrency seriously (like Elixir).

Dependency hell is s big one.

Monolith syndrome is another and one of the huge perks of Elixir is that it forces you to build in a way that makes separating out parts later on much simpler.

Performance is "the" major one because it's one of those things that you just can't overcome easily with Ruby. Usually that leads long term to refactoring a part of your system in another language like Go just for performance sake.

The routing layer is one of the biggest issues that is incredibly difficult to solve in non-compiled languages.

People are familiar with callback hell in JavaScript but the same thing happens overtime from using all of those before/after callbacks, nesting from inheritance, etc.

Rack middleware is great until you only want it on some of your requests. At that point things end up in a top level controller that other controllers are inheriting from which forces those parts to get hit after the router. Phoenix has something called pipelines that basically lets you define your middleware stack for sets of routes or even based on request matching like "accepts json" vs "accepts html".

ActionCable has just been added to handle websockets but whether or not they will actually scale remains to be seen. Phoenix has been built for it from the ground up and it's very impressive. You can find the 2 million websockets on a single server benchmark with some Googling.

RAM and CPU usage is better. Concurrent processes have built in supervisors that know how to restart them on failures and know how to drop associated concurrent jobs as well. It's as easy as Go routines but with fault tolerance.

Erlang eco system libraries are usable and bring a lot to the table so it's not like starting from nothing. The "awesome-elixir" page on github is a great reference.

It's functional programming with immutable data structures which forces you to think about problems a bit differently, but also ensures a better concurrency model since there is no such think as a mutex lock.

The built in hot code deploys from Erlang gives you zero downtime deploys on a single machine. Although I haven't yet tried this, people have suggested that this means you could deploy to with millions of connected websockets without breaking the connections (in the same way that Erlang was built to do this with phone systems without dropping calls).

It's a little bit mind blowing and as you can probably tell, I'm excited. ;)

Thanks a lot. I'm going to research this once I get home. You may have just saved my future project time/money.

I have to say I'm loving reading the thoughtful and insightful comments on this thread.

With any programming language and/or framework you have to pick your poison. Rails backloads a lot of big development obstacles that ultimately you may never actually encounter in the life of your app. The issue regarding gems can be aggravating. But the speed in which you can get your app built cannot be understated. Rails is not a one size fits all, and you might eventually outgrow rails (i.e. Twitter). Be grateful the framework got you to the point you could outgrow it, rails helped you get there.

In the original article, he indicates Swift, Rust, and Go are tomorrow's languages. The issue really is that the level of support in the various frameworks, the eons of bug-crushing and feature additions, and the libraries available, are going to be behind for some time. This is why I'd still gladly pick Django today.

What is "the future" isn't really so interesting as what is productive.

Yes, performance matters a bit, but development time is usually much more expensive than adding a few nodes to an autoscaling group, and not worth the cost of using less fleshed out libraries.

In my experience as a professional Python dev and a hobbyist Gopher, Go's libraries are a lot less convoluted than Python libraries. In Python, you see a lot of libs that try to do everything for everyone (think long args lists and functions that try to guess the right thing to do based on arg types) whereas Go libraries just kind of snap together neatly. Go tends to be more productive for me than Python specifically because its philosophy values simplicity and orthogonality over complexity and scope breadth.

> Yes, performance matters a bit, but development time is usually much more expensive than adding a few nodes to an autoscaling group, and not worth the cost of using less fleshed out libraries.

Sequentially, Go outperforms Python and other interpreted languages by a wide margin (usually a factor of 10). Things get really interesting with Go because it can be massively concurrent without messing around with large async refactors. At work, we're hoping our first iteration (i.e., before any async refactors) of our Python application to handle something like 5-10 concurrent requests per machine (without degrading response times), but I'm confident a single Go process could handle at least 10X that load with better response times. This order-of-magnitude difference seems fundamentally different from the perspective of "throwing hardware at the problem". Further, Go's library story is fairly complete (for web services; GUIs and other domains are still lacking)--at least it's been a long while since I've lacked a complete library for some task.

Again, performance isn't everything.

Go has specialized a bit towards low-level operations, and I tend to strongly dislike what it does with exceptions and the way those involved veto language features.

As for libraries, I'm talking about things on the level of, say, Django or ORMs.

I don't disagree that there are other criteria besides performance, only that Go services will likely cost an order of magnitude less than Python services, and the development velocity is pretty much on par (and much better for concurrent tasks, since Go is much more expressive here).

Go is heavily optimized toward performance and rapid development. Go also takes a hard philosophical bent against redundant features, like exceptions, under the "less is more" and "simple is better than complex" axioms; it's actually the same philosophy that Python's zen espouses, except Go actually adheres to it.

Regarding libraries, there are numerous web frameworks and several ORMs. I'm unfamiliar with Django, but I will say that Go's standard HTTP library is a tremendous improvement over Flask. Also, I've not yet found an ORM that saves time or trouble over hand-coding SQL (in particular, SQLAlchemy is a real bear).

Fully agree with the post. Any time you're making decisions based on some dogma versus 'what is the best way to solve my current problem' you aren't guaranteeing an optimal solution.

Depending on the project, I think you have to give weight to long-term maintenance and on going development as well. If you're building SASS software that people use daily and may be in the market place for a long time, you'll need to balance both solving today's problems with being able to meet the future.

It's possible in this scenario, going with a proven solution like Rails me be it. I just wanted to point out that our solutions sometimes have to consider future considerations as well or have to consider continual development of a legacy product. Sometimes developers consider only whats best in the moment, and that has negative long-term consequences.


The thing is in many cases you had to make a choice between performance and productivity. With things like Elixir/Phoenix you don't really have to make that choice. Maturity argument again is moot as you are building on top of Erlang/BEAM that's very mature and has very good tooling. For people coming from Ruby the syntax also makes transitioning less of a pain.

In the comments of that HN post this link was posted which I found highly informative regarding the matter: https://speakerdeck.com/tehviking/surviving-the-framework-hy...

It seems to me that a version of the Innovator's Dilemma might apply to software frameworks as well.

By the time a project gets large enough it starts optimizing for its major stakeholders. New use cases or new ways of rethinking common use cases come along, and the small libraries that approach it from scratch have a narrowly-defined advantage. If the advantage is significant enough (e. g. virtual dom for browser UI), then new frameworks start being written around them, bringing back some but not all of the features of the older frameworks.

At some point (different for each user/use case) the newer frameworks have enough functionality that people start considering them over the older ones for new projects. When enough of that happens, the older frameworks start looking like yesterday's software.

PHP is the day before yesterday's software, but it still gets a shitload of profitable work done.

I agree with this quite a bit. Even in my own projects, I love using Rails for web stuff, but I would never use Ruby for games. It's a pain to distribute working binaries, and really is not an ideal language for games.

I've seen the biggest benefit from a client heavy approach even with rails. Make the api the core of your system, makes it easier to refactor down the road into microservices. For a lot of web apps there is no real need for server side templating, once you get beyond server templating its easier to make native versions of your app or use xamarian to access the same api from a common c# codebase for native. Place your business logic in the api and there's really nothing for someone to steal from view source because your clients are just REST wrappers.

Sometimes I wonder if Ruby and Rails is 5x faster then now by default and allow really simple scaling without much thoughts, would it still get so much critics?

Most of the time People will answer saying moving away from Rails as you scale is a good problem to have. But the day Rails isn't fast enough or scale easy enough is coming a lot quicker as the Internet Population expands.

And the good old saying of passing this to Morre's Law no longer works as we haven't had much CPU improvement.

I am hoping JRuby with Graal and Truffle will fix that.

Rails wasn't even the best choice when it appeared.

What would you say was the best choice when Rails appeared?

Since then, has Rails been the best choice at any point, in your opinion?

Anyone finding any of this resonating really owes it to themselves to try elixir / phoenix and, at the very least, keep an eye on it.

As more of the computational elements of UIs shift from server-side HTML to client-side Javascript, server-side frameworks like Rails, Django, PHP, etc. become less relevant.

Fast forwarding, many apps are (or will be) big JS blobs using APIs/microservices back to the server. In that version of the future, frameworks like Rails can get in the way more than they help.

I've come to the conclusion that those who defend weak/dynamic type systems and other unsafe toolchains simply buy into the fallacy of the uber-developer: the belief that while other, lesser developers need static typing and analysis, I'm so superior that I will never introduce those class of bugs, ever.

I like Elixir quite a bit, and it doesn't have a strong type system. The pattern matching removes a lot of the pain of weak types.

Could you point out where the author of this post even came close to suggesting that Rails is for great developers who don't need static typing?

Or did you accidentally post this unrelated opinion in the wrong thread?

I'm responding to the article that the author linked to, which does mention static typing. This comment is an attempt at a hypothesis for why some developers dismiss the importance of such features/tools.

I found this equally true for the other side of argument too. Some people choose to ignore that Polymorphsim is a dynamic typed behavior. (Its general being multiple dispatch.) And the faith to compiler seems not come from the understanding of what a compiler is. The author of the original post doesnt seem to recognize Java is also a slow, interpreted language. Haha.

It simply boils down to what you're most proficient with. Depending on the problem, you're likely to encounter some technologies are better suited than others. That to me is where you'll get the most bang for the buck, being able to decide on the right tool for the problem.

why do most people only see the extremes?

you don't have to use bleeding egde libs instead of rails...

hapi instead of koa

react instead of cycle

ember instead of react


Because we do love them, just like Vim vs Emacs, PHP vs Ruby, Go vs Elixir, jQuery vs React... But there is always something what I personally find very positive between all these differences. Please look at Windows and the Linux - some years ago we got used to installing a dual-boot environments and now we may experience Canonical's Ubuntu on Windows with real Bash.

Great follow up article. Choose the right tool for the job.

"Choose the right tool for the job"

What exactly does that mean? It's a vague response that people have used for years when they don't want to explain why they chose a particular tool. In my experience, many developers take the path of least resistance and use what they are comfortable with and that's why "it's the right tool for the job".

The problem is more that writing a post that is a list of if you have problem X use solution Y is a nonstarter. People like different things, have different skill sets, and are dealing with a different set of requirements. Finally, it is the sort of thing you would have to keep up to date with the latest version of every framework, language, and OS.

To discuss by means of example, lets talk about floors.

You decide to redo the floor in your place of residence. Do you:

0. Hire it out, using a cheap contractor

1. Hire it out, use a vendor in the middle of the quality/cost curve

2. Hire it out, using the classiest floor shop in town

3. Do it yourself, using a rental sander and a youtube video for training, sand your floors down and refinish using stain the guy at Home Depot recommended

4. Do it yourself, tear the floors out and replace them from the beams up using reclaimed lumber from the local artists collective.

5. Do it yourself, linoleum is fast to install, looks okay, and its super cheap.

6. Do it yourself, spend 6 years learning carpentry from a master artisan in the wilds of Scandinavia, fell your own timber using an axe you made yourself, assemble the timber into the master work of flooring using expensive danish hand.

Personally I try to do #1 for floors and #4 for software but that doesn't meant that works for you. If you have already done the first half of #6 I would be temped to just go all the way.

That said if someone gets bored we could do a sort of survey on a timed basis and rate different tools for different strengths ans weaknesses. Something where you could be like "optimize speed of development versus XML Parsing Quality" and it would give you a nice chart as long as you provide a few quick survey answers.

Might Give writing it a try later on. would be interesting to see what metrics people cared about.

Sometimes that's exactly what it means. The reason you see frameworks like Rails catching on, slow and bloated as it can be (and I say this as someone that loves the RoR ecosystem), is that developer time is generally more expensive than CPU time.

Couldn't agree more. Business (the people who pay us to code) generally doesn't care about performance if it's "good enough to ship". Time to market, on the other hand, is a matter of life and death.

Life and death also hang on other factors that swing the argument in the other direction, like can you scale quickly if you are the next big thing, are you stable, is your uptime acceptable, are there huge security holes that can tear your company to the ground over night...

Speaking in generalities isn't very useful.

Each project has to weigh the pros and cons of each decision. It's basic engineering.

Well, why not? "My team and I are familiar with these tools and confident that we can use them to deliver the desired result" seems like a fine reason to call something the right tool for the job.

They aren't the same thing but there's basically no room between "these are the tools I know"-thinking and "if all you have is a hammer"-thinking.

Freely admit this is somewhat irrelevant though as most languages are the difference between a felling-ax and a splitting-ax or two sizes of screwdriver, as opposed to hammer vs drill.

Well, I assume most people have a handful of tools they are familiar with and choose from among them (although the proliferation JavaScript-based stuff absolutely everywhere might call that assumption into question).

Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact