Preskoči na vsebino
agiledrop logo
  • Rešitve
  • Naročniki
    • O podjetju
    • Zgodovina
    • Ekipa
    • Akademija
    • Odprta delovna mesta
    • Ugodnosti za zaposlene
    • Poklicna pot razvijalcev
    • Uvajanje in mentorstvo
    • Izobraževanje zaposlenih
  • Blog
Kontakt
Footer Agiledrop logo
Sedež podjetja v LjubljaniStegne 11a, 1000 LjubljanaVeč o sedežu podjetja v Ljubljani
gold creditworthiness
Pisarne
  • Poslovna enota Celje
  • Poslovna enota Maribor
Skupnost
  • Drupal.si
  • Pravno obvestilo
  • Varstvo osebnih podatkov
Kontakt
  • Zaposlovanje:
    [email protected]
  • Prodaja:
    [email protected]
  • Telefon:
    +386 590 18180
© 2013-2025 AGILEDROP Ltd
  • Politika piškotkov

Konec monolita: kdaj ločiti backend in frontend

Ales

Objavljeno na14. jul. 2025v

Razvoj

V tem članku si bomo ogledali, kdaj in kako ločiti backend od frontenda. Najprej bomo šli čez predstvitev ključnih pojmov, nato bom predstavil monolitno in ločeno (decoupled) arhitekturo, podal praktične korake za decoupled ter predstavil praktične izkušnje na realnem projektu.

 

Pojmi

Spletna aplikacja je digitalna storitev, ki omogoča nakupovanje, pregledovanje vsebin ali komuniciranje preko brskalnika. Imamo dve strani aplikacije: vidno stran (oz. frontend) in zaleni del (oz. backend). Na frontendu uprabnik vidi gumbe, slike, design, itd.; backend pa si lahko predstavljamo kot nek motor, ki obdeluje zahteve.

Monolitno arhitekturo si torej lahko predstavljamo kot ogromen kamnit blok oz. monolit. Vse je trdno zlepljeno skupaj, če se začne rušiti en del, to ogroža celotno strukturo. Enako je v monolitni aplikaciji; sprememba enega elementa lahko povzroči težave v celotnem sistemu.

Za razliko od monolitne arhiekture pa ločena arhitektura spominja na gradnjo iz modularnih blokov. Posamezni deli so med seboj povezani, a vsak stoji na svojih lastnih temeljih.

Če pride do težav v enem modulu, to ne vpliva na ostale. Kljub neodvistnosti vsi deli usklajeno sodelujejo.

 

Monolitna arhitektura

Monolitna arhitektura pomeni, da sta frontend in backend tesno povezana na enem sistemu. Uporabljata se ista podatkovna baza in strežnik, različni deli aplikacije pa so močno odvisni eden od drugega.

Glavna težava tega pristopa je to, da lahko okvara enega elementa povzroči verižno reakcijo, ki nato vpliva na celotno aplikacijo. Posledično lahko posodobitve postanejo zapletene, vzdrževanje pa drago in časovno zahtevno. Kljub tem izzivom pa je ta tip arhitekture še vedno pogosta izbira za manjše projekte.

 

Prednosti in slabosti monolitne arhitekture

Glavna prednost monolitne arhitekture je hitrejše uvajanje sprememb v začetni fazi, ker je osnova hitro postavljena. Tudi debugiranje je lažje, saj je celoten sistem poenoten in je lažje slediti spremembam.

Poleg tega so začetna stroškovna bremena dosti manjša, saj monolit ne zahteva kompleksne infrastrukture ali orodja za uporavljanje strežnikov in storitev, kar zmanjša stroške in tehnično zahtevnost.

Tudi vodenje projekta je bolj enostavno, ker je lažje upravljati različice in vzdrževati dokumentacijo, kar je zelo ugodno za manjše ekipe. Zaradi vseh teh predosti je monolit še vedno zelo priljubljen izbor za začetne projekte, kjer sta ključni hitrost in enostavnost.

Seveda pa se tu pojavijo tudi minusi. Če, na primer, posodobite prijavni obrazec, se lahko pokvari izvoz podatkov. Zato je potrebno omejiti vzporedno delo backend in frontend ekip, ker lahko backend zakasni.

Posodabljanje je dolgotrajno in stresno, posledica pa je downtime, torej, da je stran nedostopna med posodabljanjem.

Nazadnje pa je pri monolitni arhitekturi tudi zelo težko uvajati nove tehnologije (predstavljajte si, na primer, da bi za novi TV morali povsem zamenjati ponudnika elektrike).

Kljub minusom je treba ponovno poudariti, da je monolit dobra izbira; ko pa postane aplikacija kompleksnejša, pa takšna arhitektura predstavlja oviro za rast.

 

Ločena arhitektura

Ločena arhitektura pomeni, da frontend (torej, kar uporabnik vidi) in backend (kar deluje v ozadju) delujeta neodvisno med seboj, povezana pa sta le prek jasno definiranih vmesnikov (API-jev, kot sta REST ali GraphQL).

Glavna prednost tega pristopa je, da lahko ekipe razvijajo in posodabljajo vsak del posebej, ne da bi vplivale na celoten sistem. Poleg tega omogoča večjo fleksibilnost – na primer, frontend lahko uporablja React, medtem ko backend teče na PHP-ju, brez da bi to povzročalo težave.

Še več, ločena arhitektura pogosto temelji na mikrostoritvah (microservices), kjer je vsaka glavna funkcionalnost (naročila, plačila, uporabniki) ločena storitev s svojim lastnim API-jem. To omogoča boljšo vzdržljivost, lažje testiranje in enostavnejše razširjanje sistema.

Kljub prednostim pa ločena arhitektura terja več začetnega načrtovanja, saj je treba jasno definirati komunikacijske protokole in zagotoviti, da vse komponente delujejo usklajeno.

 

Prednosti ločene arhitekture

  • Fleksibilnost: Frontend lahko uporablja različne tehnologije (React, Vue, mobilne aplikacije) brez sprememb na backendu.
  • Neodvisnost ekip: Frontend in backend ekipe lahko delajo ločeno in paralelno.
  • Skalabilnost: Lažje prilagajanje rasti in prometu – možno je npr. skalirati samo backend.
  • Večja ponovna uporaba: En backend lahko uporablja več različnih frontendov (spletna stran, mobilna aplikacija, itd.)
  • Hitrejši razvoj: Ločene ekipe lahko hkrati razvijajo in uvajajo spremembe, kar pospeši čas do trga.
  • Boljša varnost: Backend lahko ostane skrit za API plastjo, kar omogoča boljši nadzor dostopa in zaščite podatkov.
  • Enostavnejša nadgradnja: Spremembe na frontendu ali backendu je mogoče uvajati neodvisno, brez večjih motenj celotnega sistema.
  • Izboljšana uporabniška izkušnja: Frontend se lahko optimizira posebej za različne naprave in scenarije, kar vodi do bolj prilagojenih in odzivnih aplikacij.

 

Slabosti ločene arhitekture

Čeprav ima ločena arhitektura številne prednosti, prinaša tudi nekaj izzivov, ki jih je potrebno upoštevati:

 

1. Večja kompleksnost

Sistem je sestavljen iz več komponent (frontend, backend, API-ji, mikroservisi), kar zahteva več konfiguracije in koordinacije.

Primer: Če uporabljate mikrostoritve, morate upravljati več strežnikov, baz podatkov in komunikacijskih tokov.

  • Težje debugiranje – napake se lahko pojavijo v katerikoli komponenti.
  • Zahtevnejše testiranje – potrebni so integrirani testi za vse vmesnike.

 

2. Večja poraba virov

Problem:

  • Vsaka komponenta (frontend, backend, API gateway) potrebuje svoje strežnike in infrastrukturo.
  • Primer: Če imate ločen frontend (React) in backend (Node.js), morate vzdrževati dva strežnika namesto enega.

 

3. Zakasnitev v komunikaciji (latency)

Problem:

  • Ker komponente komunicirajo prek omrežja (API klicev), lahko pride do zamikov v odzivnosti.
  • Primer: Če API strežnik odgovori počasi, se uporabniški vmesnik "obesi".

Posledica:

  • Slabša uporabniška izkušnja (če ni pravilne optimizacije).
  • Potreba po cachiranju in optimizaciji API klicev.

 

4. Težave z doslednostjo podatkov

Problem:

  • Če imate več neodvisnih storitev, lahko pride do razlik v podatkih.
  • Primer: Frontend prikaže, da je izdelek na zalogi, a ga na backendu že ni več na voljo.

Rešitev:

  • Uporaba sinhronizacijskih mehanizmov (npr. dogodkovno vodenje – Kafka, RabbitMQ).

 

5. Večja odvisnost od API-jev

Problem:

  • Če API-ji niso dobro dokumentirani ali stabilni, lahko pride do prekinitev dela.
  • Primer: Če backend spremeni strukturo odgovora, se frontend lahko pokvari.

Posledica:

  • Potreba po strogih standardih komunikacije (OpenAPI, GraphQL sheme).
  • Verzioniranje API-jev, da se prepreči lomeče spremembe.

 

6. Težje razvijanje za manjše ekipe

Problem:

  • Ločena arhitektura zahteva več specializiranih znanj (frontend, backend, DevOps).

Posledica:

  • Višja začetna ovira – manjših projektov se morda ne splača ločevati.

 

Praktični koraki

V tem delu si bomo ogledali praktične korake za decoupled arhitekturo. Prvi korak je načrtovanje poslovnih ciljev, zaradi katerih se sploh ločuje frontend in backend. Ponavadi je glavni cilj izboljšanje uporabniške izkušnje ali pa povečanje agilnosti razvoja.

Potrebno je tudi identificirati najbolj kritične točke monolita, kar so postavitve, zmogljivost in nestrukturirana koda. Poleg tega je potreben jasen in natančen popis vseh funkcionalnosti, kot so moduli, odvisnosti oz. zunanji API-ji.

Najlažje je začeti z majhno, a ne kritično funkcionalnostjo, in omogočiti, da se jo izpostavi preko API-ja. Nato je treba identificirati funkcionalne enote, kjer ekstrahiramo logične module (kot so na primer uporabniki, naročila, plačila). Tu si lahko pomagamo z Domain Driven designom za določitev scopinga.

Seveda je treba uvesti tudi API vmesnike, ki morajo biti točno definirani, načrtovani in kompatibilni s starejšimi verzijami. Tu si lahko mogoče pomagamo s Swagger API, ki je namejnen dokumentiranju API-jev.

Potrebno je tudi sprotno testiranje in postopno prehajanje z monolitske na ločeno arhitekturo. Osebno stojim za tem, da je treba nujno imeti verzijoniranje, monitoring in continuous development / continuous integration kot standard.

 

DDD – Domain-Driven Design

Domain-Driven Design (DDD) je pristop k razvoju programske opreme, ki postavi poslovno domeno in strokovnjake iz domene v središče razvoja. Cilj je, da programska rešitev neposredno odraža kompleksnost in pravila dejanskega poslovnega sveta.

DDD pomaga razdeliti sistem na jasno definirane kontekste, kar olajša odločanje glede tega, za katere dele aplikacije je smiselno ločevanje frontenda in backenda. To omogoča boljši fokus, manj odvisnosti med moduli in učinkovitejše usklajevanje med ekipami.

Sestavljen je iz entitet, vednostnih objektov, agregatov, repozitorijev in poslovne logike.

DDD omogoča boljšo usklajenost med poslovnimi potrebami in kodo. Je razdelitev sistema na samostojne dele, in omogoči lažje spreminjanje sistema, znatno pa tudi olajša komunikacijo med tehničnimi in poslovnimi ekipami.

 

Rezultati in izkušnje na realnem produktu

Zdaj pa bi rad predstavil arhitekturo produkta, na katerem že nekaj časa delam. Gre za decoupled arhitekturo, kjer za backend uporabljamo Drupal, za frontend uporabljamo Next.js in React, za API vmesnik pa uporabljamo GraphQL. Za caching skrbijo Varnish, Redis in Drupal Cache, Solr pa uporabljamo za zelo učinkovito iskanje.

 

Drupal

Drupal je odprtokodni sistem za upravljanje vsebin (CMS), namenjen ustvarjanju kompleksnih in varnih spletnih strani. Je zelo prilagodljiv in razširljiv ter se pogosto uporablja za portale, intranete, velike korporativne strani, vladne spletne strani in univerze.

Razširljiv je z moduli, ki so lahko core, contrib ali custom moduli. Podpira najboljše SEO prakse, večjezičnost in različne APIje. Je fleksibilen pri modeliranju podatkov (na primer preko tipov vsebin in taksonomij), zaradi rednih varnostnih posodibitev pa je tudi stabilen in varen.

Vsebuje prijazen uporabniški vmesnik za urednike, ki lahko gradijo strani brez kode – omogoča kreacijo novih tipov, povezav med entitetami, različnih prikazov podatkov in seznamov (tukaj bi izpostavil modula Views in Display Suite). Zelo močna stvar je tudi upravljanje pravic in vlog za različne uporabnike.

Drupal je klasičen monolit, ki omogoča enostaven prehod na decoupled sistem, zgrajen pa je na PHP-ju in frameworku Symfony. Idealen je za projekte z enostavno implementcijo in postopnim prehanjanjem na decoupled arhitekturo. Ima tudi svoj lasten caching sistem ter podporo za konfiguracijsko upravljanje – vse konfiguracije je mogoče eksportirati v YAML datoteko in jih dati v Git.

Še ena pomembna funkcionalnost Drupala so namestitveni profili, ki omogočijo vnaprej definirane konfiguracije za enostavnejše repliciranje okolij. Torej, če imaš produkt, imaš vse odvisnosti in konfiguracije v profilu; ko namestiš Drupal, imaš opcijo izbrati ta profil in lahko v 5 minutah postaviš svoj produkt.

 

GraphQL

Kot sem že omenil, za API vmesnik med frontendm in Drupalom uporabljamo GraphQL, ki je poizvedovalni jezik za lažje pridobivanje podatkov. Razvili so ga pri Facebooku leta 2012, javno pa objavili 3 leta kasneje, 2015.

Glavna značilnost GraphQL-a je, da imamo samo eno končno točko oz. endpoint, iz katere pridobivamo podatke (za razliko od, na primer, REST-a, kjer imamo več končnih točk). To omogoča shema, ki vsebuje definicije podatkovnih tipov, relacije med entitetami in operacije za branje in pisanje podatkov.

S pomočjo sheme točno določimo, kateri podatki bodo v odgovoru; stranka torej vpraša točno to, kar potrebuje, in nič druga. Poleg tega lahko tudi predvidimo, kakšen bo rezultat odgovora. GraphQL torej omogoči popolno kontrolo nad podatki, saj bolj kontroliramo zgolj podatke.

GraphQL uporablja SDL oz. Schema Definition Language, jezik za definiranje sheme, ki vsebuje osnovne podatkovne tipe (INT, Float, String, Boolean, ID), pa tudi tipe ENUM, Interface, Union ter arraye. Lahko ustvariš tudi svoj lasten podatkovni tip (na primer datum).

Tipe lahko označimo za neprazne tako, da jih označimo z klicajem. Druge posebnosti SDL pa so mutacije in poizvedbe, s katerimi pridobivamo oz. spreminjamo podatke.

Zdaj pa bom na praktičnem primeru pokazal, kako naredimo tipe in pozivedbe z GraphQL-om. Vse pozivedbene operacije v shemi definiramo v tipu Query z metodo newsitem; ta prejme argument ID, ki je obvezen zaradi klicaja, ter poskrbi, da bo rezultat strogo tipiziran newsItem. Nato čisto definiramo tip NewsItem, ki vsebuje polja ID, UID, title, author, tag-e in body.

Ko poženemo poizvedbo, dobimo rezultat v JSON obliki. Ta nam vrne točno določene podatke, ki smo jih želeli pridobiti. Čisto levo vidimo JSON, ki se preko frontenda pošlje na backend, na sredini pa lahko vidimo, kakšen odgovor bo frontend prejel nazaj iz backenda. Na frontendu lahko poljubno izbiramo, katera polja bomo dobili oz. katera pač potrebujemo.

Nato imamo še mutacije, ki so namenjene shranjevanju in posodabljanju podatkov, vse te operacije pa izvedemo pod tipom Mutation v naši shemi. Spet definiramo, kakšni podatki bodo prišli v backend, s tipom input NewsInput, pri katerem je obvezen podatek title. V tipu Mutation pa definiramo ime funkcije, ki prejme ta newsInput. Na sredini imamo primer, kako izgleda JSON na frontendu, na desni pa, kakšen je rezultat.

 

React & Next.js

Kot že rečeno, za frontend uporabljamo React in Next.js. React je JavaScript knjižnica za gradnjo uporabnških vmesnikov. Osredotočen je na komponente, ki jih je mogoče ponovno uporabiti. Uporablja virtualni DOM za boljšo zmogljivost, na voljo ima tudi upravljanje stanja, podpirata pa ga zelo široka skupnost in bogat ekosistem orodij.

Next.js pa je ogrodje, bazirano na Reactu, in ima podporo za server side rendering in static site generation. Omogoča dinamične poti in API poti, ima tudi opcijo za osveževanje strani brez ponovne gradnje celotne strani. Next.js je idealen za decoupled arhitekture z backend sistemi, kot je Drupal.

Za zaključek bi rad pokazal še, kako gre zahtevek iz brskalnika do MySQL-a in obratno. Torej, najprej uporabnik sproži akcijo na briskalnku (na primer vidi izdelek), nato Varnish preveri, ali je odgovor za ta URL že v predpomnilniku; na desni strani lahko vidimo, kako v headerju requesta ponavadi zgleda če je “hit” ali “miss”. Če je hit, potem je Varnish cache uspel in stran se naloži v zelo hitrem času, tj. par milisekund.

Če pa je miss, pa gremo naprej na Next.js, kjer se preko server side renderinga pošlje request na GraphQL, ki preveri, če je rezultat v Redis cachu, in če ga ni, gre naprej na Drupal backend. Ta nato preveri, če je rezultat v internem Drupal cachu, če ga ni, pa se naredi MySQL poizvedba na podatkovno bazo.

V obratno smer pa proces deluje tako: imamo podatke, iz MySQL-a gremo v Drupal, kjer se nastavijo cache tag-i, nato pa iz Drupala v GraphQL modul, kjer se spet nastavijo cache tag-i za specifično poizvedbo. Iz GraphQL nato vrne odgovor Next.js, ki izriše stran s vsemi React komponentami na brskalnik, hkrati pa se HTML odgovor shrani v Varnish. Tukaj so ključne točke naslednje:

  • V Varnish se splača investirati, saj cachira HTML ali pa celo API odgovore. Pomembno je izpostaviti, da to velja za get metode oz. za poizvedbe.
  • Redis je v pomnilniku delujoča ključ-vrednost podatkovna baza, ki se uporablja za shranjevanje fragmentiranih podatkov, kot so GraphQL poizvedbe in predpomnilnik entitet (entity cache) v Drupalu.
  • Drupalov sistem predpomnilnikov ponuja več plasti, vključno z:
    • Predpomnilnikom za izris (render cache) – za shranjevanje izrisanih elementov, kot so bloki, pogledi (views), itd.
    • Dinamičnim predpomnilnikom strani (dynamic page cache) – za hitrejše nalaganje dinamičnih vsebin.
    Poleg tega omogoča prilagodljivo upravljanje predpomnilnika z:
    • Oznakami predpomnilnika (cache tags) – za invalidiranje povezanih vsebin.
    • Konteksti (contexts) – za prilagajanje predpomnilnika glede na razmere (npr. jezik, vloga uporabnika).
    • Časovno omejenim predpomnilnikom (max-age) – za nastavitev življenjske dobe vsebin v predpomnilniku.
  • MySQL pa je zadnja instanca, če ni podatkov v nobenem predpomnilniku.

 

Zaključek

Ločena arhitektura omogoča, da front end ter back end ekipe delujejo ločeno, in tako nudi večjo fleksibilnost ter hkrati poveča agilnost razvojnega procesa. Najpogostejša razloga za implementacijo ločene arhitekture sta izboljšanje uporabniške izkušnje ter enostavnejše nadgraditve in razširjanje sistema.

Related blog posts

Blog post card background image.

Kako podpiramo lokalno razvijalsko skupnost

Objavljeno  19. jun. 2025  v Podjetje, Razvoj, Skupnost 
Blog post card background image.

Osnovni UI/UX principi, ki bi jih moral poznati vsak razvijalec

Objavljeno  04. mar. 2020  v Razvoj