Generally you don’t want to reuse the same API for different types of clients, you want backends for frontends (BFF) that are specialized for each use and can be moved forward in their own pace. The needs and the requirements differs a lot between a browser, app and server-to-server call.
And just because you serve HTML doesn’t necessary mean that you backend code is tightly coupled with the view code, HTML is just one adapter of many.
A boundary doesn’t get better just because you slip a HTTP barrier in between, this is the same type of misconception that has driven the microservice hysteria.
> you want backends for frontends (BFF) that are specialized for each use
third time I've heard this thing and the reasoning still escapes me.
First there's ownership. Backend team owns API. Frontend teams own clients (web/android/ios/cli) etc. Do you now have a BFF for each client type? Who owns it then ? Don't you now need more fullstacks ?
there's confusion.
Now you have 2 sets of contracts (API-BFF, BFF-clientIOS, BFF-clientAndroid, ...). You now have more human synchronization overhead. Changes take longer to percolate throughout. More scope for inconsistencies.
And there's performance.
Adding more hops isn't making it faster, simpler or cheaper.
Isn't is better to have the API team own the single source of ownership ?
> Do you now have a BFF for each client type? Who owns it then ? Don't you now need more fullstacks ?
everyone has an opinion, but ime ideally you'd have 1 bff for all clients from the start
> there's confusion. Now you have 2 sets of contracts (API-BFF, BFF-clientIOS, BFF-clientAndroid, ...). You now have more human synchronization overhead. Changes take longer to percolate throughout. More scope for inconsistencies.
yep, i have literally experienced the chaos this can cause, including the endless buzywork to unify them later (usually its unify behind the web/html bff which breaks all kinds of frontend assumptions)
> Isn't is better to have the API team own the single source of ownership ?
it depends on what it means 'api team'... but ideally bff has its ownership separate from 'backend' wether that is in 'api team' or outside i think is less important ime
but... ideally this separation of ownership (backend backend, front end for backend) allows each to focus on the domain better without mixing up say localization in the lower level api's et
iow having a bff is sort of like having the view model as a server... that way multiple clients can be dead simple and just map the bff response to a ui and be done with it
Companies do this, but it is really hard to support. I prefer teams that own an entire vertical slice. Then they know their API and more importantly, The WHY? their API does what/how it does. A BE team can never know the entire context without exposure to the end use IME, and there is far less ownership. YMMV and it will ultimately come down to how your company is organized.
Yes. I’m generally against specialization and splitting teams. This of course depends on what type of organization you have and how complex the frontend is. iOS and Android is usually complex as it is so they are typically specialized but I would still keep them in the team.
Specialized teams not only creates synchronization issues between teams but also creates different team cultures.
What this does is that it induces a constant time delay for everything the organization does. Because teams no longer can solve an entire feature the organization instead spends more time on moving cards around in the planning tool of choice. The tiniest thing can require massive bureaucratic overhead.
Solutions also has a tendency to become suboptimal because no technician has an general overview of the problem from start to finish. And it also quite common that the same problem is solved multiple times, for each team.
By making BFFs specialized, instead of the teams, you don’t need to spend time to create and design a generalized API. How many hours hasn’t been wasted on API design? It adds nothing to customer satisfaction.
This also means that you separate public and private APIs. External consumers should not use the API as your own web client.
Specialized BFFs is not only to have a good fit for the client consuming it but it also about giving different views of the same underlying data.
E.g assume we have an article with multiple revisions (edits). Handling revisions is important for the Admin API but for the web client that serves the final version of the article not at all, it shouldn’t even be aware of that the concepts of revisions exists.
Creating a new a BFF is as easy as copy&paste an existing one. Then you add and remove what you need.
The differences between BFFs is usually how you view your schema (GET). Writing to your model (POST) is likely shared because of constraints.
What is then different views of the same data? An SQL query (or VIEW). Too many APIs just maps a database table to an endpoint 1:1, those APIs are badly designed because the consequence of that is that the client needs to do an asynchronous HTTP JOIN to get the data it needs, very inefficient.
By writing SQL to fit your BFFs you will then realize that the ORM is the main problem of your architecture, it usually the ORM that creates the idea that you only have one view of the same data, one table to one entity. But SQL is a relationship model, you can’t realistically express that with 1:1 only.
By removing the ORM you will also solve the majority of your performance issues, two birds one stone scenario.
Ownership of a BFF should ideally be by the ones consuming it.
iOS and Android can usually use the same BFF, they don’t differ that much to warrant a new BFF. If there are any differences between the two, give them different endpoints within the same BFF for that specific use case. When designing APIs one should be pragmatic, not religious.
BFF is nothing more than an adapter in hexagonal architecture.
> Yes. I’m generally against specialization and splitting teams. This of course depends on what type of organization you have and how complex the frontend is. iOS and Android is usually complex as it is so they are typically specialized but I would still keep them in the team.
Right why have someone _good_ at a particular domain who can lead design on a team when you can have a bunch of folks who are just ok at it, and then lack leadership?
> Specialized teams not only creates synchronization issues between teams but also creates different team cultures.
Difference in culture can be cultivated as a benefit. It can allow folks to move between teams in an org and feel different, and it can allow for different experimentation to find success.
> What this does is that it induces a constant time delay for everything the organization does. Because teams no longer can solve an entire feature the organization instead spends more time on moving cards around in the planning tool of choice. The tiniest thing can require massive bureaucratic overhead.
I've seen this true when I was by myself doing every from project management, development, testing, and deployment. Orgs can have multiple steak holders who might throw a flag at any moment or force inefficient processes.
> Solutions also has a tendency to become suboptimal because no technician has an general overview of the problem from start to finish. And it also quite common that the same problem is solved multiple times, for each team.
Generalists can also produce suboptimal solution because they lack a deeper knowledge and XP in a particular domain, like DB, so they tend to reach for an ORM because that's a tool for a generalists.
> By making BFFs specialized, instead of the teams, you don’t need to spend time to create and design a generalized API. How many hours hasn’t been wasted on API design? It adds nothing to customer satisfaction.
Idk what you're trying to claim, but API design should reflect a customers workflow. If it's not, you are doing it wrong. This requires both gathering of info, and design planning.
> This also means that you separate public and private APIs. External consumers should not use the API as your own web client.
Internal and external APIs are OK, this is just a feature of _composability_ in your API stack.
> Specialized BFFs is not only to have a good fit for the client consuming it but it also about giving different views of the same underlying data.
If the workflow is the same, you're basically duplicating more effort than if you just had a thin client for each platform.
> E.g assume we have an article with multiple revisions (edits). Handling revisions is important for the Admin API but for the web client that serves the final version of the article not at all, it shouldn’t even be aware of that the concepts of revisions exists.
Based on what? Many comment systems or articles use an edit notification or similar for correcting info. This is a case by case basis on the product.
> Creating a new a BFF is as easy as copy&paste an existing one. Then you add and remove what you need.
That sounds terrible, and very OO. I'd rather generate another client for my openapi documented API, in whatever language is most appropriate for that client.
> The differences between BFFs is usually how you view your schema (GET). Writing to your model (POST) is likely shared because of constraints.
That's a stretch, if I need a form, I likely need the same data if I'm on iOS, Android, native, or web. Again it's about execution of a workflow.
> What is then different views of the same data? An SQL query (or VIEW). Too many APIs just maps a database table to an endpoint 1:1, those APIs are badly designed because the consequence of that is that the client needs to do an asynchronous HTTP JOIN to get the data it needs, very inefficient.
Yes, those API are not being designed correctly, but I think you said folks are wasting too much time on design, so not sure what your arguing for here other than to not just try and force your clients to do excessive business logic.
> By writing SQL to fit your BFFs you will then realize that the ORM is the main problem of your architecture, it usually the ORM that creates the idea that you only have one view of the same data, one table to one entity. But SQL is a relationship model, you can’t realistically express that with 1:1 only.
Yet ORMs are tools of generalists. I agree they are generally something that can get in the way of a complex data model, but they are fine for like a user management system, or anything else that is easily normalized.
> By removing the ORM you will also solve the majority of your performance issues, two birds one stone scenario.
That depends a lot on how the orm is being used.
> Ownership of a BFF should ideally be by the ones consuming it.
Why? We literally write clients for APIs we don't own all the time, whenever we call out to an external/3p service. Treat your client teams like a client! Make API contracts, version things correctly, communicate.
> iOS and Android can usually use the same BFF, they don’t differ that much to warrant a new BFF. If there are any differences between the two, give them different endpoints within the same BFF for that specific use case. When designing APIs one should be pragmatic, not religious.
The workflows Shou be the same. The main difference between any clients are the inputs available to the user to interact with.
> BFF is nothing more than an adapter in hexagonal architecture.
You are comparing apples with oranges. I'm talking about organization, you about
individual developers.
I can have fullstack that is better than a specialist. Specialist only means that they have specialized in one part of the architecture, that doesn't necessarily mean that they solve problems particular well, that depends on the skill of the developer.
And the point is that even if they do have more skill within that domain, total overall domain can still suffer. Many SPAs suffer from this, each part can be well engineered but the user experience is still crap.
If your developers is lacking in skill, then you should definitely not split them up into multiple teams. But again I'm talking about organization in general, that splitting teams has a devastating effect on organization output. Difference in culture will make it harder to move between teams, thus the organization will have much more difficult time planning resources effectively.
BFF is all about reflecting the need of the client, but the argument was the a generalized API is better because of re-usability. The reason why you split into multiple BFFs is because the workflow isn't the same, it differs
a lot between a web client and a typical app. If the workflow is the same you don't split, that is why I wrote
BFF per client type, a type that has specific workflow (need & requirement).
> This is a case by case basis on the product.
Of course, it was an example.
> That sounds terrible, and very OO. I'd rather generate another client for my openapi documented API, in whatever language is most appropriate for that client
I'm talking about the server here, not the client.
> That's a stretch, if I need a form, I likely need the same data if I'm on iOS, Android, native, or web. Again it's about execution of a workflow.
But the authentication and redirects will probably be different, so you can reuse a service (class) for updating the model, but have different controllers (endpoints).
> Yes, those API are not being designed correctly
Every generalized API will have that problem in various degrees, thus BFF.
> Yet ORMs are tools of generalists.
Oh, you think a fullstack is generalist and thus doesn't know SQL. Why do you believe that?
> That depends a lot on how the orm is being used.
Most ORMs, especially if they are of type active record, just misses that mark entirely when it comes to relationship based data. Just the idea that one class maps to a table is wrong on so many levels (data mappers are better at this).
ORM entities will eventually infect every part of you system, thus there will be view code that have entities with a save method on, thus the model will be changed almost from everywhere, impossible to track and refactor.
Performance is generally bad, thus most ORMs has an opaque caching layer that will come back and bite you.
And typically is that you need to adapt your database schema to what the ORM manage to handle.
> We literally write clients for APIs we don't own all the time,
The topic here is APIs you control yourself within the team/organization. External APIs, either that you consume or you need to expose is different topic, they need to be designed (more). The point is internal APIs can be treated differently than external ones, no need to follow the holy grail of REST for your internal APIs. Waste of time.
But even with external APIs that you need to expose they can be subdivided into different BFFs, no need to squeeze them into one, this has the benefit that you can spend less time on overall design of the API, because the API is smaller (fewer endpoints).
> That's what a client is...
I'm specially talking about server architecture here, the client uses the adapter.
Agreed! There are many things in IT industry that are prone to this kind of almost magical thinking, and "boundaries" / "tight coupling" is one of them. I realized that when tried to actually compare some stuff I had been doing at work through years, being fascinated with uncoupling things. Well, if you start measuring it, even at the top level (time, people, money spent) then it is so clear that there are obvious tight couplings at architecture level (like data on wire containing some structure or transferring a state of application), and it is very tempting to remove them. But then we may actually find ourselves having a subtle tight coupling, totally not obvious, but effecting in a need of two teams or even two tech stacks and a budget more than twice the size because of communication / coordination costs.
And just because you serve HTML doesn’t necessary mean that you backend code is tightly coupled with the view code, HTML is just one adapter of many.
A boundary doesn’t get better just because you slip a HTTP barrier in between, this is the same type of misconception that has driven the microservice hysteria.