Seems like you couldnt have front end engineers with this philosophy. Or you could but it would be very unproductive. Because theyd need backend changes for every API call.
While this may be true to some extent, I think front end has plenty to deal with even if you do ship them the exact data they need.
Primarily, this philosophy encourages you to maintain a strict connection between needed use cases, and the code that enables them. Once that connection is severed, your code expands beyond the required use cases, and you end having to maintain support for phantom/theoretical use cases.
This approach would also be a nightmare if you ever decided to refactor the frontend. You'd be forced to do double the work since failing to update your backend would probably result in nonsensical legacy naming... I'd also dread to think what would happen if you also used the backend to serve a mobile app. You'd end up spending 40% of your time trying to figure out what to name fields before eventually going full circle and reverting back to logical generic names :|
And the moment your SaaS is growing, and your customers request access to your API:
Instead of just implementing ACLs/permissions on existing APIs you have to develop and maintain two APIs,
one for the customers (that will get outdated with lot of missing features and be less battle-tested)
and one “real API”.
Our public API is fit for the use-cases of our big customers that want deep integrations, and our frontend’s API is able to handle our specific workflows.
We have a bunch of shared backend code, but the endpoints that our API customers use are very specific. Sometimes we build custom endpoints for a single customer which would be useless for our frontend/services. Keeping them separate allows them to gain needed functionality without trying to bolt it on to existing internal APIs, and cluttering it all into one messy blob.
Of course our internal API is a mess in a bunch of other ways but at least we don’t have to deal with the public parts making it even messier
Redesign: I've responded to the redesign argument in another comment. It's easy to find if you search the page for "rare event".
Mobile app: this is addressed in the article.
Naming: Usually most naming for different parts of pages is handled by the design(er), but even if not, once you have an approximate naming convention for parts of the site, naming becomes easy. And the stakes for these names aren't that high, because you are only scoping everything down to a single page, so global consistency and precision in naming is not that imporant. It just needs to be enough for someone to understand what it most likely refers to on this page.
Ignoring my general thoughts on full stack engineering for the sake of brevity—this works okay if your FE and BE have enough overlap in necessary skill set (e.g., same language) but in my experience when you need to hire a senior Rails+Vue3 developer or something you’re going to be tearing your hair out.
Yeah. This is suggesting to me that the "model" live in the back-end obviously and the "view" is separated across the front-end and back-end. I think that does sound more straightforward for many cases. So working on the "view" requires being not exactly a "full-stack" engineer but at least being able to make changes both on your front-end part of the view that makes API calls and back-end part of the view that serves them. I think that makes sense. You can still have fully "back-end" developers that handle the database and actual server, and fully "front-end" developers that handle ui design and content.
Every API call was so form fit to the UI that nearly every UI tweak needed frontend and backend changes.
It didn’t need to be this way (there was a lack of engineering skill and leadership), but even past the surface level much of the backend code beyond the API interface also became form fit to the specific use case meaning many times seemingly simple changes required near total reimplementation of all of the business logic and other underlying code.
End of the day, showing the same data or exposing the same flows elsewhere in the application required nearly a total reimplementation on the backend. This created an explosion in size of the codebase and complexity.
This whole idea seems to basically be going back to RPC-based APIs and all the drawbacks that led to everyone kind of collectively agreeing REST was better (even if most people only sort of half implement it).
Our approach, staring down a roadmap of projects that basically involved exposing the same functionality over and over with different pictures in front of it was to steer _hard_ the other direction.
We sat down and put together an API specification that laid out the general shape of an API. Not the specific resources, but for any given collection/resource how it should be exposed. We found common “tough” use cases and figured out up front how to expose those RESTfully and documented the patterns to maintain consistency. We put down a framework in code to make compliance with the spec the “easy” path for most cases.
Then we approached the rest of the design from an API perspective, not a frontend or backend perspective. For any given flow/operation/etc, what would a good interface look like for this. (This is very similar to figuring out what the interface for a module/class/etc should look like, given its responsibility, before writing it.) Then we built it.
The end result has been that more and more frequently requests and even entirely new projects require _no_ backend involvement. Often the FE team doesn’t even need to ask any questions—given any endpoint that exposes a collection of resources, they know _exactly_ how to work with it because they’re all the same.
When new business rules or requirements come in, we no longer need to apply them in 5 or more different places across two codebases. And we’ve still maintained a good separation of frontend and backend duties to the point our FE team is busy but kind of bored—they’re only really concerned with the view/display logic at this point.
Company history is largely lost to the mists of time, but the API routes were all prefixed `/v5/`. I can only imagine how much further along the company would be if they’d spent the last decade building on top of a foundation instead of rebuilding the foundation every two years as they have been with the RPC model.
> showing the same data or exposing the same flows elsewhere in the application required nearly a total reimplementation on the backend. This created an explosion in size of the codebase and complexity.
I'm trying to understand how this is possible. Couldn't the backend logic that contributes this response fragment in one endpoint be extracted and reused to contribute the same response fragment in another endpoint?
Was backend not modularized and reused?
The way I understand your approach, you ended up building and maintaining CRUD resources similarly to how they would exist in a naive public API, but the difference is that you spent extra time to build more meaningful, rich, business-level resources than serving nearly raw database records.
This is probably a good compromise that isn't disagreeing with the article as much as you seem to be implying. The difference between your approach and the article's approach is a small side-step. You either let the front-end fetch your rich business-level resources separately, or you package them into pages and serve them in a nice single package. Or you can build pages as per the article, and extract these rich resources that you display in those pages into separate endpoints for some additional flexibility. Either way, you end up with rich use-case driven resources, packaged differently.