PHP_INT_MAX, kein PHP_INT_MIN und ein WTF

Bei der Prüfung von Usereingaben sollte man Zahlen auch dahingehend vergleichen, ob diese auch noch überhaupt im erlaubten Bereich liegen.

Nach oben kein Problem

Ob eine Zahl zu gross wird kann man relativ leicht mit PHP-Bordmitteln feststellen.


if (PHP_INT_MAX<=$meineZahl) {
//...
}>

Damit läßt sich schnell und einfach feststellen, ob eine Zahl den erlaubten Integer-Höchstwert von 2147483647 übertrifft oder eben nicht.

Interessant ist übrigens, dass Zahlen, die über PHP_INT_MAX hinausgehen zu einem Float werden – somit könnte man auch entsprechend den Datentyp vergleichen und darüber dann eine Schlussfolgerung ziehen. Man kann weiterhin ganz normale Größenvergleiche durchführen, allerdings sollte man bei der Nutzung von Filterfunktionen aufpassen:


$ergebnis = filter_var($variable,FILTER_SANITIZE_NUMBER_INT);

Das Beispiel liefert dann keinen Integer mehr, sobald $variable größer PHP_INT_MAX wird und somit könnten entsprechende Vergleiche fehlschlagen.

Eine entsprechende Max-Funktion für Float – PHP_FLOAT_MAX – gibt es leider nicht.

Ein Blick nach unten

Nun könnte man meinen, es gäbe auch ein PHP_INT_MIN, doch #meep#, leider nicht. Warum auch immer: Es gibt keine entsprechende Min-Funktion für Integer!

Kurios wird auch das verhalten des Typs, wenn man sich der Untergrenze des Int-Bereiches nähert. Während man nach oben recht einfach prüfen kann, ob man sich im normalen Bereich aufhält – ob nun durch PHP_INT_MAX oder eine Typprüfung auf int bzw. float – ist das im negativen Zahlenbereich so eine Sache, aber erstmal etwas Code:


$minzahl = -2147483647;
var_dump($minzahl);
var_dump($minzahl-1);

$minzahl = -2147483648;
var_dump($minzahl);
var_dump($minzahl-1);

Das Ergebnis?


int(-2147483647)
int(-2147483648)

float(-2147483648)
float(-2147483649)

Wie man sieht, ist sich PHP nicht so ganz einig, welchen Datentyp denn nun die Zahl –2147483648 hat, Integer oder Float – vielmehr kann in diesem Grenzbereich auch keine Aussage treffen, ob man nun den Bereich unterschreitet oder nicht – zumindest nicht ohne Zuhilfenahme einer Konstanten.

Neues Mobile – Template

Ich habe nun endlich auch eine vernünftige Mobilversion meines Blogs. Bei Blogger kann man diese (derzeit noch) neue Funktion aktivieren, indem man über die Adresse http://draft.blogger.com geht und sich dort mit seinen Blogger-Daten einloggt oder direkt eingeloggt draufklickt.

Hier mal ein Screenshot vom derzeit aktuellen Mobilthema:

Das ganze ist derzeit noch im „Draft“-Status. Sobald Google die neuen Blogger-Funktionen bereitstellt, die derzeit schon in den USA aktiviert werden, wird sich das ganze sicher noch farblich besser anpassen lassen.

Ich finde das ganze schon jetzt super, vor allen Dingen viel besser auf einem Smartphone lesbar als die „normale“ Seite, die man dann nicht mehr lesen kann.

Und an der Stelle gleich mal meine Frage: Wer schaut sich dieses Blog in der Mobilfassung an und wie findet ihr dieses neue Mobilthema? Würde mich ehrlich interessieren.

sprintf und float-Zahlen in mySQL-Querys

Floats, also Fließkommazahlen, in eine DB zu schreiben sollte man können. Dachte ich bis vor kurzem 😉

Und deshalb, vor allem als Hinweis an mich selbst: Falls ein Query mit einem – vorher bereits vom Punkt befreiter, das Komma in Punkt umgewandelten – String plötzlich nicht mehr korrekt ausgeführt wird, dann liegt das höchstwahrscheinlich an zwei Sachen; allein, eine war mir dann neu:

  1. Du übergibst deinem Query die Parameter via sprintf (oder äquivalenten davon) und (jetzt kommt das neue)
  2. dein Server spricht plötzlich Deutsch!

Um einen fehlerhaften Query aber dauerhaft zu vermeiden, setze ich vor meinen Query nun die Sprache des Systems auf die Sprache der Datenbank und dannach wieder zurück. Den Quellcode habe ich stark vereinfacht mal hier angefügt.


// Wechsel zur internen Sprache der DB, als Beispiel fest im Code
$old = setlocale(LC_NUMERIC, NULL);
setlocale(LC_NUMERIC, 'us_US');

// Query ausführen. Werte im Query werden via sprintf eingegeben
// ...

// Zurück zur normalen Einstellung
setlocale(LC_NUMERIC, $old);

Ich hoffe, ich kann damit mal jemanden aus der Patsche helfen, wahrscheinlich bin ich aber wieder mal selbst mein bester Kunde 😉

String mit array-strings durchsuchen – Performance der Funktionen

Ich suche in einem String nach Teilstrings, die ich in einem Array habe. Die Funktion array_search macht leider genau das Gegenteil, deshalb brauche ich an dieser Stelle eine eigene Funktion.

Doch welche String-Suchfunktion verwende ich?
Zur Auswahl stehen folgende Funktionen, sollte ich was vergessen haben bitte ich um kurze Meldung:

Hier mal der Versuch einer Messung, wie schnell die Funktionen ihre Arbeit erledigen. Dazu lasse ich alle Funktionen nacheinander den String durchsuchen, das ganze mache ich je Funktion 9999 mal, um eine Tendenz sichtbar zu machen. Und ja: Quick and Dirty Code, ich bin mir dessen bewusst.


$arrHaystack = array( 'hallo',
'welt',
'foobar',
'php5',
'suchfunktion',
'bob',
'und',
'alice',
'suchen',
'strings',
'in',
'arrays',
'Lorem','ipsum','dolor','sit','amet','consetetur','sadipscing','elitr','sed','diam','nonumy','eirmod','tempor','invidunt','ut','labore','et','dolore','magna','aliquyam','erat','sed','diam','voluptua','At','vero','eos','et','accusam','et','justo','duo','dolores','et','ea','rebum','Stet','clita','kasd','gubergren','no','sea','takimata','sanctus','est','Lorem','ipsum','dolor','sit','amet','Lorem','ipsum','dolor','sit','amet','consetetur','sadipscing','elitr','sed','diam','nonumy','eirmod','tempor','invidunt','ut','labore','et','dolore','magna','aliquyam','erat','sed','diam','voluptua','At','vero','eos','et','accusam','et','justo','duo','dolores','et','ea','rebum','Stet','clita','kasd','gubergren','no','sea','takimata','sanctus','est','Lorem','ipsum','dolor','sit','amet','Lorem','ipsum','dolor','sit','amet','consetetur','sadipscing','elitr','sed','diam','nonumy','eirmod','tempor','invidunt','ut','labore','et','dolore','magna','aliquyam','erat','sed','diam','voluptua','At','vero','eos','et','accusam','et','justo','duo','dolores','et','ea','rebum','Stet','clita','kasd','gubergren','no','sea','takimata','sanctus','est','Lorem','ipsum','dolor','sit','amet','Duis','autem','vel','eum','iriure','dolor','in','hendrerit','in','vulputate','velit','esse','molestie','consequat','vel','illum','dolore','eu','feugiat','nulla','facilisis','at','vero','eros','et','accumsan','et','iusto','odio','dignissim','qui','blandit','praesent','luptatum','zzril','delenit','augue','duis','dolore','te','feugait','nulla','facilisi','Lorem','ipsum','dolor','sit','amet','consectetuer','adipiscing','elit','sed','diam','nonummy','nibh','euismod','tincidunt','ut','laoreet','dolore','magna','aliquam','erat','volutpat');

$iIterations = 100;
$suchsatz = array('meas magna','mia diam','im garten sind bob und alice','elixier des nichts');

$iMax = count($suchsatz);
$iStart = microtime(1);

for ($i=0;$i<$iIterations;$i++)
{
$iTake = mt_rand(0, $iMax);
foreach ($arrHaystack AS $key => $value)
{
if (mb_substr_count($suchsatz[$iTake], $value)>0)
{
break;
}
}
shuffle($arrHaystack);
}
$iEnd1 = microtime(1);

for ($i=0;$i<$iIterations;$i++)
{
$iTake = mt_rand(0, $iMax);
foreach ($arrHaystack AS $key => $value)
{
if (mb_stripos($suchsatz[$iTake], $value)!==FALSE)
{
break;
}
}
shuffle($arrHaystack);
}
$iEnd2 = microtime(1);

for ($i=0;$i<$iIterations;$i++)
{
$iTake = mt_rand(0, $iMax);
foreach ($arrHaystack AS $key => $value)
{
if (mb_stristr($suchsatz[$iTake], $value)!==FALSE)
{
break;
}
}
shuffle($arrHaystack);
}
$iEnd3 = microtime(1);

for ($i=0;$i<$iIterations;$i++)
{
$iTake = mt_rand(0, $iMax);
foreach ($arrHaystack AS $key => $value)
{
if (preg_match('/'.$value.'/i', $suchsatz[$iTake])>0)
{
break;
}
}
shuffle($arrHaystack);
}
$iEnd4 = microtime(1);

printf('--------------------------'."\n");
printf('mb_substr_count() -> %f'."\n",$iEnd1-$iStart);
printf('mb_stripos() -> %f'."\n",$iEnd2-$iEnd1);
printf('mb_stristr() -> %f'."\n",$iEnd3-$iEnd2);
printf('preg_match() -> %f'."\n",$iEnd4-$iEnd3);
printf('--------------------------'."\n");

Hier die Ergebnisse:
————————–
mb_substr_count() -> 15.756097
mb_stripos -> 16.490042
mb_stristr -> 16.938911
preg_match -> 14.681287
————————–

Schön zu sehen, dass meine intuitiv gewählte Funktion mb_substr_count() die Arbeit anscheinend am schnellsten erledigt. Überraschend für mich, dass der regex Platz 2 belegt und dass die anderen Funktionen einen so großen Abstand zu den beiden ersten Plätzen aufweisen.

Update 08.01.2011:
Habe den Code mal den Kommentaren angepasst. Das Array der Wörter ist nun 240 Felder groß, es wird nun auch zufällig einer von 4 Sätzen durchsucht. Nach jedem Treffer wird das Wort-Array zufällig neu ‚geschüttelt‘. Das sollte alle Caching-Sachen ausschalten.

Dabei bildet sich wirklich ein neues Bild (bei 100 durchläufen). Platz 1 geht nun an den regex, Platz 2 an substr_count, dicht gefolgt von den beiden stri-Funktionen. Insgesamt ist aber kein nennenswerter Abstand mehr vorhanden (im Gegensatz zum ersten Test), weshalb ich sagen kann: Nehmt, womit ihr am besten klarkommt. In High-Performance Umgebungen folgt dem Testergebnis.

Secondary Drive 0 not found

Kennt jemand diese Meldung?
Secondary Drive 0 not found

Bei mir trat diese Meldung nach einem Festplattenwechsel auf. Meine alte IDE Platte war mit 80GB wirklich etwas klein geworden, also kommt eine neue SATA 500GB rein (WD Caviar Black, nettes Ding, schnell, leise, toll).

Also, neue Platte rein, Festplatte kopieren mit dem Paragon Partition Manager (ich bekomme da kein Geld für, ich poste den Namen, weil ich das Tool toll finde und ich dafür seinerzeit kein Geld bezahlt habe, weil es auf einer Heft-CD als Vollversion dabei war – ich wollte von der HeftCD aber eine andere Vollversion, deshalb sage ich, dass ich da eigentlich kein Geld für bezahlt habe und ich merke grade, dass ich abschweife*). Bis hierhin alles okay, 80GB in weniger als einer Stunde kopiert, super!

Dann die alte Platte ab und siehe da: Es kann aus o.a. Grund nicht gebootet werden.

Langer Rede kurzer Sinn: Die Lösung war, dass ich alte IDE Kabel vollständig entfernen musste und dann auch das Gerät (die SATA Platte) im BIOS richtig einstellen musste (nix mit Auto-Erkennung, war wohl zuviel für meinen alten Dell).

Nun rennt in einem 8 Jahre alten Rechner eine neue Festplatte mit neuer und schneller SATA Technik. Manches ist wirklich schneller geworden, u.a. der Startvorgang, manchen ist immer noch lahm, aber so ist das Leben. Auf jeden Fall: Mein Rechner funktioniert wieder und hat mehr Platz.

Ich hoffe, ich kann hiermit evtl. mal jemanden aus der Patsche helfen…

* Eine Mythenmetzsche Abschweifung muss aber erlaubt sein 😉

KISS – oder wie umständlich muss es noch werden?

Passend zum DRY-Artikel nun der zum Thema KISS. Nein, nicht die Rock-Band-KISS, sondern ein Prinzip der Softwareentwicklung, das besagt: „Mache es so einfach wie möglich!“.

Immer wieder sehe ich Code, der akademisch bestimmt mit Note 1 ausgezeichnet wird. In Java, C++, Delphi oder anderen compilierenden Sprachen hat das ganze auch durch seinen Sinn und seine Daseinsberechtigung. Aber in PHP sieht die Sache anders aus.

PHP ist eine Interpretersprache und wird es auf absehbare Zeit auch erstmal bleiben. Interpretersprachen haben im Grundprinzip eines gemeinsam: Sie durchlaufen den Code während der Ausführung Zeile für Zeile, Schritt für Schritt. Und genau da liegt der Schwachpunkt: Je mehr Zeilen ein Code hat, desto länger braucht der Interpreter, den Code zu durchlaufen. Je länger der Interpreter braucht, umso größer wird die „Time-to-Response„, also diejenige Zeit, die zwischen Anforderung an den Server (Aufruf der Seite) und Antwort des Servers (Auslieferung der Seite, also des generierten Quelltextes) liegt. Und diese Zeit sollte „as small as possible“ sein (wer wartet schon gern auf seine Seite).

Dieses Problem potenziert sich meist, da der normale User erstmal eine (allgemeine) Startseite ansurft und sich dann durch die Seite bewegt; dabei ruft er meist spezialisierte Seiten mit mehr Aufgaben für den Server auf. Mehr Aufgaben, mehr Inhalt, mehr Code, länger warten, nicht gut!

Warum nun das ganze hier im Zusammenhang mit PHP?
In PHP lassen sich selbstverständlich schöne Objektorientierte Konstrukte bilden, die auch von vielen Seiten als „richtig“ proklamiert werden. Ein Beipiel sei dies (in Pseudocode, nicht wundern):



holeBenutzerdaten();
// mach was damit


// ab hier nun die funktionen, diese liegen alle
// in unterschiedlichen klassen, dateien usw.

function holeBenutzerdaten()
{
prüfeEingabe();
ladeBenutzerdaten();
return;
}

function prüfeEingabe()
{
prüfeSpezifischeEingabe;
ladeIrgendwasUnwichtiges;
prüfeNochmal;
}

function prüfeSpezifischeEingabe()
{
prüfeObEingabeValideIst
ja: prüfeDieEingabeNochmalMitWasAnderem
nein: ladeFehlerbehandlung; gibFehlerAnFehlersystem; zeigeFehler;
}

// So, und nun noch 20 Dateien mehr und ca. 60 Funktionsaufrufe

Nicht schön, denn hier wird, anstatt das Problem zu erledigen, von einer Funktion zur nächsten gesprungen. Unschön dabei: Jede Zeile kostet Zeit und die gilt es in einem guten Projekt so gering wie nur möglich zu halten.

Es gilt das Prinzip: So viel wie nötig, so wenig wie möglich! Nicht mehr, nicht weniger. Dazu aber noch später mehr.

Und nun Beispiel 2: Die reine Lehre sagt, dass veränderliche Werte in Variablen abgelegt werden sollen und diese Variablen dann an einen einheitlichen Ort. Nennen wir das mal „Config-Dateien“, dann kann sich jeder was drunter vorstellen. Diese Config-Files kennen wir alle, meist stehen da mindestens die MySQL Zugangsdaten drin, manchmal auch noch was anderes, zumeist belangloses. Das ist soweit auch gut und richtig und sollte – in einem gewissen Rahmen – auch gemacht werden … allerdings sollte man es dabei nicht übertreiben.

In diesem Beispiel möchte ich zeigen, wie man – unter dem Aspekt des Konfigurierens und Auslagerns – eine ganz simple Sache sehr kompliziert machen kann … und dafür in gewissen Kreisen sicherlich noch großen Beifall ernten wird.

Urspung des ganzen ist ein Aufruf, ähnlich wie dieser:


mysql_query("SELECT * FROM user");

Warum schreibt nun in die Config-Dateien nicht rein, wie die Tabellen heißen und benutzt dann nicht den statischen Wert, sondern die Variable? Und warum nehmen wir dann nicht eine Funktion? Die kann man dann immerhin noch mit Unit Tests auf ihre korrekte Funktion testen!? Das sieht dann so aus:


public function getTbluser() { return 'meineUserTabelleInMysql'; }

und die kann man dann so nutzen:


mysql_query("SELECT * FROM ".getTbluser());

Toll, oder? Ändert sich nun der Tabellenname, dann muss man das nur an einer Stelle ändern und gut ist. Kommt doch dem DRY-Prinzip zugute.
Noch besser wäre es doch, wenn wir nun auch alle Feldnamen in festlegen … weil … die können sich ja auch ändern. Also los, Feldnamen auch. *tipptipptipp* Toll. Ach ja, die Variablennamen könnten sich ja mal ändern. Also auch die rein und per $$ eingebungen, damit es auch geht.

Und der Code sieht dann doch gleich viel … übersichtlicher aus:


mysql_query("SELECT ".getTblUserField1().",".getTblUserField2()." FROM ".getTblUser()." WHERE ".getTblUserFieldSort()." = $$configFileTblUserFeldSort");

Super, oder? Kommt man nun noch dazu, diese ganzen, sich ständig verändernden SQL Kommandos noch zu ersetzen, dann hat man doch ein völlig einfach konfigurierbares System vor sich, oder etwa nicht?

Ihr merkt es schon, ich drifte ins Zynische ab – aber nur gaaanz leicht, das mag daran liegen, dass ich von diesem Code in letzter Zeit zu viel gesehen habe – , nochmal also zur Klarstellung:
Nein, so macht man es nicht!

Warum nicht? Dazu gibt es gleich mehrere Punkte.
Zum einen kann man es nicht mehr lesen. Das ist ein sehr wichtiger Punkt, unterschätzt das nicht, denn zum einen sitzt ihr nicht bis in alle Ewigkeit an einem Code – nichts ist schlimmer, als nach Monaten wieder alten Code lesen zu müssen und nicht zu verstehen – und zum anderen werdet ihr an der Qualität eures Codes auch innerhalb der Entwicklungsabteilung gemessen! Schwer verständlichen Code zu schreiben mag einen Marketing-Menschen noch leicht beeindrucken können, ein guter Programmierer dagegen wird euch – wenn ihr Glück habt nur leise – verfluchen.

Zum anderen muss der Interpreter jedesmal wieder in die entsprechende Funktion springen und das braucht Zeit. Nein, viel ist das nicht, wenn das nur eine Tabelle ist, nur ganz, ganz wenig Zeit, wirklich. Allerdings: Hat man erst so eine schöne Funktion, die einem die entsprechenden Tabellen und Felder referenziert, dann benutzt man das doch nicht nur für die Abfrage selbst, nein, auch im Code kommen dann anstelle der Feldnamen die Funktionsnamen vor.


$res = mysql_query("SELECT ".getTblUserField1().",".getTblUserField2()." FROM ".getTblUser()." WHERE ".getTblUserFieldSort()." = $$configFileTblUserFeldSort");
$name = $res[getTblUserField1()];
// anstelle von
// $name = $res['name'];

(ja, ich weiß, dass da ein mysql_fetch_irgendwas fehlt)

Und das für jede Tabellenabfrage im Code … und jedes Feld … in jeder Abfrage … und dazu noch in jedem Kontrollkonstukt im Code, also jeder for-Schleife, jeder Ausgabe, in jedem if, in jedem switch und und und … Leute, das summiert sich. Da kommen schnell dutzende Funktionssprünge vor und das sind Zeiten, die nicht sein müssen!

Warum sollte meine Anwendung langsamer sein, als es sein müsste. Die wird von ganz allein langsamer, sobald nämlich immer mehr Benutzer gleichzeitig was wollen, dann summieren sich die Zeiten nicht nur, nein, die multiplizieren sich mit jedem Request! Also, jeder Flaschenhals ist es wert, dass er refaktorisiert wird. Warum nicht gleich von Anfang an alles richtig machen?

Und mal ehrlich: Wie oft ändern sich die Tabellennamen und man ihr als Entwickler müsst wirklich nur die Configs ändern? Na, ehrlich, komm *inDieSeiteStubs* Na also, noch nie gesehen, jede Umstellung der Tabellennamen hatte schon immer eine mehrstündige Umstellungsphase begründet … zusammen mit dem Verlust einiger wichtiger Gramme Körpergewicht 😉

Und hatten wir nicht eben erst erwähnt, wie wichtig die Lesbarkeit des Codes ist? Sicher, ihr habt das Projekt grade erst begonnen und wisst noch alles aus dem Kopf. Aber, wie gesagt, ihr seit meist nicht allein an einem Projekt und – selbst wenn – auch nicht immer „am Stück“ dabei. Euer Kollege würde gern wissen, warum ein bestimmter Request langsam ist oder gar nicht funktioniert und schaut im Code noch und trifft auf so einen Query. Nun muss erstmal mühsam der eigentliche, der „echte“ Query zusammengebaut werden, denn der Kollege hat keine Ahnung, welche Felder ihr ansprecht.

Aber der Tabellenname könnte sich doch mal ändern!
Warum sollte sich der Tabellenname ändern? Ja, auf Shared-Hosting-System kommt es schon mal vor, dass man in einen Webspace viele Webanwendungen packt und da kann es auch vorkommen, dass mehrere Anwendungen ihre Benutzertabelle eben ‚user‘ nennen. Warum auch nicht, es ist der passendste Name dafür! In solchen Fällen – wenn ich also weiß, dass so eine Situation eintreten kann – benutze ich die Option eines Praefix, der jedem Tabellennamen vorgestellt wird und an zentraler Stelle definiert ist.


// Im Config-File
define('DB_PRAEFIX','myPraefix_');

// Im Code
mysql_query("SELECT * FROM ".DB_PRAEFIX."user");

Das hat den Vorteil, dass man den SQL immer noch lesen kann und auch die Tabelle auf dem DB-Server wiederfindet, auch wenn man keine Kenntnis über den Inhalt von DB_PRAEFIX hat. Der Code bleibt lesbar und so ziemlich jeder Entwickler weiß auch, warum ihr das macht.

DAS ist es zum Beispiel, was dass KISS Prinzip sagt: Macht es einfach! Nicht nur euch, sondern auch anderen. Nein, ihr sollt nun dabei nicht vergessen, Sicherheitsmechanismen einzubauen oder Usereingaben zu filtern, wir wollen auch nicht zurück ins PHP3 Monolithen-Zeitlalter, aber dazu bedarf es keiner Funktion, die eine Funktion aufruft, die eine Funktion aufruft, die wiederum … ihr ahnt es schon.

Meine KISS Anforderungen sind ungefähr diese

  • – Die Gesamttiefe der Funktionsaufrufe darf 3 Ebenen nicht überschreiten (die aufgerufene Seite nicht eingeschlossen). Je weniger, desto besser.
  • – Funktionen sollten so wenig wie nötig aufgerufen werden
  • – Funktionen sollten etwas machen, nicht nur Namen liefern (return ‚tbluser‘; )
  • – Funktionen sollten das machen, wofür sie da sind. Nicht mehr!

„Klar“, sagt nun jeder, „aber wie bekomme ich dies oder das dann hin, das geht dann gar nicht mehr“.
Bei vielen dieser Fragen kann man sagen, es ist die berühmte Ausnahme von der Regel und sicherlich ist hier und da eine Ausnahme sicherlich ratsam. Man soll schließlich das ganze gerede und die ganzen schönen Buzzwords nicht als „In-Stein-gemeisselt“ verstehen. Leider zeigen viele dieser Ausrufe aber auch, wie groß die Abhängigkeit von bestimmten Frameworks oder Programmierparadigma ist.

Ich will hier keine Diskussion auslösen über Sinn und Unsinn von Frameworks oder Paradigmen, ich zeige – wie so oft in der Softwarearchitektur – das Optimum. Der Rest liegt bei euch, der Weg ist das Ziel 😉

Über eure konstruktive Meinung dazu würde ich sehr freuen – obwohl ich mehr mit empörten Kommentaren rechne *schnellUnterDenTischDuck*!

Pattern? Sowas mache ich nicht!

Der PHP Hacker fragt „Haben Pattern versagt?“ und hier ist mein Senf dazu.

Mag jetzt auch mal ein wenig den Stil der „anonymen Programmierer“ haben, aber ich programmiere nicht mit dem Ziel, ein bestimmtes Pattern umzusetzen, sondern mit dem Ziel, ein bestimmtes Problem zu lösen. Dies mache ich auf dem – für mich – besten Wege und der Weg ist für jedes Problem, sogar für jeden Kunden, anders. Meist weiß ich gar nicht, dass ich gerade ein bestimmtes Pattern umsetze oder dass der Weg, wie ich etwas mache, schon einen „XY Pattern“ namen hat.

Schande über mich – ich würde bei dem im Artikel genannten Recruiter wohl keinen Job bekommen – aber meine Fragen wären wirklich:

  1. Muss man Pattern (auswendig) kennen, um gut programmieren zu können?
    Sicher sind Kentnisse über „best practices“ – und aus diesen sind die Pattern ja entstanden – hilfreich, aber muss ich deswegen gleich „in Pattern denken“? Sicher nicht.
  2. Ist es sinnvoll, auf Biegen und Brechen ein Pattern umzusetzen, auch wenn die Problemlösung darunter leidet?
    Ganz klar: Nein! Das Pattern sollte sich immer der Problemlösung unterwerfen! Was nützt es mir, dass mein Code in 2.000 Zeilen das XY Pattern sauberst umgesetzt hat, die Problemlösung aber nur 20 Zeilen lang gewesen wäre (und kein Spagetthi-Code ist!).
  3. Muss ich mich nun schämen weil ich das XY Pattern nicht kenne oder bin ich etwa kein guter Programmierer?
    Ich denke, es kommt drauf an. Wenn man die „best practices“ versucht umzusetzen und sauberen, lesbaren, skalierbaren und funktionsfähigen Code schreibt, dann muss man nicht unbedingt sagen können, dass dies nun teilweise X, Y und Z Pattern darstellt. Es kommt IMHO drauf an, dass der Code die o.a. Kriterien erfüllt und nicht zwanghaft Punkt 2 umsetzt.

Das wäre mein – wie gesagt – mein Senf dazu. Was denkt ihr darüber?