Separation of concerns
Organizing schemas by features and teams
Apollo Federation introduces an important new principle to modular schema design: proper separation by concern. It's the key architectural quality that allows separate teams to collaborate on a single product-centric graph without stepping on each other's toes.
When you start thinking about how to break up a monolithic schema into modular parts, it can be tempting to divide things up by type. For example, you could make one module responsible for the User
type, another one for your Product
type, and a third one for the Review
type:
This may seem to make sense at first, but it quickly breaks down. The problem is that features or concerns usually span types. For example, suppose we want to add a new topNegativeReviews
field to the Product
type in the above schema. Even though it lives on the Product
type, this addition is almost certainly the responsibility of the team responsible for reviews. This isn't just a conceptual point about team structure: the product service won't know how to resolve a query for topNegativeReviews
, because data about reviews is stored in the reviews system (as a reviews table with foreign key references to products, for example).
Another way to think about the same problem is to consider an important type like User
or Product
. Often, no single team controls every aspect of such types, and it becomes quite awkward to colocate the definitions of each field on such types.
So instead, Apollo Federation allows you to extend an existing type with additional fields, using GraphQL's extend type
functionality. That means we can break up a schema across boundaries that correspond to features or team structure. For example, a team working on a new reviews feature could develop their changes in one place, combining new types like Review
with extensions to existing types, like adding the ability to navigate from a User
or Product
to the associated reviews:
The result is the best of both worlds: an implementation that keeps all the code for a given feature in a single service and separated from unrelated concerns, and a product-centric schema with rich types that reflects the natural way an application developer would want to consume the graph.