Archiv der Kategorie: art of code

Rethink yourself…

— Teaser —

Ich mache nun schon eine ganze Weile Software im und für das Internet – seit 1999 um genau zu sein – und heute muss ich meinem Herzen mal Luft machen.
Liebe Juniors, liebe Seniors: Hört auf, mein Internet kaputtzumachen.

— Kleiner Exkurs – Wie alles begann —

Als ich anfing, professionell Software zu entwickeln (ich also Geld für etwas bekam, was ich gerne machte), da schrieb man das Jahr 1999 – es ist also schon eine Weile her. Damals™ war das Netz noch recht neu im Massenmarkt, es gab keine Androiden oder iPhones und Webseiten rief man auf dem Computer zu Hause mit einem Browser ab. Die Leitung in dieses neue Netz war eher langsam und kostete dazu in Deutschland sowohl einen monatlichen Festbetrag als auch noch einen Geldbetrag pro Zeiteinheit (meist ein paar Pfennige pro Minute, lies bei Wikipedia nochmal über die Deutsche Mark nach, wenn dir Pfennige nichts sagen). Kurzum: Zeit war ein doppelt treibender Faktor in diesem Internet. Zum einen war Zeit kritisch, weil die Leitung nicht so schnell war (ein winziger Bruchteil heutiger Technik) und zudem war es auch noch teuer, je länger man online war (Flatrates kamen erst später).

In diesem Umfeld bekam ich nun Kontakt mit dem Internet und lernte, wie die Technik zur Darstellung von Webseiten funktioniert, was das TCP/IP Protokoll ist (und warum dieses Protokoll so toll ist, bis heute) und was alles zwischen dem „ich drücke enter, nachdem ich die URL eingegeben habe“ und „der Browser ist endlich fertig, das Modem kann wieder aus“ so alles passiert – dies prägt mich bis heute. (Zur Erinnerung: Das Modem kann aus heißt, dass ab dann kein Geld mehr bezahlt werden musste … und es heißt auch, dass ab dann auch kein Internet mehr zur Verfügung stand; dies für die jüngeren unter euch).

Ich habe damals also – geprägt von Zeit- und Geldnot – viel gelernt, vor allem darüber, wie man die Informationen einer Webseite schnell und datenoptimiert an den Browser bringt. Generell war die Optimierung von Code an die Aspekte Schnelligkeit und Robustheit (beide sind gleichwertig zu betrachten) von großem Interesse und allgemeiner Usus, ähnlich wie heute Unit Testing zum „guten Ton“ gehört, so war es damals vor allem optimierter Code, der zum Handwerkszeug gehörte; erschien dein Code nicht optimiert, warf das kein gutes Licht auf dich und dein Können.

Das Resultat des Ganzen war Code, der schnell und stabil vom Server zum Browser gesendet wurde und dort komplett (und möglichst fehlerfrei) bis zum nächsten „Cache renew“ verbleiben konnte, damit die Leute sich deine Seite möglichst offline in Ruhe durchlesen konnten.

Wer jetzt ganz genau mitgelesen hat, der erkennt so manchen Kunstgriff, so manche Technik wieder, die heutzutage einen anderen Namen hat oder dem einfach ein neuer Anstrich gegeben wurde. Im Kern ist es aber nichts anderes ist als das, was schon vor über 25 Jahren zum guten Ton gehört hat. Begriffe wie „Client side caching“ kommen da vor, „Server side purging“, „Load balanced optimization“ und der Begriffe vieler sagen dem ein oder anderen bestimmt etwas.

— Paradigmen —

Ouch, ein schweres Wort, ein Wort zudem, bei dem sich 10 Entwickler im Raum nicht einigen können, was es denn genau bedeutet. In diesem Fall hier bedeutet es so etwas wie „verschriftlichte best practices“ im Sinne von: Wir haben damals viel ausprobiert, viel gelernt und haben versucht, dass, was sich als das Beste herauskristallisiert hat, niederzuschreiben, damit es die Leute nach uns nicht so schwer haben. Damit da etwas ist, woraus diese neuen Leute schneller lernen können und die alten Fehler nicht wieder machen (denn das spart Zeit, mit denen man wieder neue Wege beschreiten kann).

Eines dieser alten und fast vergessenen Paradigmen heißt abgekürzt YAGNI und ausgeschrieben steht es für „you aint gonna need it“ und bedeutet soviel wie „du brauchst das nicht“. Meistens wird dies zusammen mit einem anderen Paradigma gebraucht, dem KISS-Prinzip, was für „keep it simple stupid“ (hier kommt wahlweise ein Komma hin oder auch nicht, ist aber für den weiteren Verlauf nicht weiter wichtig). KISS soll einem sagen, dass man Dinge einfach halten soll, sprich: Gibt es mehrere Lösungswege für ein Problem, dann nimm das simplere. Klingt doch logisch, oder? Wer befasst sich gern mit schwierigen Lösungen, wenn es eine einfachere gibt, die genauso funktioniert. Der letzte Teil ist übrigens wichtig, denn zur Entscheidung, ob ich eine einfachere Lösung nehmen kann, bedarf es natürlich der Forderung an diese Lösung, dass diese bitte auch mein Problem lösen soll. Eine einfache Lösung, die mein Problem nicht oder nur zum Teil löst, ist nutzlos wie eine leere Rolle Toilettenpapier – theoretisch machbar, praktisch aber nicht zu empfehlen.

Bewaffnet mit dem Wissen um diese alten „best practices“ können wir nun einen Schritt weiter gehen.

— Wie Webseiten funktionieren —

Der technische geneigte Leser möge mir verzeihen, wenn ich in diesem Kapitel nur ganz grundsätzlich auf die Funktion des technischen Ablaufes eingehe, aber dieser reicht für ein grundsätzliches Verständnis zum Thema sicherlich aus, ohne den nicht-technischen Leser zu überfordern.

Prinzipiell funktioniert das Netz so, dass „ich“ als Benutzer eine Ressource bei einem Server anfordere und dieser mir eine Information zusendet, ob er mir diese ausliefern kann oder nicht (und dann auch, warum nicht). Im Weiteren gehen wir mal davon aus, dass wir keinen technischen Defekt haben und alle Ressourcen, die wir haben wollen, auch da sind, wo wir diese anfordern.
Ist eine Ressource vorhanden, dann liefert mir der Server eine Information dazu (200-OK) und meistens auch eine Antwort im „body“ welches dann die Ressource ist (ich sagte ja, ganz stark vereinfacht).

Im speziellen Fall einer Webseite können dies folgende Dinge sein:
– Die Seite selbst
– Zur Seite gehörende Dinge wie
— CSS
— Javascript
— Bilder
— sonstiges

Und eines ist noch gut zu wissen: Oben sprach ich von „ich“. Dieses „ich“ in diesem Fall der Browser. Dieser sendet eine Anfrage an den Server, der Antwortet dann und der Browser muss mit dem Ergebnis dann umgehen (und ggf. noch mehr Ressourcen nachladen).
Nur: Was macht der Browser denn da genau?

— Was der Browser spricht —

Der Browser, heutzutage ein Zwiespalt zwischen Chromium-basierten und dem Firefox, kann im Prinzip nicht viel mehr als es schon Browser in der alten Zeit konnten: Er kann HTML.
HTML – die „Hypertext Markup Language“ – ist das Grundgerüst jeder Webseite. Jeder. Wirklich.
Im Prinzip kann der Browser ohne HTML keine Webseite darstellen und egal auf welcher Seite im Netz du bist, du kannst ja mal in deinem Browser auf „Quelltext anzeigen“ gehen und siehst: Ja, HTML, definitiv.

Ok, der Browser kann auch noch ein paar Dinge mehr, dazu gehören z.B. Bilder anzeigen, Töne abspielen, Styles „verstehen“ und JavaScript interpretieren. Was braucht man sonst noch für eine Webseite, egal welche? Genau, nichts mehr. Das war’s. Alle Webseiten bestehen aus diesen Dingen.

Du brauchst ein Grundgerüst aus HTML, damit der Browser überhaupt etwas damit anfangen kann. In diesem HTML stehen dann diverse Dinge, zum Beispiel auch, ob der Browser noch etwas nachladen soll, nachdem er mit dem HTML interpretieren fertig ist. Dazu können Stylesheets gehören – die CSS Dateien – oder auch JavaScript, was eine Seite wieder dynamisch erscheinen lässt.

Aber die erste Sache, der Browser macht, ist HTML laden und interpretieren.

— Damals zu heute —

Die ersten Seiten im Netz bestanden nur aus HTML und dienten in erster Linie dem Informationsaustausch. Das Besondere an diesem Austausch war, dass man nicht nur Informationen darstellen konnte und sie „jeder“ (der es sich leisten konnte) abrufen konnte. Vielmehr war es die fantastische Möglichkeit, diese Informationen auch in Beziehung zueinander zu stellen. Das heißt, sprach man in einer Seite z.B. von Wikipedia, dann konnte man eine Beziehung zu einer anderen Seite herstellen, die dann diesen Begriff näher, tiefer, besser erklärte, so dass man seinen eigenen Kontext nicht immer wieder für Erklärungen verlassen musste. Eine tolle Sache, heute kennt man das als „Links“ auf Webseiten.

Ein wenig später kam dann der Wunsch auf, Seiten nicht mehr nur um ihrer Information wegen ins Netz zu stellen. Es kam – wie bei den meisten Dingen – auch darauf an, sie „schön“ zu präsentieren, was nach ein paar kurzen Irrungen und Wirrungen zu dem führte, was die meisten als CSS kennen. Die Möglichkeit, die Inhalte im HTML vom HTML getrennt gestalten. So sahen dann die Informationen ein wenig besser aus und konnten (manchmal, nicht immer) leichter gelesen werden.

Irgendwann zwischen „Wir haben das Internet erfunden“ und heute kam jemand auf die Idee, in diesem Internet doch auch dynamische Inhalte sehen zu wollen. Bis dahin war das Netz recht statisch. Es gab Seiten, Seiten standen in Beziehung zu anderen Seiten, aber im Prinzip hat sich eine Seite, war sie einmal online, nicht mehr geändert … zumindest nicht von selbst.
Die Technologie, die dynamische Inhalte ermöglichte, ist bis heute unter dem Namen „JavaScript“ bekannt (und nochmal: JavaScript hat nichts mit Java zu tun!!1!).

Diese Dinge, von erfahrener Hand respektvoll zusammen gefügt, ergaben zumeist informative Seiten, die überdies auch noch schön waren. Denkt man, in der Masse waren es meist blinkende Terrorwüsten ohne Inhalte, dagegen sind Cookie-Banner schon unaufdringlich – aber ich schweife ab, lassen wir uns die Illusion, dass die Webseiten mit HTML, CSS und JS gut funktionierten und ihren Sinn erfüllten.

Hier könnte die Geschichte nun zu Ende sein … wenn da nicht der „Ruf der Experten“ gekommen wäre.

— Berühmte Zitate —

Berühmte Zitate sind auch sowas wie „best practices“, allerdings nicht mit lehrender- sondern mit mahnender Funktion.
Besonders gut passt hier „Der Weg zur Hölle ist mit den besten Absichten gepflastert“, was uns so langsam in die Neuzeit des Netzes bringt.

— Soziale Medien als Motor —

Irgendwann nach 2010 (dem Datum des ersten iPhones und damit dem Massendurchbruch des mobilen Internets und damit dem Vormarsch sozialer Medien) kamen Entwickler der sozialen Medien auf Ideen, um Ihre Webseiten (nichts anderes ist ein soziales Medium technisch gesehen) schneller und effektiver an jedermann zu bekommen. Mobiles Internet war damals teuer (ähnlich wie das Internet generell ein paar Jahre vorher auch zu Hause) und damit die Leute die sozialen Medien auch unterwegs gern (und damit viel) benutzen, mussten die Seiten schnell geladen werden (auch das passt zu den Erfahrungen der Jahre vorher). Soziale Medien aber möchten auch viele Informationen an den Mann bringen, was zunächst dem Prinzip des „schnell“ eher entgegengesetzt ist. Wie bekommt man nun „schnell“ und „viel“ übereinander?

Das überlegten sich viele Leute, die Ergebnisse waren zumeist recht enttäuschend und alles andere als schnell (oder gar einfach). Dennoch, irgendwann hatten ein paar schlaue Menschen nicht nur die zündende Idee, sondern auch gleich die passende (und funktionierende) technische Lösung dafür: reaktive Webseiten. Du kennst das heute als „infinite scrolling“, d.h. du bist bei deinem Lieblingssocialnetzwork und kannst scrollen bis der Arzt kommt, es geht einfach immer weiter und weiter und weiter (auch als Doomscrolling bezeichnet). Der Trick hierbei ist, dass die Inhalte nicht im initialen Requests deines Browser zu finden sind, sondern die Dinge werden „on the fly“ immer dann geladen, wenn du am Ende der geladenen Daten bist. Heute geht das recht zügig, so dass der normale Netznutzer auch im mobilen Falle nichts oder nicht viel davon mitbekommt.
Und damit fängt das Problem so langsam an, konkret zu werden.

— Die „Lösung“ —

Massenhaft Daten dynamisch ohne Seitenwechsel nachzuladen bedeutet, dass wir mit den Standardmitteln nicht weit kommen. Daten nachladen ohne eine neue Seite zu laden bedeutet, dass wir die Daten per JavaScript nachladen müssen. An und für sich ist das nichts neues und auch, je nach Einzelfall, auch nicht per se schlecht. Es gibt durchaus Szenarien, wo das Sinn macht und auch sinnvoll ist. Das Problem eskalierte allerdings anders.

Ein großes soziales Netzwerk „erfand“ (nicht wirklich, wir vereinfachen aber mal) ein JavaScript-Framework, dessen Grundgerüst nicht mehr die Ergänzung von HTML darstellte, vielmehr begreift sich dieses Framework als Grundgerüst selbst, so dass sämtliche Arbeiten zur Darstellung der Homepage nicht mehr per HTML (und CSS und JS) getätigt werden, sondern samt und sonders in JS selbst durchgeführt werden. Für den jungen und unerfahrenen Entwickler bietet das den „Vorteil“, dass er „seine“ eine Sprache nicht verlassen muss und alles komplett „ohne Stilbruch“ aus einem Guss erledigen kann. Kein Witz, dies ist wirklich eine der Argumentationen für diese Vorgehensweise und dummerweise glauben bis heute viele Entwickler, dass das eine gute Sache wäre.

— Der Stand der Dinge —

Kommen wir nun zu den Details und damit dahin, wo es schmerzt. Nicht im Sinne von „es funktioniert nicht“, sondern im Sinne von „warum glaubt ihr, dass das eine gute Idee ist“. Kurzum, sehen wir die „Lösung“ mal an.
Der aktuelle Stand der Dinge ist der, dass viele junge Entwickler damit groß werden – und auch so ausgebildet werden -, dass alles in JS erledigt werden kann, was dann oft zu dem Irrglauben führt, dass auch alles in JS erledigt werden muss und JS-Frameworks sozusagen alternativlos sind.

Aber was passiert eigentlich bei diesen Frameworks?
Bauen wir uns doch mal ein gedankliches Beispiel: Lass uns eine Seite für eine Arztpraxis bauen, vielmehr, lass uns zwei Seiten bauen, gleiches Layout, gleiche Funktionen, das eine mit einem JS Framework, das andere klassisch.
Beim JS-Framework brauchen wir gar keines konkret heranziehen, da der Funktionskern prinzipiell gleich ist. Von daher können wir einen Pseudo-Funktionsansatz darlegen, der zur Veranschaulichung auch völlig ausreichend ist.

— Der Framework Ansatz —

Natürlich benötigen wir zunächst mal ein installiertes NodeJS nebst npm. Dann brauchen wir entsprechend natürlich auch unser geliebtes JS-Framework (hier Name einfügen) und das zieht sich dann auch gleich mal alle seine Abhängigkeiten in Form diverser JS-Pakete ran. Dabei benötigt natürlich auch jedes Paket wieder seine eigene Abhängigkeiten von anderen Paketen, die npm natürlich auch gern für uns auflöst, runterlädt und an seinen Platz in den `node-modules` Ordner legt. Allein die Vanilla für das Framework wiegt bereits jetzt eine Menge.

Dann müssen wir natürlich auch die Seite selbst bauen, d.h. wir müssen routing einstellen, (Pseudo-)Klassen anlegen, Komponenten registrieren und benutzen, alles so verpacken, dass es das Framework auch versteht und dann am Ende die Inhalte der Seite anlegen.

Anschließend laden wir alles auf unseren Webserver, stellen den entsprechend so ein, dass der auch korrekt in das Framework routet und rufen dann die Seite auf.
Wenn man sich jetzt den Spaß macht und in den Browser eigenen Entwicklertools nachsieht (drück doch mal F12, wenn du nicht weißt, wovon ich rede), dann nimmt sich der Aufruf meist recht viel Zeit und ist auch recht groß. Du siehst das ganz unten in den Entwicklertools bei den „Netzwerkanalysen“ wo steht „xyz Anfragen, xyz übertragen, Beendet: xyz ms“.

Merk dir diese Zahlen mal, sowohl was die Anzahl der Requests angeht, als auch die Größe der übertragenen Daten.

Der Kern des Ganzen, warum ich diesen Ansatz kritisiere, ist der, dass zunächst einmal Tonnen von Daten Clientseitig durch ein Framework geroutet werden, um dann am Ende doch wieder zu einer kleinen Arztpraxis-HTML-Seite zusammenzufallen. Der Aufwand, um hier zum Ergebnis zu kommen, ist recht hoch, gleichwohl der Nutzen doch eher überschaubar bleibt. Möge mir jemand das Buch der Erkenntnis reichen, den bisher sehe ich da keinen Vorteil.

— Der klassische Ansatz —

Wir erstellen Seiten+1 Dateien, eine ist für das CSS, die anderen sind die eigentlichen Seiten. Da bauen wir einfach die Seiten, die wir brauchen und nennen die „xyz.html“, die zusätzliche nennen wir „xyz.css“ und die ist nur für das CSS. Okay, wir könnten noch eine machen, eine „xyz.js“, aber mal ehrlich, warum? Das wird eine Arztseite, dynamisch ist anders.

Wenn wir fertig sind, laden wir die alle auf den Server und sind fertig – html und css können alle Webserver per Default ausliefern, dafür sind die gebaut worden *zwinkersmily*.

Auch jetzt schauen wir nochmal in den Netzwerkanalysen nach und siehe da, exakt Seiten+1 (oder +2, je nachdem ob wir eine js mitliefern oder nicht) Requests wurden gemacht. Ich gehe fast jede Wette ein, dass die Größe und die benötigte Zeit für das Abrufen der Seite wesentlich kleiner sind als mit dem anderen Ansatz.

— Von Hämmern und Nägeln —

„When all you have is a hammer, everything looks like a nail!“ … das ist ein schlauer Spruch, den man sich tief im Gehirn verankern sollte. Du bist ein Junior, du kennst dich mit JS aus. Okay, aber warum kennst du dich nur mit JS aus? Weißt du, dass alle JS-Frameworks am Ende auch nur HTML auswerfen? Was anderes kann dein Browser einfach nicht darstellen. Auch Electron nicht (ist auch nur ein gemappter Chromium-Browser). Die wollen alle nur HTML haben.

Und nun mal eine Frage: Warum gibst du ihm nicht einfach HTML?
Es mag sicherlich ganz toll sein, wenn man einen Hammer hat. Damit kann man wunderbar Nägel in die Wand hämmern. Wenn du allerdings nur einen Hammer hast, dann fängst du auch an, Schrauben in die Wand zu kloppen (oder wer-weiß-wohin noch) und oberflächlich betrachtet funktioniert das auch …. zunächst. Aber der Teil, den du nicht siehst, der erhält durch unsachgemäße Benutzung Schäden (in dem Beispiel: Der Dübel wird zertrümmert, die Schraube zerstört). Und offenbar ist das ja auch erst einmal in Ordnung, weil: Das kleine leichte Bild, was du da aufhängst, das hängt doch. Ergo: Funktioniert.

Was bei deinem kleinen Bild noch ok zu sein vermag, das hält allerdings die Analogie zur Softwareentwicklung nicht mehr aus. Sicher mag dein Projekt im kleinen Rahmen (lies: auf deinem Rechner oder kurz nach dem Live-Start) noch funktionieren, was passiert aber, wenn dein Projekt plötzlich ein Erfolg wird? Von jetzt auf gleich strömen nicht mehr 2 Besucher pro Stunde deine Seite, sondern 20.000 pro Minute. Hält dein Projekt das aus? Die Schraube in der Wand wird mit Sicherheit keinen Elefanten aushalten, so kaputt wie die innen drin ist.

Jetzt sagt so mancher „meh, das ist unrealistisch“. Ist es das? Ist es nicht das, was sich alle Entwickler wünschen, dass „dein“ Projekt wie eine Bombe einschlägt und erfolgreich wird? Ich wünsch mir das jedes Mal und aus dem Grund bereite ich mich auch darauf vor, dass es mal so weit kommt. Ich betrachte als verantwortungsvoller Entwickler nicht nur den normalen „alles ist rosa“ Weg, ich betrachte vor allen Dingen die aus der Mathematik bekannten Grenzwerte, die Randbereiche, die „Roten Zonen“, die Kehrpunkte, kurzum: Ich bin da, wo es weh tut, in der roten Zone.
Warum? Ganz einfach: Wenn es in der roten Zone funktioniert, dann funktioniert es überall!

Warum die ganzen Umwege über Frameworks, Komponenten, Abhängigkeiten von eher fragwürdigen 3rd Party Librarys (wann wurden die zuletzt aktualisiert? Welche Sicherheitslücken haben die eigentlich?).

— Security —

Apropos Security!
Ich selbst baue nicht nur beruflich Webprojekte, ich baue die auch im Privaten, zum Teil auch für das Ehrenamt. Mein Anspruch an meine privaten Projekte ist nicht anders als der Anspruch für die beruflichen Projekte. Ergo untersuche ich den Code für meine Projekte auch (nicht nur, aber auch) auf die Sicherheit. Dazu gibt es Tools und Anbieter, die einen dabei unterstützen (verlass dich aber nicht nur auf andere, denkt auch selbst).
Meine Web-Projekte basieren zumeist auf dem TALL-Stack, d.h. im Kern ist es PHP auf der einen und JS auf der anderen Seite. Was mir nun auffällt ist, dass ich wesentlich (!) mehr Meldungen zu Sicherheitsproblemen in den JS-Teilen bekomme als in den PHP Teilen. Damit meine ich in beiden Fällen die jeweiligen 3rd Party Librarys, die zwangsläufig sowohl bei PHP als auch bei JS installiert werden. Es ist erschreckend, dass sich da eine Quote von 17:1 rauskristallisiert (nochmal für Juniors: auf 17 Sicherheitsmeldungen zu JS kommt eine für PHP, Tendenz eher steigend auf Seiten JS).

— Fazit —

Eingangs erwähnte ich bereits die best practices aus grauer Vorzeit, „YAGNI“ und „KISS“. Meine Beobachtung ist aber, dass diese Paradigmen entweder nicht mehr beachtet werden oder deren Existenz schlicht unbekannt ist.

Wenn die dir unbekannt waren, dann freut es mich, dass ich es dir näher bringen konnte. Du kannst dich gern weiter in diese Prinzipien vertiefen und diese verinnerlichen, es wird dazu beitragen, aus dir einen besseren Entwickler zu machen.
Wenn es allerdings nicht beachtet wird, dann heißt dies ja, dass diese Paradigmen durchaus bekannt sind und schlicht aus gottgegebener Selbstherrlichkeit missachtet werden. Aber: Warum? Machst du irgendwas besser, weil du mehr Dinge auf das Problem wirfst, ohne es besser zu lösen? Wahrscheinlich nicht. Mein Eindruck bei dieser Sparte („ich ignoriere mal dieses alte Zeug, das ist alt, heute machen alle JS, basst scho“) ist leider, dass viele zum einen gar nicht den Überblick und damit das Wissen haben, was da eigentlich im Hintergrund passiert und zum anderen nur sehr wenige bereit sind, sich dem „alle machen das“ entgegenzustellen.

In meinem Kopf geht dann immer ein Schild mit einem sehr sinnigen Spruch hoch:
„Fresst mehr Scheiße, Milliarden Fliegen können sich nicht irren!“
Soviel zur Weisheit der Masse 😉

Mein persönlicher Anspruch ist, dass ich das immer das „limes(beste Projekt)“ baue und dazu gehört auch, dass ich mir zuerst die Aufgabenstellung anhöre und erst dann entscheide, mit welchen Technologien man das wohl lösen könnte. Mein Werkzeugkasten umfasst mehr als nur eine Sprache und mehr als nur ein Framework und dies alles aus Jahren der Erfahrung, des Scheiterns und Verzweifeln, des Wegwerfen und „Machen wir die Nacht durch und schreiben es neu“-coden.

Aspekte wie Sicherheit, Robustheit und Schnelligkeit (alle sind gleichwertig) haben bei mir immer Vorrang vor irgendeinem „das geht noch hübscher, wenn wir library xyz noch requiren“ Ansatz. Zuerst muss es funktionieren, es muss stabil sein, schnell und sicher.
Hübsch kommt dann und CSS mit HTML kann in der Regel bereits 90% deines JS-Frameworks abdecken, man sollte nur mal die Doku von HTML komplett lesen.

Ständiges Hinterfragen deines Wissens wird dazu beitragen, dass du ein besserer Entwickler wirst; ein Leitstrahl kann für dich derselbe Satz sein wie für mich: „scio me nihil scire“.

CRUD – Theorie und Praxis

CRUD, dieses Vorgehen sollte eigentlich jeder kennen … falls nicht, CRUD ist die Kurzform für „Create, Read, Update and Delete“ und ist vereinfacht gesagt als Checkliste zu sehen und gilt nicht nur für PHP.

Du hast in deiner Anwendung zum Beispiel eine Liste aller User, die soll editierbar sein. Du kannst nun CRUD als Checkliste benutzen und einzeln abhaken:

  • Create: Kann ich neue User erzeugen? Check!
  • Read: Kann ich eine Liste aller User ausgeben UND kann ich im Editfall einen User darstellen? Check!
  • Update: Kann ich die Daten eines Users ändern? Check!
  • Delete: Kann ich einen User löschen? Check!

Hast du bei allen ein „Check!“, dann bist du technisch auf dem Mindestlevel angelangt. Herzlich Willkommen 😉

Soviel zu Theorie. In der Praxis sehe ich es leider oft, dass CRUD viel zu wörtlich genommen wird. Besonders das C und das U sehe ich oft als zwei Dinge in der Anwendung.

Warum nun ist das schlimm? Nun, ich arbeite mit Legacy-Anwendungen. Diese sind teilweise vor vielen Jahren begonnen und verrichten bis heute ihren Dienst. Innerhalb dieser Anwendungen gibt es immer wieder den Fall, dass eine Datensatzart die CRUD Bedingung erfüllen muss, d.h. ich habe eine Liste von (Beispiel) Usern oder Kunden, die kann man ändern, die kann man neu erzeugen, die kann man löschen usw.

Nun mein Appell an alle: Bitte, fasst C und U zusammen. Bitte!

Es gibt nichts schlimmeres, als dass man ein „create“ Script und ein „update“ Script hat, beide machen im Prinzip das gleiche (Prüfung der Daten, Normalisieren der Daten usw.), aber im Endeffekt hast du 2 Scripte. Du hast also „duplicate code“. Und das ist nicht nur „bad smell„, dies ist einfach nur „bad style“. Eine Änderung an der Logik der User (Stichwort neues Feld) und du musst beide Scripte aktualisieren. Falls deine Anwendung mehrere solcher Listen hat und das neue Feld mehrere betrifft darfst du die „2“ gern entsprechend faktorisieren.

Also, bitte, bau die ein „edit“ Script, prüfe die Variablen, normalisiere diese und mache alles fertig. Dann nur noch die Unterscheidung „neu“ oder „ändern“ und gut ist. Das sind aus meiner Erfahrung nur ein if-else (oder switch) und das entsprechende SQL-Kommando. Die Ausführung des Kommandos ist dann ja wieder das selbe und kann außerhalb der Verzweigung stehen.

Dieses eine Script läßt sich jetzt viel leichter skalieren, verstößt nicht mehr gegen den „copy paste detector“ und läßt dich einfach ruhiger schlafen.

Just my 2 cent ….

Hat YAGNI ausgedient?

Ich las eben einen interessanten Artikel im phpMagain online. In „Abwärtskompatibilität vs. langfristiges Planen“ geht es über einen Blogbeitrag von Anthony Ferrara, in der dieser u.a. darüber schreibt, dass er die Optionen seiner Funktionen als array anlegt, obwohl das ja teilweise gar nicht sein müsse. In die Zukunft gesehen macht es aber Sinn, da ja bald neue Optionen hinzukommen werden, da sich jede Software weiterentwickelt und seine Funktion somit flexibel ist und ihre Signatur sich nicht weiter ändern muss.

Allerdings, und das steht ja auch im Artikel des phpMagazins, wiederspricht dies dem YAGNI Prinzip, das – vereinfacht – besagt, dass du alles, was du aktuell nicht brauchst, auch nicht entwickeln sollst.

Ich finde, dass passt dann nur auf Software, die du einmal entwickelst und die dann einfach vor sich hin altert. Software, die du vorher im Detail planst und dann nie wieder ansiehst. Kurz, Software, die hoffentlich heute in der Form nicht mehr gebaut wird.

Heute verändert sich Software stetig und ständig, „und das ist auch gut so“, denn sonst würden wir alle niemals Updates installieren müssen. Aber im Gegenteil müssen wir heutzutage so viele Updates installieren, dass manchen Hersteller gar nicht mehr nervt fragt, sondern uns ganz bequem mit „Silent updates“ auf dem neuesten Stand hält.

IMHO werden Anwendungen und Webseiten heute um ein vielfaches schneller und öfter aktualisiert wie noch vor wenigen Jahren. Und Software, die aktualisiert wird, wird oft auch erweitert. Es werden ja nicht nur Sicherheitslücken geschlossen oder Bugs gefixed, es kommen oft auch neue Features und Funktionen hinzu, altbekanntes fällt manchmal weg, kurz: Die Software verändert sich und damit auch ihr Code, ihre Funktionen und dessen Signaturen.

Was hat das nun mit YAGNI zu tun? Nun, YAGNI würde besagen, dass man eine Funktion minimalst aufbauen soll, ein Beispiel, eine Funktion liefert uns Benutzerdaten aus einer Datenbank:

public function getUser() {
//...
}

Diese Funktion würde alle User zurückliefern. Im Laufe des Lebens der Anwendung merken wir, dass ein Filter auf „getUser()“ wohl sinnvoll wäre, also ändern wir die Signatur:

public function getUser($id)

liefert nun genau einen User mit einer speziellen Id.

public function getUser($id = -1, $name)

kann nun auch einen User nach Namen liefern, wenn wir id auf -1 setzen.

public function getUser($id = -1, $name, $nameAsLike)

kann nun auch – bei $nameAsLike=true und id=-1 – einen Namen „teilweise“ liefern.

Diese Liste ließe sich nun bestimmt weiter fortsetzen, ihr kennt das sicher alle. Sicher entspricht dies dem YAGNI Prinzip, denn im Laufe der Versionen der Software kam immer nur genau so viel dazu, wie unbedingt erforderlich war. Aber war das gut so?

Vorausschauender wäre es gewesen, sich kurz Gedanken zu machen und dann zu entscheiden

public function getUser(array $options=array())

Nun kann dort auch jeder der obigen Evolutionsschritte der Software eingebracht werden, die Signatur der Funktion braucht allerdings dazu nicht geändert zu werden und damit gibt es auch weniger potentielle Fehlerquellen im Rest des Codes.

Vielleicht müssen wir vom starren YAGNI weg, hin zu einem YDNNI, einem „You Defenitly Not Need It“, einem Paradigma, dass es erlaubt, vorausschauend zu Entwicklen, dass einem aber trotzdem untersagt, völlig Sinnfreie oder sogar Kontraproduktive Dinge zu entwickeln.

Die Sache mit dem array scheint sich langsam aber sicher dank oder trotz YAGNI zur „Best Practice“ durchzusetzen. Setzt ihr Optionen auch als array um oder benutzt ihr da völlig andere Wege?

 

Windows Developer System – Der Webserver (02)

Kommen wir in der Reihe des Windows Developer Systems nun zum Kern eures Entwickler-Systems, dem Webserver. Es gibt verschiedene Möglichkeiten, welchen Webserver man als Entwickler benutzt. Die Haupt Zielplattform wird sicherlich immer noch der gute, alte Apache Webserver sein. Da wir als Windows-ianer aber etwas verwöhnt sind, was Installation und Konfiguration von Software angeht benutzen wir für diesen Teil den Zend Server. Der hat den Vorteil, dass er komplett fertig als „One-Click-Installer“ reinkommt und nichts kostet außer ein paar Minuten Zeit.

Zuerst begibt man sich auf die aktuelle ZendServer Downloadseite und wählt die für sich passende Installation aus. Aktuell gibt es dort den ZS für PHP 5.3 und PHP 5.4 zur Auswahl.

Die Downloadseite des Zend Servers

Es wird zum Download AFAIK kein Account benötigt, falls doch ist dieser kostenfrei und auf jeden Fall die Mühe wert.

Nachdem ihr den Server runtergeladen habt, könnt ihr die Installation wie gewohnt starten. Der Server ist wirklich einfach zu installieren. Beim Zielverzeichnis können wir der Einfachheit halber Den Pfad “C:\” wählen, der Server wird dann unter “C:\zend” installiert. Die kurzen Dateipfade werden uns später die Arbeit etwas leichter machen, wenn es darum geht, Virtuelle Hosts aufzusetzen – dazu später mehr.

Das wirklich schöne am Setup des Zend Servers ist, dass im Schritt “Custom Setup” ganz unten die Option “MySQL Server” angewählt werden kann und damit nicht nur ein MySQL Server runtergeladen wird, sondern das Ganze auch fix und fertig serviert und konfiguriert wird. Wirklich praktisch!

Custom Setup des Zend Servers

Die restlichen Optionen müsst ihr nach euren Anforderungen setzen, ich belasse meist alles so wie es ist und füge nur die Option des MySQL Server hinzu, dann habe ich schon ein funktionierendes System.

Die Installation dauert je nach Optionen, Downloadgeschwindigkeit und CPU ein paar Minuten. Zeit für einen Kaffee 😉

Nach der Installation _kann_ es sein, dass manche Rechner neu starten müssen, andere jedoch nicht. Tut wie euch geheißen und ihr bekommt anschließend den kompletten Zend Server als Trial-Verison für 30 Tage. Keine Angst, nach Ablauf der 30-Tage verwandelt sich die “echte” Zend Server in die “Free”-Version, die genauso als Entwickler-Basis verwendbar ist – nur ein paar Profi-Features fehlen, das wirklich wichtige bleibt aber erhalten.

Je nach Präferenz könnt ihr in den Diensten von Windows nun auch den automatischen Start von “Apache” und “MySQL Server” auf “Automatisch” belassen oder auf “Manuell” setzen. Ich setze den Apache meist auf Manuell und starte diesen bei Bedarf, der MySQL Server läuft dagegen ständig, da ich öfters mal Datenbankabfragen aus meiner IDE starte, während ich programmiere. Aber auch hier: Eure Bier, macht’s, wie’s euch beliebt.

In eurer System-Tray (neben der Uhr) habt ihr nun auch ein schickes neues Icon, ein Klick drauf und ihr könnt den Server starten, stoppen oder restarten wie es euch gefällt. Ein Doppelklick führt zu einer netten Übersicht, die in der Praxis aber kaum Bedeutung hat.

Ob ihr nun glaubt oder nicht, euer Webserver mitsamt MySQL-Server ist nun installiert und einsatzbereit. Yes, it’s that easy!

Wenn der Apache gestartet ist erreicht ihr die Konfigurationsseite des ZendServers unter der URL

http://localhost:10081/ZendServer/

Beim ersten Aufruf (oder nach einem Update) müsst ihr den Üblichen EULA’s zustimmen und angeben, ob ihr den Server als “Development” Server benutzt oder als “Production”, dann ein Password für den Admin-Zugang eintragen und fertig ist der Server!

Zend Server Dashboard direkt nach Installation

Im Punkt “Configurations” könnt ihr einzelne Komponenten (de-)aktivieren und auch alle Teile der php.ini bearbeiten, inkl. Erklärungen. Grade für Neulinge im Bereich Webserver sehr praktisch. Der Server kann nach allen Änderungen die Ihr braucht per Klick neu gestartet werden.

Der größte Teil unter dem Mneüpunkt “Applications” fällt übrigens nach dem Ende der Trial-Phase weg und betrifft eh nur Cloud-“Zeug”, was erstmal nicht von belang sein soll. Wir wollen ja unser lokales System aufbauen und die Grundlage dafür ist nun vorhanden.

Schaut euch also nun in Ruhe euren neuen lokalen Webserver an. Im nächsten Teil geht es weiter mit der Konfiguration der Virtuellen Hosts und was man damit schönes machen kann.

include oder require?

Was soll der PHP-Entwickler benutzen, include oder require bzw. include_once oder require_once?
Und wo liegt da eigentlich der Unterschied?

Die Frage kommt oft, deshalb an dieser Stelle mal ganz klipp und klar und kurz:

require bzw. require_once benutzen, denn: Sowohl include wie auch require binden eine Datei ein, aber, sollte ein Fehler in der includierten Dateie sein, so bricht require mit einem E_COMPILE_ERROR ab, während include fröhlich mit einer WARNING weitermacht.

Im Sinne der Vermeidung von code-smells fällt eure Wahl also auf require bzw. require_once.

Windows Developer System – Die Grundlagen (01)

Ich stelle euch hier vor, wie ihr Stück für Stück eine professionelle PHP-Entwicklungsumgebung unter Windows erstellt und das ganze ohne besonders viel Aufwand. Die meisten Tutorials in dieser Richtung – zumindest die, die ich kenne – gehen immer davon aus, dass ihr Linux benutzt – und wenn doch mal Windows erwähnt wird, dann meist mit dem Seitenhieb, doch mal endlich ein „richtiges“ Betriebssystem zu benutzen.

Ich selbst habe 2 Maschinen, beide mit Windows7, und dieses Tutorial basiert daher natürlich auf dem Betriebssystem Windows. Ihr könnt aber davon ausgehen, dass ihr, wenn ihr unter Windows entwickeln wollt, keine Einschränkungen gegenüber den Linux-Leuten habt, ihr habt nur andere Kommandos – auch wenn die Pinguine euch manchmal was anderes erzählen wollen. Am Ende ist doch eh nur der Code wichtig und der läuft sowohl unter Windows wie unter Linux.

Anfangen möchte ich mit einem Überblick und nötigen Grundlagen, alles weitere kommt dann Stück für Stück. In jedem Teil findet sich ein Inhaltsverzeichnis mit den jeweils anderen Folgen dieser Serie.

Auf jeden Fall wünsch ich euch viel Spaß beim lesen und viel Erfolg beim Umsetzen.

Inhaltsverzeichnis:

Windows Developer System – Die Grundlagen

Zuallererst brauchen wir natürlich ein Windows, welches auch immer. Es sollte im Prinzip auf jedem Windows ab XP funktionieren, testen kann ich – wie oben schon erwähnt – nur auf Win7; Kommentare zu anderen Windows-Varianten wie z.B. Vista, XP oder sogar Win2000 wären nett 😉

Linuxianer oder Mac-User dürfen natürlich gern mitlesen. Bei den Anleitungen zur Installation werde ich aber gnadenlos Windows-lastig sein, dafür könnte sich das Mitlesen bei der Benutzung von PEAR und den damit verbundenen Code-Analyse-Tools aber lohnen. Mein Tipp: Dabeilesen ist alles 😉

Eure Festplatte sollte noch ein paar MB oder besser GB Platz haben, natürlich vor allem für die „große“ Software wie den Webserver und die lokale Datenbank, als auch für eine professionelle IDE … die Puristen unter euch können natürlich auch weiterhin im Notepad2, Notepad++ oder dem Programmers Notepad arbeiten; viele Features einer IDE können einem Entwickler in der täglichen Arbeit allerdings sehr viel lästige Arbeit abnehmen (siehe die 10 Regeln für Entwickler – Punkt 3).

Die Frage an dieser Stelle lautet: „Warum sollte ich das machen?“. Die Antwort ist trivial: Weil es deine Arbeit verbessert und erleichtert, weil es dir viele Möglichkeiten gibt, dich selbst und deine Fähigkeiten zu verbessern. Und bestimmt noch mehrere Dutzend Antworten, die dir aber auch alle im Laufe dieses Tutorials klar werden. Darum!

Von hier aus geht es nun also nahtlos weiter zum nächsten Punkt, dem downloaden und installieren des lokalen Webservers.

Method-Chaining in eigenen PHP-Projekten einsetzen

Klassen und Objekte kennt ja nun mittlerweile fast jeder, ein PHP-Framework wie ZendFramework oder CodeIgniter haben sich sicherlich auch schon viele zumindest mal angesehen … will ich hoffen. Nun, auch wenn man die Frameworks nicht direkt einsetzt, so kann man doch viel von ihnen lernen. Viele der Techniken, die in bekannten PHP-Frameworks eingesetzt werden, entstanden entweder aus dem großen Ästhetischen Faible, den nun mar jeder Entwickler hat oder schlicht aus Faulheit der Programmierer 😉

Egal, eines der – wie ich finde – tollen Features in vielen Frameworks ist die Möglichkeit, mehrere Funktionen eines Objektes hintereinander aufrufen zu können, ja, es sieht schon fast wie ein normaler Satz aus, was dann im Editor steht und seinen Dienst verrichtet. Diese Möglichkeit der sog. “Fluent Interfaces” nennt man “Method-Chaining” (und wieder im Bullshot-Bingo gewonnen, *strike*).

Kleines Beispiel, kennen wir alle, unsere Basisklasse:

class Base1 {
function macheEins() {
// some magic here
}
function macheZwei($parameter) {
// more magic here
}
}

Das ganze rufe ich nun auf:

$myBaseClass = new Base1();
$result1 = $myBaseClass->macheEins();
$result2 = $myBaseClass->macheZwei($result1);

Was passiert? Das Ergebnis des Aufrufs von “macheEins” ist der Parameter für “macheZwei”. Das ganze sieht strukturiert aus und ist lesbar, was also soll man besser machen können? Nein! Bitte jetzt nicht sagen, man könne doch sowas machen:

$myBaseClass = new Base1();
$result2 = $myBaseClass->macheZwei($myBaseClass->macheEins());

Sicher, es funktioniert, aber: NEIN! Macht das nicht! Warum? Ganz einfach: Debugge das mal, viel Spaß. Denn wenn man erst einmal mit so einem falschen Verhalten anfängt, dann verschachteln sich schnell auch mal 5 oder 8 Funktionen ineinander und finde dann mal den Fehler, viel Spaß! Also: Ganz klares “So nicht!”.

Aber wie dann?

Zunächst müssen uns im klaren sein, was die Klasse macht. Offenbar braucht “macheZwei” ein Ergebnis einer Berechnung einer anderen Funktion der Klasse. Dieses Ergebnis könnte man doch genauso innerhalb der Klasse speichern und dann benutzen.

class Base2 {
private $valueHolder;
function macheEins() {
$this->valueHolder = someMagic;
return $this->valueHolder;
}
function macheZwei() {
return $this->valueHolder * someMoreMagic;
}
}

Schon erfüllt die Klasse auch die Anforderungen, aber … so richtig “fluent” will das ganze nicht werden, obwohl ja nun im Aufruf von “macheZwei” der Übergabeparameter fehlt. Was nun? Und wie sieht denn so ein “Fluent Interface” mit “Method-Chaining” nun aus? Der Aufruf sähe in unserem Beispiel in etwa so aus:

$myBaseClass = new BaseFluent();
$result2 = $myBaseClass->macheEins()->macheZwei();

Aber unsere derzeitige Klasse unterstützt das nicht! Wie bekommen wir unsere Klasse nun “Fluent”?

Nun, dazu müssen wir diese massiv umbauen. Der größte Umbau ist, dass die einzelnen Methoden nicht mehr direkt die Ergebnisse liefern, sondern “nur” das Objekt selbst zurückgeben … und darin liegt auch schon der ganze Trick. Den Methodenaufruf kann ich immer nur auf einem Objekt machen. Eine Methode, die mir einen Basisdatentypen zurück liefert, kann ich dafür nicht gebrauchen, da ich auf diesem Basistypen (int, String, array, …) keine weiteren Methoden meiner Klasse aufrufen kann.

Nehmen wir mal an, im letzten Code stünde statt “new BaseFluent” ein “new Base2”. Dann würde der Aufruf:

$result2 = $myBaseClass->macheEins()->macheZwei();

folgendes bedeuten: Rufe die Methode “macheEins” auf dem Objekt “myBaseClass” auf, diese gibt den Datentyp von valueHolder zurück (nehmen wir mal an, es wäre ein integer mit dem rein zufälligen Wert 42), rufe dann auf dem Objekt 42 die Methode “macheZwei” auf … *meep* Fehlermeldung, “42” ist kein Objekt, hat daher generell keine Methoden und erst recht keine spezielle Methode mit dem Namen “macheZwei” also Fehler und Script Abbruch.

Der Trick besteht nun darin, dass die Methoden des Objektes nicht mehr die eigentlichen Ergebnisse zurückgeben, sondern das Objekt der Klasse selbst; darauf darf man ja dann auch wieder Methoden derselben Klasse aufrufen, also bauen wir flugs die Klasse um:

class BaseFluent {
private $valueHolder;
function macheEins() {
$this->valueHolder = someMagic;
return $this;
}
function macheZwei() {
$this->valueHolder *= someMoreMagic;
return $this;
}
function getValueHolder() {
return $this->valueHolder;
}
}

Man erkennt nun, wohin die Reise geht. Getter und Setter werden implementiert, um die Daten zu holen, die Methoden geben uns $this zurück, worauf wir weiterhin Klassenmethoden aufrufen können und wir haben nun unser “Fluent Interface” für “Method-Chaining” in PHP realisiert; war doch gar nicht schwer und hat auch gar nicht weh getan, oder?

In der freien Wildbahn trefft ihr auf diese Art des Codens übrigens ganz stark beim ZendFramework an, bei CodeIgniter geht es wohl auch, denke ich (ich mache mich da erst seit kurzem fit und bitte alle CI-Fans, meine Unwissenheit zu entschuldigen). Es macht aber auch Spaß, dass bei eigenen Klassen umzusetzen, die sowieso umgearbeitet werden sollen. Sieht einfach viel übersichtlicher aus. Und noch ein Tipp: Mehr als zwei Verkettungen sollten untereinander stehen, also so:


$myBaseClass->macheEins()
->macheZwei()
->macheDrei()
->undNochMehr();

Viel Erfolg damit …

10 Regeln für Entwickler

Es gibt viele „Regeln“ zum Programmieren, viele „Goldene Regeln“; das hier sind meine.

  1. Glaube nicht, wisse!
    Glauben heißt, nicht zu wissen. Sei kein Gläubiger, sei ein Wissender! Hebe dich von der Schar derer ab, die nur Oberflächliches kennen, jene, die nur auswendig lernen, was in den „xyz for dummies“ Büchern steht. Du bist anders, du bist smart: Du verstehst, was da steht!
     
  2. „Know your Enemy“
    ”Kenne deinen Feind”; lerne Sachen, die du hasst; verdamme nicht einfach Dinge, die neu oder anders sind: Lerne Sie, verstehe, warum diese Dinge so sind, warum ein Autor das auf diese Weise gelöst hat und wieso nicht anders. Verinnerliche neues, sei bereit für die Änderung, wiege alle Optionen ab: Und dann nimm die am besten passende!
     
  3. Notepad? Benutz eine IDE!
    Benutze eine IDE; Lerne die Features “deiner” IDE kennen und nutze diese Gnadenlos aus! Verstehe, dass jeder „seine“ IDE braucht und das keine IDE wirklich besser ist als eine andere: Es kommt nur auf den Entwickler an, der den Code schreibt!
     
  4. Benutze Standards
    Standards wurden von schlauen Menschen entwickelt, damit diese auch mit Code zurecht kommen, den weniger schlaue Hacker schrieben; du benutzt deinen eigenen Standard nicht, weil du ein guter Entwickler bist; Du benutzt deinen eigenen Stil, weil du die Standards bisher nicht verstanden hast! (siehe 1,2)
     
  5. Object to go
    Klassen erleichtern dir das Leben: Sie lösen eine Aufgabe und das machen Sie effizient; ist die Klasse gut, macht Sie das sogar auf einer abstrakten Ebene und du kannst die Klasse nicht nur für dieses Problem einsetzen, sondern für alle ähnlichen Probleme. Aus (1) erkennst du, wie toll das ist, du nimmst die Klasse mit und bist fast am Ziel. Klassen und Objekte sind dein Freund: Benutze Sie auch!
      
  6. Kommentiere weise
    Kommentiere deine Funktionen, deine Klassen, eine extrem schwer zu verstehende Stelle im Code oder eine Stelle, in der du mal von der internen Norm abweichen musstest; Kommentiere nichts triviales; Kommentiere keine Kommentare -> das ist Code, kein Chat!
     
  7. Hacke nicht, komponiere
    Programmier kann jeder, wahrhaft entwickeln ist eine Kunst. Die richtige Wahl der Werkzeuge, das Arrangement der Funktionen, die Sitzordnung des Frameworks, die kurze Ruhe vor dem Beginn des Deployments … Du programmierst nicht, du komponierst Code und diese Kunst kann keiner Würdigen … außer ein anderer Codeponist.
     
  8. Bleib auf dem Teppich
    Ja, du bist der tollste Coder der Welt, aber keiner nimmt es zur Kenntnis? Liegt daran, dass keiner deinen Code lesen kann. Lesbarkeit ist wichtig, vor allem für dich selbst. Lies dich mal nach 12 Monaten und 4 Zwischenprojekten wieder in deinen „hochoptimierten“, „perfekten“ und „commentless“ Code ein … und dann weißt du, dass du (3),(4),(5) und (6) nicht verstanden hast. Sechs, setzen … Anfänger!
     
  9. Teile und herrsche
    Wussten schon die Römer, nur du weisst es wieder nicht. Teile dein Wissen, denn wenn du nicht fähig bist zu lehren, dann hast du es nicht richtig verstanden (siehe 1 und 2). Bringe dein Team auf deinen Wissenstand und messe dich regelmäßig mit stärkeren, mit schlaueren, mit „Wissenden“ … denn nur im direkten „Code-Wettkampf“, sei es nun mündlich oder als Code-Kata, kannst du erst über dich hinaus wachsen, deine Schwächen erkennen (und die hast du, glaube mir) und damit erst bist du in der Lage, dich zu verbessern. Wisse, dass du nichts weist; Plato wusste das auch … und du lernst das auch noch vom Kollegen nebenan!
     
  10. Don’t Panic
    Die wichtigste Regel und ich hoffe, ich muss dazu nichts mehr sagen!
Dies sind meine Regeln,
es gibt viele Regeln, aber diese sind meine…
Wie sehen deine aus???

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?