DRY – Don’t repeat yourself.
Das kennt jeder, das _sollte_ jeder wissen. Und so gut wie jeder, der etwas Ahnung hat, versucht es so oft es geht umzusetzen.
Allerdings: Das gilt nicht nur für Funktionsnamen, das DRY-Prinzip geht weiter. Es meint IMHO auch, dass man für viele ähnliche Abfragen sich am besten Wrapper baut, die dann die Anfrage an eine Funktion leiten, die die eigentliche Antwort produziert. Die Wrapper „füttern“ die eigentliche Funktion nur mit den richtigen Fragen.
Ein Beispiel: Siggi Scriptkid hat ein Klasse zur Benutzerverwaltung geschrieben, die braucht er in seinem aktuellen Projekt. Er speichert seine Benutzerdaten in einer MySQL Datenbank und muss nun seiner Klasse folgende Fragen stellen und erwartet folgende Antworten:
- Hole mir den Benutzer mit der ID 5
- Hole mir den Benutzer mit der Mailadresse xyz
- (noch viele weitere, ähnliche Fragen mehr)
Siggi schreibt also ganz fleißig Funktionen in seine Klasse:
(Stark vereinfacht, es fehlen Filtern der Usereingaben, maskieren der SQL String und vieles mehr; der Code dient nur als Beispiel!)
class User
{
public function getUserByID($userid)
{
$ressource = mysql_query('SELECT vorname, name
FROM user
WHERE userid = '.$userid);
$user = mysql_fetch_assoc($ressource);
return $user;
}
public function getUserByMailadress($email)
{
$ressource = mysql_query('SELECT ID, mail, userlevel
FROM user
WHERE mail = "'.$email.'"');
$user = mysql_fetch_assoc($ressource);
return $user;
}
}
Nun trifft man auf folgendes Problem: Die Felder der jeweiligen Rückgabe sind unterschiedlich. Auch wenn Siggi nun hingeht, und in beiden Funktionen die Felder gleich setzt, ergeben sich Wartungsschwierigkeiten:
- Was ist, wenn noch mehr, ähnliche Funktionen hinzukommen? Dann bekommt Siggi wirklich Arbeit!
- Was ist, wenn Siggi der „user“ Tabelle noch mehr Felder hinzufügen muss und es 6 Funktionen gibt?
- Was ist, wenn Siggi auch nur eine der Funktionen vergisst?
Um es kurz zu machen: Hier greift das DRY-Prinzip NICHT! Der o.a. Code sollte einem Entwickler, der nicht Siggi Scriptkid heißen möchte, nicht passieren.
Aber wie wende ich das DRY-Prinzip nun an?
Okay, ich schreibe mal meinen Vorschlag dazu:
class User
{
public function getUserByID($userid)
{
return $this->getUser('ID='.$userid);
}
public function getUserByMailadress($email)
{
return $this->getUser('mail='.$email);
}
private function getUser($where)
{
$ressource = mysql_query('SELECT ID, vorname, name, mail, userlevel
FROM user
WHERE '.$where.'
LIMIT 1);
$user = mysql_fetch_assoc($ressource);
return $user;
}
}
Ich schaffe eine private Methode, die die Daten aus der Datenbank holt. Diese ist die einzige Methode, die das macht, somit habe ich nur eine Stelle, in der ich zukünftig Felder ändern muss, wenn sich welche ändern.
Die „alten“ Funktionen verbleiben als Wrapper-Funktionen und übergeben der privaten Funktion nur die richtigen Parameter, um ihre eigene Aufgabe erfüllen zu können. Dann leiten Sie Antwort einfach als eigene wieder zurück.
Auf diesem Wege verinfache ich die Pflege, bin in der Lage, meine alten Funktionen weiterhin nutzen zu können – mit dem Vorteil, dass nun alle Antworten einheitlich sind – und bin darüberhinaus in der Lage, sehr schnell verschiedene neue Funktionen zu schreiben, die mit neuen Fragestellungen klarkommen, z.B. Benutzer mit E-Mail x und Passwort y.
Was haltet ihr von dieser Vorgehensweise. Ich selbst halte sie für praktiabel und gut, was meint ihr? Gut? Schlecht? Gibt es bessere Vorgehensweisen?