Lagdelt arkitekturWow. Lenge siden sist. Jeg er blitt et barn rikere, og har lært masse om hvordan verdensveven er tenkt fra et arkitekturståsted. Tidligere innlegg her har jo med å forklare Representational State Transfer, og hvordan man kan anvende denne arkitekturstilen i systemer som ikke er verdensveven. Siden sist har vi på jobben (Escenic AS) kommet mye lengre med vår tykke klient, som snakker med en server over HTTP, hvor vi har forsøkt å bruke REST slik det var tiltenkt. Det jeg vil dele med dere i dag er tanken om vevens lagdeling. Lagdeling er en av Roy Fielding sine begrensninger. Konkret er det slik at man utnytter det enhetlige settet med verb (i HTTP, GET, PUT, POST, DELETE osv) og selvforklarende meldinger. Lagdeling illustreres best med en proxy server, som kanskje din internettleverandør har, for at de skal spare båndbredde. Kina har en hel mur med slike proxy servere, men ikke for å spare båndbredde, kan dere tro. Det innlegget du ser på nå har antakelig også gått gjennom noen lag før den når dine øyne:
Jeg vil også våge å tro at netleseren har en proxy, nemlig dens innebygde browser cache. Denne lagdelingen er innebygget i HTTP, og det gjøres ofte helt usynlig for (mesteparten av) selve nettleseren din. Men denne lagdelingen stopper gjerne i applikasjonene som bruker HTTP for å snakke med serverene. Klientkoden er gjerne en grøt med objekter som sender meldinger til hverandre, tråder som sparker igang arbeid, og av og til noe som gjør et kall til HTTP PUT for å sende den greia over til serveren. En ting vi har skjønt (helt nylig) er at man kan ta lagdelingen et hakk videre, nemlig å ta arkitekturen til webben (REST) og implementasjonen (HTTP), og tilby et nytt lag inni applikasjonen. Vi skjønte tidlig at vi måtte ha abstraksjoner over HTTP, og beholdt metoder i koden vår for f.eks. å ta en URI og returnere et flott objekt. Men det vi ikke skjønte da vi gjorde det var at vi egentlig implementerte et nytt “lag” i ånden til vevens arkitektur. Hadde vi skjønt det, hadde vi antakelig dette laget sett mer fullstendig ut, og ikke litt “hullete” som det er i dag. Et eksempel. Du har en URI som du er interessert i å se på. Koden din vil ikke vite om HTTP, men vil gjøre et funksjonskall og få tilbake et objekt som du så kan spørre ut. Ikke noe rå byte-strøm. Så man lager en metode som ser omtrent ut som slik: Og man hacker det sammen slik at det virker, for de forskjellige media typene man har. Vips så har man abstrahert bort HTTP, og programmerer’ne får et simpelt read(“http://api.mysite.com/v3/23432”). Dog er det er flere problemer:
Rådet jeg gir i dette innlegget er å fullfør abstraksjonen. Tilby (semantisk) de samme tingene som HTTP tilbyr, men gjerne i abstrahert form. Ikke abstraher vekk optimistisk låsing, cache validering og andre juveler i HTTP. Det kan hende at Restlet API’et har noe for seg på klientsiden også. Vi syntes det ikke helt fungerte den gangen da vi så på det for et par år siden, og vi endte da opp med en hullete abstraksjon over HTTP, hvor vi hele tiden må lappe for å tilby det og det aspektet ved HTTP. Til nå har vi tatt med
Poenget her er at vi er godt på veit til å lage en java-abstraksjon som tilbyr alle (viktige) deler av HTTP. Hvis vi hadde tatt den helt ut ville vi kunne også gjort flere kule ting med mellommenn (proxy):
Jeg lukter et eller annet REST klientrammeverk i dette her, noe som hjelper programmerer’ne lage gode RESTful klientapplikasjoner uten å måtte dille så mye med RFC2616, men allikevel få en applikasjon som følger vevens arkitektur. God programmeringshøst! Å bruke web arkitektur i ikke-web-programvareSkalerbarhet i tradisjonell softwareutvikling innebærer ofte at man gjør seg mindre avhengig av databasen, og introduserer en objektcache i minnet til en eller flere servere. Problemer oppstår når dataene forandrer seg under skjørtene på serveren. Da kan man låne noen teknikker fra webben: HTTP har nemlig særdeles gode mekanismer for å kunne skalere. Først må man akseptere at ikke alle nodene i en server vil til enhver tid se de aller siste dataene. Hvis du lager en børsapplikasjon som skal tjene penger på day-trading er det kanskje greit å ha de siste tallene, og ikke en 60 sekunder gammel kurs. Kan man akseptere litt elde (noen sekunder) er mulighetene mange. Ok punkt en er å putte objektene inn i cache, men det er jo ikke så spennende. Noen ganger vet man at objektet forandrer seg et spesielt klokkeslett. Slikt kan man nytte seg av: Man tar HTTP’s Cache-Control: max-age og gjør noe tilsvarende med objektene når de puttes i en cache. Hvis man vet at objektet ikke er gyldig etter et visst klokkeslett er det bare å fortelle cache’n dette. Hvis objektene fakisk brukes til videre oppdatering mot databasen (f.eks. du forandrer en liten ting og O/R mappingen tar og lagrer hele greia) så låner man If-Unmodified-Since eller enda bedre: If-Match fra HTTP og "gjør det selv. Når man får et objekt som skal sendes ned til databasen, så sjekker man versjonsnummeret til objektet man fikk er det samme som versjonsnummeret i databasen. Versjonsnummeret må selvfølgelig ikke være noe som klientkoden kan forandre på. Modifiseringsdato funker også om man ikke liker versjonsnummer. Hva om dataene har forandret seg? Jo, det er jo HTTP 412 Precondition Failed som får en liknende vri i koden din. Slikt kan stort sett unngås ved å gjøre noe som tilsvarer en unconditional GET—nemlig å forbigå cachen når man henter data for oppdatering. Ingen kan garantere at andre holder seg unna dataene om ikke man har en form for pessimistisk lås da. Utrolig nok har ikke Wikipedia noen entry for Pessimistic locking, bare Optimistic locking. Hvis objektene forandrer seg av ymse årsaker, så kan man låne mnot sin lovende Cache Channels slik: Med jevne mellomrom (et par ganger i minuttet) henter cachen ut en liste med endringer fra databasen, og fjerner så utdaterte objektene fra cachen. Finnes det flere cacher vil de alle hente samme liste med jevne mellomrom, og er det virkelig mange cacher kan jo listen over endringer caches den også. Nettoresultat:
Ganske stilig. Motto? Les HTTP spec’en (igjen)! Metadata i HTMLHTTP handler jo om hypermedia: Du mottar et dokument som har lenker til andre dokumenter. Men visste du at det er mulig å lenke til andre dokumenter uten å putte lenkene inni dokumenter? HTTP deler jo responsen i data og metadata, nemlig i selve dokumentet og headers (“hoder”?). Header’ene beskriver selve dokumentet sett utenifra; f.eks. HTML blir jo ofte hyllet som det ultimate hypermediaformatet, på grunn av Men å si at dette andre dokumentet er en i en rekke av dokumenter (next/previous), eller at atom feeden til dokumentet er her: Det er jo metadata! Jeg ønsker ikke å måtte forkludre dokumentet mitt. Hva om jeg returnerer et dokument som ikke har rom for lenker? Putt dem i HTTP header’ene istedenfor i HTML header’en: Link: <http://my/other/reference.txt>; rel="alternate"; type="text/plain" Link: <http://mypage/me>; rev="made"; title="John Doe" Mark Nottingham har forsøkt å beskrive Personlig anser jeg at metadata hører hjemme i HTTP header’en, og ikke i dokumentet. Metadata i dokumentet er jo plutselig data. At HTTP og HTML begge støtter både data og metadata er litt kunstig, og speiler kanskje det faktum at webben stammer fra fil-servere som ikke hadde noen særlig rik meta-modell. Både Last-Modified, Content-Length og Allow støttes jo av ethvert filsystem, og HTML fikk jo tilogmed 1 Link Header esw.w3.org Eksempler på HypermediaDen lille CSS-saken som Alexander postet her om dagen fikk meg til å tenke:
Så her sitter jeg og skriver igjen! Hypermedia er jo egentlig bare media (tekst, bilder, video) med hyperlenker til annet media (mer tekst, bilder, video). Når man sier hypermedia er det jo HTML man tenker på: HyperText Markup Language. Naturlig, ikke sant? Men hva med f.eks. CSS? Er ikke det er hypermediaspråk? Sier man ikke i CSS at man ønsker det bakgrunnsbildet på dette elementet? Og da refererer man jo til bildet ved hjelp av en URI Og da tenker jeg: Er det andre opplagte hypermediaformat man bør vurdere når man skal gi fra seg representasjoner? JSON blir ofte disset fordi det sies at det ikke er et hypermediaformat, og det har man jo rett i. CSS har en egen “uri” funksjon for å uttrykke hypertekstlenker. JSON har ikke det. XML blir ofte hypet opp som et veldig bra hypermediaformat, men det er jo helt feil. XML har heller ingen “uri” funksjon for å si at dette attributtet eller denne strengen her er faktisk en URI som en UA bør bruke til noe. Slikt må (for både XML og JSON) uttrykkes i andre dokumenter som beskriver strukturen i dokumentet. Ironisk nok gjøres dette i XML ved hjelp av URI’er: xmlns:foo=“urn:foo” Her sier man at dokumentet ligger i namespacet foo. Neste linje sier at namespacet foo identifiseres ved hjelp av URI’en urn:foo. Dernest sier man at namespacet urn:foo har et XML schema som ligger klart til henting på http://bar—en XML prossessor kan hente denne for å sikre seg dokumentet er gyldig. Til slutt må man si til prosessoren at prefixet xsi faktisk er XML Schema Instance namespacet, som igjen blir identifisert ved hjelp av nok en URI. XML parseren slipper å hente skjemadefinisjonen for xsi fordi parseren skal kjenne igjen denne bare på bakgrunn av URI’en.
Men spør du meg, er det mye magi bare for å gjøre XML til et überhypermediaformat. XML Schema Instance er også et lite dyr, men med litt øvelse kan man sikkert definere at et attributt er av type anyURI. Dermed kan hvemsomhelst som leser dokumentet og skjemaet ditt, kjenne igjen URIer. Men hva skal man bruke det til? Huff :-) JSON tiltaler meg. Det er Lists og Maps i skjønn harmoni. Et rent datautvekslingsformat som ikke forsøker å spesifisere datatypen utover noen enkle primitiver. Det er ikke noe problem å uttrykke en URI i et JSON dokument; Det er jo bare en streng som alltid. Så blir det opp til spesifikasjonen av JSON-dokumentet (som kanskje ligger i prosatekst slik som hele Atom Publishing Protocol Misforstått: URIURIer er en av hjørnestenene i webbens arkitektur. Alle websider har en adresse, en oppskrift for å hente en spesifik webside. Opprinnelig het disse URLer fordi de lokaliserte websider på nettet. F.eks. denne sonen har URI’en http://web-arkitektur.origo.no/ Det er sonens kanoniske identifikator. Jeg kan gi URIen til andre og de vil kjenne den igjen som en URL og skjønne at den peker på noe: URIen er også sonens URL—man kan skrive det inn i en nettlos, og så forsøker den å hente innholdet. Voilá. Men arkitekturen bygger også på at man kan identifisere hva som helst En vanlig misforståelse er at URIer angir nettopp websider. Det gjør de ikke. De fleste URIer på webben i dag gjør det (stort sett websider, bilder, CSS og javascript), men noen URIer gjør det ikke. Min oppfattning av URIer er at de kan identifisere hva som helst: For eksempel bygger XML Namespaces på URIer. Et XML Namespace er ikke en webside eller en skjemadefinisjon, men et abstrakt konsept om et unikt navneområde for XML tagger. Det er ingen forventning om at man skal kunne putte inn en namespace URI i en braoser og få f.eks. et skjemadokument. Namespace URIen er primært for å identifisere namespacet fra andre namespaces. Det er en identifikator. JSP Taglib URIer har samme funksjon. De er der kun for å identifisere et tag library fra et annet tag library. Her forventes det heller ikke (strengt tatt) at man må eller kan hente noe hvis man går til et taglib URI. Taglib URIer er ikke nødvendigvis URLer. På denne måten kan URIer brukes til å identifisere ting uten at man må sette opp ett nettsted for å servere innhold. Ting som ikke kan servere innhold. For eksempel mennesker, bygninger, produkter, lyspærer, og stoler kan i teorien gis egne URIer og refereres til. Andre som kjenner til de samme tingene kjenner også disse tingenes URIer og kan dermed kjenne igjen URIen hvis vi ser den. XML prosessorer som kjenner igjen et xml namespace URIer. JSP prosessorer som kjenner igjen taglib URIer. RDF er et språk som har tatt dette til sitt hjerte. RDF er et språk som lar deg uttrykke kunnskap om relasjoner mellom ressurser. URIer brukes her for å identifisere personer, firmaer, blogger og blogginnlegg, og attributter på disse: navn, overskrifter, forfattere osv. Man kan uttrykke at en person er forfatter til en bloggentry, at personen har navnet sånn og sånn, og at han kjenner disse andre personene, og at de har disse navnene. Her og der kommer det også “rdfs:seeAlso” som sier at her er en URI som forteller deg mer om denne ressursen. Hva er poenget med URIer som ikke lar seg “hente”? For en webutvikler kan det være meningsløst. Det skjønner jeg. Men i softwareutvikling kan det brukes som en generisk måte å referere til ting. Primærnøkler? Hvorfor ikke? Sannsynligvis vil alle dataene leve med samme scheme (http har grei semantikk…) og et hostnavn hvor dataene “lever” (i kanonisk forstand) Det som gjenstår er “path” til dataene. På samme måte som på en web server er pathene dine en uendelig stor tomt som skal deles opp. Poenget er at det gir universell adresserbarhet. Hvemsomhelst i verden kan referere til tingene dine, presist og nøyaktig. Hvorfor velge en annen identifikator enn URIer? The Great Specificity SwindleSitePoint har en god artikkel om spesifisitet i CSS:
Artikkelen tar for seg misforståtte kroker av CSS, som cascading, hvilken rekkefølge CSS-regler brukes, og hvilke selektorer som får presedens. Kule URIer!Begrepet Cool URIs stammer fra dokumentet Cool URIs don’t change skrevet av Tim Berners Lee tilbake i 1998. Hvis du ikke vet hvem Tim er får du vel finne ut av det først. Kort sagt: Kule URIer er de som ikke forandrer seg. De inneholder ikke spor av hvilken teknologi som er i bruk; de inneholder ikke navnet på forfatteren. De inneholder ting som klart identifiserer ressursen. VG startet på nett på slutten av forrige århundre og brukte den gang URIer som så slik ut: Dagbladets URIer har ikke vært like men man får tak i sider tilbake fra 1998. Dagbladet eksponerer fortsatt “.html” extension som gir et sterkt inntrykk av de fortsatt publiserer statiske filer til en simpel webserver. HTML er jo ganske avlegs; kanskje man finner opp noe mye bedre og ønsker å gå over til det; da er man låst til at alle de gamle URIene hevder at de var HTML Og selvfølgelig Aftenposten da: Begredelig. Jeg blir vel flamet for den siste URIen. Men for å ta mine kule URI-briller på: i 2000 forsøkte man seg på å legge inn et CGI-script med det resultat at alle URIene forandret seg. Og så byttet man publiseringssystem og alt forandret seg igjen. Jommen greide de ikke å gjøre det igjen i 2005 (men da med en manuell browserbasert redirect). Men det er verdt å legge merke til at innenriks og utenriks er to helt klare avdelinger og at de helt siden 1998 heter "iriks og “uriks”. Ergo er det rimelig å anta at slik informasjon faktisk hører hjemme i URIen til nyhetsmedier. Historien er altså full av URIer som er laget av folk som ikke skjønner hva en URI faktisk er. Det er lett å slenge opp et CGI script og lage en PHP som henter en dings, men da sier du at URIen til dingsen din faktisk er /cgi-bin/en.php?dingsID=123… Tenk heller hvilke URIer som vil overleve systemskift etter systemskift uten sære omskrivninger i over hundre år! “/dingser/123” eller “/dingser/2007/rar-dings” eller “/2007/10/02/dingser/rar”… Så krever du at programvare du kjøper for å håndtere innholdet ditt skal holde seg til det URI skjemaet du velger. Få URIer inn i kravspekken! Og utviklere: Tenk dere om! (Pass Opp! Stein kastet i glasshus!) Hypermedia som motoren for applikasjonstilstandOverskriften er en fornorskning av Fielding’s “Hypermedia as the engine of application state” og er nok det prinsippet som har størst sprik mellom utviklernes forståelse og den faktiske arkitekturen i webben. I et hypermedium som verdensveven er så er din www-browser en applikasjon. Browseren har en tilstand som beskrives kort og konsist ved hjelp av URI linja øverst. Hvis du velger deg et bokmerke og åpner en tradisjonell webside så får du opp denne siden. Alle andre kan gjøre det samme og vil se det samme som deg. Klikker du så på en lenke havner du gjerne på en ny side, og tilstanden til browseren er nå denne nye siden. Hypermedia driver applikasjonstilstanden din. Alle har vært borti søk hvor man POSTer formen til serveren. Resultatet er at URIen ikke gjenspeiler tilstanden til browseren. Man kan ikke sende URIen til noen andre, og man kan ikke lage noe bokmerke. Det bryter med idéen om at applikasjonstilstand (browser) styres av hypermedia (lenker til URIer). Eller for eksempel frames. Med en gang man lager en side med frames mister man dette aspektet ved hypermedia; det er vanskelig, om ikke umulig å komme tilbake til en side med frames, simpelthen fordi det bryter med web arkitekturen. Hypermedia er ikke lengre det som driver tilstanden; den driver flere mini-tilstander som hver har sin URI (og som gjerne snakker sammen). Det finnes andre mindre opplagte ting som gjør det vanskelig å holde applikasjonstilstand i URIen: Cookies. La oss si at vi ønsker en cookie som lagrer de sidene du har besøkt, og på bakgrunn av den kommer med forslag til sider du antakelig liker, som Amazon gjør. Du kan nå ikke lage noe bokmerke til en side med forslagene dine fordi andre folk har ikke denne cookien og får ikke samme tilstand som deg. Hadde man puttet historikken i URIene ville det vært no problemo fordi URIen ville inneholdt alt som trengs for å gi de samme forslagene. Noen browsere cacher sider i historikken og lar deg browse dem ved å trykke back-knappen. Noen cacher litt vel agressivt, noen gjør en conditional GET for å verifisere at innholdet er oppdatert. Hvis man har fått satt en cookie vil back-knappen vise deg nytt innhold—ikke det gamle! Cookies ødelegger også for proxy caching ved at responsen blir avhengig av hva man har satt i en spesiell cookie. Man kan fikse dette med Vary headere men det gjør at responsen blir avhengig av alle cookies og ikke den som forandret hvordan websiden så ut… Det er så lett å trå feil. Både for oss utviklere som lager CMSer osv, og for malverksutviklere som jobber i PHP, Ruby, JSP osv. Hva er nå web arkitektur?Så går startskuddet for et storstilkt eksperiment, nemlig å få utviklere til å skjønne den arkitekturen som ligger til grunn for verdensveven. Sonen burde kanskje hete vevarkitektur for å ikke erte på seg språkrådet eller det frie språkrådet men la gå. Jeg har ikke tenkt å kreve at alle setter seg ned og leser Roy T. Fielding sin doktoravhandling som virkelig vil kan gjerne gjøre det. Det er tungt materie men hvis du skjønner den kommer du langt. Avhandlingen beskriver de veivalg som ble tatt da www ble laget, hvilke protokoller som kom før, og hvilke krav man hadde til et slikt distribuert system. For eksempel skulle systemet ikke dette sammen dersom en server gikk ned. Dette er jo selvfølgeligheter i dag men tilbake i 1992 fantes det ikke et client server program som var uavhengig av serveren. Tilsvarende måtte man minske antall “tur-retur” meldinger på nettet. Dette manifesterte seg i at en web samtale nå består av to meldinger: “request” (som oftest GET) og “response” (som oftest 200 OK). Enkelthet var en annen målsetning. Innhold skulle være enkelt å skrive. Hypermedia (rik tekst med lenker til mer informasjon) ble valgt fordi det enkelt tillater uendelig komplekse vev av dokumenter. Protokollen forble tekstbasert fordi det skulle være enkelt for utviklere å lage server og browsere. Alt innhold på web’en har også unike adresser. “Universal Resource Locator” ble omsider til “Uniform Resource Identifier” men fyller samme rolle. Alle web-sider har en URI. Du kan putte URIer i websider med a href tagger, og det funker utmerket. Du kan også skrive det på en gul lapp og henge det på kjøleskapet hjemme. en URI er universell og er lett gjenkjennelig. Disse konseptene er det nok mange som skjønner men det som er problemet er kanskje setningen “Hypermedia as the engine of application state”. Vi får ta det senere! Velkommen! [Edit: title] Webarkitektur
Følges av 64 medlemmer.
WWW ble et så enormt vellykket teknologisk prosjekt at utviklerne selv ble tatt på senga. Roy T Fielding som var med på å skrive standardene for WWW skrev doktoravhandlingen sin om arkitekturstilen til WWW. Mange utviklere misforstår WWW fordi de aldri har gått inn for å forstå arkitekturen bak. Vi ønsker et opplyst utviklersamfunn som skjønner WWW. Mer om sonen Webarkitektur er en sone på Origo. Les mer Annonse | ||