[oop] programmeren naar data of behaviour?
Ik vroeg me ineens iets af. Een van de $_SERVER variabelen bevat een string met de encoding-types die de client ondersteunt.
Nu heb ik in mijn request\client object een method getEncodingTypes() gemaakt waarmee je die string kunt opvragen. Nu is mijn vraag... (ik heb namelijk echt geen idee of hier een "stelregel" voor geldt...) of je het beste kunt programmeren naar data of naar behaviour. Daarmee bedoel ik het volgende:
Hoe ik het nu doe, programmeer ik naar data. Namelijk:
Code (php)
Wat er dus gebeurt, is dat ik data ophaal (de string met encoding-types) waarmee ik vervolgens iets ga doen (namelijk controleren of het type "gzip" aanwezig is).
Wat ik ook kan doen, is programmeren naar behaviour (gedrag/functionaliteit).
Voorbeeld:
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<?php
$client = $request->getClient();
if ($client->hasEncoding('gzip')) {
// doe iets
}
?>
$client = $request->getClient();
if ($client->hasEncoding('gzip')) {
// doe iets
}
?>
Hier haal ik dus geen data op, maar "vraag" ik aan de client of hij het encoding-type "gzip" heeft.
Heeft van deze 2 methodes eentje de voorkeur? Is daar een "stelregel" voor, of maakt het niks uit en is het net wat je zelf leuk vindt?
2e voorbeeld.
Je hebt hierdoor als het ware meerdere niveaus in collecties:
• client <--> server
• client{request} <--> server{response}
• client{request{content-encoding}} <--> server{response{compression}}
Misschien een ander voorbeeld verzinnen, want het eerste voorbeeld is niet per se onbruikbaar.
In een threaded language zoals C#.NET kan het bijvoorbeeld zo zijn dat je een "state" opvraagt.
Code (php)
1
2
3
4
5
6
2
3
4
5
6
if ( Obj.HasType("blaat") )
{
var calc = DoeEenBerekening();
var val = Obj.GetTypeValue("blaat");
calc.value = val;
}
{
var calc = DoeEenBerekening();
var val = Obj.GetTypeValue("blaat");
calc.value = val;
}
Het probleem wat je kan hebben is dat je eerst kijkt of "blaat" bestaat. Vervolgens zou een andere thread dat type weer verwijderd kunnen hebben door een ander request.
Vervolgens wil je wel "GetTypeValue()" aanroepen wat dan reslteert in vervelende fouten. Om dit te voorkomen heb je in die talen wel weer locking, maar het gaat om het principe.
In PHP heb je dan welliswaar niet zo zeer last van Threading problemen. Maar je zou het zelfde voorbeeld kunnen verplaatsen naar iets als wanneer je eerst checked of een record in je DB bestaat, en vervolgens haal je het er pas uit. Het zou tussen de "has" en "get" al verwijderd kunnen zijn.
Dit principe heet "Tell, don't ask". Als je meer info hier over wilt en meer voorbeeld wilt hebben dan zou ik gewoon het een en ander even doorlezen hierover:
http://martinfowler.com/bliki/TellDontAsk.html
https://www.google.nl/#q=tell+dont+ask+oop&safe=active
@Ward: je uitleg is spot on. Je hebt inderdaad een client en server als onderdeel van het request. En een response als antwoord op dat request. In de response wil je dan via het request aan de client vragen of deze bijv. gzip ondersteunt.
@D Vivendi:
Ik snap (nog) niet helemaal nog wat je bedoelt eigenlijk :-s
Wat is precies het verschil of ik vraag welke types er aanwezig zijn (situatie a) of dat ik vraag of een specifiek type aanwezig is (situatie b)? Waarom is optie b volgens het "tell don't ask" principe niet goed?
Ook nog een andere vraag:
Ik zag dat mensen cheken met strpos of een bepaalde encoding method bestaat:
Is dit niet een "tricky" manier van controleren? Stel dat er ook een encoding type "bugzip" zou bestaan, dan zou strpos een positief resultaat opleveren. Dat is dan toch geen veilige manier van controleren? Of zie ik dat verkeerd?
Niet-hoofdlettergevoelig controleren met stripos() in een Yoda-conditie met een strikte gelijkheid vind ik zelf netter. Kwestie van smaak:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3
Het zal waarschijnlijk niet mis gaan de komende 10-20 jaar, maar als je zekerheid wilt dan doe je het strikt op basis van de bovenstaande regels.
PS. zoals ward zei: niet hoofdletter gevoelig, spaties kun je negeren geloof ik
Het zal waarschijnlijk niet mis gaan de komende 10-20 jaar, maar als je zekerheid wilt dan doe je het strikt op basis van de bovenstaande regels.
PS. zoals ward zei: niet hoofdletter gevoelig, spaties kun je negeren geloof ik
Gewijzigd op 18/03/2014 13:34:11 door Dos Moonen
Ik heb al geprobeerd uit te leggen waarom je dat niet op jouw "B" manier wilt doen, maar juist volgens het "Tell, don't ask" pricipe. Er is zat leesvoer hier over te vinden, als je echt geintreseerd bent dan zoek je gewoon heel wat informatie op en neem je dat door. Daarna snap je het echt wel, het is geen rocket science.
Ik bedoel eigenlijk dit: stel dat er een comppressie methode "bugzip" bijkomt, dan zou "gzip" matchen met "bugzip". Hoe voorkom je zoiets? Strpos is toch niet echt een veilige manier om iets te controleren?
@D Vivendi:
Ik snap het principe niet. In het voorbeeld wordt gezegd dat je iets opvraagt, wat even later weg kan zijn. Echter, in dit geval haal je verder niks op. Je vraagt of de client iets ondersteunt. Het is niet zo dat de client dat het ene moment wel ondersteunt, en even later ineens niet meer. Vandaar dat ik niet begrijp op welke manier het "tell, don't ask" principe hier van toepassing is.
Al gezegd: HTTP is hier niet hoofdlettergevoelig. Als je daar omheen fietst met stripos() in plaats van strpos(), dan ben je er eigenlijk al, want de implementatie van ob_start('ob_gzhandler') in PHP controleert zelf achter de schermen al óf er een acceptabele compressie wordt gevraagd en past de gevraagde compressie vervolgens toe. Dat hoef je niet nog eens zelf na te bouwen.
Stel je hebt een string:
$string = "foo, barbarapappa";
Als je nu wil kijken of in die string de waarde "bar" aanwezig is, dan zou dat met strpos resulteren in een positief resultaat omdat barbarapappa een match oplevert. Echter, er is helemaal geen waarde "bar". Mijn idee is dan ook dat strpos geen veilige manier is om waardes in een string te controleren.
Klopt, ik heb je een link gegeven waar staat uitgelegd hoe je de accept-encoding header moet parsen. Dus als je wilt kun je het veiliger maken. De vraag is of het nodig is.
Quote:
Ik snap het principe niet. In het voorbeeld wordt gezegd dat je iets opvraagt, wat even later weg kan zijn. Echter, in dit geval haal je verder niks op. Je vraagt of de client iets ondersteunt. Het is niet zo dat de client dat het ene moment wel ondersteunt, en even later ineens niet meer. Vandaar dat ik niet begrijp op welke manier het "tell, don't ask" principe hier van toepassing is.
En wat als je ergens anders die zelfde "$client->hasEncoding()" gebruikt om vervolgens wél $client->getEncondigStrcuture()" oid aan te roepen? Dat weet je van te voren toch nooit. Wellicht heb je die methode nu niet, maar misschien wil je dat in de toekomst wel.
Het gaat hier ook om het "principe", vadaar de naam "Tell, don't ask principle". Het legt uit wat het idee er achter is, welke gevaren er achter kunnen schuilen etc. Als je die ideeën gewoon eens door lees, dan krijg je vanzelf antwoord op al die vragen.
Dan kun je uiteindelijk ook voor jezelf bepalen of je het wel of niet wilt toepassen. Het enige wat ik er mee wil zeggen is, dat mensen hier al over negedacht hebben en dat je daar meer over kan lezen als je wilt.
Gewijzigd op 18/03/2014 14:02:34 door D Vivendi
@D Vivendi:
>> En wat als je ergens anders die zelfde "$client->hasEncoding()" gebruikt om vervolgens wél $client->getEncondigStrcuture()" oid aan te roepen? Dat weet je van te voren toch nooit. Wellicht heb je die methode nu niet, maar misschien wil je dat in de toekomst wel.
Sorry, ik doe echt m'n best om te begrijpen wat je bedoelt. Stel dat ik het voorbeeld iets wijzig, misschien kan ik dan beter overbrengen wat ik bedoel, en misschien kan jij dan uitleggen wat jij bedoelt en valt bij mij het kwartje.
Laten we de encoding types vergeten, maar laten we hetzelfde voorbeeld gebruiken om de browser te checken.
We zouden dat weer op deze 2 manieren kunnen doen:
Code (php)
1
2
3
4
5
6
2
3
4
5
6
<?php
$browser = $client->getBrowser();
if ($browser === 'internet explorer') {
// doe iets
}
?>
$browser = $client->getBrowser();
if ($browser === 'internet explorer') {
// doe iets
}
?>
Of...
Jij zou kiezen voor de 1e optie, maar ik begrijp de redenering erachter niet.
Ik wil alleen weten of ie een bepaalde browser gebruikt. Zijn browser zal gedurende het request niet ineens veranderen, en als ik weet dat de browser bestaat, dan hoef ik die niet via een get method te getten. Het kwartje valt bij mij nog niet.
Dan schrijf je een kleine parser voor dit specifieke type string. Zoals Dos ook aangaf. Daarin zul je vervolgens moeten vastleggen wat een acceptabel "woord" is waarop gecontroleerd kan worden (denk aan spaties, komma's of komma's gevolgd door een spatie en kleine letters, hoofdletters of mengvormen). Tot slot controleer je of het gezochte woord voorkomt in de string.
In wezen doe je iets vergelijkbaar ook bij een regexp: die voer je een instructie met verschillende regels in een pattern, waarna die regels achter de schermen worden geëvalueerd. En als het met een regexp kan, dan hoef je zelf geen parser te schrijven. Misschien een idee?
Wat ik zou kunnen doen is de spaties verwijderen, en dan exploden:
Code (php)
1
2
3
2
3
<?php
$_SERVER['HTTP_ACCEPT_ENCODING'] = explode(',', str_replace(' ', '', $_SERVER['HTTP_ACCEPT_ENCODING']));
?>
$_SERVER['HTTP_ACCEPT_ENCODING'] = explode(',', str_replace(' ', '', $_SERVER['HTTP_ACCEPT_ENCODING']));
?>
Dan wordt het een array:
En dan is het een stuk makkelijker, want dan kun je in_array gebruiken. Maar nu moet ik dus wel eerst die string ombouwen naar een array. En ik vraag me af of dat niet een beetje over de top is.
Of je dat kunt doen met een regexp? Vast wel, maar daar ben ik nog niet zo goed in.
Quote:
14.3 Accept-Encoding
The Accept-Encoding request-header field is similar to Accept, but restricts the content-codings (section 3.5) that are acceptable in the response.
Accept-Encoding = "Accept-Encoding" ":"
1#( codings [ ";" "q" "=" qvalue ] )
codings = ( content-coding | "*" )
Examples of its use are:
Accept-Encoding: compress, gzip
Accept-Encoding:
Accept-Encoding: *
Accept-Encoding: compress;q=0.5, gzip;q=1.0
Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0
The Accept-Encoding request-header field is similar to Accept, but restricts the content-codings (section 3.5) that are acceptable in the response.
Accept-Encoding = "Accept-Encoding" ":"
1#( codings [ ";" "q" "=" qvalue ] )
codings = ( content-coding | "*" )
Examples of its use are:
Accept-Encoding: compress, gzip
Accept-Encoding:
Accept-Encoding: *
Accept-Encoding: compress;q=0.5, gzip;q=1.0
Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0
Weet je nog wat ik zei over meer maar goed te volgen kleine stapjes versus weinig complexe stappen (regex in dit geval)?
>> Weet je nog wat ik zei over meer maar goed te volgen kleine stapjes versus weinig complexe stappen (regex in dit geval)?
Ja, beter kleinere stapjes en het overzicht bewaren.