Sam Newman, a consultant and author of Building Microservices, writes about microservice architecture and patterns like Backend for Frontend.
Commenters call his book great and link his Backend for Frontend pattern page, noting it goes into more depth than other articles.
I appreciate you calling me out on my wording, because you are spot on. If anything GraphQL “bleeds” even more into my front-end code. I think the appropriate way to frame it is that GQL is a more targeted, holistic solution to the problem of fan-out data aggregation from the perspective of a UI client. Every UI codebase I had that depended on protos had significant chunks of code transforming the data more appropriate to our UI domain objects (that lived either in the front-end code base or one abstraction higher in a "BFF" [1]). Our UIs usually wanted to work with denormalized data structures, which was obviously in conflict with the proto models owned by small individual microservices.
GQL simultaneously addresses those two specific problems: resolution of normalized data, and giving UI consumers the power to declaratively fetch their desired data shape. It also has first-class TypeScript support through Apollo and the open-source community built around that.
I think it’s important to stress the tooling support, because you are correct… oneofs and union types are conceptually the same thing. A lot of it comes down to ergonomics in how you consume those types. In code generation GQL unions represent themselves as actual TypeScript union types, which means I can write type guards or switch on their discriminant to narrow to their correct member, whereas proto oneofs use a string value to access the correctly populated property. Small things in the day-to-day, but in how…
Frontend development involves I/O (server data fetching), which has implications
- it is async
- it can fail
- it is slow
TLDR you need a programmer to hand-orchestrate the I/O.
REST (HATEOAS) link abstraction permits a general solution to data-driven user interfaces (this is why web browsers are a generic user interface for simple html-only applications), but they are slow due to the way the data fetching is handled - see former facebook manager Pete Hunt's quote here (2014) which predates GraphQL https://news.ycombinator.com/item?id=7601774. Essentially we are talking about the object/relational impedance mismatch, which has performance implications and generally requires hand optimizing by a programmer (tweak the backend queries to batch a lot of stuff and minimize database round trips; tweak the frontend to do as few network requests as possible..this causes the backend-for-frontend pattern (anti-pattern) where you get N backends each hand coded... you can't abstract over this and also have good performance. http://samnewman.io/patterns/architectural/bff/) So you need programmers to figure out the right perf compromises and write the same shitty glue code over and over.
BUT if you have a graph oriented database with something like GraphQL to query it from the frontend, it's pretty easy to imagine abstracting over this stuff in a way that doesn't require hand-tuned performance e.g. Relay and Netflix Falcor, just needs one generic backend, and this paves the way for…
The BFF pattern[1] may be more useful today to many, due to various types and sizes of devices and different sorts of integrations.
MVC can be used in its place, but it would often introduce unnecessary complexity, e.g. additional controllers.
MVC works for contextually equivalent interaction, which is still very useful, too.
Mostly just do what makes sense.
The challenge is, as it has been, how to be flexible, smart, and forward-looking, but developing quickly for what’s needed now.
But whether you’re coding a quick prototype or designing a large project (which is risky because a feedback loop from all users may be longer), focusing too much on the how and specifics instead of the overall experience may get you into trouble later.
For example, you could have what sounds ideal: microservices, individual teams each working on them focused on their own goals, powering a site with the latest, well-used JS framework, able to deploy quickly and developing quickly with a lot of fun-but-professional-looking communication, and end up with a slow, broken application.
[1]- https://samnewman.io/patterns/architectural/bff/
This is BFF pattern described many years ago. Here's the standard way I build this kind of thing: Develop your APIs per functional or really per system. One for content, one for identity, one for ads or whatever. Then you build an orchestration tier that does pretty much what OP says. It stitches the various services together and returns a page model. The ideal is to reduce round-trips and cognitive load on FE dev. If you need the top 3 pieces of relevant content, plus an ad plus the user's first name, return all of that and nothing else. The last piece is just SSR. Use next or nuxt or whatever and you can output HTML on the server or stich it on the client with one codebase seamlessly.
https://samnewman.io/patterns/architectural/bff/
I actually found the article from Sam Newman went into greater depth: http://samnewman.io/patterns/architectural/bff/
Interesting to see this creates new problems, such as blocking calls to dependant services downstream, and what services you declare as critical or not. Also duplicate code is unavoidable. So if you're attempting this pattern, keep those things in mind since you will have limited technology choices.
Sound Cloud is using Scala here.
https://developers.soundcloud.com/blog/building-products-at-soundcloud-part-3-microservices-in-scala-and-finagle
Edit: Found their mention of technology
I was just reading the other day this article about the Backend for Frontend pattern (BFF) which suggests the best way to avoid tight coupling is for services you don't want tightly coupled to be owned by different teams, and to allow reasonable duplication of functionality between them. Everybody knows how hard it is to get another team to implement functionality for you.
This is where I got the BFF pattern from:
http://samnewman.io/patterns/architectural/bff/