The Rails Way is wrong and has led thousands of projects to an unmaintainable state of highly coupled software assets.
In order to keep the growing complexity maintainable, and to maximize reusability, people now start to introduce “micro services”, which are physically separated, completely stand-alone applications that provide a subset of the application’s functionality via a document API.
DHH is absolutely right when criticizing this approach.
Not only does a “micro service” increase the complexity for deploys, because now, you have to roll out 17 applications and not just one, it also makes it almost impossible to test the application under real-life conditions.
The test environment will have countless mocks for “micro service” endpoints and results in half-assed pseudo images of production. The tests you write are better than no tests, but I doubt the pain for setting them up outweighs their integrity.
Now you have a fragmented system with loose coupling and a tremendous maintainance effort.
Micro Services! And Now?
People make it look as if “micro services” are the only alternative to a monolith.
They make it look as if you either have the choice between a huge pile of rubbish with many internal dependencies – your Rails Way monolith. Or your devops engineers – that you had to hire to take care of your system – have to deploy up to 17 applications every time APIs change.
This is absolute bullshit.
A monolith the way DHH leverages it is the excuse for a horrible software architecture without any encapsulation (called The Rails Way). The micro service architecture is the attempt to decouple things by enforcing physical boundaries.
Both are a nightmare.
What About Good Object Design?
Micro services are great if parts of your system are to be written in another language, or if you really need physical extraction for scaling or global reusability.
I have no intention to maintain 17 separated micro services along with my base application, not to speak of the testing apocalypse that is gonna come with that. I haven’t seen a single working, testable micro service system so far. If you have one, please invite me and change my mind.
On the other side, monolithic Rails apps are terrible, quickly become unmaintainable and testing will be a third-class citizen for the sake of “development speed”.
I don’t see what’s so hard about having a proper object design in one, monolithic Rails app?
You can have cleanly composed, separated layers with interfaces that allow reusability and simple testing and debugging.
You Can Have a Nice Service Architecture Within a Monolith.
You can have stand-alone components in your monolith, just not the Rails Way.
We have dispatching, deserialization, validations and forms, transactions and business rules, decoration and rendering, authorization and persistence, just to name a few. How on earth are we supposed to implement all that using three primitive abstraction layers?
The Rails Way is wrong. However, don’t let that mislead you to the conclusion that the only ways out of this are either micro services or, even better, switching to a new fancier language, just to do all the same architectural mistakes, again.
Decouple your logic from the actual framework, ship independent components in gems and introduce interfaces between your layers. This is only possible if you actually have abstractions, which could be service objects, endpoints, view models and higher-level abstractions.
Don’t let the monolith be an excuse for a shitty software architecture.
13 thoughts on “The Only Alternative to a Rails Monolith are Micro Services? Bullshit!”
The title is not much relevant to the article’s body. The title opposes the idea that Micro Services are the only alternative to Monolith so the readers will probably infer there are other alternatives to Monolith and seek for them in the article. Unfortunately there is no suggestions for other alternatives.
Linh Dam: Oh, I thought the very last paragraph gives you some ideas.
Someone tweeted a link to this presentation slide which talks about the very same. Thanks!
Your final paragraph suggests building a more decoupled, maintainable version of a monolith than a typical “Rails Way” monolith.
Even adding endpoints and APIs will not get you away from a monolith. A monolithic architecture is characterized by knowledge of the entire system spreading to the entire system. Microservices talking over JSON APIs are likely to be no less a monolith than a rails app.
All of this to say, I generally agree — if building a monolith is what you know and feel comfortable with, learn to build a better monolith. It’s not a flawed architecture.
Nathan: That is an interesting view, “monoliths know about the entire system”. In what way does a “real” SOA differ from that approach, then? Doesn’t a service client have to know semantics and syntax of the service provider, too? How would you characterise a SOA then (because you say services with JSON APIs are still monoliths)?
Microservies are just as much a team pattern as they are an architectural one. If your team is smaller than say 100 developers, it doesn’t make sense to go down this path.
As for never seeing a single working, testable microservices system; give Adrian Cockcroft, Sam Newman or Martin Fowler a call. I’m sure they can set you straight.
Nathan: A pub/sub service architecture is another story – super keen to play with some concepts here. But, again, that only works if you have a clean, separated architecture (which you already said).
Jeff: Interesting point on the team size! As I point out, I think micro services are extremely helpful, but not to cut down your Rails monolith complexity. Even smaller teams should have better architected systems with strong interfaces.
Calling Fowler sounds like a good idea, I just checked my address book and found his number between God and Jesus.
Good post & discussion. I don’t know anything about Rails, but Django web apps can often “end up” like this. Agree you need versatile abstractions so you’re not forced to shoehorn your app into “The Rails/Django/Whatever Way”. On top of that you need Vigilance.
p.s. in your address book, F is between G and J?
I can appreciate what you are saying here, but I strongly disagree. Coupled services are a rare thing in the world of microservice development; in fact, they’re a non problem. A good message broker or something like a well versioned protobuf will fix that for you. Also, I disagree completely with microservice complexity. Dockerfiles are stupidly easy to create (less time than a unit test) and even easier to deploy to an EC2 box. Our ops team doesn’t even manage deployments (they are that easy).
There are a lot of technologies out there to solve these problems and the reward completely outweighs what you’d get with a monolith. Words cannot impress how AWESOME it is to make a dozen releases a day and have a system where minimal effort is needed to scale. And I won’t even go into how microservices make problem solving a whole helluva lot easier.
I will admit that microservices are not good for everything, but to outright pan them like you have just shows ignorance. They solve way more problems than you’ve given them credit for.
Thanks David, you’re pointing out some amazing points here.
First of all, let me clarify: I didn’t intend to say microservice architectures are bad – I tried to point out that they are not a good replacement for a screwed up Rails application.
I love that you suggest Docker for a quick environment setup, I’d like to learn more how you structure your test suites for each component of your application? Because that’s where I see a real pain point.
Do you think using a “microservice framework” could help, and can you recommend any? Because am not entirely convinced by your argument of “use a good message broker” or “a well versioned protobuf” to fix “that” for me. I believe in patterns with actual implementations for it, I’ve heard the “use a service object to fix your Rails app” argument too many times – it doesn’t help anyone.
Exited to hear your opinions. Again: this rant is about people with fucked up Rails apps and then deciding that a “microservice solution” will fix everything, nothing against a well-working system here.