API a šetření přenosu odkazem na objekt

petersveter

API a šetření přenosu odkazem na objekt
« kdy: 25. 02. 2024, 00:07:38 »
Povedzme ze mam API ktore vracia zoznam clankov. Kazdy clanok ma nazov, obsah, kategorie, autora... a povedzme ze napriklad autor je objekt ktory obsahuje viacero udajov, mimo ID, ako je napriklad meno, url profilu, odkaz na avatar...

Bezne je kazdy clanok vo vratenom zozname samostatny objekt s plne vyplnenymi entitami. Co ak by som ale vratil odpoved tak, ze linkovane objekty by boli vedla vrateneho zoznamu a samotne embedovane objekty by boli len ID ako odkazy na konkretny objekt?

Cize namiesto:

Kód: [Vybrat]
{
  "articles": {
     123: {
       "title": "foo",
       "body": "bar",
      "created_at": 1223456,
      "created_by": {
          "id": 45678,
          "name": "Some User",
          "avatar": "http://www.foobar.com/avatar.jpg"
       }
     }
  }
}

by odpoved bola:

Kód: [Vybrat]
{
  "articles": {
     123: {
       "title": "foo",
       "body": "bar",
      "created_at": 1223456,
      "created_by": 963
     }
  },
   "authors": {
        963: {
          "id": 45678,
          "name": "Some User",
          "avatar": "http://www.foobar.com/avatar.jpg"
       }
   }
}

A teda klient by si to musel vyskladat sam. Rozmyslam nad tym uz nejaku chvilu lebo mi pride celkom zbytocne robit vypisy objektov kde vratim 50 hlavnych zaznamov a 50x je tam rovnaky uzivatel, co je 49x viac informacii o uzivateloch nez je realne treba poslat. A samozrejme su tam aj dalsie objekty, mozno kategorie, obrazky s metadatami a proste cokolvek.

Rozmyslam ake to ma negativa to takto riesit, ale zatial som nansiel nic dolezite, tak ze aky je konsenzus?

Taktiez aj na backende je lahsie si len spravit zoznam objektov ktore treba nasledne nacitat podla id a len vlozit do odpovede nez prechadzat hlavny zoznam a hladat ktory objekt kam patri. Na frontende zase klient nemusit robit nic ine len response.authors[article.created_by] a ma autora.
« Poslední změna: 25. 02. 2024, 14:05:34 od Petr Krčmář »


alex6bbc

  • *****
  • 1 659
    • Zobrazit profil
    • E-mail
Re:API a setrenie prenosu linkovanim na objekty namiesto embedovania
« Odpověď #1 kdy: 25. 02. 2024, 06:52:47 »
kdyz posles vsecky data tak klient nemusi udrzovat nejaky vnitrni stav seance. jinek musi klient udrzovat stav a musis hlidat poradi posilani dat, aby ti treba stare data neprepsaly nove.

Re:API a setrenie prenosu linkovanim na objekty namiesto embedovania
« Odpověď #2 kdy: 25. 02. 2024, 09:04:00 »
Přesně to samé jsem udělal loni v jedno projektu a fungovalo to bez problémů.
Jen jsem tam neměl zvláštní ID (jako máš v příkladu 963), ale použil rovnou ID autora (45678).
U mě to dávalo smysl i proto, že seznam osob nebyl rozsáhlý a na klientovi se s těmi vazbami pracovalo (nešlo jen o created_by) a k záznamu se daly osoby i přidávat (vybírat ze seznamu), takže jsem ten samostatný seznam osob stejně potřeboval.

Re:API a setrenie prenosu linkovanim na objekty namiesto embedovania
« Odpověď #3 kdy: 25. 02. 2024, 09:10:20 »
Je to možné to tak udělat, ale nejspíš to bude typický příklad předčasné optimalizace. Máte změřené, o kolik se tou vaší optimalizací zkrátí nebo prodlouží čas potřebný na získání odpovědi? O kolik se zmenší objem přenášených dat? Je akceptovatelné to, že se čas pro získání odpovědi prodlouží kvůli zmenšení dat? Bude to zmenšení dat měřitelné, když používáte kompresi? A pokud vám to všechno vyjde tak, že to má přínos – je ten přínos adekvátní tomu, jak se zkomplikuje kód na serveru i na klientovi?

Mimochodem, dá se to udělat i tak, že ty data o autorech nebude posílat server rovnou, ale nechá jejich dotažení na klientovi. Klient může mít cache a bude se dotazovat jenom na ty autory, které v cache ještě nemá. Pro nacachované autory to pak bude ještě rychlejší, pro ty nenacachované ještě pomalejší.

Stejně tak může jít o předčasnou optimalizaci, pokud ta data budete na serveru spojovat dohromady. Pokud už máte na klientovi komponentu, která dostane ID autora, stáhne si k němu potřebné údaje a ty zobrazí, je předčasná optimalizace cpát ta data do seznamu článků a dělat druhou komponentu na zobrazení autora, která data dostane rovnou.

Závěr je stejný, jako u každé jiné potenciální předčasné optimalizace – nedělejte to, dokud nezměříte, že je v tom opravdu problém.
« Poslední změna: 25. 02. 2024, 09:14:10 od Filip Jirsák »

alex6bbc

  • *****
  • 1 659
    • Zobrazit profil
    • E-mail
Re:API a setrenie prenosu linkovanim na objekty namiesto embedovania
« Odpověď #4 kdy: 25. 02. 2024, 09:12:24 »
pripadne i json jde zkomprimovat a poslat mene dat.


petersveter

Re:API a setrenie prenosu linkovanim na objekty namiesto embedovania
« Odpověď #5 kdy: 25. 02. 2024, 09:38:08 »
Přesně to samé jsem udělal loni v jedno projektu a fungovalo to bez problémů.
Jen jsem tam neměl zvláštní ID (jako máš v příkladu 963), ale použil rovnou ID autora (45678).
U mě to dávalo smysl i proto, že seznam osob nebyl rozsáhlý a na klientovi se s těmi vazbami pracovalo (nešlo jen o created_by) a k záznamu se daly osoby i přidávat (vybírat ze seznamu), takže jsem ten samostatný seznam osob stejně potřeboval.

Samozrejme to 963 je blbost a malo to byt 45678 :D  cize sa bavime o rovnakej veci. Ja uz mam par rout kde to pouzivam a rozmyslam to hodit na vsetky skratka. Ako som pisal, nevidim zatial ziadne nedostatky tohto riesenia kedze vsetky data su v odpovedi, ide len o to ako si ich klient spracuje a mysli mze je jedno ci napriklad meno autora bude response.results[0].author.name alebo ci to bude response.authors[response.results[0].author].name.

Re:API a setrenie prenosu linkovanim na objekty namiesto embedovania
« Odpověď #6 kdy: 25. 02. 2024, 09:47:23 »
Ako som pisal, nevidim zatial ziadne nedostatky tohto riesenia
Nedostatky jsou následující:
  • Je to složitější na implementaci na serveru.
  • Je to složitější na implementaci na klientovi.
  • Pokud má klient dostatečně rychlé připojení k serveru, bude déle čekat na odpověď.
Ten poslední bod mi připadá nejzajímavější, protože pokud by „dostatečně rychlé“ připojení bylo vše, co je dnes běžně dostupné, znamenalo by to, že tímhle vylepšením zkomplikujete kód a ještě zpomalíte aplikaci drtivé většině uživatelů.

petersveter

Re:API a setrenie prenosu linkovanim na objekty namiesto embedovania
« Odpověď #7 kdy: 25. 02. 2024, 10:13:28 »
Ako som pisal, nevidim zatial ziadne nedostatky tohto riesenia
Nedostatky jsou následující:
  • Je to složitější na implementaci na serveru.
  • Je to složitější na implementaci na klientovi.
  • Pokud má klient dostatečně rychlé připojení k serveru, bude déle čekat na odpověď.
Ten poslední bod mi připadá nejzajímavější, protože pokud by „dostatečně rychlé“ připojení bylo vše, co je dnes běžně dostupné, znamenalo by to, že tímhle vylepšením zkomplikujete kód a ještě zpomalíte aplikaci drtivé většině uživatelů.

??????? mam pocit ze asi nezijeme na rovnakej planete. ani jeden z tych bodov nema absolutne ziadne opodstanenie. Najskor si vobec nepochopil co sa tu riesi, inak si tu odpoved neviem vobec vysvetlit.

petersveter

Re:API a setrenie prenosu linkovanim na objekty namiesto embedovania
« Odpověď #8 kdy: 25. 02. 2024, 10:25:37 »
Mozno pomoze ak to napisem ako schemu(kde posty su primarny objekt dopytu):

Kód: [Vybrat]
Response
{
  "posts[]": {
    "id": "ID",
    "channel": "ID",
    "title": "string",
    "teaser_text": "string",
    }
  },
  "channels[]": {
    "id": "ID",
    "name": "string",
    "handle": "string",
    "summary": "string",
  },
}

Cize ak chcem pre prvy prispevok z posts najst kanal kam patri tak si ho vytiahnem z response.channels namiesto toho aby ten kanal uz bol priamo v poste. Jasne ze rychlejsie je to ak response.channels je mapa a nie pole ale to uz su implementacne detajly.

A takto mozem vratit 100 postov ale len 5 kanalov napriklad, cize usetrim 95x velkost co by zabrali duplicitne kanaly. A to moze byt kludne aj 1kb a ked za den bude takych requestov 1000 tak to je hned mega za den, 30 mega za mesiace alebo 365mb rocne. A to je len jedna routa. Cize ta datova uspora moze byt nesmierne vysoka.
« Poslední změna: 25. 02. 2024, 10:28:12 od petersveter »

Re:API a setrenie prenosu linkovanim na objekty namiesto embedovania
« Odpověď #9 kdy: 25. 02. 2024, 10:44:05 »
??????? mam pocit ze asi nezijeme na rovnakej planete. ani jeden z tych bodov nema absolutne ziadne opodstanenie. Najskor si vobec nepochopil co sa tu riesi, inak si tu odpoved neviem vobec vysvetlit.
Nebojte, programovat se může naučit každý, i vy. Takže cesta na mou planetu vám není uzavřená.

Začneme klientem. Už ten váš kód je zjevně složitější, než prosté přečtení údajů o autorovi ze záznamu o článku. Když budete chtít mít kód bezpečnější, přidáte tam typy – a ta vazba na autora najednou nebude moc dobře typově kontrolovaná. Když k tomu vytvoříte třeba JSON schema, budete tu vazbu muset popsat slovně, nebude deklarovaná přímo ve schématu. V klientském kódu bude více míst, kde může něco chybět – s čímž byste se měl v bezpečném kódu vypořádat.

Na serveru bude kód také složitější. Předpokládám, že data jsou uložena v nějaké relační databázi. Takže místo jednoduchého joinu, který klidně bude schovaný za nějakým ORM, budete muset nejprve načíst data o článcích, pak si z nich na serveru vytaháte ID autorů a pošlete druhý dotaz na data o autorech. A výsledek pak spojíte. Takže opět komplikovanější a hůře spravovatelný kód. Databáze mají limity na to, kolik hodnot můžete vložit do klauzule IN, takže ten váš kód nebude univerzální. Až někdo za pár let použije tu samou funkci pro export všech článků, narazí na nějaké instanci s počtem autorů větším než 1000 na to, že to nebude fungovat.

No a zpomalení odpovědi serveru plyne z toho, jak to bude aplikační server zpracovávat. V případě jednoduchého joinu je to jednoduchý dotaz na databázový server, odpověď DB serveru a z ní už se sestaví odpověď pro klienta. Takže jeden roundtrip na databázový server. Když budete ta data o autorech donačítat dodatečně, budete mít nejprve dotaz na články, počkáte na odpověď – to je první roundtrip na DB server. Na základě odpovědi pak vytvoříte druhý dotaz na autory – takže druhý roundtrip na DB server.

Abyste se tomu vyhnul, musel byste se na aplikačním serveru buď vrátit k tomu joinu a na aplikačním serveru pak vyzobávat data o autorech a cpát je do samostatné struktury, nebo tu logiku přenést na databázový server a implementovat tam.

Tj. všechno jsou to jen komplikace (i když třeba drobné), ale vůbec nevíme, zda to bude mít nějaký přínos, nebo zda to pro uživatele dokonce nebude zhoršení.

petersveter

Re:API a setrenie prenosu linkovanim na objekty namiesto embedovania
« Odpověď #10 kdy: 25. 02. 2024, 10:58:17 »
Ocividne problem nie je v navrhu/rieseni ale individualnej interpretacii implementacie, lebo nic z uvedenho sa mna netyka ani na stranke serveru, ani na stranke klienta.

Re:API a setrenie prenosu linkovanim na objekty namiesto embedovania
« Odpověď #11 kdy: 25. 02. 2024, 10:59:17 »
A takto mozem vratit 100 postov ale len 5 kanalov napriklad, cize usetrim 95x velkost co by zabrali duplicitne kanaly. A to moze byt kludne aj 1kb a ked za den bude takych requestov 1000 tak to je hned mega za den, 30 mega za mesiace alebo 365mb rocne. A to je len jedna routa. Cize ta datova uspora moze byt nesmierne vysoka.
Vy se nepohybujete v jiném světě, ale v jiném čase. Zdravím do roku 1998. Tady u nás v roce 2024 není 365 MB ročně nesmírně vysoká úspora. Je to něco tak malého, že ani nikoho nenapadne se o tom bavit. Je to třeba velikost méně než deseti fotek z mobilu (ano, dnešními mobilními telefony se běžně fotí).

Ten 1 kB, který „ušetříte“, to je velikost jednoho paketu. Takže z hlediska uživatele neušetříte žádný čas. Pokud klient není někde na pomezí pokrytí signálem, nepozná rozdíl mezi doručením krátkého a dlouhého paketu. Jediné, co klient pozná (když to bude měřit), je zpomalení o ten druhý roundtrip do databáze. To budou v jednom datovém centru desítky až stovky milisekund, takže reálně to uživatel nepozná – ale proč mu čekání na data prodlužovat, byť jen o desítky milisekund?

A pak jste v tom vašem výpočtu úplně zapomněl na to, že přenášená data se komprimují. Pokud nemáte na serveru zapnutou kompresi, začněte tím, že ji zapnete.

Re:API a setrenie prenosu linkovanim na objekty namiesto embedovania
« Odpověď #12 kdy: 25. 02. 2024, 11:01:06 »
Ocividne problem nie je v navrhu/rieseni ale individualnej interpretacii implementacie, lebo nic z uvedenho sa mna netyka ani na stranke serveru, ani na stranke klienta.
Na straně klienta už jste sám uvedl příklad, kde se vás to týká. A tu implementaci na straně serveru, kde byste to nemusel řešit, bych teda chtěl vidět.

petersveter

Re:API a setrenie prenosu linkovanim na objekty namiesto embedovania
« Odpověď #13 kdy: 25. 02. 2024, 11:03:09 »
Pointa otazky bola: "ano, nasadili sme to, funguje to bez problemov", alebo "ano, skusali sme to, mali sme problemy s A, B, C tak sme sa vratili na povodnu schemu".


A pak jste v tom vašem výpočtu úplně zapomněl na to, že přenášená data se komprimují. Pokud nemáte na serveru zapnutou kompresi, začněte tím, že ji zapnete.


Co je to kompresia?

Re:API a setrenie prenosu linkovanim na objekty namiesto embedovania
« Odpověď #14 kdy: 25. 02. 2024, 11:29:11 »
Pointa otazky bola: "ano, nasadili sme to, funguje to bez problemov", alebo "ano, skusali sme to, mali sme problemy s A, B, C tak sme sa vratili na povodnu schemu".
Ano, nasadili jsme to v některých specifických případech, kdy jsme si změřili, jaký to má přínos; zvážili jsme negativní dopady, kterým rozumíme; a z porovnání nám vyšlo, že se to vyplatí. Počítáme s tím, že pokud se do budoucna změní způsob použití, budeme to muset změnit.

Plošně jsme to nenasazovali, protože o problémech jsme věděli dopředu a nepotřebovali jsme to zkoušet, abychom na ně přišli. Držíme se obecného principu, že předčasná optimalizace, která není podložená daty, je špatná optimalizace.

Co je to kompresia?
Kompresia dát. Doporučuju přepnout si článek na češtinu nebo lépe angličtinu, v nich jsou články obsáhlejší než ve slovenštině.

Přenášená data komprimuje rovnou webový server, v aplikaci se o to vůbec nemusíte starat. Jenom se na serveru zapne podpora komprese a vyberou se algoritmy, které se mohou používat. Prohlížeč s požadavkem serveru pošle informaci, které kompresní algoritmy podporuje, server podle toho vybere ten nejlepší, který podporuje také, a data při přenosu online komprimuje a klient zase dekomprimuje. Opakovaná data v JSONu jde komprimovat velmi dobře. Výsledná velikost zkomprimovaného JSONu s opakujícími se daty a s vaší úpravou bude pravděpodobně hodně podobná, dokonce by po té vaší úpravě mohla být zkomprimovaná data i větší. Snadno to zjistíte tak, že si vyrobíte ty dva JSONy s plným a vaším „vylepšeným“ formátem a zkomprimujete je pomocí gzipu – to je základní kompresní algoritmus, který podporují všechny prohlížeče včetně historických. A uvidíte, jak moc se od sebe velikost těch zkomprimovaných souborů liší.