Když refactoring není řešení aneb nové centrum.cz

Logo centrum.czTenhle příběh začíná u starého projektu – webových portálů centrum.cz, atlas.cz a volny.cz. Dříve se jednalo o velmi oblíbené a hojně navštěvované weby. Dnes mají už největší slávu za sebou a slouží spíše jako rozcestník do dalších služeb mediálního domu Economia, jako je třeba web Aktuálně, Ihned, DVTV či centrum mailu. Návštěvnost dlouhodobě mírně klesá, stále ale web točí přes 3,5 milionu návštěv denně, což je asi o 3 499 991 návštěv více než má můj blog.

Weby byly dlouhodobě v udržovací fázi, sem tam se něco udělalo, ale každý zásah byl velmi náročný, protože web byl technicky v nevyhovujícím stavu, jelikož se na něm za mnoho let vystřídalo mnoho individuí. Na druhou stranu, původní koncept statického HTML, cachovaného na disku, generovaného jednou za pár minut cronem a cachovaného varnishem bylo pro svůj účel perfektní – stabilní, nenáročné a blbu vzdorné. Jednoho dne pánové nahoře (a tím nemyslím Ježíše), nejspíše nad sklenkou skotské při procházení stránek seznam.cz, rozhodli, že se na webu začne doporučovat a cílit obsah na míru návštěvníkovi. Jelikož jsem v té době ještě nebyl teamleadem a nepodařilo se mi protlačit úplnou změnu technologií, bylo dle mého názoru chybně většinou rozhodnuto, že se tato funkcionalita implementuje do původního projektu v PHP. O půl roku později, po překročení pátého deadlinu, asi po půl roce vývoje, světe div se, měli jsme dynamickou funkční homepage centrum.cz. Bez kompromisů se to neobešlo, pár lidí kvůli tomu přišlo o život (pracovní), ale slavili jsme vítězství, leč Pyrrhovo. Stabilitě a návštěvnosti to totiž nepomohlo, naopak. Tehdy poprvé jsem v hlavě uslyšel ty temné javascriptové hlasy.

Pomalu ale jistě se mi začala v hlavě utvářet myšlenka nového webu v nodejs a reactu, běžícím v AWS a ta myšlenka my nedala spát. Nedalo mi to, párkrát jsem si přivstal (tzn. přišel jsem už na půl desátou) a vytvořil jednoduchý koncept, jak by to mohlo fungovat. Tento jsem předvedl chlebodárcům, kteří nejspíše díky mému nadšení byli ochotni přimhouřit oko a povolili nám sem tam nějakou tu storku nacpat do sprintu. Byl to ale boj o každý kousek sprintu, o každý bodík. A byli jsme v tom. Abych zahladil, že je celý článek pouze chvalozpěvem o mém géniu, rozhodl jsem se retrospektivně zhodnotit, co bych nyní udělal jinak. Tedy co jsem podcenil, nevypočítal nebo prostě neřešil a z čeho je možno se poučit, neboť

„Ti, kdo si nepamatují minulost, jsou odsouzeni k tomu ji opakovat.“ (George Santayana)

V této počáteční fázi přepisu mě napadá hned první, velmi důležitá věc:

Analyzujte rozsah práce, co vlastně přepisovaná stránka dělá, jak funguje a proč.

Je totiž velmi pravděpodobné, že zodpovědné osoby budou chtít, aby Vaše nová stránka fungovala podobně. To, že si myslíte, že něco vylepšíte neznamená, že se jedná doopravdy o vylepšení. Když například přepisujete stránku, kde většina návštěvníku tvoří starší generaci, bude krásné hejbací a moderní UI připadat pěkné jenom Vám. Horší je to ale s funkcionalitami, o kterých ani nevíte. Jejich vliv může být v konečném důsledku fatální a způsobit, že například vyberete nevhodnou technologii, což bude mít za násleledek v lepším případě jen nedodržení termínu. To se nám naštěstí nestalo, i tak jsme ale přišli až v průběhu přepisu na některé šílenosti, jejichž funkcionalitu bylo třeba analyzovat a implementovat do reactu a na rovinu, nejednou jsem zapochyboval, bude-li to vůbec možné. Některé z nich zmíním dále v článku.

Nespoléhejte pouze na rendering u klienta.

Servírování webpackem zbuilděného statického javascriptu, který se vykoná u klienta v prohlížeči a kterému pouze podstrčíte JSON data, zní jako jackpot. Realita je ale taková, že googlebot momentálně podporuje javascript tak „napůl“ a ostatní crawleři plus mínus vůbec. A být vidět je přeci hrozně důležité. Dalším problémem jsou starší či ještě nezakázané prohlížeče (IE), které v našem případě dělají stále skoro 15% z celkové návštěvnosti. Myslíte, že v IE11 fungují Promises? ES2015? Vůbec. Jako bonus dokonce ignorují HTML komentáře, kdyby jste náhodou chtěli pro tyto prohlížeče použít nějaký bluebird…  Takže buď zdvojnásobíte výsledný bundle o zbytečné polyfilly, nebo server-side rendering. My jsme to vyřešili tak, že na BE detekujeme user-agent hlavičku, podle ní se nakonec rozhodujeme, jestli server side rendering uděláme či ne. Je totiž hardwarově (=finančně) mnohem náročnější a nehezký a ideální by bylo ho nedělat vůbec. Tedy moderním prohlížečům servírujeme pouze statický javascript a prázdné HTML s JSON daty. Ostatní dostanou postaru vygenerované HTML. Dobrou zprávou je to, že react na FE dokáže poznat, že HTML je vygenerováno z BE a sám se automaticky napojí, vše tedy funguje naprosto stejně a návštěvník vlastně nic nepozná a boti nemusí umět javascript. Pro názornost přikládám výkonnostní výsledky testů na naší preprodukci, jejíž konfigurace je totožná s produkcí. Konkrétně to momentálně celé běhá v dockerech v ECS na třech obyčejných t2.medium instancích – 2jádra, 4GB ram v AWS, které se většinu času flákají. Každá nás stojí cca 500 kč/měsíc, když si ji předplatíte. Tedy vzhledem k návštěvnosti 3,5 mega denně prakticky zadarmo. Odbavit dokážeme až 300 requestů za sekundu. Pokud by náhodou výkonnost nestačila, používáme autoscaling.

benchmark-serverside
server-side rendering
bez server side renderingu
bez server-side rendering

Zjistěte, jak funguje na webu reklama.

Když jsme začínali s přepisem, nevěděl jsem o tom vlastně nic, jen to, že tam reklamu máme. Nakonec se to ale ukázalo jako velká komplikace. Na reklamu se totiž používaly různé vkládače javascriptů, typu Adobe tag manager apod. Reklamy samotné byly psány ve vanilla javascriptu, v lepším případě byly naše, a měli jsme je pod kontrolou, ale některé byly třetích stran a nikdy jsme vlastně nevěděli, co z toho vyleze. Některé dokonce vkládaly celé iframe, některé používaly jsonp. Některé i načítaly jquery. Naprostá anarchie. To pro mě bylo nemilým překvapením. Navíc reklamy zasahovaly do DOMu stránky. A to je u reactu problém. On si totiž s DOMem rád hraje sám a jakýkoliv zásah může v lepším případě způsobit jen přepsání externí změny. V horším bum bác. Muselo tedy dojít k nastavení pravidel. Do kódu jsem implementovali reklamní divy, u kterých jsme následujícím trikem zařídili, aby se o ně nestaral.

  shouldComponentUpdate() {
    return false;
  }

Reklamy po dohodě mohou tyto bloky znásilňovat dle libosti, ostatní musí nechat na pokoji. Uvidíme jak to bude fungovat. Doporučuji tedy projít si funkčnost reklam v předstihu, aby jste pak nedostali z obchodního headshot, zvlášť pokud z reklamy máte většinu příjmů.

Spočítejte si, kolik bude provoz stát.

Tak nějak jsem očekával, že naše nová homepage bude mnohem rychlejší. Nodejs je efektivnější technologie než PHP. Navíc hodně dbáme na kvalitu kódu, cachujem a optimalizujem. Někdy až moc. Zátěžové testy dopadly nadmíru dobře a provozní náklady v AWS vycházely lehce nad tisícovku měsíčně, což je na odbavení tak velkého trafficu vítězství. Pak přišla sprcha. Cena za přenesená data. Rázem jsem zjistil, že provozní náklady na stroje, úložiště či balancery nejsou ani 10% z celkové ceny. V našem případě je totiž stránka dynamická a každý návštěvník dostane jiná, doporučená data na míru. To mimo jiné znamená, že cachování na úrovni HTML a dat je blbost. I když to dělá blbých 50kb na uživatele, při návštěvnosti 3,5 milionu denně to ale je přežraných 175 přenesených gigabajtů. A to nechceš. Kdybych si tohle spočítal už na začátku, mnohem více energie a času bychom věnovali optimalizaci přenesených dat… Nutností je tedy cachovat a gzipovat vše, co je možné. K tomu Vám jednoduše pomůže CDN. A to, co cachovat nemůžete, maximálně optimalizujte. Posílejte uživatelům minimum dat a raději je třeba načítejte až po kliku či scrollování. Možná se budete reálně divit, jak málo uživatelů doscrolluje na konec stránky. Nicméně nezapomeňte, že botům by jste měli dát vše už od začátku, jinak bude Vaše stránka špatně indexována.

Cachujte, cachujte, cachujte.

Nodejs je ideální na cachování. Snažte se udělat co nejvíce operací jen jednou, na začátku, při startu aplikace. Není přeci třeba sestavovat konfigurace či načítat články z databáze na každou návštěvu uživatele. Časy PHP jsou už pasé a takhle se to dnes nedělá. Konfigurace si sestavte jednou, na začátku. Na články se ptejte jednou za minutu. Na tom vlastně stojí celý koncept nového centrum.cz. V pravidelných intervalech se doptáváme na nové články z různých zdrojů a ty pak sestavujeme uživatelům na míru. Vše má u sebe přímo nodejs a tedy při zpracování requestu si nesáhnu ani jednou do databáze či někam jinam. A tak to má být.

Mějte fallback.

Může se stát cokoliv. Útok, selhání hardwaru, nicméně uživatel by nikdy neměl vidět, že Vám to nejede. Vymyslete tedy, jak doručit uživatelům nějaký záložní obsah, i když vám to nejede. My si například párkrát za hodinu generujeme statický HTML otisk do cloudového úložiště S3. Jakýkoliv 5xx status code jdoucí z našeho serveru je transformován na úrovni CDN v 200 s návratem tohoto HTML.

 

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *