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.
I'm making a point that Wordpress is also "yesterday's software" and there's nothing wrong with making that choice.
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
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.
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.
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.
Edit: how do you scale? For example, do you just have lots of nodes running your authentication microservice for all of your active apps?
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.
If you enjoyed early adopter status in elixir phoenix, wait till it is Rails mk 2. It will suck big time.
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 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.
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.
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.
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.
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!
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
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
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.
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.
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.)
I think if you more fairly compare Rails with Django, Flask, Laravel, etc. you might find the differences aren't so great.
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, 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.
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.
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.
'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.