mthie spaces

PHP - das Ende einer Ära

20.09.2014 13:06

Vorweg: Ich habe in den letzten 12 Jahren mein Geld mit PHP verdient. Ich war immer der Meinung, es handle sich dabei um "echte Programmierung". Oh Mann, ich war jung und brauchte das Geld.

Vor ein paar Jahren kam dann Python hinzu, die Versuche zuvor mit diversen anderen Sprachen wie Ruby lass ich jetzt mal weg. Python war für mich wie die Erlösung. Python war schneller, Python war strukturierter. Python hat eine Einrückvorgabe gegen lazy Entwickler, die der Meinung sind, dass man jede Zeile anders einrücken und damit Übersichtlichkeit verhindern kann. Es ist eine tolle Sprache. Für mich als Google-Fanboy war die Nutzung auf der Google-AppEngine anfangs auf Python (oder Java, aber mal ehrlich!) beschränkt.

Ich war in der Scriptsprachen-Welt. Man sagte immer, damit könne man am Schnellsten mal eben was hinzaubern. Das stimmte. Das war meine Welt. Ich hab immer Arbeit bekommen. Das war okay so.

Dann kam Go.

Es war keine Liebe auf den ersten Blick. Go sah komisch aus. Der Typ steht bei der Definition hinter dem Namen. Was für 'ne schräge Syntax. Dachte ich. Aber wie lernt man eine Sprache am Besten? Man liest anderen Quelltext danacht macht man es dann einfach mal selbst.

Was mir recht schnell auffiel: die Quelltexte verschiedener Entwickler sahen gleich aus. Alles war irgendwie schön strukturiert. Das Zauberwort heisst "gofmt". Die Programmiersprache bringt seine Coding-Conventions mit. Wie geil ist das denn?

Bei PHP gibt es für jedes Framework seine eigene Coding-Convention.

Hä? Ach ja! Und es gibt auch PSR (1 und 2 sind für Style da). PSR ist Scheisse! Bei Klassen und Funktionen werden die öffnenden geschweiften Klammern in die nächste Zeile gerückt. Bei ifs und Schleifen in die gleiche Zeile. Bei Funktionsaufrufen macht man die oeffnende Klammer ohne Leerzeichen hinter dem Funktionsnamen. Bei ifs und Schleifen (egal ob for, foreach, while) macht man ein Leerzeichen vor die öffnende Klammer. Was für ein inkonsistenter und unübersichtlicher Mist! Konfiguriert nur ein Kollege in der Firma seinen Editor falsch, hat man Chaos. Und dieses soziale Problem technisch zu lösen, ist sehr nervig.

Und dann ist da noch die Sprache PHP selbst. Ursprünglich entwickelt als Template-Sprache, wurde inzwischen so viel an der Sprache rumgefummelt um sie irgendwie professioneller zu machen.

Man konnte in dieser Template-Sprache plötzlich auch auf Datenbanken zugreifen.

Und dann kamen die Jungs von Zend.

Zeev und Andi dachten sich, dass es scheinbar eine total tolle Idee sei, den eh schon laxen Programmierern das Leben zu erleichtern. Sie dachten sich, dass man den alten Funktionsnamen, die alle klein und mit Unterstrichen geschrieben wurden, eine CamelCase-Syntax für die objektorientierten Sachen hinzufügen könnte. Die Funktionsparameter waren eh schon in einer zufälligen Reihenfolge, also hat man dann mit einer neuen Version diese Fehlentscheidungen gar nicht erst behoben, sondern einfach weitergemacht wie bisher.

Namespaces

Wer zur Hölle war da eigentlich besoffen als die Namespaces auf der Tagesordnung standen? Bei Java setzt man einfach noch einen weiteren Punkt vor den Namen (namespace.localname). Das ist eh deren Syntax. Bei C++ nimmt man ähnlich wie beim statischen Methodenaufruf noch einen weiteren doppelten Doppelpunkt (namespace::localname). Aber ein Backslash? Ein typisches Escaping-Zeichen? Echt mal!

Model, Controller und View in einem

Hier macht PHP meines Erachtens die meisten Fehler. Für so manchen Entwickler sind ja Design Patterns (nein, ich meine keine Photoshop-Vorlage!) ein Fremdwort. Andere halten es für veraltete Weisheiten. Aber MVC gehört zu den Dingen, bei denen mir oft die Nackenhaare hochstehen, wenn ich mir so manchen PHP-Code anschaue: Da werden in der einen Zeile Datenbank-Abfragen gemacht und in der nächsten Zeile nach der for-Schleife steht direkt HTML. Danach kommt dann wieder ein if mit Abfragen, ob im $_GET oder $_POST irgendwelche Werte stehen - man also Controlling-Mechanismen abbildet.

Die Pflege eines Projekts in solcher Form möchte niemand übernehmen, der bei klarem Verstand ist.

Die Datenbank-Konnektoren sind doof

Wenn ich mich in PHP mit einer Datenbank verbinden will, brauche ich viel Hoffnung. Nehmen wir mal MySQL als beliebteste PHP-Datenbank. Es gibt diverse Möglichkeiten, mich damit zu verbinden:

  • mysql_* Methoden: sind seit PHP 5.5 als deprecated markiert und werden irgendwann ganz entfernt. Alte große Projekte, die darauf aufbauen, werden zukünftig also ihre PHP-Version nicht upgraden können
  • mysqli_* Methoden: man hat irgendwie versucht, die mysql_* Methoden objektorientiert zu bekommen und pflegt dann diesen Baum weiter. Aber auch nicht ausschließlich objektorientiert. Wäre ja echt uncool, mal etwas richtig zu machen
  • ODBC: Oh mein Gott, muss ich wirklich schreiben, warum das keine schnafte Idee ist?
  • PDO: Nachdem ODBC ja so ein Windows-Ding war, musste man was plattformübergreifendes haben, mit dem man angeblich transparent die Datenbank wechseln kann. So es denn Konnektoren gibt. Mit MySQL ist es recht einfach. Das wurde alles implementiert, aber will ich mein PHP selbst kompilieren um eigene Konnektoren hinzuzufügen und es dann auf 100 Server verteilen?

Schauen wir uns doch mal an, wie es Go macht:

	import (
	  "database/sql"
	  _ "github.com/go-sql-driver/mysql"
	)

	db, err := sql.Open("mysql", "user:password@/dbname")

Was machen wir hier? Wir importieren zuerst mal das SQL-Paket, welches Go grundsätzlich mitbringt. Danach importieren wir den Konnektor, eine in Go geschriebene Version des Konnektors - am Ende reden wir hier ja auch nur von ein paar Binärdaten, die da durch eine Connection geschoben werden. Wenn mir der Konnektor nicht zusagt, importiere ich einen anderen. Ich muss ja nichts weiter ändern als diese Import-Zeile. Der Rest wird durch das SQL-Package geregelt.

Wenn man die Datenbank ändert, hat man in jeder Sprache den Aufwand, dass die SQL-Statements anders sind. Das kann man nicht anders lösen, aber die Einbindung einer Datenbank geht einfacher.

Alles wird immer wieder wiederholt

Bei jedem Start, bei jedem Request - es wird immer alles von vorne gemacht. So ist das mit Scriptsprachen, die nicht kompiliert sind. Nicht nur bei PHP. Man stelle sich vor, man hat einen wirklich schlimmen Wulst aus XPath-Anweisungen. So um die 300+ Stück.

In Script-Sprachen wird der XPath-Ausdruck mit jedem Aufruf neu geparsed und kompiliert, um angewandt zu werden. Hat man nur Prozesse einer Software, die die Anfragen beantwortet (z.B. einen Server lokal, dem über FCGI die Anfragen weitergeleitet werden), wird das Parsen und die Kompilierung einmal gemacht und nur angewendet. Am Ende kann man damit ca. die 10- bis 10.000-fache Menge an Requests verarbeiten.

RAM-Management ist eine Seuche

Möchte man große Datenmengen verarbeiten und gerne auch mal was im RAM behalten, ist vor allem PHP wirklich schlimm. Da wird bei der DOMisierung eines 500 MB XML-Files auch mal 4 GB RAM verbraucht. Und man kann eben nicht alles mit Stream-Parsern erledigen.

Der schlechte Einfluss durch Java

Meist findet man ja in einer Firma Programmierer für Java und für PHP. Die Javaner werden besser bezahlt (weil man Java an der Uni lernt und nicht im Keller). Die PHPler wollen dann auch soviel Geld also schreiben sie wie Java, statt die Stärken ihrer Sprache zu nutzen.

Damit kombinieren Sie dann die Nachteile beider Sprachen. Also langsam UND kompliziert statt schnell und simpel.

Siehe dazu diverses Tooling, dass nochmal Annotations und Kommentare live nachverarbeitet: Das macht den langsamen Interpreter mittels Reflection gleich noch eine Ecke langsamer. Java braucht sowas, weil es nicht dynamisch typisiert ist. PHP eigentlich nicht.

Komplexe Anwendungen für Admin-Tätigkeiten

Wenn man in einem Verzeichnis und all seinen Unterverzeichnissen mal alle Dateien umbenennen möchte und keine Shell-Scripte bauen kann und schon ein PHP-CLI installiert ist, dann mag das alles noch okay sein. Mir begegnen aber immer häufiger Scripte, die dann unzählige Abhängigkeiten zu ganzen Frameworks haben. Da ist dann alleine schon das Deployment ein Schlag ins Gesicht. Diese Eigenschaft teilt sich PHP aber mit sehr vielen anderen Scriptsprachen.

Ein Single-Binary ist da schon ein Segen.

PHP muss und will mithalten

Anfangs von Entwicklern anderer Sprachen eher belächelt, hat PHP immer mehr User bekommen. Das ist natürlich auch der heutigen Kultur geschuldet, dass alles irgendwie schnell gehen muss und man mal eben kurz was hinkotzen muss. "Wir müssen da ein System auf die Beine stellen. Das muss nächste Woche fertig sein. Wie, in ProgrammierspracheX dauert das 14 Tage? Kannst du das nicht mal eben in PHP machen? Wir machen das dann irgendwann ordentlich."

So oder ähnlich läuft es oft. Und aus irgendwann wird nie. Und aus hingeflanschten Systemen werden nach Jahren Projekte, bei denen es nur 2 von 25 Entwicklern gibt, die da komplett durchsteigen. Und wenn dann doch jemand mal den Hammer in die Hand nimmt, wird die nächste Version völlig over-engineered, da PHP ja inzwischen viel mehr Möglichkeiten bietet.

Das Problem der meisten PHP-Entwickler: Sie hören auf Userwünsche statt die Sprache schneller und stabiler zu machen. Da werden nämlich dann Wünsche nach anonymen Funktionen laut, die man von JavaScript kennt. Oder Traits, weil jemand mal gehört hat, dass man Mehrfachvererbung braucht.

One language to rule them all! Not.

Das alles in einer Templatesprache. Vor 15 Jahren, als die erste große Dotcom-Blase kam, nannten sich Leute, die HTML geschrieben haben "Programmierer". Danach hat man Templates geschrieben, um HTML dynamisch auszugeben. Die nennen sich heute Programmierer. Jede Sprache hat seine Vorteile und seine Einsatzgebiete. Man versucht PHP zu einer Universalsprache zu machen und die Entwickler der Sprache leiden unter Featuritis.

Was ich versuche auszudrücken: PHP ist eine gute Sprache, wenn man HTML dynamisch ausgeben/generieren möchte. Aber diese Fähigkeiten gilt es zu optimieren und kein halbes Betriebssystem drumherum zu schrauben.

Warum ich das Error-Handling in Go mag

06.09.2014 15:12

Immer wieder lese oder höre ich, dass Go-Anfängern dieses ständige

if err != nil

nicht gefällt. Selbst auf dem sehr lustigen Vergleich If programming languages were weapons kam dieser Punkt auf:

Ich bin da eher der Meinung, dass man falsch an die ganze Sache ran geht, wenn man das so sieht. Fangen wir doch mal an, mit anderen Lösungsansätzen zu vergleichen.

try-catch-Blöcke

Seit es PHP5 gibt, sind try-catch-Blöcke in PHP möglich und erfreuen sich großer Beliebtheit. In Java gibt es das natürlich schon länger und selbst Python hat Exceptions.
Leider gibt es grad in der Scriptsprachen-Welt sehr viele Hohlbirnen, die der Meinung sind, es sei total knuffig, einfach um alles in der main()-Methode ein try mit entsprechend generischem Catcher zu setzen.
Einfach alles abzufangen und in den eigentlichen aufrufenden Methoden immer davon auszugehen, dass sich schon der äußere Catch drum kümmern wird, dass zumindest eine Fehlermeldung ausgegeben wird, kann man schon so machen, ist aber leider sehr kurz gedacht und führt z.B. bei Web-Applikationen dazu, dass man nicht eine spezifische Meldung sieht, was grad gegen die Wand gefahren ist, sondern ein Error 500 oder ein "An error occurred" - das führt dann gerne dazu, dass Menschen Bescheid sagen, dass die Webseite nicht funktioniert.

$ok-Variablen

Es geht natürlich noch besser. Ganz ohne spezielle Fehlerbehandlung. Man schleift einfach durch die gesamte Software ein $ok (mit oder ohne Dollarzeichen hängt jetzt einfach mal von der Sprache ab). Sobald ein Fehler auftritt, setzt man diese dann auf false und schon weiss der Rest des Programms, dass er so nicht weiterarbeiten darf. Warum genau nicht und was vielleicht noch zu tun ist (DB-Connection schließen, Schreibvorgänge finalisieren), hat dann den Rest auch nicht zu interessieren.

if err != nil

Ich muss gestehen: Als ich mit Go anfing, fand ich das ziemlich komisch. Die Methoden hatten multiple Rückgabewerte und oft war der zweite vom Typ error.
Go beschwert sich selbstverständlich auch, wenn man multiple Rückgaben hat, aber nur eine Variable zuweist.

Nehmen wir also folgende Beispielmethode:

func Foo() (string, error) {
	return "bar", errors.New("My Error")
}

Was also nicht geht:

func main() {
	bla := Foo()
}

Es muss lauten:

func main() {
	baz, err := Foo()
	if err != nil {
		// Error Handling
	}
	fmt.Print(baz)
}

Oder man entscheidet sich wirklich explizit dafür, den zurückgegebenen Error zu ignorieren:

func main() {
	baz, _ := Foo()
	fmt.Print(baz)
}

Aber genau das ist der Punkt: Man muss sich explizit dafür entscheiden, genau diesen Fehler zu ignorieren oder ihn eben weiter zu verarbeiten, zurückzugeben oder was auch immer. Das zwingt den Entwickler dazu, sich aktiv damit auseinanderzusetzen, was als nächstes passiert oder was passieren könnte.

Ich mag das.

Hunderte Webseiten gehackt - warum nur?

17.03.2014 20:44

Es wurden also diverse Typo3-Webseiten gehackt. Soso. Ich mach jetzt einfach mal keinen Typo3-Flame-Post, sondern stell einfach mal die Frage: Warum?

Scheinbar wurde die eigentliche Schwachstelle aktuell noch gar nicht gefunden und das ist eigentlich das Fatale daran. Ich predige immer wieder, dass es keine wirklich geile Idee ist, jede Anfrage durch Scripte zu schießen. Man findet dabei immer eine Lücke, die einen simplen Zugang zum Server ermöglichen.

Hier nochmal ein paar Fragen für die typischen Website-Betreiber:

  • braucht man bei jeder Anfrage an den Server ein Script, was die Seite generiert und raushaut oder kann man die Seite einfach bei jeder Änderung generieren, als statische Datei ablegen und ausliefern lassen?
  • muss das Administrations-/Redaktions-Tool immer von jedem erreichbar sein oder kann man dieses anderweitig schützen?
  • braucht man jedes Script im Document-Root oder kann man diese vielleicht in einen Bereich legen, wo eben nicht jeder dran kommt?
  • wollt ihr euren Server wirklich immer selbst betreuen oder kann man dies auch jemandem überlassen, der Ahnung davon hat, auch wenn es teurer als ein 30-Euro-Root-Server ist?

Grad im Agenturbereich ist es mir schon häufiger aufgefallen, dass es immer noch nicht normal ist, seinen Serverbetrieb aus der Hand zu geben, obwohl dort oft nur Hobby-Admins sitzen, die schon mal gehört haben, wie man einen Apache installiert. Wenn man sich dann die Updates auf dem Server anschaut, sieht es meist düster aus. Wenn es dann darum geht, den Scripten entsprechende Rechte zu geben, endet es meist im
chmod -R 777 *.

Es gibt einfach so viel mehr Dinge, die so eine dynamische Website an Pflichten mit sich bringt, als nur ein Update-Button-Drücker einmal im Monat, wenn man zufällig sieht, dass es für Wordpress ein Update gibt.

</watchever>

18.12.2013 02:13

Vor einigen Monaten hiess es bei uns: "Lass uns mal Lovefilm kündigen und watchever ausprobieren, hab da bisher nur Gutes gehört". Gesagt getan, dank der jeweils monatlichen Kündigungsfristen.

Es war auch so schön einfach, die PS3 anzuwerfen, den Film auszusuchen und loszulegen. Denkste!

In den letzten Wochen liefen bei uns alle Doctor Who Staffeln, die watchever auch komplett anbietet (Lovefilm hat von der letzten Staffel nicht alle Folgen und Maxdome hat nur die 1., 2. und 5. Staffel). Nachdem wir dann ab der dritten Folge von der PS3 auf den Rechner geschwenkt haben, weil die Konsolen-Version der Software ständig abstürzte, wenn es mal eine kleine Störung im Bild gab, ging es grob. Zwar waren immer mal wieder ein paar Sekunden verloren gegangen, aber ich hab das dann immer leichtfertig auf "ist halt ein Stream" geschoben.

Will heissen: Glücklich war ich nicht, aber wir haben uns respektiert. Das Filmangebot war auch so lala, aber wenn man nach dem dritten Film, den man gesehen hat (nicht ohne Störungen) wirklich suchen muss, um was ansatzweise Spannendes zu finden, ist für mich das Angebot einfach nicht passend.

Ich habe es allerdings heute geschafft, meine bessere Hälfte zu überzeugen, mal "Friendship!" zu gucken. Nicht jedermanns Sache, aber der Schweighöfer ist halt irgendwie cool. Leider haben wir 4/5tel des Films nur gehört und uns zusammengereimt, da die Störungen im Film so unendlich schrecklich waren. Entweder sahen wir ein schwarzes Bild oder ausschließlich Artefakte. Mit der Playstation ging es gar nicht, mit dem Rechner war es eine Katastrophe.

Nunja, was so ein Freggel ist wie ich: Man vermutet ja erstmal die Probleme im eigenen Haus. Also startete ich den Router neu, probierte es mal mit dem Microsoft-Browser (die Streaming-Anbieter haben immer noch nicht kapiert, dass Silverlight eine ganz beschissene Idee ist) und sogar einen anderen Rechner. Letzteres zeigte mir, dass es nicht an uns liegen konnte, da die Aussetzer exakt an den gleichen Stellen passierten.

Es ist mir schleierhaft, wie solche Anbieter, die von Investoren und Eigentümern reichlich Geld in den Rachen geworfen bekommen, überleben können. Leider ist Netflix in Deutschland immer noch nicht vertreten, aber bei denen ist die Technik wenigstens ausgereift(er) und man kann es sogar mit einem Chromebook ansehen, da man einen Fallback auf Flash hat.

Was habt ihr so für Erfahrungen, vielleicht auch mit anderen Anbietern?

Ghost - das kannste schon so machen

15.10.2013 20:43

Hey, ein neues Blogsystem hat das Beta-Licht der Welt erblickt. Beta. Wirklich Beta. Anders kann man Ghost bisher auch nicht nennen.

Ich hab es mir mal etwas angeschaut, nicht ganz tief reingeschaut, aber grob einen Überblick verschafft.

Fangen wir doch mal damit an, dass es in JavaScript geschrieben ist, um auf Node.js zu laufen. Nun muss man dazusagen, dass Node nicht unbedingt meine erste Wahl wäre, um ein Blog zu betreiben, ist es für die meisten Leute, die heutzutage ein Blog haben, wohl eher unbenutzbar. Und wenn man versucht, es auf einer sinnvollen Cloudplattform wie Heroku zum Laufen zu bringen, wird einem direkt gesagt: "Tu's nicht!". Das widerum hat mich natürlich nicht davon abgehalten, es trotzdem zu tun.

Warum keine sinnvoll skalierende Cloud-Plattform unterstützt wird? Weil man lokal Dateien speichern möchte. Eines der größten Fehler, wie ich finde. Warum will eine Blogsoftware, die in diesem Jahrzehnt angefangen wurde zu schreiben, auf die eigene Festplatte schreiben? Warum baut man es nicht gleich so, dass man z.B. in ein S3-Bucket hochlädt? Das wäre nun wirklich kein Beinbruch.

Dann geht's weiter. In der Standard-Konfiguration will Ghost in eine sqlite-Datenbank persistieren. Nun hört man natürlich ganz oft, dass sqlite eine fantastisch skalierende Datenbank ist. Nicht. Aber man kann natürlich auch mysql verwenden. Nur muss man sich diese Konfiguration erstmal schön zurechtsammeln und -frickeln.

Die Mail-Konfiguration, die notwendig ist, um einen User anzulegen (komische Aussage auf deren Website) ist auch irgendwie merkwürdig und in der Default-Konfiguration auf mailgun eingestellt. Das liess sich zum Glück im Zusammenhang mit Heroku am einfachsten konfigurieren.

Als es dann lief, stolperte ich darüber, dass man irgendwie einen User anlegen müsse. Schade nur, dass man danach diesen Sign-Up gar nicht mehr deaktivieren kann. Wäre ja aus Sicherheitsgründen vielleicht gar keine so ungeile Idee.

Über das Frontend sag ich mal erstmal nix, dazu haben die anderen Hippster in diesem Internet schon genug geschrieben.

Was ich aber noch loswerden möchte ist, dass ZIP-File mit dem Source-Code ein schönes Blender-Paket ist. Installiert man alle notwendigen Node.js-Pakete, sind alleine diese schon 25 MB groß. Ich will ja nix sagen, aber wenn man Wordpress schon eine Konkurrenz machen will, sollte man deren 15 MB unkomprimiert schon unterbieten können.

Was ich aber schon einen guten Anfang finde, ist im Übrigen, dass man komplett auf HTML 5 gesetzt hat und dass alles über Templates generiert wird und nicht über PHP-Files mit reingewurschteltem HTML.

1