MijnOBA


Zo, de eerste Javascript applicatie
“powered by Knutselsmurf” is een feit.
Ik beschouwde Javascript altijd als een speelgoedtaal waarmee je advertenties en tellers en andere overbodige toeters en bellen aan HTML kon toevoegen. Dat oordeel dateert van 10 jaar geleden, toen ik het voor het eerst gebruikte bij de website van mijn vriendin. Het was in de tijd dat je mensen nog kon imponeren met plaatjes waar wat aan veranderde als je muiscursor er overheen ging.

Ongeveer een jaar geleden kwam de taal opnieuw in mijn gedachten, toen ik iets interactiefs wilde maken voor OBA. Een soort formulier, het was nergens voor nodig de server lastig te vallen voordat alles er op stond. Formuliervalidatie is bij uitstek een taak voor Javascript.
OBA is een website die wordpress als motor heeft. De content wordt up to date gehouden door een ander systeem dat ik gebouwd heb. Dat gebruikt alleen PHP, maar voor deze nieuwe applicatie zou PHP geen goed idee zijn. We gebruiken namelijk een reverse caching proxy om de website lekker snel te houden, en alles wat PHP gebruikt breekt dat systeem. Het prototype gebruikte wel PHP, maar de uiteindelijke versie zou helemaal met Javascript moeten werken.
De gebruikelijke manier om persoonlijke voorkeuren door te geven aan een website is via cookies.
Dat wilde ik niet. Die cookies zouden erg groot worden, waardoor het systeem traag zou gaan werken. Bovendien wilde ik alleen maar statische content laten serven door nginx. Tot een half jaar geleden werkte OBA nog met PHP op de webserver, en je zag het systeem met de dag trager worden. Vanaf het moment dat ik het systeem splitste in een front-end en een back-end, kreeg het vleugels. Het paste weer met gemak in de 512MB VPS.

Telkens als een van de leden iets publiceert, wordt de OBA voorpagina geupdate. Daarnaast wordt elke 10 minuten 1/6 deel van de blogs op de voorpagina bezocht door onze spider, om de comment-counts op te halen. Normaal zie je dat pas, als je de hele pagina opnieuw ophaalt.
Ik heb een systeem bedacht, waarbij d.m.v. AJAX technieken slechts dat deel van de pagina dat nieuw is wordt opgehaald. WordPress kan dat niet, de template van het theme produceert altijd 1 pagina. Ik moest dus een paar extra ingangen maken, zodat mijn script afzonderlijke posts kon ophalen.
Ik heb een tijdje nagedacht over verschillende alternatieven.
AJAX ( Asynchronous Javascript And XML ) is een verzameling al langer bestaande technieken waarmee het mogelijk wordt een deel van een pagina te vernieuwen, terwijl de rest blijft staan. Als je bijvoorbeeld met je F5 toets een pagina vernieuwt, wordt de hele pagina vervangen. Daarnaast bestaat al sinds mensenheugenis Flash ( zoals de bekende Youtube filmpjes ge-embed in pagina’s ).
Bij AJAX is het geen embedded object waarin je iets ziet bewegen, de hele pagina kan veranderen. Websites hebben deze technieken massaal omarmd, overal zie je de extra venstertjes die bovenop de website lijken te zweven, allemaal mogelijk dankzij AJAX technieken.
De X in AJAX staat voor XML, maar het kan in feite elk soort data zijn. MijnOBA gebruikt JSON ( JavaScript Object Notation ).
Oorspronkelijk reageerde Javascript op de muis en het toetsenbord, om websites een beetje interactief te maken.
AJAX technieken voegen daar het netwerk aan toe. Het script dat aan een pagina gekoppeld is reageert nu ook op het binnenkomen van data vanaf internet.
En daarmee verdwijnt het verschil tussen een website en een applicatie grotendeels, de website wordt een App.

Met de webserver waarover wij kunnen beschikken is het niet mogelijk data ongevraagd naar de clients te pushen. Dat zou de snelste methode zijn. Wij gebruiken het iets langzamere polling, waarbij de client op gezette tijden een request naar de server stuurt.
Ik heb gespeeld met het idee om alle nieuwe posts naar elke client te sturen, maar dat zou telkens een piek in het dataverkeer veroorzaken. OBA levert geen tijdkritische informatie. Ik had een client een verzoek kunnen laten sturen als ” stuur mij alles dat nieuw is sinds …. “. Maar dat soort verzoeken kan niet makkelijk afgehandeld worden door een proxyserver.
Daarom heb ik een tussenstap gemaakt :
Een inhoudsopgave. En om het dataverkeer nog verder te decimeren, heb ik de inhoudsopgave gesplitst in een “max 1 uur oud” en een “alles”.
Clients die inschakelen vragen de “alles” op en daarna elke 5 minuten de “recent” versie, en die 2 worden gemerged door het script.
Die 2 filetjes kan nginx heel simpel cachen.
De inhoudsopgave bevat precies genoeg info voor het script om te bepalen of het de post opvraagt of niet :
Auteurnr, post-nummer, publicatietimestamp, updatetimestamp.
Het filetje dat gekoppeld is aan het postnummer bevat alles waarmee Javascript een div element kan maken zoals wordpress het ook zou maken.
Het bleek verrassend eenvoudig om wordpress zo aan te passen dat het die json filetjes produceert. Het is niet eens nodig binnen wordpress events af te vangen, je hoeft alleen maar op verzoek van de proxyserver een json filetje te maken. Die proxyserver zorgt er wel voor dat zulke verzoeken niet vaker komen dan 1 keer per minuut, wat de back-end makkelijk aan kan.

Omdat het een wordpress extentie is, maak ik natuurlijk gebruik van alles wat wordpress al aan boord heeft. De scripts die de json filetjes produceren zijn klonen van de xmlrpc interface. De applicatie zelf is gebouwd als een page-template van een theme. WordPress heeft een mechanisme om scripts te schedulen, zodat een pagina die een bepaald script nodig heeft daar op tijd over kan beschikken, zonder dat het dubbel wordt gedownload. Erg handig.
Themes verdelen een pagina netjes in widget area’s en de applicatie gebruikt een widget voor de bediening. Het ziet er uit alsof het zo hoort, en het is heel makkelijk te maken.

jQuery.
Wordpress maakt zelf gebruik van de jQuery javascript library. jQuery is goud waard. In eerste instantie viel het me tegen wat je er mee kon, soms spaarde het wat tikwerk uit. De grote kracht van jQuery zit echter in het opvangen van browserverschillen. Zonder jQuery zou je daar constant rekening mee moeten houden, nu hoef je alleen maar te denken : hoe vertel ik dit aan jQuery ?

Internet Explorer.
Waarschijnlijk het meest gehate stuk software ter wereld, en verdiend.
Crapware.
Het is me inmiddels duidelijk wat de strategie van Microsoft is :
Neem zitting in standaardisatiecommittees. Daar kun je leren wat je concurrenten van plan zijn, en die plannen kun je daar frustreren.
Ongeveer een jaar voordat een nieuwe standaard uitgekristaliseerd is, breng je een product op de markt dat niet compatible is met de toekomstige standaard. Je klanten willen de boot niet missen, dus die gaan software ontwikkelen voor jouw systeem. Concurrenten die zich aan de afgesproken standaard houden, zien zich straks geconfronteerd met voldongen feiten en zijn gedwongen 2 sets standaards te volgen : jouw standaard en de echte standaard.
Klanten die jouw browser gebruiken, zien zich later door het verschijnen van volgens de nieuwe standaard werkende software gedwongen de volgende versie van jouw browser aan te schaffen, anders kunnen ze bepaalde websites niet goed gebruiken. Je geeft die browser gratis weg, maar hij werkt natuurlijk alleen op de nieuwste Windows versie, die niet gratis is.

Toen MijnOBA klaar was, ben ik nog ruim een week bezig geweest om aanpassingen aan te brengen opdat het ook met MSIE zou werken.
Volgens mij heeft Microsoft veel mensen in dienst die gewend zijn aan Basic ( Beginners All-pupose Symbolic Instruction Code, nog erger dan Cobol )
Mogelijk willen ze ook klanten van dienst zijn die dat alleen begrijpen.
Javascript (ECMA-script) is een object-georienteerde scripttaal die je natuurlijk prima kan gebruiken alsof het Basic is. Ga je bij Microsoft kijken hoe hun baksels werken, dan krijg je zulke voorbeelden.
Variabelen hebben bij Microsoft voorbeeldcode allemaal een global scope, en niets is object-georienteerd.
Het MijnOBA script is helemaal objectgeorienteerd geschreven. Dat bleek lastiger dan ik dacht, want als je ergens op klikt, wordt er een clickhandler aangeroepen, een method van je object. Binnen die functie ga je er van uit dat “this” de betekenis heeft : “binnen dit object”.
Zo werkt het wel in andere object-georienteerde talen, maar niet in JavaScript.
Daar is de betekenis van “this” afhankelijk van het event dat de method aangeroepen heeft.
Oeps.
Er is een mooie oplossing voor : bound functions. Je kan een functie definieren met dezelfde eigenschappen, maar met een aan je object gekoppelde “this”.
Je moet het een paar keer lezen, maar over veel dingen is goed nagedacht door de makers van Javascript.
Alleen hebben ze dat bij Microsoft niet gedaan, dus je moet nogal wat code toevoegen om dingen als bound functions te laten werken als het script wordt uitgevoerd door JScript van de MSIE browser.
Ik vind gemiddeld genomen object-georienteerd programmeren “de nieuwe kleren van de keizer”, maar een van de voordelen is wel, dat een object zijn eigen namespace is. Er kan nooit een conflict ontstaan, en je hoeft dus ook geen belachelijk lange namen te gebruiken voor variabelen.
De AJAX completion-handlers zitten dus ook in mijn object.
Ik vertel jQuery dat ik data nodig heb van de server, en welke method die data gaat verwerken als hij het opgehaald heeft.
Dat werkt bijna magisch. ( op wat timing probleempjes na )
Alleen kunnen zelfs de slimme jongens van jQuery geen manier verzinnen om dat te vertalen naar de Microsoft methode.
Ten eerste, omdat je server extra headers moet toevoegen aan de responses, anders is het niet veilig, volgens Microsoft.
Ten tweede, omdat Microsoft code een object (XDomainRequest) in de global space nodig heeft om de server-reply ergens aan te kunnen koppelen.
Als je eenmaal gewend bent aan jQuery Ajax, is het een vreemde gewaarwording dat dezelfde methode bij Microsoft niet werkt.
http://msdn.microsoft.com/en-us/library/cc288060(v=vs.85).aspx#properties
( er stond een fout in, ik heb een mailtje van Microsoft waarin ze me bedanken dat ik ze er op wees, ik denk dat ik het ga inlijsten )
Als je een XDomainRequest object als lokale variabele gebruikt in een functie, zul je in de access log van de server zien waarom het niet werkt :
“Client closed connection while awaiting server-reply”
Juist ja.
Het moest even indalen.
2 Dagen werk naar de knoppen.
Je hoeft ook niet te proberen XDomainRequest een method van je Object te laten aanroepen als callback, zoals je met jQuery doet.
Wil niet, je moet een functie in de global space definieren.
Die functie heeft vervolgens de Eval methode nodig om de callback aan te roepen. Iedereen weet dat Eval de deur is naar cross-site scripting attacks.
De attacker zou immers de hosts file kunnen manipuleren, waardoor het script data van een andere server krijgt. Ik heb dus een controle in de Microsoft callback gebouwd, om zeker te zijn dat die data afkomstig is van mijn eigen server.

tools :
Zonder softwaregereedschap had ik het nooit voor elkaar gekregen. Ik heb een server met Ubuntu en dezelfde combinatie van nginx en apache waar OBA ook mee werkt. Nginx heeft een gebruiksaanwijzing, maar die moet je niet teveel vertrouwen, testen is beter.
Firebug is een browserextentie waarmee je Javascript kan debuggen. Het voegt een intelligent console toe aan je browser, zodat je boodschappen naar een console kan sturen zonder dat je schermoutput verandert. Internet Explorer heeft er een nagemaakte versie van met minder mogelijkheden. Daar heb je eigenlijk niet veel aan. Er is een Firebug voor Firefox en voor Google Chrome. De Firefox versie is de meest uitgebreide, die kan ook gebruikt worden als console voor de FirePHP plugin, een PHP debugger.

Informatie over Javascript, browsers, DOM etc. komt van Mozilla Developer Network. Vroeger gebruikte ik vaak informatie van W3Schools, maar ik heb door schade en schande geleerd dat die website niet deugt. Hij staat altijd bovenin de zoekresultaten, maar SEO-optimalisatie is het enige waar ze goed in zijn. De informatie die je krijgt is vaak verouderd, incompleet of gewoon onjuist.

Ik heb JS-Lint gebruikt om er achter te komen hoe het met de kwaliteit van mijn javascript code zat. Browsers klagen niet snel. JS-Lint is een kritische syntax-checker voor Javascript. Het was erg leerzaam voor mij als beginnend Javascript programmeur om te zien waar hij zoal op let.

Ten slotte gebruik ik YUI-compressor om het script zo klein mogelijk te maken. Het is geen compiler, maar hij haalt alle overbodige tekst uit het script. Comments, whitespace, returns gaan er uit en variabele-namen worden ingekort tot de kleinst mogelijke lengte. Je scripts worden er ongeveer half zo groot door. Een bijkomend voordeel is, dat ze niet makkelijk te doorgronden zijn voor amateur-hackers.

Overigens is het belangrijk je code zo te ontwerpen dat het makkelijk te debuggen is. Het is moeilijk om daar richtlijnen voor te schrijven.
Ik verdeel mijn code in routines die een beschrijvende naam hebben, en ik begin het testen door elke routine zijn eigen naam naar het scherm te laten schrijven. Later haal ik dat weg, maar door hier een tijdje naar te kijken wordt het een soort liedje in je hoofd, en ga je het programma veel beter begrijpen. Dit soort dingen leer je niet van een opleidingsinstituut, ik heb ooit bij Volmac (Gap Gemini/ Sogeti ) een cursus gehad waar ik je leerde dat iedereen op de hele wereld op dezelfde manier ( hun manier ) software moest maken, anders kon iemand anders het niet lezen. De namen van alle routines moesten beginnen met een letter en dan 3 cijfers, en je mocht in het hele programma alleen hoofdletters gebruiken, anders konden sommige compilers het niet verwerken. Het was natuurlijk Cobol, en hoewel de mogelijkheden om het voor mensen ook leesbaar te maken in Cobol erg beperkt zijn, mocht je ook nog eens een deel van die mogelijkheden niet gebruiken. Debuggen was niet de bedoeling, je moest alles van tevoren ontwerpen, dan moest je een uitvoervoorspelling maken en dan mocht je maximaal 10 keer de compiler gebruiken en als het dan niet werkte kreeg je strafpunten.

Mijn eigen methode werkt andersom. Ik maak veel fouten. Er zijn mensen die minder fouten maken dan ik, maar er bestaan geen mensen die geen fouten maken. Ik maak helemaal geen ontwerp op papier. Ik heb een computer. Ik maak geen uitvoervoorspelling. Er komt uitvoer uit. Als die me niet bevalt, pas ik het programma aan. Ik maak geen ontwerp in pseudo-code. Ik schrijf meteen in code wat ik bedoel en in comments wat ik nog moet maken.
Ik stop debug hulpmiddelen in mijn code, en die blijven er in zitten. Een goede foutafhandeling verdient zichzelf terug, al lijkt het in eerste instantie overdreven.

Ik heb nagedacht over misbruik en namaak. OBA heeft daar in het verleden last van gehad.
Dit script kan niet gebruikt worden om even heel simpel alle content van OBA op je eigen website te zetten.
Onze server controleert natuurlijk wat een browser als referer opgeeft, daar zal het al meteen op stuk lopen.
Daarnaast maakt de Same Origin Policy die browsers hanteren het onmogelijk om een client te bewegen data op te halen van OBA terwijl het script afkomstig is van een namaker.
Maar dat is niet genoeg. Een server zou OBA kunnen bezoeken en alles kopieren.
De constructie met een table-of-content bood echter een handvat om misbruik te ontmoedigen.
De namaker zou een filetje nodig hebben dat ik louter en alleen om juridische redenen heb toegevoegd.
Dat filetje bevat alleen een copyright notice en een paar willekeurige getallen.
Maar die getallen heb je echt nodig om de table-of-content te vinden.
Technisch is het een obstakel van niks, maar juridisch is het vrij stevig : zonder schending van de auteurswet lukt het niet om een mirror van OBA te maken. Bovendien maakt het veranderen van het filetje elke kopie waardeloos : bona-fide clients veranderen dan mee en namaak scripts niet.

Read Offline:
This entry was posted in Wordpress and tagged , , , , . Bookmark the permalink.

20 Responses to MijnOBA

  1. I like this a lot.. 😀

  2. beheerder says:

    Facebook is alweer “uit”, dus ik heb geen “like” button 😉

  3. Maar ik heb het wel geplaatst op facebook. Kan het alsnog geliked worden. https://www.facebook.com/OnafhankelijkeBloggersAssociatie

  4. Grutte Pier says:

    Ik heb een ‘stukje’ geschreven…. zegt ie dan.
    😉

    Mijn complimenten!

  5. beheerder says:

    Het is niet eerlijk, maar vaak is het resultaat niet evenredig aan de inspanning. Dit stukje is heel snel geschreven, maar ik zit ook weleens dagenlang tegen iets simpels aan te hikken.

  6. Ximaar says:

    Het lijkt goed te werken en heb ‘m ingesteld op de excludemanier.

    Javascript heb ik een jaar of 8 terug gebruikt voor mijn website. Als je daar een zoekwoord intikte, kon je later dat met een ‘doorzoek’-knop alle plekken van dat zoekwoord binnen een pagina vinden. Dat lukte me redelijk eenvoudig omdat ik toen nog een website met frames had. Ik heb dat tot op heden nog niet op andere websites gezien. Later kwam de Google Toolbar die hetzelfde kon, maar dan bij alle websites. En nog wat later kwam het in de browsers, maar doorgaans vind ik die methode te omslachtig in het gebruik.

    In web-log op Typepad was het goed te gebruiken. Ik liet er de kopfoto en de achtergrond mee wisselen, de reclame onderdrukken en de reacties van een volgnummertje voorzien. WordPress heeft nu zelf een systeem om kopfoto’s te wisselen. Er zijn wat thema’s met reactienummering, maar die scoren op kolomindeling en bijvoorbeeld regelafstand erg slecht. Zij laten terecht javascript niet toe, want bij Typepad was het erg goed mogelijk om via javascript in een reactie het hele weblog te verzieken. 🙂

  7. beheerder says:

    Time flies.
    Frames liggen alweer op de mestvaalt van de historie.
    Geen enkel CMS zal ook meer toestaan dat bezoekers een script invoegen in een reactie. Op die manier wordt het wel erg eenvoudig om mensen hun passwords te ontfrutselen.

    De manier waarop OBA je comments telt heeft niets te maken met Javascript. Je blog wordt na publicatie bezocht door onze spider, die een keer per uur naar de comment-RSS kijkt. Die spider geeft vervolgens aan OBA door wat hij gezien heeft. Bijna science fiction 🙂

  8. Glaswerk says:

    Impressive!

    Iedereen weet dat Eval de deur is naar cross-site scripting attacks.

    Het is dat je ons allen er zo fijntjes aan herinnert, bij velen zal die kennis alweer een beetje weggezakt zijn 😉

  9. beheerder says:

    Op OBA stond de waarschuwing dat het een lang en technisch verhaal was. Vanwege het jargon gehalte. Voor de gemiddelde web-app programmeur zal het wel allemaal gesneden koek zijn, helaas reageren die nooit op mijn blog.

  10. Dwarsbongel says:

    Indrukwekkend en interessant verhaal!
    Ik merk wel dat ik er alweer een tijdje uit ben… In het “buizen”-tijdperk was ik een van de eersten die schakelingen met transistoren bouwde (1962), en mijn eerste programmeerervaring was met BASIC (1978) en vervolgens diverse Assemblers.
    Ik heb diverse methoden geleerd om gestructureerd te programmeren, en voor grote programma’s, zoals voor ziekenhuis-oproepsystemen (was mijn vak) vind ik dat onmisbare hulpmiddelen om het geheel overzichtelijk te maken; het gaat daar soms om leven en dood.
    PASCAL is mijn favoriet om “leesbare” en onderhoudsvriendelijke programma’s te maken. De taal C vond ik vragen om problemen.
    Ik heb even aan PHP en Javascript geroken, maar dat was na mijn “afvloeiing”(2000). Na 40 jaar techniek ben ik geloof ik niet meer zo gemotiveerd om nog als hobby diep in allerlei nieuwe technieken te duiken…

  11. beheerder says:

    Sommige dingen moet je ook niet willen.
    Ik kan je wel even bijpraten :
    Pascal is een prima taal, ook vandaag nog te gebruiken.
    Compilers worden echter voor steeds minder toepassingen gebruikt. Eigenlijk alleen nog als het echt snel moet werken. Je ziet op steeds meer plekken scripttalen verschijnen. PHP zou ik je niet aanraden. Als je zelf iets maakt, kun je dat zo gestructureerd maken als je zelf wil, maar PHP code van anderen is vaak onleesbaar. PHP is gemaakt om tussen HTML tags verstopt te worden en dat levert vaak onleesbare troep op.
    Veel mooier is Python, ook een scripttaal, kan ongeveer hetzelfde, maar is veel gestructureerder.
    Voor Javascript is geen alternatief, vrees ik, maar het heeft niet zoveel bezwaren als PHP.

  12. Grutte Pier says:

    I love The Talk… 😉

  13. beheerder says:

    But can you do the walk ? ( who framed Roger Rabbit ? )

  14. Grutte Pier says:

    Uuuh….. *kuch* Moonwalk?

  15. knutselsmurf says:

    Ik kreeg net een wat onvriendelijke reactie ( hij bleef hangen in moderatie ) :

    Comment:
    Leuk stukje hoor, maar waarom wil je weten waar ik allemaal geweest ben op internet? Waarom sta je gebruik van je site niet toe zonder tracking cookies?
    En dat voor een iemand met verstand van zaken.
    Om te kotsen. Echt waar.

    Dus ben ik even uitgelogd, en ik heb mijn cookies weggegooid. Daarna heb ik de pagina ververst, om te kijken welke cookies ik had :
    PHPSESSID
    Alleen geldig op dit domein, levensduur : sessie.

    Ik vraag me af wat de vraagsteller bedoelt ? Ik heb geen “trackingcookies”, want ik gebruik geen diensten van externe partijen. Iedereen mag mijn site bekijken, stuur je cookies, dan doe je dat ongevraagd, ik lees ze niet.

  16. knutselsmurf says:

    OK, misschien bedoelt de vraagsteller niet mijn site maar OBA.
    De oprichter van OBA houdt van grafiekjes, die externe partijen voor je kunnen maken. Het interesseert haar niet waar bezoekers geweest zijn, alleen wat ze binnen de site doen. Voor mijnoba zijn de resulterende cookies alleen maar lastig, want ze kosten bandbreedte en de applicatie gebruikt ze niet. Tot nu toe is het me nog niet gelukt ze tegen te houden. Zelfs een “cookieless subdomain” houdt ze niet tegen, want wordpress sproeit cookies als een koe met diarhee.

  17. Grutte Pier says:

    Ik denk ook dat OBA wordt bedoeld (?!)

  18. beheerder says:

    Klopt. Ik vond hem daar in de access-log. Daar heb je geen tracking-cookie voor nodig.
    Referer : nujij.nl
    Met die mensen die elkaar afblaffen op nujij.nl wil ik zowiezo niets te maken hebben.

  19. Op nujij heeft hij ook gereageerd. Het zit hem niet lekker dat als je de cookies niet accepteerd, je wordt door verwezen naar de google zoek pagina. Ik zit nu te bedenken of er niet een andere leuke redirect is.

    Wel grappig dat iemand die zo paranoia op cookie acceptatie bij OBA reageert, wel gewoon een account bij NUjij heeft. Alsof je daar niet getracked wordt.

    Ach….je hebt ze er bij.

  20. knutselsmurf says:

    Ik vind die hele cookie-wetgeving een gedrocht, en ik weiger mijn blog op te sieren met popups die je het idee geven dat er een bom onder je toetsenbord zit.

    Ik heb geen idee of je ook voldoet aan de eisen, als je mensen alleen maar informeert over het gebruik van cookies op je site en over de manier om ze in je browser uit te schakelen. Je stuurt ze nu weg, omdat je je aan de regels wil houden, maar ik snap de regels niet en ik maak geen blog om mensen te ergeren of weg te sturen, dus van mij hoeft het niet.

Leave a Reply

Your email address will not be published.