[HN Gopher] Don't build a general purpose API to power your own ...
___________________________________________________________________
Don't build a general purpose API to power your own front end
(2021)
Author : aabbcc1241
Score : 208 points
Date : 2023-08-20 08:39 UTC (14 hours ago)
(HTM) web link (max.engineer)
(TXT) w3m dump (max.engineer)
| anymouse123456 wrote:
| I've built both models (and more too) over decades.
|
| There are lots of questions one might ask before deciding between
| these two (or other) approaches:
|
| * Where does this team want the boundary between client and
| server in terms of user experience, server load and substantial
| UX interaction latency?
|
| * Can this frontend team independently plumb a changes all the
| way through the database?
|
| * Are backend teams always available for (or interested in) every
| minor update?
|
| * Are both halves of the application deployed on the same
| schedule?
|
| These are a handful of the first questions I'd ask before trying
| to push either solution at this point in time, the answers would
| likely lead to more questions.
| FrustratedMonky wrote:
| Think this is describing other frameworks that do this. Isn't
| this how ELM works? Or ELM architecture in general?
|
| This is kind of how some 'functional' web api's work.
| Y-bar wrote:
| > Imagine if you could just send it the whole "page" worth of
| JSON. Make an endpoint for /page/a and render the whole JSON for
| /page/a there. Do this for every page. Don't force your front-end
| developers to send a bunch of individual requests to render a
| complex page. Stop annoying them with contrived limitations.
| Align yourselves.
|
| Why not just send HTML as a single response at this stage?
| Sometimes it feels like we are doing web development more complex
| than it needs to be.
| shaftoe444 wrote:
| > Imagine if you could just send it the whole "page"
|
| Could have stopped here
| aatd86 wrote:
| Maybe for separation of concerns between data and UI? The
| browser is not going to be the only client?
| philderbeast wrote:
| you can have seperation of data and UI and still send the
| whole page.
|
| The vast majority of the time, the browswer is infact going
| to be the only client.
|
| once you reach the point where its not, then build the api
| to suit the new client rather then trying to build one that
| does both.
| aatd86 wrote:
| True, you could insert something in the middle, that
| generates a page depending on the user-agent. But then it
| requires extra SSR logic.
|
| But on the other hand, you can have a iOS or Android
| based app that depends on the same data. So the browser
| is not the only client in general, especially nowadays, I
| think?
| regularfry wrote:
| That's the crux of the question. The BFF approach says
| that you _remove_ logic from the client and put it in a
| server-side component. Not that you add extra logic. Then
| you _might_ find that you need to copy that server-side
| component sideways for a new client, if the view layer in
| that client is sufficiently different to what you already
| have. The browser can be the only client of its BFF API;
| the mobile apps can either speak to the same API or have
| their own.
|
| Dramatically more important than any theoretical,
| abstract consideration in deciding whether this can work
| is what your teams look like. The client team should
| almost certainly own the BFF API, which has implications
| for skillsets and maturity.
| aatd86 wrote:
| That's only for a react type of application if I'm not
| mistaken?
|
| If so, that doesn't handle the general case (native apps
| for instance)
| nonethewiser wrote:
| Well now you're building a general purpose API
| aatd86 wrote:
| I think there is a middle-ground concern here: avoiding
| request waterfalls.
| CharlieDigital wrote:
| That's what the database is, isn't it? The separation layer
| between the raw data and how it's projected into some
| interface (user or otherwise).
| aatd86 wrote:
| Yes in a way. There are a bit more layers in-between.
|
| In fact, you can see it as 2 decoupled kinds of database:
|
| - the storage database
|
| - the working in-memory UI database that holds the data
| represented (e.g. on your screen (GUI)).
|
| The goal in general is to modify the data contained in
| this UI database and then to push the changes to storage.
| [deleted]
| croes wrote:
| I think it's about API as such and not about how to serve the
| webpage.
|
| No matter of JSON or HTML don't built a general purpose API if
| it's only your frontend.
| JaggerJo wrote:
| This breaks once you need to update parts of the page without
| reloading everything.
| marginalia_nu wrote:
| In that case you can just parse the DOM clientside and insert
| it into the page.
| loloquwowndueo wrote:
| You can still return html partials from your endpoints and
| use htmx to swap content without a full reload :)
| JaggerJo wrote:
| yes, but then it's not one request per page
| loloquwowndueo wrote:
| Only if there's an update - htmx will encourage you to
| render full html pages but still gives you the ability to
| do in-place updates which is what most folks think a JS
| front end with a json Api backend and client side
| rendering is needed for.
| halfcat wrote:
| HTMX can swap multiple DOM elements from a single HTTP
| response
|
| https://htmx.org/extensions/multi-swap/
| Y-bar wrote:
| JS can update the DOM dynamically.
|
| Nothing prevents the main response from being served as
| regular HTML and subsequent XHR request for some parts of a
| page being JSON or some such data format. In fact I bet that
| sending server-side rendered HTML is faster than sending a
| full structured page as JSON which has to be decoded, parsed,
| and then converted to HTML.
| timeon wrote:
| Reminds me early AYAX days.
| holoduke wrote:
| I run a popular app (native ios and android) and a web
| version. I find having A single json serving api much
| easier to maintain. The frontends are isolated projects.
| The backend is just a simple layer with static data served
| as json. If you would have static html it means you need to
| update all static files whenever a ui change is needed.
| Makes it overly complicated. Caching becomes also a
| challenge and the so does the performance. Currently just
| running a few Hetzner instances to serve 50k requests per
| second. That would be really hard with a server side
| rendered html.
| halfcat wrote:
| Do you build each interface with different tools (e.g.
| Swift, Java, and React), or one of the unifying tools
| (Flutter, React Native, etc)?
| Y-bar wrote:
| > If you would have static html it means you need to
| update all static files whenever a ui change is needed.
| Makes it overly complicated
|
| We do use a templating engine and separate CSS files, so
| no, not at all, all static files does not need updating
| on every change.
|
| > Caching becomes also a challenge and the so does the
| performance
|
| Not at all, not even on black fridays.
|
| > That would be really hard with a server side rendered
| html.
|
| Why do you pose that hypothetical when our real-world
| experience is easy?
| robertoandred wrote:
| Then you're stuck with two kinds of templating.
| runeks wrote:
| The is exactly what HTMX does and it works: allow returning a
| HTML response and statically annotating a part of the DOM to
| be replaced with that.
|
| Granted, this requires JavaScript on the front end, but it's
| a framework that can be shared between different websites, so
| you're not writing any custom JavaScript for your site.
| vidarh wrote:
| Around 2005 was the first time I "accelerated" a website by
| requesting the whole page in the background and swapping out
| what had changed.
|
| We eventually trimmed what was returned a bit, but just
| getting rid of the page transition was 90% of the work.
| strictfp wrote:
| That's true. But that's only really a concert if you're
| building an SPA. If you're not, having multiple pages is
| generally faster than running some js framework to reload
| parts of the page. Plus that you get the benefit of every
| state combination having it's own URL. You don't need to
| write any custom state reconstruction code.
|
| This was the original design of REST as applied to the web.
| It was explicitly designed in such a way that it was
| forbidden to reload parts of the page. This makes it so that
| every state has it's own URL and you therefore can link to
| every state. Deep linking if you wish, for all of the web.
| madsbuch wrote:
| This is exactly how next.js works. But even more importantly:
| Why not use GraphQl in this situation? This is exactly what it
| excels at:
|
| 1. The backend can be entity centric, like it does best 2. The
| frontend can request a page worth of data from diverse entities
| in a single go.
| SoftTalker wrote:
| Yeah, this goes back a couple of decades where "page a" was
| just "page-a.asp" or "page-a.php" and you did everything to do
| with that page in that file. Simple, and you could mostly make
| changes to page a without worrying that you'd break other
| pages.
|
| Need page b? Copy page-a.asp to page-b.asp, gut the page-a
| logic, and put in the page-b logic.
|
| Before you get too nostalgic for these simple days, do we
| rememember why we stopped developing web pages that way?
| Muromec wrote:
| Because you can't have a lot of itneractivity with a nice
| responsive UI like this if your network has high latency and
| low bandwidth. So we pushed a lot of logic to the browser.
| Now it turns out it doesn't scale well, so maybe we should go
| back to copying page a to page b and calling it a day, same
| way we came back to static linking once disk space stopped
| being limiting factor.
| slotrans wrote:
| > ...do we rememember why we stopped developing web pages
| that way?
|
| Because we needed an API for our mobile apps, and once we had
| that, SPAs seemed convenient.
|
| It was definitely, absolutely NOT because the page-centric
| way of building sites didn't work (it does), or because SPAs
| are better (they aren't).
| oceanplexian wrote:
| I'm a systems engineer and SPA's are a superior
| architecture to deal with from a delivery POV. It is very
| difficult to cache a dynamic web app with a CDN. There are
| ways, like SSI, managing variants, Purging, and so on, but
| a huge pain. And if you don't have a sophisticated CDN and
| are using something like Cloudfront, forget about all those
| fancy features.
|
| SPA? I can serve the whole thing with static files and
| remove 90% of the traffic from my web server. The API can
| be served from a different path from the static files. API
| requests are super tiny and more tolerant to fluctuating
| network conditions, and you can hide a lot of that with
| Javascript.
| TheCleric wrote:
| Exactly. Even non-SPA frameworks (such as NextJS with
| static builds) mean you can compile all of your frontend
| code to S3 (where it's a negligible cost) and only pay
| for the API instances.
| ThatPlayer wrote:
| I have a hobby project that's very static: a website for
| viewing webscraped snippets of writing from another site.
| I hosted it on Github Pages. I didn't want to use a
| static site generator which would've generated easily
| 10,000 files and with all the duplicated code would have
| put me above GitHub's 1GB limit for Github Pages.
| Similarly Cloudflare Pages has a 20,000 file limit.
|
| So instead I combined it into various JSON files. Now I
| have a SPA downloading the JSON as necessary, and don't
| need any API/backend/database. I'm considering moving to
| sqlite now there are official WASM builds.
| fastboy wrote:
| [dead]
| wiseowise wrote:
| Got to pump CV with frameworks you know? Promotions don't write
| themselves. Bonus point: job security. And when you leave who
| cares what poor shmuck will have to support it?
| renegade-otter wrote:
| How did we get to the point where simple and effective server-
| side pages are either unknown as a way of doing things or are
| considered to be a technical heresy?
|
| Younger developers scoff at us fossils and the olden ways, but
| this is exactly how this ignorance of classic, tried-and-true,
| performant patterns results in atrocious complexity and
| performance, only because "this is how things are done".
|
| It HAS to be a BFF, it HAS to be 15 different microservices and
| 20 different AWS toys, right? There is no other way? Are you
| sure?
|
| It seems like we are talking about the whole industry, but it's
| largely he Node ecosystem in my experience (which is
| effectively - the industry). It's not like there is not Rails
| development being done out there, with nothing but a trusty
| Postgres database.
|
| Ironically, our existing architecture patterns are beginning to
| resemble J2EE - a bulky, slow, expensive, boiler-plate-laden
| process where a simple site costs one million dollars and
| performs like shit.
| rewmie wrote:
| > How did we get to the point where simple and effective
| server-side pages are either unknown as a way of doing things
| or are considered to be a technical heresy?
|
| We are not at that point nor we were ever at that point, or
| close to it.
|
| Server-side rendering has been a hot topic in JavaScript
| framework circles for over a decade, and React famously
| solved that problem so well that it is now a standard, basic
| technique.
|
| Also, just because you throw the same buzzword around that
| does not mean the problem stayed the same. Reassembling a
| javascript-generated DOM with a coherent state is not the
| same as sending a HTML document down the wire. And you know
| why people started assembling DOMs with JavaScript? Because
| sending HTML documents down the wire was too slow and did not
| allowed for any control over aspects that dictate perceived
| performance.
| LapsangGuzzler wrote:
| Because JavaScript rules web dev and the JS community has
| pushed so many mainstream ideas that have turned out to be
| duds. It's a major echo chamber due to its size relative to
| other web dev communities.
|
| I also partly blame the careerist obsession around always
| learning new technology, because it's becoming obvious that a
| lot of the "new stuff" over the last decade created more
| problems than solutions. Don't get me wrong, learning is an
| important part of the job, but we've created a culture of
| constantly pushing new technology to pad resumes and feed our
| insecurities around irrelevance instead of solving problems.
| jwells89 wrote:
| Hype, which the web/JS community seems particularly
| vulnerable to, also plays a big part. Yes proven tech is
| safe and reliable, but choosing it is so much less fun than
| getting swept away by the tide of whatever the newest
| "revolution" is. Don't you want to be part of the wave?
| bheadmaster wrote:
| It seems to me that the more people use <thing>, the less
| evidence of quality of <thing> is required by the people
| using <thing> - everyone just assumes everyone else knows
| what they're doing.
|
| It becomes something akin to a religion - after all, 2
| billion Christians can't be wrong, can they?
| nonethewiser wrote:
| Can you pick a less antagonistic example?
| brightlancer wrote:
| The adage I learned decades ago was "a billion Chinese
| can't be wrong".
|
| If PP had used that, would it have been antagonistic?
| Racist?
| bheadmaster wrote:
| Would you prefer I used Judaism instead? Or Islam?
|
| Or do you consider my point about network effect in tech
| stacks being similar to religious beliefs to be
| antagonistic by itself?
| toyg wrote:
| Eat shit - billions of flies cannot be wrong. (cit.)
|
| More seriously: once a bit of tech becomes mainstream, it
| becomes politically easier to use it. Your manager has
| not heard of <cool tech>, but he did read about React in
| some business magazine. So when the choice is between
| React and bheadmaster's Funky Funkness Framework, he'll
| go with React.
| ricardobayes wrote:
| No one ever got fired for choosing React
| ncallaway wrote:
| > everyone just assumes everyone else knows what they're
| doing.
|
| It's not just that. There are practical reasons to choose
| the bandwagon, even if you know it's not the technically
| optimal approach.
|
| If you're planning on hiring junior and mid level
| engineers, for example, it's a great help if they already
| know the technologies involved. Your hiring pool for
| React is a lot bigger than for a more obscure tool.
| Additionally, the popular tools also tend to be stable
| and long lasting, with good support.
|
| So, there are compelling business reasons to choose
| what's popular, even if you aren't making assumptions
| about the technical quality just because its popular.
| ecf wrote:
| It's because you fossils keep thinking server-side rendering
| is the right call for everything and won't consider other
| possibilities.
| oefrha wrote:
| If you want to build a moderately complex interactive
| experience that doesn't suffer from roundtrip latency on
| every single interaction, you need to recreate the
| interactive parts of DOM in JavaScript anyway (ignore wasm),
| else you need to do imperative updates which quickly become a
| nightmare. jQuery-oriented development is a classic for sure,
| doesn't mean people want to go back to it.
| evantbyrne wrote:
| The current SPA paradigm was adopted to solve a number issues
| that engineering teams were facing. Your sentiment is one I'm
| seeing a lot more as of recently, which leads me to believe
| we're approaching the end of the current web development
| paradigm. There's too much time wasted writing _glue_ when
| developing SPAs: database queries, back-end controllers, data
| serialization, network requests, front-end state, shadow dom,
| etc. Lots of frameworks coming out that essentially remove
| the need to write glue code. I expect this trend to continue
| until we reach the point where you are mostly just coding a
| few things: schema, non-generalizable business logic, and
| presentation.
| martinald wrote:
| Blazor Server, while definitely not the right thing for all
| applications, is the best solution I've found to this.
|
| You write all the code in one language (C#), and it streams
| the changes to the clientside as needed automatically. It
| means you can call the database in your 'frontend' HTML
| layouts directly and gets rid of all the glue code. You
| have no serialization problems because you are using the
| same classes everywhere, and the component structure keeps
| things very clean.
|
| I would say I am about 5x more productive in Blazor Server
| than any other frontend technology. You don't need to write
| APIs at all. It's just like writing static server side
| rendered pages but you can do dynamic stuff. It is honestly
| like magic.
|
| It does come with some huge downsides though, in that it
| needs to keep a websocket open to stream all the DOM
| changes from the server, and this also has
| memory/performance issues on the server (needs to keep
| state on the server all the time). Which basically rules it
| out of anything that needs to work over intermittent
| connections (mobile), and very high scale stuff (probably
| could be done with enough server RAM, but it's not the
| right tool for that).
|
| However, it's perfect for boring line of business
| applications that will only be accessed on solid internet
| connection, which is many of them.
|
| There is also Blazor Webassembly which removes the
| websocket part, and lets you code frontend and backend in
| C# still, sharing a lot of classes, though you do need some
| glue code to connect the database. I've heard people are
| having good results with gRPC for that; but haven't looked
| into it much (blazor server works fine for most apps IMO).
| troupe wrote:
| Is this kind of what Vaadin does?
| martinald wrote:
| Hadn't actually heard of that. Might be similarish but
| Blazor uses standard html/css/JS and just sends DOM diffs
| down the wire. Don't think at first look Vaadin works in
| the same way.
| troupe wrote:
| Ah ok. So the server keeps track of what the client
| should look like and just keeps it up to date?
|
| If so that sounds like a very nice model that would make
| it a lot easier to get back to just using simple HTML and
| delegate the complexity to the framework or server
| process. Are there other projects beside Blazor that use
| this type of approach?
| evantbyrne wrote:
| Not super famliar with blazor, but something like this
| sounds like what I would consider the halfway point to
| the next paradigm. I think you have to go further in
| simplification of the back-end as well.
| hot_gril wrote:
| Not sure what a BFF is, but having separate frontend and
| backend development doesn't mean you have 20 microservices.
| yu3zhou4 wrote:
| I think BFF might stand for Backend For Frontend in this
| context
| hot_gril wrote:
| "A BFF layer consists of multiple backends developed to
| address the needs of respective frontend frameworks, like
| desktop, browser, and native-mobile apps."
|
| Ok. Yeah that's only for huge scale things.
| Hel5inki wrote:
| I don't find that to be an accurate representation of
| BFF. I've used BFF with a browser FE to simply weave
| several microservice endpoints into a tailor-made api for
| the frontend. This reduces the burden on the
| microservices by removing the need to make many endpoints
| for clients and helps reduce network calls on the FE
| sarchertech wrote:
| Most of the time time BFF just means that instead of
| having the frontend call endpoints A, B, and C. It calls
| a single endpoint D, which calls A, B, and C and handles
| aggregating and transforming the data into the specific
| form the frontend needs.
| tcoff91 wrote:
| A BFF is just an API gateway that is tailored to a single
| frontend. It's especially helpful if the frontend is a
| native application as opposed to a web application, hence
| why it was a pattern championed by Netflix. If you have
| some native client out there and you can't guarantee that
| the user will update it, it's helpful for it to only talk
| to a single service so in case you want to evolve your
| backend architecture, you can update the BFF
| implementation and the existing native app won't be
| broken by your backend changes.
|
| Having a native app out there in the wild on customer
| computers that is coupled to a bunch of different
| microservices is hell for when you want to change your
| backend without breaking your customers' experience and
| forcing them to update.
| TeMPOraL wrote:
| I think it's the difference between generations of people for
| whom JS was an extra thing to enrich HTML documents, vs.
| younger generations that see HTML as merely a rendering
| target for JS.
| thrashh wrote:
| It's because if you want to continue getting a job, you want
| to use what other people are using.
|
| Using most static page frameworks is like using ColdFusion
| for your career advancement.
| godzillabrennus wrote:
| We have a boot strapped and profitable app with thousands
| of customers written in Django that has been operating fine
| since 2009 with new entrants raising and spending millions
| to build fancy BFF/Micro Service solutions, hiring sales
| people, losing money for years, only to publicly state they
| have finally gotten to 300 customers.
|
| Job security is relative.
| kmstout wrote:
| I'm torn. On the one hand, there are many websites I hate
| interacting with because they are unnecessarily structured as
| JS clients exchanging data with a remote server via a network
| link. On the other hand, it's easier for me to develop
| libraries and CLI clients of my own, these days getting quite
| far with Firefox dev tools' network view and "copy as curl,"
| and only occasionally having to actually read the code in
| those JS clients. In the old days, I would have to resort to
| some ugly and comparatively brittle page scraping.
|
| This new world sucks for the interactive user in a browser
| (which is me often enough), but it's great for the guy who
| wants to treat a website as just a remote provider of some
| kind of data or service (also me often enough).
| nonethewiser wrote:
| > How did we get to the point where simple and effective
| server-side pages are either unknown as a way of doing things
| or are considered to be a technical heresy?
|
| Demand for interactivity. A real demand - that's why desktop
| apps are now web apps.
|
| It can be over applied, sure, but there are great reasons not
| to serve html templates. The trend is not some massive
| incompetence.
| sarchertech wrote:
| Incompetence is the wrong word, but in an industry that
| grows so fast that 3 years of experience is considered
| senior, many people aren't even aware that the old ways are
| an option.
|
| In my experience, the percentage of large react sites where
| someone sat down and seriously considered using old
| fashioned server side rendering, but decided on React
| because the site actually required a huge amount of
| interactivity is close to zero.
|
| Every React site I've ever been involved with in in the
| last say 7 years was using React because "that's the way
| it's done", and anything else was just a post hoc
| justification.
| ethbr1 wrote:
| There's also an interactivity _requirement_ (as in, this
| is impossible without interactivity) and an interactivity
| _desire_ (as in, UX folks want an interactive feature).
|
| So many websites now pretend they're in the former
| category, but would work just fine if they implemented a
| less-interactive form. That's how it was done in the old
| days! "No, you can't have that. Here's the best we can
| do." "Oh, that's fine."
|
| But I expect more of what's driving complicated
| backend/frontend split design these days is shipping the
| org chart (in companies large enough to have frontend and
| backend teams) and technology-by-consultant (where the
| right technology is whatever you can get a consultant
| in).
| barrkel wrote:
| Because you want to paginate. Update the page piecemeal based
| on an event from another user. Because you want to use the same
| data on multiple pages, and want to write the authorization and
| filtering logic once.
| Muromec wrote:
| >Why not just send HTML as a single response at this stage?
|
| Is it time to discover memcache again? I think it's about time.
| tylercrompton wrote:
| Something about injecting HTML from an API, even from a
| controlled server, feels wrong.
| prmph wrote:
| But that's the point: its not an API, it's just an app web
| server.
|
| There's nothing wrong with a web server serving HTML; that's
| their whole purpose.
| littlecranky67 wrote:
| Feels like the author misses the point of an SPA. If you have
| website where every "view" is a /page/a etc., SPA might not be
| the best choice. But in an SPA i can be dynamic, and trigger
| data retrieval/sending without route changes.
|
| A very basic example is if I have a checkbox that allows the
| user to subscribe to push notifications. On click I sent a xhr
| request to the backend POST `/subscribe/1234` which registers
| the subscription. Next time I'll check `/subscriptions` or
| similar to see if the checbbox is in "checked" state (i.e. we
| are subscribed). This is basic functionality which requires a
| concise REST/JSON API, and has nothing todo with your
| page/route layout a la /page/a, /page/b etc.
| Falmarri wrote:
| Having form elements automatically update the back end is
| extremely annoying UI imo. There's usually no indication that
| it's actually doing that, and if there is I generally don't
| trust it.
| hakunin wrote:
| Author here.
|
| We do this for SPA. The POST can be supported just like you
| explained. Then you can either reload the "page" to see that
| the checkbox is checked, because backend will include that as
| part of the page, or (as an optimization) reload just that
| checkbox if you created a specialized resource for it. The
| entire page is still there for you to fetch upon transitions.
|
| Among pages, you will still need a few individualized
| resources sprinkled around for
| optimizations/reloads/fragment-paginations. The difference
| between that and a complete API is that they will be entirely
| design driven. If a table needs paginating, and is built with
| data from multiple resources, you will not provide 2
| resources, and expect front-end to paginate and glue them
| together. Instead, you provide a complete paginated resource
| for this table, where data is ready to be displayed as-is.
| littlecranky67 wrote:
| That us exactly how stuff worked around 2005. And no, you
| should not do a full form post just to toggle a checkbox.
| yakshaving_jgt wrote:
| Why not?
| valenterry wrote:
| As a user, I can think if a couple of reason immediately:
|
| - I don't like page (re)loads. They are usually slower
| and more likely to fail, compared to a lightweight
| request. Especially in scenarios with a bad connection
|
| - If they fail, it's harder to retry, I see a connection
| timeout page. With a SPA I see an error message,
| potentially with a retry button. Or even better: the SPA
| retries for me a few times.
|
| - I can continue to see all the rest of the page while
| the action is running
|
| - I can potentially start other actions in parallel
|
| - I prefer to not lose any progress of things on the
| side, e.g. text-boxes where I already entered/changed
| some text
|
| - It's easier to inspect what goes wrong by looking at
| the network tab. Okay, most users don't do that, but for
| me it's still a pro
|
| There are also advantages, but I think nowadays the cons
| outweight those for me.
| yakshaving_jgt wrote:
| I'm convinced this is HN-themed satire.
| jaza wrote:
| Gotta say I disagree with this idea. RESTful APIs have become the
| norm for a reason, and in my opinion it's dangerous and damaging
| to suggest abandoning them for a whole swathe of back-ends.
|
| Re: YAGNI. I worked on a product where, about 10 years ago, they
| decided to build proper APIs (for the first time), mainly to
| power their own front-end, but they also told the paying clients
| that they were welcome to use them. Didn't take some clients long
| to start using and loving those APIs. (Granted, they were
| enterprise clients, with their own significant dev resources,
| that's not the case for all software.)
|
| Re: front-end doesn't really have freedom. Yes it does! If one
| day page A needs a list of X, and there's already a nice generic
| API endpoint to list X, then only a front-end code change is
| needed.
| sdflhasjd wrote:
| > RESTful APIs have become the norm for a reason
|
| What would you say those reasons are though? I think they
| mostly boil down to cost.
|
| I agree with the article, but mostly for a reason the article
| didn't press on: performance and responsiveness. Making loads
| of small requests sucks, and on a mobile, it sucks times ten.
| HTTP/2 and whatnot have improved things but when you have even
| a small dependency tree of data, you can't avoid the network
| latency and it can quickly add up to a second or more of
| unresponsiveness.
|
| Obviously this doesn't apply (or matter) in some circumstances,
| but in many applications I think it's worth the extra cost.
| timeon wrote:
| > and on a mobile, it sucks times ten
|
| People often like to design for mobile devices but not for
| mobile connections.
| Attummm wrote:
| The other added benefit is sharing the data with other teams,
| and of companies.
|
| Everything has the same flow. And if a custom api call is
| needed for a particular frontend page, it can always be made.
| But won't be the norm.
| weego wrote:
| No, what we have is everything trending towards a monoculture
| where every solution is a minor iteration or flavour change to
| systems that solved problems for companies at scale such as
| meta/google.
|
| We regularly see developers talking about optimising js loops,
| dom updates etc in products that are little more than blogs
| with a few interactive elements.
|
| Most of us work on things that will get ripped out and redone
| within a couple of years, yet dev culture tells us we should be
| focusing on developing for every possible future with reuse and
| scale in mind, and that's unfortunately false.
| marginalia_nu wrote:
| > [pointless changes] in products that are little more than
| blogs with a few interactive elements.
|
| I wonder if a lot of this isn't busy work to justify having
| engineers on staff.
|
| You need engineers on staff to make changes when that is
| necessary, but you don't typically need to constantly be make
| such changes. At the same time the engineers can't be seen
| doing nothing, so this type of work is invented.
| zelphirkalt wrote:
| You are saying engineers should build software, that
| doesn't frequently require changes to fit some new use
| case? Outrageous. Then we would have to do proper
| engineering and make things flexible, anticipating
| potential use-cases. We would have to heed advice written
| in books such as PAIP (or more recently "Software Design
| for Flexibility"). Can we be expected to know literature of
| our own field?
| davidmurdoch wrote:
| I agree with everything but
|
| > We regularly see developers talking about optimising js
| loops, dom updates etc in products that are little more than
| blogs with a few interactive elements.
|
| In which I see the opposite. Developers don't optimize
| because "DevEx" is a feature of a codebase, but performance
| is treated as an afterthought.
| szundi wrote:
| At my company most code we did in 20 years ago is there and
| working. Providing b2b service for 5k customers.
|
| Thanks god it's Java.
|
| Our competitors are lost trying to tinker with the old PHP or
| redoing everything with cutting edge node/js dead end techs.
| whynotminot wrote:
| You think node js is dead end tech?
| halfcat wrote:
| I interpreted the statement as, "dead end tech, which
| happens to use node/js".
| tootie wrote:
| There's a well-established answer to this that I've done for
| years that satisfies both and it's the BFF pattern. The crux of
| which is an orchestration tier. A simple pass-through API
| gateway which can interface with all your thoughtfully-
| designed, single-purpose APIs, extract and transform one or
| more payloads and serve up a single payload that maps one-to-
| one with a frontend. I've deployed this architecture for years
| on some large-scale sites. It works very nicely. Bonus is that
| you can manipulate and even swap out entire backend pieces
| without worrying about your frontend.
| NovaX wrote:
| qlio [1] was a really elegant implementation of this pattern
| before it was named and popularized. That provided a nice
| decoupling of the FE/BE teams by allowing very quick
| iterations, with an early means to compose apis to simplify
| the marshalling.
|
| [1]: https://tech.ebayinc.com/engineering/announcing-ql-io
| gorjusborg wrote:
| I also disagree.
|
| I agree that pretending you have multiple clients sets up a
| more difficult bar to meet. I agree that bar might be overkill
| for some projects.
|
| The idea that it is overkill for all projects is a leap I can't
| follow. Optimizing for greenfield development speed is
| something inexperienced devs often do, and that's what this
| feels like.
| [deleted]
| jgilias wrote:
| The problem is not building a general purpose API, the problem is
| over thinking it. There's a sweet spot where you build the API
| just slightly more flexible than your FE needs at the time, yet
| without wasting time on making it fit 'all possible future use
| cases'.
|
| Then you can later on whip up a mobile app if needed, let the
| clients use it, whatever. And evolve it accordingly.
| runeks wrote:
| I disagree. Trying to generalize a single implementation into
| an interface is always problematic. And that's exactly what
| inserting an API between the FE and BE is if your only UI is a
| web page.
|
| If, later on, you want a mobile app, then an API can easily be
| deduced from your current, working UI, instead of trying to
| imagine what the UIs of your web FE and mobile app have in
| common.
| Spiwux wrote:
| Don't think I could disagree any harder. Requirements change.
| Business needs change. You want your FE to be able to evolve
| independently without having to wait for the BE to implement the
| precise logic you need.
| another-dave wrote:
| As well as your FE team forced to wait on BE changes for new
| features, you've also created busywork for the BE team anytime
| there's a FE refactor/restructure to boot.
| bramblerose wrote:
| An organisation that separates frontend and backend teams
| will naturally converge to an architecture where the
| collaboration between frontend and backend is minimized
| (i.e., a generic REST API) -- Conway's law.
|
| This doesn't mean that an actual cross-functional team that
| contains both frontend and backend developers can't use the
| proposed single-purpose API to run circles around the split
| team.
| another-dave wrote:
| Regardless of cross-functional teams, I think having to
| make changes at an API level at the backend for UI changes
| will negate a lot of the benefit.
|
| For clarity, I don't think you need to treat your own
| front-end like an external consumer & think it's fine to
| have bespoke endpoints as needed.
|
| What I'm skeptical of is the author's suggestion that a
| backend endpoint brings back presentational info like
| "leftBoxTitle".
| hakunin wrote:
| One extra thing I have confirmed after writing this article: it's
| usually a bad idea to reuse back-end data in multiple places on
| the front-end.
|
| If you think about functions or object constructors in general,
| it kind of makes sense. One of the most important architectural
| practices I've ever discovered is: don't pass in the parameters
| that you have, pass in the parameters that the function needs. So
| if you have companyName, and you are constructing a page that has
| a title, you shouldn't pass it companyName: companyName, you
| should pass it pageTitle: companyName (parameter name: parameter
| value). It's crucial that the parameter is named after what is
| needed, not what you have. This is kind of the essence of what
| the article is suggesting.
|
| If your front-end is reusing a lot of fields from back-end, it's
| likely that you're passing it what you have in your
| database/resources, and not what it needs -- fields for
| constructing the UI, configuring the views. Moreover, I rarely
| see front-end going through the exercise of defining exactly what
| they need. The article encourages more of that.
|
| Once the front-end starts reusing the generic back-end fields
| everywhere, you lose track of your use-cases. Everything you ship
| from the back-end becomes potentially important for mysterious
| reasons that not even front-end can easily understand anymore.
| Front-end already built complex dependency trees based on these
| generic fields. If you actually untangle these trees, it might
| turn out that your front-end can only exist in 5 different
| "modes", but you can no longer see that in the tangled mess. You
| can no longer streamline and optimize these 5 configurations.
|
| So to summarize: pass what is needed, not what you have is a good
| general architectural rule that's also applicable between back-
| end and front-end.
| kdazzle wrote:
| I don't know about this. I do think people tend to prematurely
| optimize by over-generalizing their APIs instead of building
| what they need. But this seems like it swings too far the other
| way.
| appplication wrote:
| This is really timely for me, thank you. I'm ignorant when it
| comes to web dev best practices (data engineering background
| mostly) but find myself suddenly having created a couple small
| backends for some of our internal (non-customer facing)
| tooling, and running into basically all of your questions.
|
| One of these I struggled with right away was "how do I ensure
| the front end and back end have consistent data sourcing and
| validation", e.g. for various forms, dropdown selectors, etc. I
| have found surprisingly few resources for general patterns
| here. So I did your anti-pattern of having an endpoint for each
| little thing (e.g. /api/v1/country-codes or something like
| that).
|
| This has felt... ok at best. One challenge, perhaps entirely
| imagined, is coherent namespacing. Part of the backend is also
| a public (internally) API. We auto-generate all our docs with
| swagger, and I was finding that the few meaningful endpoints I
| had were diluted by the mess of individual endpoints for the
| frontend. So I threw these under /api/v1/config. Feels like a
| junk drawer but at least it cleaned things up.
|
| I like the idea you're proposing here for having one API per
| page, I think it makes a lot of sense. It also eliminates the
| "I guess I'll add another endpoint" and changed it to "let me
| add another field". Feels more granular and scoped. I will be
| giving this a try!
| nonethewiser wrote:
| I don't think what he's suggesting is common whatsoever. Take
| that however you want.
| appplication wrote:
| Because I'm otherwise uninformed to pros/cons here and
| don't have the benefit of experience to fall back on, what
| are the alternative suggestions for best practices for
| these types of problems? For context, my app is a single
| backend dev (me), separate frontend team that tasks on as
| needed. Backend dev resources are unlikely to expand beyond
| me for the 2-year horizon.
|
| I also have all context on vision for direction of the web
| app, and field all user feedback and requests. Front end
| team has no context on user needs, and does not keep any
| roadmap for the app. So it seems like the above recommended
| pattern could make sense in that I could drive more front
| end work from the backseat, so to speak.
| theptip wrote:
| I think the standard evolution of an API is:
|
| 1) basic CRUD API for your objects (eg DRF generated
| model-API in Django). Really easy to build. Client is
| assumed to have some magic knowledge (eg which country
| code style you use). Ideally as much of the smarts as
| possible is server-side, but early on you can compromise
| on this.
|
| 2a) for reads, notice you need nesting / joins, add
| nested fields. Maybe notice these joins are slow and make
| them optional; build some expanded=true or
| with_subobject=true type query params.
|
| 2b) for writes, notice that CRUD is getting hard to
| maintain as frontend can create n^2 possible states for n
| fields, and backend validation needs to consider all
| other fields for each update. Move complex state
| transitions to mutation/action/verb endpoints instead of
| PUT(any fields). Add your first "status" fields.
|
| This gets you quite far, likely to be fine for 2 years
| and beyond. After this there are lots of options
| depending on needs, and overhead associated with more
| layers/abstraction;
|
| 3) use something structured like GraphQL, or just
| refactor the API to do away with directly updating
| objects. Maybe lean into Finite State Machines if you
| have a small number of objects with complex transitions,
| endpoints trigger those parameterized transitions.
|
| Another option to consider is a server-side rendered
| framework with client-side hooks like Django+HTMX, Rails
| Hotwire, Elixir Livewire, where the frontend devs are
| working on styling, design, templates, and most/all the
| actual app logic is backend code. This gets you
| surprisingly far these days. If you are the one defining
| all the features, you'll iterate quicker in this mode.
| appplication wrote:
| Thanks for the thorough comment, I appreciate your
| insights. I was thinking about something like htmx since
| it seems to be getting a lot of positive buzz lately. The
| only thing keeping me from going that way is that I can
| offload most of the frontend work to folks who understand
| it better.
|
| For 2b, could you elaborate a bit? Is this like having
| dedicated handling for specific functionality? If I
| understand you, for example instead of PUT-ing some
| status on /myobject/{id}/, I could have something like
| /myobject/{id}/update_status/. And the benefit here is
| assuming that setting status is not a straightforward
| transition (maybe requires other transformations, etc),
| that this lets you better compartmentalize this complex
| logic instead of having one giga-endpoint for all PUTs?
| 8bithero wrote:
| Given that you're the sole backend developer with a
| focused vision for the app, the Server-Informed UI
| approach described in the article could work well for
| you. It simplifies the backend architecture and makes it
| easier to coordinate with your frontend team.
|
| However, for long-term scalability, you might run into
| issues with this approach. If so, take a look at "Bounded
| Contexts," a technique in Domain-Driven Design that helps
| break down your application into manageable, scalable
| units.
| ericmcer wrote:
| I... don't like this.
|
| You are basically saying we should take a name that conveys
| info about its content (companyName) and change it to something
| that contains none (pageTitle).
|
| I can tell if a field is being used for a page title by looking
| at the html, I can't tell what it contains unless it is named
| well. Additionally if I ever want to hop into the backend my
| time on the frontend will have given me 0 context if you are
| renaming all the fields.
|
| Also if you want to use Typescript this would prevent a bunch
| of automated type generation you could do.
| jackblemming wrote:
| Like most things, it depends. If you have a generic math
| module, you of course want generic parameter names. It would
| be weird to have a differential math library with a bunch of
| random terminology from another domain mixed in.
|
| If the page only makes sense if a company name is used as a
| title, then of course use companyName as the variable.
| rvnx wrote:
| It's a very curious way of doing things.
|
| The result with this strategy is that you may need the
| companyName and end-up at some point with code that does
| back:
|
| companyName = pageTitle
|
| or worse:
|
| companyName = pageTitle.split(' - ')[0]
|
| Because there is a moment when you will need to get the
| companyName again for some comparison or some whatever logic
| (e.g. is selected account profile current company ?)
|
| This feels very confusing.
|
| Instead pass companyName and keep it that way until the very
| last moment that you display it on the page (e.g. when
| rendering the view/template)
| hakunin wrote:
| The whole point is that when you need companyName for
| another thing, you should create a parameter `anotherThing`
| and backend will set companyName into it as well. It's
| designed to make it very weird to _not_ do that, so that
| you don't do that.
| [deleted]
| EGreg wrote:
| You guys are each partially right. What you need is
| MIDDLEWARE.
|
| On the one hand, you have some data coming in format X.
|
| On the other hand, you need the data in format Y.
|
| What you need is to define how to map X to Y. And then when
| you request Y, a way to indicate what parts of X you really
| need, so the code getting X can optimize, if it needs.
|
| In my experience, the real issue is how to _cache_ the X -
| should we be caching all of it depending on the Y, or should
| we be caching parts and understanding how they fit together.
| I have had problems with updating caches, and I am looking
| for solutions!
|
| https://news.ycombinator.com/item?id=36146520
| valenterry wrote:
| I think what you are looking for a is "(pure) functional
| reactive programming".
|
| The problem with caching is that it is very often highly
| individual and it usually comes with drawbacks, i.e. you
| win performance here but lose it there or you win
| performance but you lose consistency. (related: CAP
| theorem)
|
| So I doubt there is any "generic" solution that will or
| even _could_ make you happy. But if you find one, let me
| know. :-)
| EGreg wrote:
| Well, in a single-threadsd environment you almost can
| have consistency, and you can cache the latest results.
| What I am saying is that if a result consists of X1, X2,
| X3 but you don't need all of them for a certain request,
| then you wind up caching X1, X2 one time, and requesting
| X1, X3 another time, what to do with the cache of (X1,
| X2)? Currently I just update the caches which are subsets
| (X1) of a cached response, and do it with manual
| individual code. I hoped that I could have some sort of
| dependency graph. Maybe reactive programming, yeah. But
| that would essentially be some sort of declarative
| language, to run pure functions which still have custom
| code. Hmm
| Philip-J-Fry wrote:
| They're suggesting using the pageTitle parameter for the
| title, and being explicit about how things are used. If you
| pass a companyName parameter, it is quite generic. You just
| happen to use the companyName for the title, but you also use
| it elsewhere. Someone might want to add some additional info
| to the title. Their solution will likely be a new parameter
| and then concatenate these values together. But if you just
| thought about being explicit to begin with, then you'd
| already have the functionality to do that.
|
| The idea is to write things as standalone components. Which
| is a pretty universal programming strategy.
| nonethewiser wrote:
| 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.
| jmilloy wrote:
| 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.
| nucleardog wrote:
| Yep, in my experience this is what it led to.
|
| 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.
| hakunin wrote:
| > 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.
| underwater wrote:
| > Every API call was so form fit to the UI that nearly
| every UI tweak needed frontend and backend changes.
|
| Having to change backend code is not necessarily a bad
| thing. Just don't structure your code as two seperate
| codebases built by two different teams.
| paulddraper wrote:
| This philosophy encourages full stack engineers.
|
| So every feature/change only needs one engineer.
| hakunin wrote:
| 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.
| 8bithero wrote:
| 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 :|
| rvnx wrote:
| 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".
| paulddraper wrote:
| Releasing a public API is.....an enormous commitment.
| Anything you do has to be maintained for years.
| BytesAndGears wrote:
| Agreed, and my company has done exactly that.
|
| 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
| nucleardog wrote:
| 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.
| jmilloy wrote:
| This and the article strike me initially as completely wrong,
| which makes it very interesting. I still want a clear
| separation between the "model" and the "view", and I guess I
| tend to assume that this corresponds to the front-end and back-
| end. Maybe that's a poor assumption.
|
| What I see here is that the "view" is split across the front-
| end and the back-end. Or in other words, the back-end contains
| both the model and the JSON API as a view. I think this is what
| is meant by "I suggest you stop treating your frontend as some
| generic API client, and start treating it as a half of your
| app."
|
| I still want a clean separation between the model, e.g.
| companyName, and the view, e.g. pageTitle. Somewhere, there
| needs to be the explicit logic (in the back-end part of the
| view) that says that the the pageTitle for page A is the
| companyName. It's okay for many different views to "reuse"
| fields from the model, but each view should have its own front-
| end and back-end components. That the view is split across a
| front-end/back-end divide through the nature of the web-stack
| doesn't change the fact that each view should remain distinct
| from the other views.
|
| So I can agree in the sense that the alternative where you
| create a general-purpose JSON API as a model _and_ view in the
| back-end, and then essentially code up an _additional_ model
| and view for each front-end page /element with logic to convert
| the API data into the necessary content is a waste of time.
| slim wrote:
| it's called Controller and it's for this exact reason that
| it's separate from the Model and the View.
| jmilloy wrote:
| I disagree, the controller is something else. The point is
| that MVC is orthogonal to backend/frontend.
| hakunin wrote:
| Arguably, the opposite is true. The view is more washed out
| across the stack if back-end supplies generic fields, and
| front-end decides how to use them. Now you no longer know who
| is responsible for which decisions, and have to look for them
| everywhere in the stack.
|
| If back-end provides the entirety of data to build the page,
| then you limit front-end decisions to UX based on the
| specific data, and no longer allow them to pull in new
| functionality or foundational business logic over to their
| side.
| Terretta wrote:
| > _arguably... view is washed out across the stack_
|
| Perhaps to argue this requires munging "view" with "front
| end"?
|
| MVC needn't mean database schema, front end, and logic. It
| could, but then what is a "view" in the database?
|
| Perhaps you're reinventing MVVM?
|
| https://en.wikipedia.org/wiki/Model-view-viewmodel
| jmilloy wrote:
| MVVM definitely came to mind as I was writing my comment.
| The model is clearly in the back end, the view clearly in
| the front, and the view model contains the explicit link
| between companyName and pageTitle and can live in either.
| Here the suggestion is to put it in the backend and serve
| it as JSON.
| Terretta wrote:
| Normally I'd say "kids these days" but all 3 of our
| accounts joined in 2010.
| jmilloy wrote:
| I think if the back end provides generic fields and the
| front end acts as an independent consumer of the API, then
| you essentially have two apps each with their own entire
| MVC (or whatever paradigm you are using), one on the front
| end and one on the back end. So I wouldn't quite say that
| "the view is more washed out across the stack" but that you
| have two views (and two models).
| hakunin wrote:
| Agree with this. Of course because front-end still gets
| to build business logic, and back-end still ultimately
| decides the basis on which to build it, the decision
| making is spread more equally between them. Perhaps
| calling it "a washed out view" is not strictly
| appropriate, but worth acknowledging that the front-end
| is at the mercy of what back-end decides to provide it.
| sroussey wrote:
| A backend model is usually just called the model as it's
| modeling the data domain (sometimes called 'domain model').
| The thing you pass to the frontend is the 'view model' which
| is often entirely different.
|
| In some CRUD situations though, they can be nearly the same
| and you can convert the domain model into a specific view
| model with some kind of adapter (how people do this varies a
| lot). This adapter will take the end user security level into
| account, for example. Also, to avoid sending lots of useless
| data for a list, you can have a list view model. But if you
| do that, be sure to either keep the two in sync, or you have
| one and keep track of whether it's partially or fully
| hydrated.
| jmilloy wrote:
| I agree that mvvc sounds exactly right, but there is still
| the question of whether the view model is created in the
| back end (which is what the article is advocating) or in
| the front end (which is what you have to do if the back end
| serves the model like a general use API).
|
| The MVC or mvvc or whatever paradigm is somewhat orthogonal
| to the technical back end/front end.
| simplify wrote:
| Full static typing alleviates this greatly, allowing you to
| pass in what you have now and decide to refactor later if/when
| you need to.
|
| For example, if you remove a field that's still needed, you'll
| receive a type error, eliminating the problem of losing track
| of use cases.
| jlawson wrote:
| It's an example of the general rule to name/implement functions
| according to what they do, not how they're used.
|
| Stated another way, when building a tool, don't let information
| about the incidental context leak into the design of the tool
| itself. It should be designed to serve its intended purpose
| independent of when, how, where, or why it was built. This way,
| it won't break when that context changes, or when it's used in
| a new context.
| xpe wrote:
| I was nodding along until this part: "It should be designed
| to serve its intended purpose independent of when, how,
| where, or why it was built."
|
| This is impossible and in many cases undesirable. As long as
| the purpose and behavior of the function is clear, it is OK
| if it has contextual roots. Actually, no, it isn't just OK,
| it is the way it must be.
|
| Take one aspect of a sorting function for example. Should it
| be stable? Or not? This decision is rooted in the context. To
| try to make the function independent of context is impossible
| and unwise.
|
| Are you making a different point?
| adammarples wrote:
| Whether it's stable or not is irrelevant, if it's
| "stable_sort()" then it always should be, if it's
| "sort(stable: bool)" then it could be. It shouldn't depend
| on why and when I intend to use it. Most importantly it
| shouldn't suddenly become stable when I pass
| "sort(companyName=Walmart) because that's what we needed to
| do for Walmart but none of the others. That's outside
| context leaking in and a big mess to maintain.
| ChrisMarshallNY wrote:
| I've done this, and agree.
|
| But it was a good exercise for me, and I ended up using the
| general-purpose backend for a specific frontend.
|
| It's just that it's way overkill. Much more complex than it needs
| to be.
|
| But it works really, really well, and is secure as hell.
| jokethrowaway wrote:
| Great article.
|
| We used to call this common sense. It's insane we drifted so far
| from being sensible.
|
| I genuinely think 90% of frontend developers should not exist:
| the web would be better and companies would have better products.
|
| I include myself in the frontenders, I do terrible apps which
| should just be simple static pages with a sprinkle of js - in my
| defense, I need the money and nobody listens to me, they say this
| is modern frontend development.
|
| For my tech not-savy clients I can deliver awesome and simple
| solutions without using the dreaded R framework.
| solatic wrote:
| Hard agree with the YAGNI conclusion. There's a certain minimal
| amount of complexity needed to build your system, you need a good
| reason to build out another layer of indirection / abstraction
| here, something like needing web + mobile for the MVP or offering
| users direct access to the API as part of the MVP. Remember: if
| you think there's value in a REST-style layer, you don't need to
| build a separate API to support that. You can just write a
| getUsers() method on the server instead.
|
| What do you get when you throw out the API layer? Easier
| refactoring (no wondering who all the consumers of GET /users
| are). No implicit contract with users who have reverse-engineered
| your API (and complain if you break it). Easier security (who
| needs API tokens?). No organizational footgun that leads to a
| frontend/backend team split and then requires a group manager to
| get new features shipped, because of course your API doesn't
| actually expose feature-specific data for features that Product
| hasn't dreamed up yet.
|
| Sure, if you're FAANG scale, it'll be easier to work with APIs.
| You'll have some Staff+ Engineer architecting everything and
| coordinating between Product and a half-dozen teams that'll take
| months if not years to ship, and everyone will be happy with
| that. Strong fences make good neighbors, and contracts keep teams
| independent of each other. But in the _early days_? Feel free to
| ship things that don 't scale.
| kstrauser wrote:
| I beat the drum of _complexity_ vs _complication_. Solutions to
| a given problem have an inherent complexity. That's the minimum
| amount of sophistication and cleverness required to implement
| them. And then there's complications (think of the watchmaker's
| term) which extra features that don't directly solve the
| problem but, well, they look kinda neat!
|
| Strive to find that inherent, irreducible complexity and solve
| at that level. Resist the urge to say "for just 20% more
| effort..."
|
| I want to get a YAGNI tattoo.
| mediaman wrote:
| If you use an API, but in a way the author suggests (conformed
| to the UI, rather than an abstraction), what's the
| simpler/better way to do auth than API tokens?
|
| I have depth of experience in a niche industry and I'm working
| to build solutions for that industry, but I'm still early on
| the learning curve of being an effective full stack developer
| to make those solutions.
| drew-y wrote:
| > Easier refactoring (no wondering who all the consumers of GET
| /users are)
|
| Unless your API calls are properly abstracted into function
| calls. No reason you can't just have a `getUsers()` function on
| the frontend, and then use your favorite "find all references"
| tool from there.
| rewmie wrote:
| I think your comment doesn't really make sense. Unless you're
| somehow assuming that the one and only way to do web apps is to
| go the dynamic html path, I don't see how your suggestion can
| even apply. Once you have a frontend that needs to retrieve
| data from a backend, how do you even address that?
|
| Your comment reads as if someone complains people don't
| actually need cars because they can just show up somewhere.
| kakapo88 wrote:
| I'm finishing a project now, using exactly this design pattern.
| Sort of backed into it, motivated pretty much by the issues
| outlined. In addition, I wanted something that is clear and
| sustainable far into the future. The simplicity of this approach
| supports that. Quite liberating.
|
| Complexity is the enemy.
|
| True, one might reasonably propose a number of what-if
| objections. But for many (most?) projects), imo this is a good
| approach.
| ChicagoDave wrote:
| I'm going to get zapped once again, but if you're building
| complex applications, custom read models automatically updated
| based on events from operational writes is the optimal way to
| connect a front-end to APIs.
|
| Each read model should have a distinct business purpose.
|
| Generic models will only confuse maintainers and they're very
| likely going to see such code as brittle and tech debt.
| TekMol wrote:
| The way HN is build is the best way to build web applications.
|
| There is a concept of a "page". A page is loaded as an html page.
| This thread for example is a page.
|
| And then there is JavaScript which does all kinds of dynamic
| stuff on a page. Like when you update this commment or when you
| collapse/expand comments.
| osrec wrote:
| I disagree. I understand a lot of people enjoy the simplicity
| of HN, but when you find a developer who really knows how to
| take advantage of the additional "bells and whistles" that come
| with modern browsers, without making them annoying, the
| experience can be significantly better than HN.
| laurels-marts wrote:
| By "bells and whistles" you mean the Web APIs?
| https://developer.mozilla.org/en-US/docs/Web/API
| TekMol wrote:
| Sites like Reddit, Twitter, Facebook would be 100x better if
| they would be built the HN way.
|
| If these companies don't have the developers to show that
| "Bloated React Single Page General API sites" make a better
| UI then who has?
| throwsubsun wrote:
| Can you elaborate on this? I'm wondering what those bells and
| whistles are, or how the experience could be "significantly
| better."
| robertoandred wrote:
| Like not having to go through two page loads just to add a
| comment.
| MrPatan wrote:
| I don't think this applies to bigger apps like an excel or
| Photoshop. I don't think HN is very "appy", to be honest.
| bofaGuy wrote:
| This is how you lock yourself into a single front end design. And
| when you get ready for the next generation of your app or site,
| now you're locked in and changing that front end design becomes
| exponentially harder.
| hakunin wrote:
| In case of a complete redesign, yes you're right. With a
| generic API you will have about as much trouble writing the
| redesign as you did the original design.
|
| In practice, a complete redesign is an incredibly rare event,
| and a good problem to have. Usually design of individual pages
| and layouts undergoes gradual, incremental changes, driven by
| real needs.
|
| A redesign that requires front-end restructuring to such an
| extent that the data supplied is no longer sufficient should
| probably involve backend collaboration. Otherwise, you're
| tasking your backend team with building a generic site builder,
| which is much harder than a specific backend for your frontend.
| gabrielmrts wrote:
| is the first time that i see that idea, sounds crazy and out of
| the box imagine a real project using it..
| qudat wrote:
| Very similar sentiment to this article https://bower.sh/dogma-of-
| restful-api
| jensneuse wrote:
| An alternative to what's suggested in this post, how about going
| API first or even API only? Don't build a frontend at all, just
| build an API. E.g. you can deploy things on fly.io just by using
| their GraphQL and REST APIs. The advantage of focussing on the
| apis is that other developers can much easier integrate with your
| service and embed it into their own applications.
| sergioisidoro wrote:
| My personal take: Don't put it all in the same box.
|
| Just have a api/v1/rest/ base path for modular well defined
| resources that can be used across your application, without
| breaking changes, or even shared to third parties.
|
| Then have a api/v1/features for coupled endpoints that return non
| standard objects, and with a more flexible lifecycle.
|
| Chances are you're better off having both instead of trying to
| cram all the use cases into one approach
| indymike wrote:
| I can't agree more: having a separate API for functionality and
| a separate one for non-standard (i.e. UI) is a great way to do
| this.
| nicodjimenez wrote:
| That's a nice approach.
| antonhag wrote:
| Most times you won't need a well-formed (REST) API to start
| with, and many times you will never need it. Most small
| projects should start without one and create one when need
| arises.
| tootie wrote:
| 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/
| [deleted]
| kgeist wrote:
| General purpose API helped us when we had several features to
| implement in a row on a tight schedule: when I was busy
| implementing feature N+1, our frontend dev was still polishing
| feature N (with changing UI/UX requirements), and she didn't need
| me (the backender) because the backend just exposed the model as
| is without knowing what the frontend looked like. She could make
| lots of changes to the UI without needing any changes to the
| backend. Yeah it translated to more API calls but it allowed us
| to decouple our work completely and deliver more features in
| parallel.
| ggregoire wrote:
| I don't know when we started splitting people into "frontend" and
| "backend" teams (FAANG influence?) and for what reasons, but 10
| years ago we hired people with a general background, smart and
| curious enough to learn SQL, HTML/CSS/JS and whatever language
| you want to use on the server, able to build some end-to-end CRUD
| features on their own. And that's like what 99% of the companies
| need.
|
| My point being: when you have the same person building the UI and
| the API, you avoid a lot of the problems described in this
| article.
| nucleardog wrote:
| After a couple decades of doing this... I'd pin it on an
| explosion of complexity and scope in the frontend.
|
| It used to be if you could find a solid engineer with some
| vague aesthetic sense they could efficiently carry something
| through from conception and design to completion.
|
| These days the scope of frontend development has increased to
| the point where learning and staying on top of it has become
| too large (in my opinion) for most people to do while also
| becoming and staying highly competent in everything else.
|
| A "full stack" developer these days is supposed to understand
| frontend development, backend development, systems
| administration, cloud operations, and what else? All of these
| are massive areas that are constantly shifting.
|
| By way of analogy, we used to have the town barber handle
| haircuts and shaves but also surgery because the main skill to
| master was precision with a blade. Then as the scope of being a
| surgeon expanded to include things besides being able to cut
| precisely, that became its own specialization. Further on, even
| within surgery each area of the body started to require so much
| specific knowledge that we further broke that down into all the
| different surgical specialties (heart surgeon, podiatric
| surgeon, brain surgeon, etc).
| ggregoire wrote:
| > These days the scope of frontend development has increased
| to the point where learning and staying on top of it has
| become too large (in my opinion) for most people to do while
| also becoming and staying highly competent in everything
| else.
|
| I feel like frontend complexity is just a meme on HN to be
| honest. How complicated is it to learn a framework like React
| (which celebrated its 10 years 3 months ago) if you have a
| background in software engineering and some basic knowledge
| of HTML/JS? Like an afternoon to read the doc? 3 days to
| practice and be totally fluent? I managed graphic designers
| who knew nothing about computers but were able to learn React
| and be very productive. Then you pick one tool to build your
| production app. Yes there are many options, but you choose
| one (I use Vite.js) and stick with it for the next 5 or 10
| years.
|
| > A "full stack" developer these days is supposed to
| understand frontend development, backend development, systems
| administration, cloud operations, and what else? All of these
| are massive areas that are constantly shifting.
|
| There is a new big thing every 10 years or so. Like the last
| one was Kubernetes and it almost 10 years old and you
| probably don't even need it. HTML5, ES6, React, Python,
| Django, SQL, Postgres, Docker, AWS, Terraform... all those
| tools have been there since almost forever (it feels like it)
| and mostly never changed. And you can build 99% of the web
| with that stuff.
|
| As I said in another comment, yes it's a lot if you are a
| junior dev fresh out of college but you probably have some
| solid knowledge of all of that if you have been doing this
| for a very long time. At least enough understanding and
| experience to know what to google when you need to do
| something and what to do with what you found.
| d357r0y3r wrote:
| Yeah, it's this.
|
| It's not that tough to keep up with FE. React has been
| dominant for closing in on 10 years now. ~2015 was probably
| peak framework fatigue. If you left the industry in 2016
| and came back now, you could probably get productive and
| you would even recognize a lot of the tools.
|
| The HN meme is that "Well ackshually you could build Figma
| with ASP.NET Forms, just like we used to do back in my
| day." That just doesn't resonate with anyone doing the work
| day to day because applications themselves (not necessarily
| the front-end tech) have a much higher bar today.
| hakunin wrote:
| In a way, this article tries to bring the alignment between the
| frontend and backend closer to the full stack days, while also
| acknowledging the increased complexity of the front-end, that
| may be deserving of its own team focused on great UX.
| Phreaker00 wrote:
| For someone who has been in this field for 20 years I remember
| starting out doing every aspect of webdevelopment myself. Then
| the bigger and more complex the projects became, the less that
| made sense.
|
| The requirements of the distinct fields have gotten to a point
| where it's very impractical and hardly worthwhile for one
| person to master them all. You can't expect someone to
| translate a design into modern components that support all
| types of devices, resolutions and contexts to also come up with
| optimized SQL queries and knowing how to choose between Docker
| and Ansible for their distributed serverless functions that
| handle a variety of external endpoints.
|
| Ofcourse not every project that uses this approach needs this
| approach, and there's still a market for the Do-It-All
| developer. My point is that the webdevelopment world of today
| isn't that of a decade ago.
| ggregoire wrote:
| > You can't expect someone to translate a design into modern
| components that support all types of devices, resolutions and
| contexts to also come up with optimized SQL queries and
| knowing how to choose between Docker and Ansible for their
| distributed serverless functions that handle a variety of
| external endpoints.
|
| Why not? Obviously you can't expect this from someone fresh
| out of college/bootcamp, but that's what I do on a daily
| basis and I'd expect this from anyone with 10+ years of exp.
| simonbarker87 wrote:
| So basically an old style MVC framework style app like RoR,
| CodeIgniter etc but made with a JSON response the describes the
| page rather like Shopify's Store Theme 2.0?
|
| Sounds great. Now since you have access to the server code
| (unlike Shopify's system described above) just return HTML and
| use your JS flavour of choice in the places where you need heavy
| JS ... like we used to make web apps.
|
| The happiest web devs I speak to are those working in the older
| MVC style, mainly RoR people. While everyone in AWS/Serverless/JS
| land is burning out and miserable with the house of cards stack
| we are balancing React on top of.
| zianKazi wrote:
| I am not a big fan of building extremely fine grained general
| purpose APIs for frontends. A lot of the burden of juggling with
| data and presenting it is shifted to the UI layer. I am also not
| a big fan of building a composite API for "pages". Now you have a
| tightly coupled frontend/backend communication. What happens when
| we split the page or have to change the format of the data? Also
| the response of such an API can be quite big and nested. Ends up
| being a dump of data with poor documentation. I would try to find
| a middle path. Building composite APIs which have a concise
| purpose for the frontend but are modular enough to be reused
| across different areas of the application. Also, I feel that most
| of the problems discussed in the post are amplified when we have
| different groups working on the frontend and backend. If a single
| team is responsible for both the backend and frontend, API
| decisions are localized and can be changed as the development
| progresses.
| xg15 wrote:
| And the htmx-ification trend continues. I guess this is sort of
| the counter movement now to all the API-First/Data-First/SPA-
| First evangelism of the last few decades.
|
| I don't quite understand why though. Or rather, why those posts
| always seem to have an intense emotional dislike to anything
| data-driven.
|
| What exactly is wrong with just using React? Or, heaven forbid,
| plain Javascript, which browsers have spent the last decades
| optimizing it make working with REST APIs and JSON as easy as
| possible.
| neon_electro wrote:
| Can you expand on "just" using React? Are you saying "what is
| wrong with using React (the framework including React the
| library and all of its friends)?", or are you saying "what is
| wrong with just using React (the library) only?"
| xg15 wrote:
| I was more thinking of React, the framework, with as little
| addons as possible. React's data model always seemed the most
| reasonable to me, if you have to use a framework or library
| at all.
| ahuth wrote:
| Nice article
|
| This is one thing I'm loving about Remix. It's how the framework
| works, so there's no need to enforce this pattern or educate
| folks about it.
|
| AND Remix's nested routing still has you break down the data
| loading into a couple different parts (1 per route segment).
|
| So it feels like you're not loading everything in one place, and
| may be less likely to make people feel like they're doing
| something "different" or "wrong". It's
| hot_gril wrote:
| The complaint about general-purpose APIs is valid. I've seen
| teammates, including senior ones, jump onto the bandwagon of some
| monstrous "data service" at work where the entire API to the
| frontend was an ORM. Absolute trainwreck.
|
| This article advocates for another extreme that I've also seen at
| work. They invented some UI language in JSON and built some
| default JS components to render it. It works for very simple
| cases, but it's too rigid for anything slightly advanced, so the
| end result is some very clunky UIs and unhappy devs. You said
| your experience was bored frontend devs; that's usually a sign
| that their value is going to waste, and probably not because the
| backend devs can do their job better.
|
| There's a good middle ground that's pretty common. You don't
| define the API to end all APIs, you don't pretend FE and BE are
| totally decoupled, you just have the frontend team ask for what
| they need and let the backend team serve it. Maybe you get an
| endpoint per page this way, but it's just sending back the data
| to populate the page rather than the actual layout. Maybe a few
| things are separate endpoints, but a reasonably low number.
| hakunin wrote:
| > This article advocates for another extreme that I've also
| seen at work. They invented some UI language in JSON
|
| This is called server-driven UI, and not what the article is
| advocating. I try to make that distinction by calling the whole
| practice server-informed UI, rather than server-driven UI. The
| article is meant to be advocating almost exactly what you wrote
| in the 3rd paragraph.
| hot_gril wrote:
| Your note says, "A Server Driven UI is when the API tells the
| client which components to display and with which content."
| Your description of server-informed UI is, "Render concrete
| boxes, sections, paragraphs, lists. Render the visual page
| structure." What's the difference?
|
| More concretely, in your example: {
| "section1": { "topBoxTitle": "Foo",
| "leftBoxTitle": "Bar", "linkToClose":
| "https://..." }, "section2": {
| ... } }
|
| I was thinking these keys are special and a different page
| would also have "section1" with "topBoxTitle," but maybe I
| misunderstood. If these keys aren't special and the frontend
| dev is just humanly interpreting this differently on each
| page then defining the actual layout to display it, that's
| probably fine. But I wouldn't describe this as rendering the
| visual page structure in the backend.
| hakunin wrote:
| It may totally be my bad for not making this part clearer
| in the article, but these structures are never meant to be
| fed into something that can automatically produce a UI.
| They are not meant to be consistent.
|
| The way I've been describing this lately -- the json
| structure should come from you squinting at the page and
| seeing approximately what needs to be on it, and creating
| as-flat-as-possible way of sending it over, that makes it
| clear enough what each field is for, but not so granular as
| to be automatable.
|
| If you have a designer in your company, I've been
| increasingly preferring to use their terminology to name
| fields. If page has "cards", "navigations", "banners"
| whatever designer calls them, call them the same way in
| JSON. This is a good middle ground. It makes sure that
| back-end passes what front-end needs, while at the same
| time making sure that front-end doesn't get the wrong idea
| that their framework can dictate and accept this json
| structure directly.
|
| So if a full JSON-based language would allow you to
| customize every page element in any way you like, this
| approach only lets you to send over decisions about this
| page, using a json payload specifically for this page and
| the ways it can change, no more no less. You cannot add an
| arbitrary box or an arbitrary section in json, and expect
| it to appear.
| rhuru wrote:
| I have building most of my modern sites with NextJS and could not
| have been happier as it gives me the flexibility of directly
| quering DB, I dont have to worry about the general purpose API.
| But if I wanted to I can just easily build it too.
| lll-o-lll wrote:
| This is good _general_ advice. Sometimes you are building a
| general library or API, and sometimes there just happens to be a
| network partition between two components that make one module. My
| general rule of thumb is that it takes 3-5 times as long to build
| a library /generic API over regular code. It also requires a very
| different mindset.
|
| Should you do that sometimes? Absolutely! In big companies you
| probably have entire _teams_ doing this for API's that are
| entirely internal. Just recognise that it is a _huge_ cost and
| only do it when the benefits are likely to outweigh the costs.
|
| That's not to say that you should _never_ think about
| generalisation when writing normal code, (one of my pet peeves is
| interfaces taking a single "something" when a collection could
| just as easily have been used), there are many ways code can
| evolve and some up-front thought can save a good deal of
| refactoring later. Just don't write a generic library when domain
| specific code will do.
| over190bpm wrote:
| My experience working on "medium sized" B2B apps in 10-20 people
| teams is that the cleanest way to design API-s is to have a
| regular REST API for the basic CRUD operations on the entities,
| and then have more specialized endpoints for specific pages,
| tables, dashboards etc. on top of that. Having specialized
| endpoints is kind of required, as the data often needs to be
| searchable, sortable, filterable and paginated, which would be
| pretty wasteful, or sometimes even impossible to do on the
| frontend. I find these kind of REST API-s pretty straight forward
| to design and implement for the most part, and as others pointed
| out, onboarding is extremely easy if the new developer on the
| team has worked in software dev at least for a year or two. This
| also makes it pretty easy and quick to transition to a fully
| public API if needed (although I have rarely seen this as a
| requirement).
|
| Edit: fixed a typo.
| davidy123 wrote:
| When are we going to get away from all the YAGNI engineering that
| has sold short the promise of the Web for more rented silos, and
| get to something more like HATEOAS?
| tuckerconnelly wrote:
| I see the point of the article, and even on a principled level I
| might agree with it (e.g., don't overly abstract). A few problems
| I see though:
|
| 1. If you make backend-only abstractions to keep your code even a
| little bit DRY, you'll have a duplication of code (both the
| abstraction and the BFF endpoint). I think it'd be better to go
| all in on the abstraction up-front.
|
| 2. This will impair the conceptual integrity of the system and
| arguably lead to development slowdowns in the long run. To quote
| Mythical Man Month: "I will contend that conceptual integrity is
| the most important consideration in system design. It is better
| to have a system omit certain anomalous features and
| improvements, but to reflect one set of design ideas, than to
| have one that contains many good but independent and
| uncoordinated ideas."
|
| 3. Your ad-hoc logic will likely be duplicated anyways across
| pages.
|
| 4. A general purpose API makes security features like RBAC much
| simpler.
|
| I think a general-purpose API is a well established abstraction
| you can rely on for pretty much any project.
| backendanon wrote:
| > This is similar but not quite the same as Server Driven UI1.
| Perhaps we could call it Server Informed UI.
|
| I think we should just move back to server side rendering, JSP
| and even ASP were great, plain HTML, some JavaScript where
| desired since we can't seem to get away from JS.
| cpursley wrote:
| The sweet-spot seems to be LiveView (Phoenix) and it's
| derivatives.
| 9dev wrote:
| Oh, right. Tell me how well that would work for Figma,
| Photoshop, or VS Code?
| unconed wrote:
| This is entirely backwards.
|
| Don't build a general purpose API so your front end can have half
| the the logic outside.
|
| Just build it the way you would as if it were local, and then
| hook it up to a back end with a git-like synchronization
| mechanism. You know, the same way you do all your own
| development.
|
| If you don't know how to do that, maybe you could learn that
| instead of arguing over REST vs GraphQL, or whether your line
| format should care what boxes are on the page.
|
| All I know is, it's fantastic to be able to add features to a
| front end, persisted in a back end, without having to write code
| on both sides.
|
| "What about validation??"
|
| Guess what, if users each have their own workspace, isolated and
| data driven, you don't need to worry about one bad request
| ruining your whole service.
| urbandw311er wrote:
| Could you point me to a sample project/source that does this
| "git-like synchronisation" you describe? At the moment this
| proposal feels vague.
| moomoo11 wrote:
| I write all my api code using a business logic "service" layer
| and a data ops "repository" layer.
|
| The endpoints are by feature not entity, although most of the
| time they overlap.
|
| This lets me move fast while keeping it simple to build the UI
| whether it's mobile or web.
| willsmith72 wrote:
| I totally agree with the general idea, and this is generally how
| I build backends these days. If there are multiple clients, it's
| usually even ok for each to have a backend which talks to the
| "master" backend.
|
| But I will never get on board with sending things like content or
| UI related stuff from the backend. I've seen too many times,
| engineers think "all our forms are the same, let's just have the
| backend send a list of input field names and types like
| 'address'". It's almost always a bad abstraction, causes pain on
| the frontend, and restricts the creativity of engineers and
| designers.
| robcohen wrote:
| Do you have the same opinion of headless CMS systems like
| Strapi?
| hakunin wrote:
| The article doesn't disagree with your second paragraph. It
| encourages to treat each "page" as a unique snowflake,
| including forms in it. I should probably do a better job to
| discourage consistency and standardization of these json
| structures. This is addressed in another one of my comments if
| you search for "my bad".
| aabbcc1241 wrote:
| previous discussion:
| https://news.ycombinator.com/item?id=28511570
| preommr wrote:
| Quite surprised at how much people agreed with this post. I
| personally don't think this is such a good idea - it's not that
| hard to write a general purpose API that covers 80% of obvious
| use cases, and have app-specific grouping of endpoints for the
| remainder. And I include things like rollilng multiple requests
| into one as part of the obvious use case. Because it's usually
| very easy to implement - either copy/paste, or 5 lines for more
| complex solutions like an orm, graphql, etc.
|
| It seems like a terrible idea to couple the backend with the
| front-end so strongly.
| padjo wrote:
| Seems like an over correction. Yes trying to make your front
| end API be your public API is probably a bad idea, but making
| your front end API completely coupled to the structure of
| your app structure is probably a bad idea too. Best approach
| is probably in the middle somewhere.
| isaacremuant wrote:
| It probably comes from misusing the API route and feeling
| they want to keep it simple, but instead heavily coupling
| things.
|
| A motivated BE that wants to be productive avoiding
| unnecessary work would probably hate being "support for
| frontend" whenever they decide to change something and a
| motivated frontend would probably want to turn themselves to
| full stack powers to not depend on someone else.
|
| It feels really bad as a pattern unless that webapp is your
| only concern and is constantly moving or something, or if
| there's no actually FE or BE but just few people maintaining
| stuff as a side concern (backend for frontend works there).
| projektfu wrote:
| As a user, this approach often leaves things in a difficult
| state. The front end works, but automating data access is a hard
| slog through inconsistent API that's not fully revealed.
| Reporting is dependent on what is planned for the front end, not
| what is needed by the user. Because the front and back are
| tightly coupled, everything is fragile unless it's baked in.
|
| I think many business apps should focus on having an API be a
| first-class citizen, and there needs to be better standardization
| in how they're organized and used. GraphQL could be part of that
| solution. It's also nice when the API lets you do the things you
| can do from the front end as well as more data-oriented tasks.
| For example, in Zoho Books, reporting isn't automated by the API,
| you'd have to roll your own or script the UI. The API should
| cover both reading and writing data items like transactions and
| downloading a PDF or Excel report using the reporting interface.
| codingclaws wrote:
| I read some of the HTMX essays [0] last week due to it being
| accepted into the GitHub accelerator program.
|
| So, a fully RESTful API must output HTML. I'm not going to go
| into why but that's what Roy Fielding (the creator of REST),
| Martin Fowler and the HTMX guy(s) say.
|
| The HTMX guy(s) also say that of course this fully RESTful API
| that outputs HTML is sometimes bad because you don't want to have
| to parse data out of HTML. So, the optimal setup is to have both
| a fully RESTful HTML API and the more common JSON API.
|
| I also think that for the fully RESTful HTML API, it doesn't make
| sense for the outputted HTML to have any JS.
|
| So, the question I'm pondering at the moment is, is a fully
| RESTful HTML API simply a website that doesn't use any JS? If so,
| then the optimal setup is to have an SSR website that doesn't use
| JS and a JSON API. Of course, under the hood, the website and the
| JSON API use the same lower level API (eg. SQL queries and back-
| end functions).
|
| What's crazy for me personally is that this is exactly how I have
| set up Comment Castles. There's the no JS website [1] and the
| JSON API [2]. But I didn't build a no JS website because of REST,
| I just prefer websites that have no front-end JS.
|
| [0] https://htmx.org/essays
|
| [1] https://www.commentcastles.org
|
| [2] https://www.commentcastles.org/api
| theptip wrote:
| Counterpoint: I did this and it worked out great. We ended up
| wanting to support direct API access from our customers and we
| were already in a good place to do so.
|
| YMMV. An observation I have is that really flexible APIs make it
| easy for the frontend to make small changes, instead of needing
| to coordinate with backend changes. On the other hand this can
| lead to maintenance problems down the road as it's hard to
| control exactly what data/state your system can transition to.
|
| I view this as one of the best pieces of tech debt to take on in
| an early-stage startup, basically keeping your options open and
| minimizing short-term friction, at the expense of taking on a bit
| more cleanup after you find PMF and start to make your backend
| more robust for the usecase you are scaling.
| Attummm wrote:
| Engineering is about tradeoffs, everything has its place. But
| it would it be good standard? How would we look at that api
| when:
|
| New frontend is needed? Other team/company would like to acces
| the data?
|
| When we other clients for example anderiod/ios app?
|
| Wouldn't a generic api, with some custom api calls. Ensure that
| we are more consistent, and require less maintenance in the
| future.
|
| That way we could focus on adding business value, or solving
| those hard problems, we normally don't have time for.
| tanepiper wrote:
| I read this and got to the end, and laughed because that's what
| we're working on (more a composition tool from different data
| sources using a headless CMS and a Knowledge Graph) - so in the
| end we do need a general purpose API since that's part of the
| USP.
| kburman wrote:
| Have to disagree with this. API is not always for FE. It can be
| consumed by other service, or a script. Making generic API helps
| reuse of common API across web pages. For example notification,
| user profile.
| caleblloyd wrote:
| The past 2 years have seen some advancements in full-stack
| frameworks with streaming components. Such as NextJS with React
| Server Components or .NET Blazor.
|
| Those would be my preference for an app that doesn't need a
| public API. If each partial layout and page component does it's
| own data loading server side, you can skip GraphQL or making a
| Full Page API and partial update APIs.
|
| Part of the problem with this is organizational though. For the
| past decade teams have largely been split between
| frontend/backend who typically work in 2 completely different
| languages/frameworks. The steaming components approach is a
| switch back to full stack and a single language/framework. Also
| every language doesn't have one of these streaming component
| frameworks, so it's not really possible to do an app completely
| in Go for example.
| rblatz wrote:
| This pattern has a name Backend For Frontend (BFF)
|
| https://aws.amazon.com/blogs/mobile/backends-for-frontends-p....
| agentultra wrote:
| Better, just don't write an HTTP API for your front end. Use a
| server side framework. Done.
|
| It's a pain coming into a project that was built the way the
| article recommends. Endpoints become RPC calls instead of
| resources serving entities. The hodgepodge of "API" calls becomes
| difficult to scale horizontally due to implied (and never
| documented) data dependencies. So you miss out on transport layer
| caching, entity caching, and a host of other goodies.
|
| All because your front end "framework" wants to live in a
| separate codebase from the server.
| hakunin wrote:
| The "page" becomes the resource for reads. You get great
| scalability, because you can use your database in the most
| efficient way possible to provide entire data for the page. You
| can maintain 100% back-end clarity on what each page depends on
| (instead of letting front-end request anything they want in any
| part of the view).
|
| I personally prefer server-side frameworks. I also understand
| when a front-end team prefers to work a certain way, has a lot
| of knowledge and tooling built-up around a certain way, and is
| worth accommodating for that reason.
| [deleted]
| Toine wrote:
| The "Controller" part of an API conceptually belongs to the
| "presentation" layer.
| ricardo81 wrote:
| It's also an ideal vector for scraping your site-specific data if
| it's an XHR request, typically an enumerating id or something a
| sitemap will spell out for more sparse IDs.
| d_watt wrote:
| I'd caveat that it can be a good idea to make it a general api if
| you're building a B2B app. These days, purchasing checklists
| often include "do you have a public api?" Saying no to that can
| be a sign of product immaturity that is worth trying to get ahead
| of, and having to maintain internal and external apis is a lot of
| overhead.
|
| It also can be good as you scale to have an API interface you can
| have a services team learn how to work with to enable "special"
| flows for customers.
| runeks wrote:
| There are clearly reasons for a backend to expose an API; no
| one is disputing that. The article simply points out that it
| should not be the default.
| indymike wrote:
| This article is good advice to get a working prototype or a
| decent solo-dev MVP website that will be re-written later. I've
| spent the last two months cleaning up the work of a developer who
| thought this way. Here's what you run into:
|
| * Front end and back end become conflated. Often times code that
| should run on the backend runs on the front end and vice versa.
| Often shortcuts like saving ui state using the same api endpoint
| you use to save data become complex, and slow down improvements
| to both the ui and the public API. Likewise data manipulation and
| in some cases even validation gets done on the wrong end, too.
|
| * You confuse UI code with application functionality. Code used
| to save the order of columns, stuff you entered the last time a
| dialog was displayed, and the convenient data structures (i.e.
| easy, not best) for the front end leak into the back end. So you
| end up spending a lot of time building back end functionality
| that has literally no utility to anyone else other than the front
| end developer.
|
| * You lose focus on your other users: developers who integrate
| and build on your product. Eventually, those developers become
| in-house people who are doing integrations and implementations
| for customers, and a messy API will really slow them down.
|
| Better advice: separate the concerns and have a separate API UI
| backend. Build exactly what you need to deal with UI state, and
| component specific UI settings. Your front end team is a perfect
| proxy for a third party developer for your public API. Take
| advantage of that. If they can't use it, or they get paper cuts,
| then paying customers will have problems, too. You'll also be
| able to on-board developers faster (easier training) and have
| better documentation.
| zelphirkalt wrote:
| Do I understand your advice/recommendation correctly?:
|
| frontend <--> UI API, only has what frontend needs <--> backend
| service with its own API
|
| In that case: What design do you suggest for the backend's
| actual API?
| ozim wrote:
| For me back end and front end being conflated is a good thing.
| Because most of the time it ends up one application anyway.
|
| If you need generic API you can make separate application that
| will be API.
|
| So if you make domain driven design your front end is separate
| concern. API for third parties is separate concern.
|
| Still in database you might have stuff not used by external
| parties but then you don't expose it in your external API. But
| you can make models on your front end API.
|
| Making "generic" solution might seem like saving time and money
| but as times go by and it turns out you have to fight with
| generic API to get things done because one is stuck in his ways
| - it definitely pays off.
| wruza wrote:
| I have some experience with it both as a user and a developer.
|
| _Code used to save the order of columns, stuff you entered the
| last time a dialog was displayed, and the convenient data
| structures (i.e. easy, not best) for the front end leak into
| the back end_
|
| As a user, I want the column order to persist when I'm moving
| between PCs or browsers or private windows.
|
| _You lose focus on your other users: developers who integrate
| and build on your product_
|
| Having done enough integrations, I prefer "what you see is how
| you work with it" mode. Because requirements usually come in a
| form of "there's a button on page X, it produces a table, take
| it". But when you approach it from the API side, this user
| story appears smeared across complex frontend code with
| numerous API calls and you basically have to reverse-engineer
| this part. Includes hours of comparing sparse docs against the
| network activity tab in the inspector pane. Very tempting to
| just $.click() the button and rip these <tr>'s out of it.
|
| That said, I don't think you don't need APIs. But your either-
| or dichotomy is wrong. If you need an API, then build it. But
| it has nothing to do with how pages work. Because if pages do
| something clever, and there's value in it, your API users will
| have to repeat it. Why not push that cleverness back to where
| it belongs.
|
| And finally,
|
| _Front end and back end become conflated_
|
| It's a whole system. Drawing an arbitrary line between graphics
| and logic _not where the boundary between them is_ and
| repeating it in company's structure - _that_ creates a point of
| view where they conflate. If you don't do that, there's no
| conflation. Everyone just does the whole task like "add an
| input there from this db column", without having to start
| complex interactions or negotiations. This separation is
| synthetic.
| ricardobayes wrote:
| This only works for small projects. Data-heavy frontend usually
| sends multiple requests to allow async rendering of different
| parts of a page with different loading times.
|
| This also doesn't work if your design changes a lot. AKA a design
| change will now mean a backend re-design too.
| rrradical wrote:
| Your first point is addressed in the article. For the second
| point, my experience is that the backend probably needs some
| work in that case anyway. If the backend is well designed, then
| only the presentation API endpoint needs to change. So a BE
| engineer is doing the tweaking instead of a FE engineer; not a
| big deal. Less of a big deal if there's no line drawn between
| FE and BE engineers.
| smarkov wrote:
| Based on my personal experience general purpose APIs lead to
| backends for frontends, which is a colossal footgun unless
| orchestrated by a mastermind. Even if you did have that kind of
| mastermind, if that person decides to leave you're left with a
| very expensive puzzle for everyone else to solve.
|
| Here's my take: don't build general purpose APIs, build general
| purpose domain actions. A user making an account is a domain
| action. Sending a notification to the user is a domain action.
| Make doing each separately easy. Make doing both at the same time
| easy. Do this with all of your domain actions and now you have an
| easy way of building exactly the kind of endpoints all your front
| ends need.
| tootie wrote:
| Curious about this take, since I've done it successfully many
| times. Orchestrating a backend for frontend is usually a pretty
| trivial task. It's usually just mapping one json to another.
| algem wrote:
| It sounds almost like the author is advocating for a really
| dumbed down BFF layer (backend for frontend) but what they are
| missing is behind the bff layer you would have general purpose
| apis. And if I interpret the article to the extreme what is the
| difference between this pattern and how html is currently served.
| Salesforce works sort of similar to what is described and it's a
| nightmare, these restrictive ideals in my experience just aren't
| good in practice because they tend to slow down development.
___________________________________________________________________
(page generated 2023-08-20 23:01 UTC)