itfag | Teknologi. Data. Læring. Deling.

TAG | php

 

Av: Kim Betti, systemutvikler og tidligere student ved HiST

Det er god skikk å separere presentasjon og forretningslogikk. Dersom en klarer å skille disse klart fra hverandre på en ryddig måte oppnår man en del fordeler som vil gjøre koden enklere å videreutvikle og vedlikeholde.

  • Designere som jobber med sidens utseende kan gjøre jobben sin uten å rote i forretningslogikken som ligger bak siden.
  • Logikk og presentasjon kan utvikles uavhengig av hverandre så lenge ikke kravene til hva som skal presenteres endres.
  • Det blir mye enklere å legge til alternative presentasjonsformer. Det er ofte aktuelt å presentere samme data som HTML, PDF, regneark samt en rekke andre forskjellige formater.

Raskt oppsummert: Datamodellen generert av forretningslogikk bør kunne presenteres på forskjellige måter uten at det krever endringer i logikken som genererer dataen. For eksempel: Kode som er ansvarlig for å hente en liste over kalenderavtaler bør ikke vite noe som helst om avtalene den henter skal presentere en liste med avtaler som HTML, RSS eller iCal!

I dette innlegget skal jeg gå gjennom hvordan en kan med en testdreven tilnærming implementere en templatemotor basert på bufring av utdata med en testdreven tilnærming. For å ikke drukne innlegget i kode har jeg bare plukket ut de mest relevante bitene. Resten av koden ligger på GitHub.

Noen få ord om meg – Jeg er utdannet treårig dataingeniør ved Høgskolen i Sør-Trøndelag og jobber nå som systemutvikler i Oslo. Det siste semestret på høgskolen var jeg studieveileder i nettfaget “Webprogrammering med PHP”. Selv om jeg til daglig jobber mest med integrasjon og Java-teknologier var det morsomt å kunne bidra med et PHP innlegg til denne bloggen!

Veldig kort om testdrevet utvikling (TDD)

I testdrevet utvikling legger en vekt på å skrive testene først. Dette tvinger en til å tenke på hva en vil oppnå med koden før en begynner med løsningen. Testdrevet utvikling består av to små steg som vi gjentar om og om igjen.

  • Det første steget er alltid å skrive en test som feiler. Ved å skrive en slik test har vi bestemt hva koden skal gjøre for oss og hvordan grensesnittet skal se ut. Dette betyr ikke at vi nå har fryst programmeringsgrensesnittet for endringer! Testdrevet utvikling legger opp til at en hele tiden forbedrer grensesnittet etterhvert som vi lærer mer om implementasjonen og problemområdet / domenet vi jobber i. Testene vi allerede har skrevet vil passe på at vi ikke bryter kode som har fungert når vi gjør disse endringene.
  • Steg nummer to er å implementere kode som tilfredsstiller testen vi nettopp skrev. Når testen gir oss grønt lys går vi tilbake til punkt nummer en og skriver en ny test som feiler. Se på grønne tester som en tillatelse til å skrive ny kode.

Disse to stegene repeterer vi helt til vi har implementert ønsket funksjonalitet og en pen og vedlikeholdbar implementasjon. Hver gang vi har implementert ny eller refaktorert eksisterende kode passer vi på å kjøre alle testene slik at vi er sikker på at de siste endringene vi gjorde ikke bryter ting som har fungert.

En myte rundt testdrevet utvikling er at det er unødvendig arbeid som reduserer produktiviteten. Dette kunne ikke være lengre fra sannheten! Det tar litt ekstra tid i starten mens man venner seg til denne måten å jobbe på, men jo lengre man praktiserer dette desto større blir utbyttet!

  • Det viser seg at kode som er lett å teste veldig ofte er god kode. Den er ofte veldefinert, gjør ikke mer enn den skal og har få avhengigheter. Det blir rett og slett for mye jobb å skrive kode med unødvendige avhengigheter dersom en skriver testen først.
  • Testene fungerer som dokumentasjon. Testene viser hvordan klasser skal brukes og hvordan de skal oppføre seg. Problemet med kommentarer i kildekode og på papir er at de ikke oppdateres sammen med koden. Disse har en lei tendens til å bli utdatert og dermed lyge om systemet. Kode kan være misledende, men den lyger ikke! Dette betyr også at testkode ikke er annenrangs kode, testkoden er minst like viktig som produksjonskoden og må vedlikeholdes på samme måte!
  • De fanger regresjoner. Dette er en av de største fordelene med enhetstester! I et system med god testdekning kan en trygt gjøre optimaliseringer og legge til ny funksjonalitet uten å være redd for å introdusere feil. Dette er helt uvurderlig i et hvert system av litt størrelse, spesielt for nye utviklere som ikke kjenner systemet!

Det er mye mer til testdrevet utvikling enn hva jeg kan ta for meg i dette innlegget. For alle som holder på med programmering vil jeg på det sterkeste anbefale å lese mer om temaet på nett og i bøker. Bøker og artikler er bra, men det beste en kan gjøre for å lære mer er rett og slett og sette i gang selv!

Templatemotor – Presentasjon av data

Nok introduksjon, la oss begynne med implementeringen av templatemotoren. Som nevn er fokuset i dette innlegget presentasjonsdelen, altså steget der vi tar en datamodell og gjør det om til noe som kan presenteres for en bruker.

Vi begynner med en veldig enkel HTML template som kun består av en HTML tagg og en variabel.

<title><?php echo $title; ?></title>

Nedenfor er et eksempel på en test vi kan skrive. Dette er en relativt stor enhetstest, i praksis skriver en som regel flere og mindre tester, men det blir for omfattende for dette innlegget. Jeg har plukket denne testen fordi den demonstrerer prinsippene godt. Hele testklassen ligger her.

public function testSimpleTemplate() {
    // Oppsett av koden vi vil teste
    $view = new View("data/simple-view.php"); 
    // Sender data inn 
    $view->set("title", "Hello World!"); 
    // Utfører en handling
    $renderedHtml = $view->render();  
    // Verifiserer oppførsel
    $this->assertEquals(
             "<title>Hello World!</title>",
             $renderedHtml); 
}

Alle testmetoder i PHPUnit begynner med prefikset test. Resten av metodenavnet bestemmer vi selv og bør si noe om forventet oppførsel som testes.

Testen ovenfor viser strukturen i en typisk enhetstest. Vi starter ofte med å sette opp grunnlagsdata som brukes til å gjøre noe med systemet før vi verifiserer systemets respons til handlingen vi utførte. De fleste testrammeverk gir støtte for dette gjennom forskjellige assert metoder. Den siste linjen i denne testmetoden verifiserer at teksten "Hello World!" har blitt satt inn i title taggen. Dersom denne antakelsen viser seg å ikke stemme vil testrammeverket feile denne testen.

Legg merke til at vi enda ikke har skrevet kode som faktisk gjør det vi ønsker! Men vi har allerede bestemt en del ting. Vi har for eksempel funnet ut hvordan vi vil at programmeringsgrensesnittet skal se ut. Dersom vi er fornøyd med dette grensesnittet i testen, vil vi forhåpentligvis også være fornøyd med det når vi senere skal ta det i bruk i logikken.

Min personlige erfaring er at det å skrive tester først veldig ofte leder meg til et bra grensesnitt. Vær dog oppmerksom på at det ikke nødvendigvis leder direkte til det “beste” grensesnittet! Det beste grensesnittet er noe en bare kan krype nærmere og nærmere gjennom mange rundturer med testing, implementering og refaktorering!

En annen ting det er verdt å legge merke til er at grensesnittet ikke er spesielt knyttet opp mot HTML. Når (om) det blir aktuelt å legge inn støtte for forskjellige formater vil vi kanskje finne ut at API-et vi har nå er for enkelt. Kanskje vil vi gjøre om klassen View til et grensesnitt (interface) med forskjellige implementasjoner som HtmlView og PDFView..? Kanskje finner vi ut at vi trenger å skille datamodellen fra View i en egen klasse..? Med tester på plass kan vi trygt eksperimentere med forskjellige løsninger uten å være redd for å bryte eksisterende kode så lenge en hele tiden jobber i små inkrementelle steg støttet av tester!

Nedenfor er en metode fra klasen View som testen ovenfor tester. Resten av klassen ligger som vanlig på GitHub.

public function render() {
    // Start output buffering
    ob_start(); 
    // Pakk ut innholdet av arrayet `vars` 
    // slik at de blir tilgjengelig som vanlige variable 
    extract($this->vars); 
    // Importer templaten
    require($this->viewFile); 
    // Returner data vi har fanget 
    return ob_get_clean(); 
}

Dette er et veldig mye brukt mønster i PHP rammeverk. Vanligvis vil all ut-data fra PHP script bli sendt i en datastrøm til brukerens HTTP klient (nettleseren) etterhvert som scriptet kjøres. Det output buffering gjør er å fange ut-data i et buffer i minnet istedenfor å sende det rett ut på nettverket.

Dette trikset kjøper oss en del fleksibilitet på bekostning av litt høyere minnebruk. Med dette på plass blir det mye enklere å implementere funksjonalitet som komprimering, mellomlagring / cache og ikke minst testing!

Lenker:

Dette innlegget har 1 kommentar. Gjerne bidra :-)

Av: Svend Andreas Horgen, høgskolelektor og faglærer i PHP

En liten nøtt i dag. Løsningsforslag kommer senere. Har du forslag til strategi for å løse problemet, så legg gjerne igjen en kommentar.

Dette innlegget har 4 kommentarer. Gjerne bidra :-)

mar/11

1

System for å samle inn bloggadresser

Av: Svend Andreas Horgen, høgskolelektor og faglærer i Webprogrammering i PHP

I forrige uke skrev jeg et blogginnlegg hvor jeg bad om innspill til hvordan en effektivt kunne samle inn bloggadresser fra for eksempel 20 studenter. Det kom mange kommentarer og gode tips (6 personer kommenterte på bloggen og en del andre på Twitter).

Idéene var gode, men selv om Etherpad, Google Docs og andre løsninger kan fungere veldig bra, så fikk jeg lyst til å programmere en løsning som gjør dette supereffektivt og så lavterskel som mulig for lærere. Problemet er bare at jeg ikke har tid. Hmmmmm, men i faget Webprogrammering i PHP skal jo studentene nå i vår løse en prosjektoppgave hvor de programmerer et webbasert system opp mot en underliggende database… Vi prøver å lage oppgaver som kan brukes i praksis, siden det er mer motiverende enn fiktive oppgaver. Tidligere semestre har prosjektoppgaven vært knyttet til ymse forskningsprosjekter. Denne gangen blir prosjektoppgaven altså knyttet til undervisningen vår.

Derfor lagde jeg i dag oppgaven slik: Lag et system for effektiv innsamling og administrasjon av bloggadresser i ulike fag. Her er en oppsummering av kravene til funksjonalitet i oppgaveteksten:

  • Systemet skal være webbasert og må ha en underliggende database hvor alle bloggadresser lagres.
  • Læreren skal kunne lage en ny lenke for et fag/semester. Denne lenken kan spres til studentene for eksempel gjennom it´s learning.
  • Studentene registrerer sitt navn, bloggens adresse, bloggens RSS-adresse, en beskrivelse av innholdet i bloggen og antatt frekvens for oppdatering.
  • Det kreves ingen innlogging for å registrere en ny blogg.
  • Med en gang en ny blogg er registrert, kan hvem som helst (som har lenken) se blogginformasjonen i bloggoversikten. Alle lenker er selvsagt klikkbare.
  • Det skal være mulig å velge hvor mye eller lite informasjon en vil se: Studentenes navn, adressen til bloggen, RSS-lenken, beskrivelsen og så videre.
  • Killer feature: Det skal være mulig å eksportere listen av bloggadresser som en OPML-fil. Dermed kan denne importeres rett inn i for eksempel Google Reader!

I tillegg er det lagt inn noen ekstra utfordringer til de ivrigste PHP-studentene, som er programmeringsteknisk mer vriene å løse.

Du tenker kanskje at dette var da mer tungvindt enn for eksempel Google Docs eller Etherpad. Nja, var det nå det? Tenk over de ekstra gevinstene. Et ferdig system gjør det superenkelt å sette i gang med blogging i et fag for en faglærer og lett å bruke for studentene. I rekkefølge skjer følgende:

  1. Læreren lager en ny lenke (et område) i systemet som er unik for denne studentgruppen (tar 20 sekunder)
  2. Læreren limer lenken inn i it´s learning slik at studentene kan bruke systemet (tar 20 sekunder)
  3. Studentene får beskjed (gjennom øvingsoppgaver) om å lage sin egen blogg og registrere adressen sin. Det tar ikke lang tid å registrere sin egen blogg (om en vet hvordan en finner tak i for eksempel RSS-lenken)

Deretter er det bare å besøke bloggene en vil til enhver tid. Enda bedre er muligheten for å importere rett inn i for eksempel Google Reader – dette er ikke mulig med mindre en har programmert systemet selv, og her er fordelen med å programmere selv helt tydelig. Jeg vil si terskelen bær være meget lav.

Jeg gleder meg til å både se de programmeringstekniske løsningene som studentene i faget Webprogrammering i PHP kommer opp med fremover, og jeg gleder meg til å teste ut systemet i de nettbaserte fagene IKT og læring og Enterprise 2.0 – Profesjonell bruk av nettet til høsten.

Har du forslag til andre nyttige ting som kunne vært med i oppgaven?

Dette innlegget har Comments off. Gjerne bidra :-)

Av: Svend Andreas Horgen, høgskolelektor, faglærer i PHP, forfatter av phpbok.no

Dette innlegget beskriver en snedig måte å bruke PHP-funksjonen strstr() på. Ja, en kan rett og slett si «vakker» bruk av strstr(). La oss si at du ønsker å sjekke for eksempel mimetypen til en opplastet fil, og vil godta flere typer. Går dette an å gjøre det på en enkel måte? Tenk over hvordan du ville gått frem for å løse dette før du leser videre.

Mange synes det er morsomt å programmere litt «out-of-the-box», så la oss se hvordan vi kan tenke alternativt og kanskje få en liten aha-opplevelse på kjøpet … les resten av innlegget

Dette innlegget har 11 kommentarer. Gjerne bidra :-)

Theme Design by devolux.nh2.me