Objektorientierte Entwicklung vs. PHP 4

05 05 2010

Zur Zeit arbeite ich an einem Wordpress-Projekt und bin nach der Umstellung auf PHP 5.3 (vorher war versehentlich PHP 4 auf dem Webspace aktiv) über etliche Deprecated-Warnungen gestolpert. Die explizite Zuweisung von Objekten per Referenz (also mit =& statt dass das Objekt mit = geklont wird) in der wp-settings.php ist schuld, denn dieses im Grunde erwartungskonforme Verhalten ist seit PHP 5 der Normalfall, Objekte werden jetzt nur noch geklont, wenn man explizit clone benutzt, so dass die explizite Zuweisung per Referenz überflüssig ist und angemahnt wird.

Nun ist es bei einem guten Hoster ein Handgriff ein, die E_DEPRECATED-Warnungen in der php.ini zu unterdrücken, von daher ist das alles halb so wild. Die Sache ist aber ein Symptom eines großen Dilemmas: Will man – aus welchen Gründen auch immer – kompatibel zu PHP 4 bleiben, muss man manchmal Code schreiben, der in PHP ab 5.3 eine Deprecated-Warnung wirft. Das TYPO3-Backend beispielsweise warf bis vor kurzem (vielleicht auch immer noch) ebenfalls Unmengen an Deprecated-Warnungen, weil es intensiven Gebrauch von eregi-Funktionen macht. Die kann man mit gutem Geschwindigkeitsgewinn und ohne Schwierigkeiten mit PHP 4 gegen preg-Funktionen austauschen, hier ist es also lediglich eine Sache von Fleiß; ganz davon abgesehen, dass TYPO3 sowieso seit Jahren kein PHP 4 mehr unterstützt. Die Sache bei Wordpress und einigen anderen Projekten mit Objektorientierten Elementen ist aber eine Zwickmühle.

Wobei es in meinen Augen keineswegs eine Zwickmühle ist, da die Lösung auf der Hand liegt: Man wirft einfach den PHP 4 Support über Bord und hält die Anfeindungen einiger Ewiggestriger aus, die nicht wissen, wie sie bei ihren Webspace eine aktuelle PHP-Version umstellt. Diese Anfeindungen kommen leider vor, und sind einer der Gründe, wieso ich zu Serendipity keinen Code mehr beitrage. Serendipity bewahrt wie Wordpress noch immer die PHP 4 Kompatibilität und steht einer zukunftsgerichteten Weiterentwicklung damit massiv im Weg. Wordpress wird wohl ab Version 3.0 (also ab demnächst) PHP 5 vorraussetzen, damit es endlich nach vorne gehen kann. Das ist im Falle von Wordpress auch bitter nötig, wenn man sich den mitunter grauenerregenden Code anguckt. Die aktuelle Beta 1 wirft aber leider immer noch die Deprecated-Warnungen.

Es gibt so etwas wie Codehygiene. Ich frage mich, wieso sich so viele Softwareprojekte mit aller Macht dagegen stemmen, ihren Code ein wenig zu warten. Eregi-Funktionen gelten schon seit mindestens fünf Jahren als um Größenordnungen langsamer, als ihre preg-Pendants. Wieso zur Hölle liest man dann als Abhilfe für Deprecated-Meldungen immer und überall, dass man die Warnungen ausschalten soll? Wo ist das Problem, sich einmal eine Nacht hinzusetzen und die veralteten und langsamen eregi-Funktionen zu eliminieren? Wieso wird unter Verzicht auf fundamental wichtige Programmiertechniken der Objektorientierung auch mehrere Jahre nach Einstellung des Supports für PHP 4 so sehr daran geklebt? PHP 4 ist veraltet, langsam und behindert massivst eine saubere Programmierung. Das ist sogar so offensichtlich, dass es jedem auffallen müsste, der nur ansatzweise objektorientiert mit PHP programmiert. PHP 4 fehlt es an fundamentalen Funktionalitäten an allen Ecken und Enden, nicht nur bei der Objektorientierung. Bitte, hört auf mit der falsch verstandenen Rückwärtskompatibilität und blickt mal nach vorne.

P.S. Ich bin übrigens latent auf der Suche nach einem neuen Blogsystem. Serendipity möchte ich den Rücken kehren, weil sich an der Front scheinbar nichts mehr tun wird. Auf PHP 5 umstellen? Neue Programmierkonzepte zulassen? Nix da, alles bleibt, wie es ist. Ein System, dessen Core so ungerne angefasst wird, ist nicht meins. Davon abgesehen, dass der Core in meinen Augen sowieso gar kein HTML ausgeben sollte. S9Y ist super stabil und funktioniert bei mir seit nunmehr fast sechs Jahren ohne jedes nennenswerte Problem vor sich hin, aber in etwa so lange hat sich auch nicht mehr wirklich etwas nennenswertes weiter entwickelt; das stimmt zwar nicht ganz, aber die Änderungen blieben insgesamt doch sehr dezent. Wordpress ist leider keine Alternative, auch wenn das Backend großartig ist. Ein Blick in den Core an beliebiger Stelle sollte ausreichend Anlass geben, das System nicht zu wollen. Was ist eigentlich aus Habari geworden?


Wordpress macht jQuery-Code in Posts kaputt

29 04 2010

Heute musste ich in einem Wordpress-Eintrag ein kleines jQuery Script einbauen, wofür ich erst mal ein DIV an den BODY anhängen musste. Im Grunde macht man sowas in jQuery mit folgendem Code:

<script>
  jQuery('<div id="soundso" class="undsoso"></div>').appendTo('body');
</script>

Leider fährt einem Wordpress hier an die Karre, wenn man das in den Post-Editor einfügt (davon abgesehen, dass sowieso alles kaputt ist, wenn man den WYSIWTFWYSIWYG-Editor benutzt). Die Automatik, die Ps um die Absätze macht, grätscht hier rein und fummelt da irgendwie noch ein p mit rein, wo es einem einen JavaScript-Fehler einbringt. Eine andere Weise, dieses DIV zu erzeugen, scheiterte an anderen Randbedingungen oder wäre sehr unelegant gewesen, deswegen musste ich das irgendwie hinbekommen. Da Wordpress normalen JavaScript-Code in Frieden lässt, habe ich letztlich auf die Standard-JavaScript-Methode zurückgegriffen, wie man DOM-Elemente erzeugt. Das sieht dann so aus:

<script>
  var d = document.createElement('div');
  d.id = 'soundso';
  d.className = 'undsoso';
  document.body.appendChild(d);
</script>

Wenn man es so macht, lässt Wordpress den Code passieren, ohne daran wohlmeinend herumzufummeln. Eine andere Möglichkeit ist das PlugIn Text Control, das auf Pro-Post-Basis die Textformatierungen abschalten kann. Das Plugin scheint auf den ersten Blick trotz des Alters (es ist von 2005) mit einem aktuellen Wordpress zu funktionieren, aber leider bietet es seine Dienste nur für Posts an und nicht für statische Seiten.

Nachtrag 06.05.2010: Man kann auch einfach radikal wie wpautop-Funktion deaktivieren, etwa mit diesem PlugIn. Das automatische rein pfriemeln von Absätzen ist nett gemeint, aber es schadet in der Praxis mehr, als es nützt; zumindest in meiner Praxis.


Qype bewegt sich nur noch langsam, rückwärts…

18 02 2010

Ich bin begeisterter Qype-Nutzer und schätze Qype als fundierten Ratgeber für Lokalitäten und Einkaufsmöglichkeiten. In letzter Zeit ärgere ich mich aber immer wieder und zunehmend über Abstriche und schlechte Entwicklungen, die ich nun mal gebündelt niederschreiben möchte.

Punkt 1 und ganz wichtig: Die Suche bei Qype ist und war schon immer ein schlechter Witze. Wenn man einen Laden sucht, dessen Namen man nicht genau im Kopf hat, ist man total aufgeschmissen, weil die Suche schon bei kleinsten Abweichungen in der Schreibweise scheitert. Immerhin wird einem dann eine Google-Suche als Alternative geboten, die auch vorher schon die bessere Alternative für das Auffinden von Läden bei Qype war. Eine Autovervollständigung würde das Problem immerhin teilweise beheben, aber langsfristig muss eine unscharfe Suche her.

Bis zuletzt habe ich Läden, die ich ums Verrecken nicht über die Suche gefunden habe, immer über die allgemeine Kartenansicht der Stadt gesucht und so zuverlässig finden können. Dieser Workaround ist aus unerfindlichen Gründen nicht mehr auffindbar. Was soll das Qype? Wo ist die allgemeine Kartenansicht über alle Kategorien hin? Dienste wie MapTheQ sind zwar cool und hübsch, aber hier fehlen etliche Locations aus für mich nicht ersichtlichen Gründen. Ein hier naheliegendes Beispiel ist der fehlende REWE hier um die Ecke in dieser Kartenansicht. Zudem ist es schon irgendwie seltsam, dass man Qype verlassen muss, um eine gute allgemeine Kartenansicht zu bekommen.

Ein weiteres Problem in der Nähe der Suche und Positionierung sind die völlig falschen Stadtteilgrenzen. Zumindest in Düsseldorf stimmen die Stadtteilgrenzen vorne und hinten nicht, so dass ich mich hier mit allen Läden um mich herum laut Qype in Stadtmitte befinde und Flingern-Nord erst östlich der Dorotheenstraße anfängt (also an der PLZ-Grenze 40233/40235). Eller und Lierenfeld stimmen auch ganz und gar nicht. Diesen Fehler habe ich bereits mehrmals im letzten Jahr gemeldet, eine Antwort bekam ich nie und behoben wurde das auch nicht. Auch hier: Was soll das Qype? Die Statteile hatten ursprünglich ja mal gestimmt.

Die kaputten Stadtteilgrenzen sind deswegen besonders ärgerlich, weil Qype einem seit einiger Zeit ständig und überall die Stadtteile statt der Städte aufdrängelt. Beispielsweise kommt man im Breadcrumb innerhalb einer Kategorie nicht mehr zurück zur ganzen Stadt. Ist man also in Shopping->Mode in Flingern-Nord und möchte andere Modegeschäfte in Düsseldorf suchen, kann man nicht einfach im Breadcrumb klicken, weil man da nur zu Düsseldorf ohne Kategorie oder eben zur Kategorie Mode in Flingern-Nord gelangt. Will man Mode in ganz Düsseldorf shoppen, muss man zurück zur Stadt und sich wieder zur Kategorie durchklicken. Ohne die Stadtteilebene war das alles kein Problem. In Berlin mag das mit den Stadtteilen essentiell sein, aber in den meisten anderen Städten ist das eher lästig. Eine Entfernungssuche wäre die klar bessere Alternative.

Kein echtes Problem, aber schon oft zu Recht bemängelt: Das "neue" Design in Türkis und rot ist nach wie vor zum kotzen abstoßend und das für Mitglieder wählbare Classic-Theme ist nichts Halbes und nichts Ganzes. OK, die neue Optik ist inzwischen durchaus rund optimiert, aber immer noch nicht mal im Ansatz so angenehm, wie das angenehme orange-grüne alte Design. Seit diesem Relaunch geht es in meinen Augen bei Qype nur noch bergab. Auch die Zahl der Beiträge pro Tag scheint seitdem zu stagnieren. Keine Ahnung, ob das stimmt, aber ich werde das Gefühl nicht los, dass Qype seitdem nur noch abbaut.

Wenig hilfreich ist da, dass man keine negativen Bewertungen mehr für Beiträge vergeben kann. Immer wieder begegne ich schlechten Beiträgen, ob zu kurz oder einfach total dämlich, ich möchte gerne schlechtes Feedback geben. Ich kenne genug gute Beispiele, wo doofe Beiträge, die mehrheitlich von anderen Nutzern abgelehnt werden, ausgeblendet werden oder sonstwie in den Hintergrund gedrückt werden. Das sehe ich als guten Anreiz, qualitativ hochwertige Beiträge zu schreiben, denn niemand mag gerne negativ bewertet werden. Ein "Weniger lesenswert" oder "Nicht hilfreich", wie es das früher bei Qype gab, ist in meinen Augen immens wichtig für die Qualitätskontrolle durch andere User. Die gelegentlich angesprochene Gefahr des Vergraulens von Neuusern sehe ich weniger, denn viele Experten sind sehr nachsichtig bei schlechten Beiträgen von Anfängern und geben gute und konstruktive Kritik. Nur loben zu können oder sonst schweigen zu müssen, entwertet das Lob in meinen Augen immens. Klar kann man auch Kommentare schreiben, aber wie alle wissen, wie schnell bei negativen Kommentaren ein Flamewar auflodert. Gut ist allerdings, dass man inzwischen sehen kann, wer einen Beitrag lesenswert fand, das ist schon ein Schritt in die richtige Richtung, um diese Lobfunktion wieder aufzuwerten. Immerhin.

Ein Ärgernis ist in meinen Augen die fehlende Möglichkeit, ältere Beiträge zu editieren, ohne dass der Beitrag nach oben geschoben wird. Ich gebe zu, dass es durchaus meine Eitelkeit ist, aber wenn ich einen frühen oder ersten Beitrag zu einem Platz geschrieben habe, empfinde ich diesbezüglich gelegentlich einen gewissen Stolz. Das führt dazu, dass ich solche Beiträge regelmäßig nicht mehr um neue Informationen ergänze, um die Position nicht zu verlieren. Zudem kenne ich das Hochschieben von Threads durch kleinere Änderungen als ein eher negativ besetztes Verhalten und würde das im Falle von Schreibfehlern schon aus diesem Grunde gerne vermeiden. So oder so: Man sollte wählen können, ob ein Beitrag bei einer Änderung ein neues Hauptdatum bekommt oder nur einen Editierzeitstempel. Ach ja, der Thread-Zusammenhang wird durch das ungefragte Umsortieren ebenfalls auseinander gerissen, konkret meine ich die durchaus übliche Bezugnahme auf die Vorredner.

Einige der hier beschriebenen Kritikpunkte finden sich auch im Qype-Feedback-Forum (nur für Insider und Experten sichtbar). Trotzdem wollte ich mal eine eigene kommentierte Sammlung von Kritikpunkten hier veröffentlichen. Ich hoffe, es ist kontruktiv genug formuliert, damit das auch ankommt. Wie ich Qype kenne, wird das sogar durchaus wahrgenommen. Das muss ich mal loben: Communitymanagement funktioniert bei Qype recht gut. Trotzdem habe ich das Gefühl, dass es seit Monaten keine echte Weiterentwicklung mehr gibt. Vielleicht gab es einen signifikanten Personalabbau in der Entwicklung? Man weiß es nicht.

Stagnation ist Tod, Qype ist immerhin nicht alleine am Markt.


Linux lernen

11 12 2009

Zu meinem Job gehört auch die Administration von Linux-Servern, wenn man nicht immer auf den guten Willen seines Hosters angewiesen sein möchte. Dazu braucht man Linux-Kenntnisse, die man irgendwie erwerben muss, bevor man öffentliche Server betreut. Grundsätzlich sollte man das zwar Profis überlassen, die wissen, was sie tun, aber manchmal muss man eben auch selber ran. Doch wie fängt man an, ohne jemanden zu gefährden? Linux-Kenntnisse hat man ja nicht einfach so gottgegeben, sondern muss sie sich erarbeiten. Ich schreibe also mal ein paar meiner Erfahrungen aus Sicht ein es Webentwicklers nieder, der ein Arbeitswerkzeug bedienen können muss.

Ich beginne mit meinen ersten (dummen) Gehversuchen, also so, wie man es nicht machen sollte. Anfang 2003 hatte ich das Shared-Hosting bei Hosteurope satt, weil ich wiederholt mit meiner Shared-IP auf SPAM-Blacklists gelandet war, es musste also eine Lösung her. Zu der Zeit kamen die ersten bezahlbaren Rootserver auf den Markt und ich war übermütig genug, ohne jegliche Linux-Kenntnisse einen solchen zu bestellen und auch noch Kunden da mit drauf zu nehmen. Ahnungslos hatte ich mich damals für Suse mit Webmin entschieden und habe das mit viel Schmerz und Tränen irgendwie zum Laufen bekommen. Also alles selbst kompiliert und eingerichtet, und danach nie wieder Updates gemacht. Von Paketmanagern wusste ich damals nicht viel und ich hatte immer Angst, dass irgendwas passiert. Nach etwa zwei Jahren habe ich alle Kunden umgezogen und den Server gekündigt. Eine gute Entscheidung, denn jetzt konnte ich wieder ruhig schlafen. Fazit: Ich hatte im Grunde nichts verstanden und mit Suse kam ich ganz und gar nicht klar.

Da ich das ganze mit der Webentwicklung dann später ernster genommen habe, kam ich irgendwann wieder in Kontakt mit Linux. Diesmal in Form einer virtuellen Maschine mit Ubuntu Server drauf. Ich war das hantieren mit XAMPP leid und wollte endlich mal lernen, mit dem Scheiß umzugehen. Das war eine sehr gute Entscheidung. Ubuntu erbt die meisten guten Eigenschaften von Debian und ist zudem auch noch hervorragend dokumentiert. Ich kann nur jedem empfehlen, die ersten Schritte mit Linux-Servern in einer virtuellen Maschine zu machen und vor allem, sich die distributionsspezifischen Verwaltungswerkzeuge zu nutze zu machen, insbesondere die Paketverwaltung. Welche Distribution einem liegt, sollte man einfach ausprobieren, ich bin mit Ubuntu auf Desktop und Server sehr glücklich. Der Debian-Unterbau ist Gold wert, alleine die Apache-Verwaltung über die hervorragend dokumentierten Konfigurationsdateien ist eine wahre Freude.

In meinem HiWi-Job hatten wir immer mit einem unglaublich langsamen Server im Rechenzentrum zu kämpfen. Wie sich später herausstellte, hatte uns der Admin eine virtuelle Maschine mit nur 128MB RAM spendiert, für eine TYPO3-Seite mit 1000 Seiten, 70 Redakteuren und hohen sechsstelligen Zugriffszahlen im Monat ist das dann doch etwas wenig. Als der Admin wechselte, wurde aufgeräumt und man bat uns, für eine Weile das Hosting selber zu übernehmen. Also habe ich einen Ubuntu-Server auf einem ausrangierten PC-Pool-Rechner aufgesetzt, der bis heute weitgehend reibungslos läuft. Gelegentlich hängt er sich auf in letzter Zeit, das scheint an einer überlasteten MySQL-Datenbank zu liegen. Merke: Auch Übergangslösungen sollte man richtig machen, denn oft werden sie zum Dauerprovisorium. Übrigens gibt es inzwischen neue Hardware und mein Nachfolger muss den ganzen Server migrieren, was überraschend einfach ist. Ich will nicht sagen, dass es eine gute Lösung ist, wenn ich öffentliche Server verwalte, aber dank Ubuntu und einiger Übung in der virtuellen Maschine habe ich das ganz gut hinbekommen. Trotzdem laufen meine eigenen Präsenzen auf einem Managed Server. Insbesondere Geschichten wie Mailserver mit Spamfiltern oder Jabber-Server lasse ich weiterhin nur Profis machen. Ein LAMP-Server bekommt man aber auch so gut hin und leider besser, als bei vielen Hostern. Was ich da schon gesehen habe… Da mache ich das dann doch lieber selbst.

Wenn ich schon Rootserver mit Plesk sehe, rollen sich mir schon die Fußnägel auf. Wer sich nicht in der Lage sieht, einen Linux-Server richtig über die Kommandozeile zu warten, sollte die Finger davon lassen. Wenn man weiß, was man tut und sich von Plesk die Arbeit abnehmen lässt, OK, kann ich zwar nicht gutheißen, aber wenigstens nachvollziehen. Aber anders herum ist es ganz bitter. Wo Plesk ist, da lass Dich nicht nieder, ist meine Regel.


Wordpress hat schlimmen Code, andere aber auch

07 09 2009

Wer ernsthaft beruflich oder auf hohem Niveau in seiner Freizeit mit PHP arbeitet und älter als 15 ist, dem stehen wahrscheinlich beim Blick in den Quellcode von Wordpress die Haare zu Berge. Code is art ist ein wunderschöner Wordpress-Slogan, der in dem Kontext aber wirklich mehr als unangebracht ist. Schlimmer als der zusammengezimmerte Kern von Wordpress, der aktuell mal wieder mit einem notdürftigen Flicken gegen den grassierenden Wordpress-Wurm repariert wurde, sind aber die meisten PlugIns. Viele sind offenbar von blutigsten PHP-Anfängern schnell und ergebnisorientiert runterprogrammiert worden, was von Wordpress ja geradezu provoziert wird und was auch großen Anteil an der Beliebtheit des Systems trägt. Jeder ahnungslose Anwender kann mit ein paar Zeilen PHP-Code schnell das erreichen, was er gerade braucht. Das erinnert mich an meine Anfänge mit PHP im Jahr 2001 mit dem damals herausragenden phpBB 1.4. Hier war im Grunde alles hartkodiert und wenn einem irgendwas nicht gefiel, hackte man irgendwie im Quellcode herum. Ein Templatesystem wurde erst mit Version 2 eingeführt und auch hier hackte man noch alle möglichen MODs in das System, was ein Update praktisch unmöglich machte. Folge waren haarsträubende Sicherheitslücken, die nicht gestopft wurden. Wordpress vermeidet dieses Modding immerhin mit einem sehr flexiblen PlugIn-System, der Zugang für Dilettanten und Anfänger wurde dadurch aber noch einfacher. Das Ergebnis sehen wir zur Zeit, Gerrit van Aaken hat das schon zusammengefasst: Bei Wordpress hilft nur ein schmerzhafter Neuanfang, so wie TYPO3 das momentan auch vollzieht und wie phpBB das auch schon zwei mal hinter sich hat.

Nun will ich nicht so viel auf Wordpress rumhacken, wenn ich es selber gar nicht benutze. Im Grunde ist das System großartig, wenn man die miese Codebasis ignoriert. Ich will auf etwas ganz anderes hinaus, nämlich die Codequalität von Serendipity-PlugIns. Wann immer ich ein Seitenleisten-PlugIn installiert habe, musste ich dessen Code bearbeiten, weil die HTML-Ausgabe standardmäßig schlimm aussah oder gar fehlerhaft war. Das PlugIn-System von S9Y ist auf den ersten Blick recht kompliziert, was totale Dilettanten vom PlugIn schreiben abhält; das ist schon mal gut. Trotzdem ist die Codequalität der PlugIns oft eher mäßig. Fast überall wird zum Beispiel der HTML-Code mit echo direkt da ausgegeben, wo er anfällt, natürlich mit irgendwelchem HTML-Code drumherum, den der Autor gerade für angemessen hielt. Kein Wunder also, dass der Output nicht immer angemessen ausfällt. Ich habe vor einiger Zeit ein eigenes Seitenleisten-PlugIn für Twitter geschrieben, weil das alte u.a. genau dieses Problem zeigte. Ein Kernfeature meines PlugIns war der Einsatz einer Templating-Engine. Die zu implementieren war PHP-seitig ein Kinderspiel für jeden halbwegs erfahrenen PHP-Programmierer. Die Frage ist nun, warum zur Hölle von den paar offiziell verfügbaren PlugIns noch fast keines so ein Templating-System mitbringt? Es täte S9Y wirklich immens gut, wenn sich mal jemand hinsetzen würde und ein paar der PlugIns auf den aktuellen Stand bringen würde. Also zumindest eine Templating-Engine einbauen und die Ausgabe entsprechend anpassen, aber auch manch andere Routine könnte mal überarbeitet werden. Gegenüber Wordpress ist das Jammern auf hohem Niveau, aber auch S9Y ist merklich in die Jahre gekommen, vor allem seine PlugIns.

Wenn ich sowas lese, pflege ich zu antworten, derjenige soll nicht jammern, sondern selber anpacken. Das gilt auch für mich, sicher. Allerdings habe ich immens schlechte Erfahrungen mit meinem Twitter-PlugIn gemacht. Das einzige konstruktive Feedback kam vom unglaublich engagierten Chefprogrammierer selber, der mir meinen ursprünglich geplanten Arbeitsaufwand mit Änderungswünschen um das Mehrfache aufgeblasen hat. Am Ende war das neue PlugIn wirklich großartig geworden, ich bin richtig stolz darauf. Die ganzen angeforderten Änderungen kreisten alle um funktionale Anpassungen an das alte PlugIn, so dass mein neues PlugIn alle Funktionen des alten hatte, nur eben diesmal in gut. Dann kam das Problem: Es gab kein Feedback von Dritten und stattdessen hat mir ein ätzender Troll auch noch ans Bein gepisst und einen extra Thread im Forum aufgemacht, um mich als Schnösel zu dissen (weil ich PHP4 Nutzer, die PHP4 Kompatibilität einfordern, als Ewiggestrige bezeichnet habe und er sich davon angesprochen fühlte). Ich habe mein Engagement für S9Y daraufhin nach ein paar Tagen Diskussion eingestellt, denn für kostenlose und gute Programmierarbeit möchte ich echt alles andere haben als von irgendwelchen undankbaren Typen beschimpft zu werden. Mein PlugIn ist übrigens nie im Repository erschienen und stattdessen gibt es ein funktional wirklich krasses anderes PlugIn; hoffentlich ist wenigstens meine Arbeit da eingeflossen und war nicht völlig umsonst. Wie auch immer: Ich werde keine Arbeit mehr zu S9Y beitragen; wenn ich etwas neu baue, reiche ich das im Forum ein und wenn sich niemand drum kümmert, soll mir das egal sein.


Nur halb so schlimm: Eigene Short-URLs

05 09 2009

Vor einiger Zeit habe ich gefordert, dass größere und oft bei Twitter verlinkte Seiten eigene kurze URLs für ihren Content anbieten. Neulich erst habe ich mir dann Gedanken gemacht, wie man Short-URLs uns so verüberflüssigen kann. Auf diese große Lösung mag ich nicht warten, aber zumindest bei der kleinen Lösung kann ich mit gutem Beispiel voran gehen. Also habe ich gerade schnell ein kurzes Script geschrieben, das kurze URLs für mein Blog in die vollen URLs umsetzt. Zum Beispiel lautet für diesen Eintrag die kurze URL http://spackblog.de/668, was mit 23 Zeichen deutlich kürzer ist als die verdammt lange volle URL und vor allem kürzer als 30 Zeichen, ab denen Twitter ungefragt mit bit.ly verkürzt.

Ich hatte eine Weile überlegt, diese Funktionalität als Serendipity-PlugIn zu veröffentlichen, aber das habe ich aus verschiedenen Gründen nicht gemacht. Ein Grund ist, dass mich ein undankbarer Vollspacko im S9Y-Forum angesaugt und als Schnösel bezeichnet hat, als ich mein letztes PlugIn dort vorgestellt habe. Ich will da gar nicht genauer drauf eingehen, Folge ist jedenfalls, dass meine Lust auf die extra Arbeit für ein S9Y-PlugIn dadurch doch sehr gesunken ist. Ein weiterer Grund ist, dass der generierte Link irgendwo im Template und noch mal im Header positioniert werden muss, damit es Sinn macht. Das kann ein PlugIn nicht flexibel alleine regeln. Man könnte den Link allenfalls dort hinpacken, wo momentan auch die Tags sind, aber das gefällt sicher nicht jedem. An die .htaccess des Blogs, oder wenn dieses in einem Unterverzeichnis steckt auch an die .htaccess der Domain muss man auch noch ran. Spricht alles gegen ein PlugIn. Sowas gehört in meinen Augen sowieso in den S9Y-Core.

Das Script funktioniert super simpel. Alles fängt mit einer Anweisung in der .htaccess an, die alles, was nach kurz-URL aussieht an das Script weiterreicht:

RewriteEngine On
RewriteBase /
RewriteRule ^(e|a|c)?([0-9]+)/?$ s9y_shorturl.php?type=$1&id=$2 [NC,L]

Man kann schon sehen, dass das Script auch kurze URLs für Kategorien und Autoren unterstützt. Der spannende Teil im Script selber ist die Datenbankabfrage, die die kurze URL aus der Datenbank ausliest:


// open a database-connection
$dbh = new PDO('mysql:host=' . $db_server . ';dbname=' . $db_database, $db_user, $db_pass);

// prepare the statement
$stmt = $dbh->prepare('SELECT permalink
  FROM s9y_permalinks
  WHERE type = :type
    AND entry_id = :entry_id
  LIMIT 1');

// execute the statement
$stmt->execute(array(':type' => $type, ':entry_id' => $entry_id));
  
// read the returned urlpart
$urlpart = $stmt->fetchColumn();

// close the database-connection
$dbh = null;

// redirect the user with a 301 status code (moved permanently)
header('Location: ' $blog_base_url . $urlpart, true, 301);
exit;

Der Rest vom Script besteht aus Fehlerbehandlung und Variablen-Vorbereitung, die ich hier mal weg lasse. Wer den ganzen Code haben will, kann sich gerne bei mir melden. Damit ist der erste Teil schon fertig, der die kurzen URLs auflöst. Für die kurzen URLs werden einfach die von Serendipity vergebenen IDs genutzt, der Parameter type kann übrigens 'entry', 'category' oder 'author' sein. S9Y führt eine eigene Tabelle für die Zuordnung von IDs und URLs, die man nur abfragen muss.

Der zweite Teil ist leider Handarbeit im Template. Man muss dazu an der Stelle, wo der Link auftauchen soll folgenden Code in der entries.tpl platzieren: <a href="http://SHORTURL_DOMAIN/{$entry.id}">http://SHORTURL_DOMAIN/{$entry.id}</a>. SHORTURL_DOMAIN muss natürlich durch die jeweilige URL ersetzt werden, in meinem Fall ist das tatsächlich eine andere Domain als die, auf der das Blog läuft. Ich habe zusätzlich noch in der index.tpl im Headerbereich im {if $entry.id} Block einen Short-URl Autodiscovery Link eingefügt, wie er hier beschrieben ist.

Das ganze arbeitet extrem simpel und macht genau das, was es soll: Wenn jemand meinen Blog bei Twitter und Co. verlinken will, kann jetzt meine 23 stellige Kurz-URL hernehmen und sich so den Scheiß mit den verkürzten URLs sparen, bei denen man nicht weiß, wohin sie eigentlich linken. Alle Seiten sollten solche eigenen Kurz-URLs haben, dann wäre das mit Twitter nur noch halb so schlimm.


Wie man Short-URLs und so verüberflüssigen kann

27 07 2009

Der Microblogging-Server laconi.ca kann jetzt auch Dateianhänge. Das ist nett und macht Twitpic und Co. langfristig überflüssig. Dateiuploads funktionieren sehr simpel: Man lädt eine Datei hoch, der Dienst generiert dazu eine Short-URL mit is.gd. und fügt diese am Ende des Dents ein. Das wars. Dabei hätte man es wahrscheinlich so viel besser machen können.

Im Prinzip ist das Problem mit Dateianhängen das gleiche, wie mit URLs allgemein und verschiedenen anderen Sachen: Sie sind im Grunde Metainformationen zur Nachricht selbst und kollidieren mit dem 140 Zeichen Reintext-Limit beim Microblogging. Das ist etwas unfair, denn URLs sind mitunter sehr lang, gelegentlich sogar länger als 140 Zeichen. Abhilfe schaffen die vielen Short-URL Dienste, aber nun weiß man zum einen nicht mehr, was sich hinter einem solchen Link verbirgt (wie bei dem hier), zum anderen können Dienste schließen und alle darüber generierten URLs würden unbrauchbar werden. Oder aber URLs werden nach einiger Zeit recycelt, was noch schlimmer ist, denn nun zeigt mein Link auf eine völlig andere Seite. Short-URLs sind also scheiße und zu vermeiden, wo es nur geht. Doch wie? Im Folgenden ein paar Lösungsansätze zum Thema.

Wie wäre es, wenn Twitter (stellvertretend für alle Microblogging-Dienste gemeint), eine URL pro Nachricht als Metaangabe erlaubt. Die einfachste Möglichkeit dazu wäre es, von URLs nur ein Zeichen bei der 140-Zeichen Limitierung zu berücksichtigen. Das hätte aber gleich zwei gravierende Seiteneffekte: Erstens bricht man die API, denn viele Dienste erwarten nur 140 Zeichen und würden die Nachricht deswegen einfach abschneiden. Zweitens würde sich schnell die Unart etablieren, ganze Sätze in nicht existierenden URLs zu formulieren und so das Limit zu umgehen. Diese Möglichkeit kommt also keinesfalls infrage.

Eine erste echte Möglichkeit wäre es, wenn Twitter von jeder Short-URL beim entgegennehmen des Tweets das Ziel auslesen würde und dieses Ziel zur Verlinkung (oder als Title-Attribut) in der geparsten Nachricht benutzen würde. In der Textversion (über die API) würde dann aber immer noch alleine die Short-URL stehen, Twitter-Clients, die diese selber parsen, bekämen also davon nichts mit. Zudem werden die URL-Shortener das gar nicht mögen, werden sie so doch brutal übergangen. Das grundsätzliche Problem bliebe bei der Lösung außerdem bestehen: Die Short-URL ist immer noch da, wird archiviert und man ist weiterhin dem URL-Shortener ausgeliefert. Vorteilhaft wäre, dass Twitter das Verfahren sofort einführen könnte und die volle Kontrolle darüber hätte. Sprich: User könnten das Verhalten konfigurieren, wenn sie es nicht mögen und Twitter kann sich aussuchen, bei welchen URL-Shortenern sie das Verfahren anwenden. Denkbar wäre auch, dass Twitter einen eigenen URL-Shortener Dienst anbietet, der das Verfahren implementiert.

Meine eigentliche Idee ist aber Folgende: Twitter erweitert seine API um ein Feld für eine URL (mit max 255 Zeichen). Das Webinterface und Twitter-Clients, die das Verfahren implementiert haben, bieten ein extra Eingabefeld für diese URL und fügen (zumindest übergangsweise) automatisch eine Short-URL dazu in die Nachricht ein. Diese Short-URL wird zweckmäßigerweise von einem dem Dienst angeschlossenen Service bereitgestellt und sollte garantiert so lange leben, wie es den Dienst gibt. Ältere Clients schicken eine normale Short-URL in der Nachricht und Twitter parst diese (bzw. die erste, wenn es mehrere gibt) und füllt die eigentliche URL in das Extrafeld ein. Als einzigen Nachteil des Verfahrens sehe ich, dass durch die Erweiterung der API das Verfahren nicht sofort in voller Schönheit in allen Clients zum Vorschein kommt. Dass so nur eine solche URL pro Nachricht möglich ist, sehe ich angesichts des 140 Zeichen Limits als durchaus konsequent und nicht als Nachteil an. Langfristig sehe ich aber große Vorteile in dem Verfahren: Es ist voll abwärtskompatibel, bringt aber neue Möglichkeiten mit. Können genug Twitter-Clients mit diesen URLs angemessen umgehen, kann man auf das Einfgen einer zusätzlichen Short-URL verzichten und hat die vollen 140 Zeichen für seine Nachricht zur Verfügung. Ein weiterer Vorteil ist, dass die Clients selbst entscheiden können, wie sie mit URLs umgehen wollen.

Ich halte das für eine saubere Lösung für das leidige Short-URL Problem, aber eben auch für andere Metadaten. Dateianhänge könnten auf die gleiche Weise implementiert werden, intern macht laconi.ca/identi.ca das offenbar ja schon so. Nur hapert es eben an der Anbindung nach Außen. Ebenfalls abgefrühstückt werden könnte dann endlich auch mal eine sinnvolle und nicht störende Geokodierung von Beiträgen. Momentan behilft man sich mit Krücken wie L:Düsseldorf, was für "Location Düsseldorf" steht, oder der sehr hässlichen Einbindung von Geokoordinaten direkt in den Nachrichtentext. Ein Metafeld für Geoinformationen würde hingegen niemanden stören, eine verlässliche Einbindung von Kartendiensten in geofähigen Clients erlauben und so schöne Geschichten wie Live-Twitter-Maps ermöglichen. Flickr hat das so schön vorgemacht.

Mancher mag jetzt einwenden, dass gerade die Einfachheit von Twitter mit dem einen Eingabefeld seinen Charme ausmacht. Dem halte ich entgegen, dass drei kleine Knöpfchen neben dem Eingabefeld für diese Metainformationen der Einfachheit keinen Abbruch tun würden, die vielen Twitter Poweruser hätten aner eine schöne Möglichkeit, ihre Tweets sauber zu halten. Kein Anfänger auf der Suche nach Einfachheit versteht Tweets, wo alles irgendwie verlinkt ist mit #Tags, !Gruppen, L:Orten, http://sho.rt/urls, RTs und @namensnennungen. Da kann man doch beim besten Willen nicht mehr von Einfachheit sprechen und eine Metaangabe für Reply-Tos gibt es schon immer und jeder weiß die zu schätzen.

Meine Forderung an Twitter und identi.ca lautet also: Erweitert Eure API um Felder für eine URL, Geokoordinaten und ggf. einen Dateianhang. Die Leute benutzen diese Sachen tagtäglich und nutzen dafür teilweise ärgerliche Krücken. Schluss damit!

Ich selber werde bei Gelegenheit meine PHP-Twitter-API derart erweitern, dass sie eingehende Short-URLs auflöst und ersetzt (und das Ergebnis cached). Profitieren wird davon mein Lifestream und die Microblog-Anzeige in der Sidebar vom Blog.

Nachtrag 24.08.2009: Inzwischen hat Twitter eine Erweiterung um Geokoordinaten zu jedem Tweet angekündigt, was gut ist. Was aber schlimmer als gedacht ist: Twitter kürzt automatisch und unabschaltbar alle URLs mit mehr als 30 Zeichen mit bit.ly. Ich hasse das, denn wenn ich von meinen 140 Zeichen 60 für eine URL opfere, dann hat das seinen Grund. Hoffentlich ändert sich das irgendwann mal wieder.


Mal wieder: Wie sollte man mit den IE6-Nutzern umgehen?

15 07 2009

So viel wurde schon zum IE6 geschrieben, so viel Hass wurde ausgeschüttet und so viele Erklärungsansätze für den noch immer beschämend hohen Marktanteil dieses Fossils wurden gebracht. Nun muss ich noch mal etwas dazu loswerden. Warum gerade jetzt? Zu einen habe ich zuletzt mehrere Tage unbezahlt mit IE6-Debugging verbracht, zum anderen hat YouTube angekündigt, den Support für den IE6 ab sofort auslaufen zu lassen. Das ist eine großartige Entscheidung, denn bisher hat sich kaum ein reichweitenstarkes Webangebot zu diesem Schritt durchringen können. Die Begründung halte ich für sehr stichhalting: YouTube sagt, dass sie der Support des IE6 glasklar messbar und nicht zu knapp Geld kostet und dass einige neue und praktische Funktionen mit vollem IE6-Support nicht machbar sind. Genau das ist der Punkt. Danke an Google für diesen mutigen Schritt. Denn nur durch Leidensdruck seiner Nutzer wird der IE6 aus den Statistiken verschwinden. Solange die Inhaltelieferanten die teilweise massiven Mehrausgaben bei der Entwicklung für den IE6 tätigen, wird sich an der Situation nichts ändern.

Ein viel gehörtes Argument ist ja, dass viele Nutzer an Firmen-PCs nur den Internet-Explorer 6 benutzen können/dürfen und so ja jetzt ausgeschlossen sind. Das stimmt. Na und? Eine reichweitenstarke Seite wie YouTube verliert dadurch vielleicht ein paar Prozent seiner Nutzer. Noch mal: Na und? YouTube ist wichtig genug, dass diese Leute im Zweifel schon einen Weg finden werden, sprich einen anderen Browser installieren. Oder sie lassen YouTube eben bleiben. Man darf nicht vergessen, dass da jemand mit einem Programm unterwegs ist, zu dessen Erscheinungszeitraum Videodienste wie YouTube noch unfassbare Zukunftsmusik waren. Woher kommt die Erwartungshaltung, dass das ohne Einschränkungen klappen muss? Ich denke, man muss sich einfach der Realität stellen. Es gibt genug Alternativen und keine davon kostet etwas.

Aber das CRM-System in unserer Firma (oder Intranet-Anwendung-XY) läuft nur mit dem Internet Explorer! Auch das höre ich immer wieder und ich habe zwei Antworten darauf: Erstens würde ich mich fragen, ob meine Intranet-Anwendung eine gute Anwendung ist, wenn sie die vorletzte Version eines so wichtigen Programmes als Zugangsvoraussetzung hat, aber da rede ich Firmen ungerne rein. Zum anderen aber spricht meiner Meinung nach nichts gegen den Paralleleinsatz von IE6 als Zugangsprogramm fürs veraltete Intranet und einem modernen Browser für das Internet. Selbst wenn es unbedingt der Internet Explorer 8 sein muss, gibt es Mittel und Wege, parallel einen IE6 zu betreiben. Zu viel Administrationsaufwand? Nun, so ist die Welt. Man denke im Firmeneinsatz übrigens auch an die haarsträubenden Sicherheitslücken des IE6, die nicht mehr behoben werden.

Aber was ist mit der Barrierefreiheit? Nutzer auszuschließen widerspricht dem Barrierefreiheitsgedanken, klar. Aber ist das hier wirklich so? Dafür muss ich eine Analogie bemühen: Man stelle sich vor, es gäbe ein Gesetz, das die Beschaffenheit von Rollstuhlrampen regelt. Alle Hersteller von Rollstühlen halten sich an diese Vorhaben und fahren prima damit. Nur der klare Marktführer hat bei früheren Modellen einmal diese Regeln anders ausgelegt und die Räder als Vielecke statt als Kreise ausgelegt. Das ist anfangs vielleicht Stand der Technik gewesen, technisch sinnvoll war es aber nie. Auf standardkonformen Rollstuhlrampen ist die Fahrt für Nutzer solcher Rollstühle dadurch etwas unbequem, weswegen alle Gebäudebetreiber ihre Rollstuhlrampen bisher sehr teuer in mechanisch sehr aufwändigen und vor allem technisch unsinnigen Varianten gebaut haben. Für die Nutzer standardkonformer Rollstühle gäbe es längst Entwicklungen, die die Nutzung von Rollstuhlrampen wesentlich bequemer und einfacher gestalten würden, aber diese sind mit den Vieleckrädern nicht oder nicht sinnvoll in Einklang zu bringen. Der Marktführer würde daher schon lange ein kostenloses Austauschprogramm für seine alten Modelle anbieten. Macht es hier Sinn, von einer Barriere zu sprechen, wenn man bei neuen Gebäuden die sich bietenden Vorteile nutzt und die Nutzer der veralteten Rollstühle zwingen würde, das kostenlose Austauschprogramm des Herstellers zu benutzen? Ich habe da meine Schwierigkeiten mit. Es geht ja nicht darum, dass der alte Rollstuhl die Rampe gar nicht mehr benutzen kann, es würde für etwas holpriger werden.

So sehe ich das auch beim IE6: Wer der Meinung ist, mit einem Browser aus dem Jahr 2001 im Jahr 2009 alle Funktionen moderner Websites genießen zu können, leidet unter massivem Realitätsverlust. Eine Website sieht komisch aus? Nun gut, da könnte man denken, der Seitenbetreiber wäre ein Idiot. Wenn aber immer mehr Websites komisch und kaputt aussehen und mir einhellig sagen, dass sie meinen veralteten Browser nicht mehr unterstützen, kann ich die alle doof finden oder mich der Realität stellen und ein Update machen. Genau deswegen braucht es Seiten wie YouTube, die die Eier haben, dieses doof gefunden werden einstecken zu können und im Zweifel ein paar Nutzer zu verlieren.

Hier kommt wieder der Geldaspekt ins Spiel. Mal angenommen, die Implementierung einer modernen Funktion ist im IE6 nicht möglich. Dann wird YouTube durchrechnen, was für einen finanziellen Wert die neue Funktion hätte. Dann wird YouTube gegenrechnen, was der Ausfall von einer angenommenen Zahl an IE6-Nutzern, die nicht umsteigen, sondern YouTube den Rücken kehren, kosten würde. Dann wird YouTube einrechnen, wieviel es wert ist, wenn x Prozent der ehemaligen IE6-Nutzer auf den Google-Browser Chrome umsteigt. Dann wird YouTube einen großen Strich unter die Rechnung machen und den IE6-Support sofort einstellen. Die Dimension, dass auch andere Google-Dienste vom Tod des IE6 profitieren, habe ich hier noch gar nicht einbezogen. Eine ähnliche Rechnung tut sich auf, wenn man die Entwicklungskosten für IE6-Zurechtbiegen gegen den Imageverlust durch etwas komisch aussehende Websites gegenrechnet.

Bei einem eigenen Projekt würde ich keinesfalls Geld in die Kompatibilität mit dem IE6 stecken und auf tolle neue Funktionen für alle anderen verzichten. Wer das Geld weiterhin ausgeben möchte, kann das ja weiterhin tun.

P.S. Ich muss dazu sagen, dass ich bei meinem letzten Auftrag einen Pauschalpreis veranschlagt und dabei u.a. die für das IE6/IE7 Debugging nötige Zeit völlig falsch eingeschätzt habe. Insgesamt habe ich nun mehrere Tage komplett unbezahlt (das entspricht meinen Fixkosten für einen ganzen Monat) da rein stecken müssen, was mich ernsthaft ärgert. Merke: Keine Pauschalpreise für so einen Mist und wenn doch, dann nicht so knapp kalkuliert.


Liebe Spammer, Adressraten ist scheiße

12 07 2009

Lieber Spammer vom EuroClubCasino (und andere), ich schalte mit sofortiger Wirkung mein CatchAll für E-Mail Adressen auf meiner Domain spackmat.de ab. Ich weiß nicht, wie ihr es geschafft habt, eine E-Mail an alle diese 14 durchgeratenen E-Mail Adressen an meinem scharfen Spamfilter vorbeizudrängeln, aber hurra, es hat geklappt. Eine kleine Portion Respekt dafür. Nun aber die Information: Die Adressen sind teilweise gut geraten und offenbar habe ich auch mit Michael Fredrichs (den ich in der Sidebar verlinkt habe) einen direkten Leidensgenossen; allerdings hat der Herr keine E-Mail Adresse unter meiner Domain, wirklich nicht. Die anderen Adressen gibt es auch nicht. Wenn ihr mich vollspammen möchtet, findet ihr meine gültige Adresse (mit dem gleichen, sonst sehr zuverlässigen Spamfilter geschützt) auf meiner Kontaktseite, völlig unmaskiert und mit mailto:-Link vesehen. Warum einfach, wenn man auch Adressen raten kann?

  • fredrichs@spackmat.de,
  • mfredrichs@spackmat.de,
  • wunschliste@spackmat.de,
  • amazonwunschliste@spackmat.de,
  • amazon.wunschliste@spackmat.de,
  • michael@spackmat.de,
  • m.fredrichs@spackmat.de,
  • gregor.nathanael@spackmat.de,
  • a.wunschliste@spackmat.de,
  • awunschliste@spackmat.de,
  • aw@spackmat.de,
  • amazon@spackmat.de,
  • gnathanael@spackmat.de,
  • g.nathanael@spackmat.de

Interessant finde ich die Trickserei mit Amazon und deren Wunschliste. Sind das viele Leute, die dafür eine extra Adresse benutzen? Wie auch immer, das Mail-CaatchAll ist jetzt deaktiviert und ich wusste bis jetzt gar nicht, dass es überhaupt noch aktiviert war.


jQuery Stolperstein: hover() und slideUp()/slideDown()/animate()

21 06 2009

Gelegentlich möchte ein CSS Dowpdown-Menü um eine kleine Animation erweitert werden, die bei der Gelegenheit auch den Suckerfish für den IE6 übernimmt. Natürlich macht man sowas mit jQuery, wenn man das sowieso eingebunden hat, in etwa so (natürlich alles innerhalb von $(document).ready()):

$('#mainMenu>li').hover(
  function(){
    $(this).find('>ul').slideDown(150);
  },
  function(){
    $(this).find('>ul').slideUp(50);
  }
);

Nun kommt es dabei immer wieder zu den selben Problemen:

Fährt man mit der Maus schnell mehrmals über einen Punkt, werden alle nötigen Animationen in eine Warteschlange gepackt und nach und nach gemütlich abgearbeitet. Das lässt sich noch leicht und logisch beheben, indem man jeweils mit einem stop() vor slideDown() und SlideUp() die Animation erst einmal stoppt, bevor man das Gegenstück ausführt. Das gleiche passiert auch bei animate() und vergleichbaren Sachen und lässt sich da auf die gleiche Weise beheben. Soweit kein Problem und nach ein paar Sekunden Google-Recherche gefunden.

Ein weiteres Problem ist das Handling der Animation bei der ersten Berührung mit der Maus: Scheinbar wird das jQuery hover Event erst bei der zweiten Berührung genutzt, bei der ersten klappt das Menü ganz normal mit der im CSS definierten Methode aus. Auch hier hilft eine Google-Recherche schnell weiter und bringt die Lösung frisch auf den Tisch: Vor der ersten Berührung (also zweckmäßiger Weise in $(document).ready()) müssen die UL-Elemente der Untermenüs mit einem beherzten Aufruf von hide() versteckt werden, auch wenn sie durch das CSS eigentlich schon versteckt sind. OK, das muss man wissen und kommt nicht von alleine drauf.

Perfide ist das dritte Problem bei Animationen mit den Ausmaßen der Untermenüs, also slideDown()/slideUp() und animate() in Kombination mit height() oder width(): Nutzt man diese innerhalb der hover() Funktion und verlässt das Element noch während die Animation läuft, speichert jQuery den zu diesem Zeitpunkt aktuellen Wert der animierten Abmessungen zwischen und animiert fortan nur noch bis zu diesem Maximalwert. Verlässt man den Menüpunkt also sofort wieder, wird das Menü bis zum Seitenreload nie wieder erscheinen, denn es ist ja nur noch etwa einen Pixel hoch und wird entsprechend auch nur bis zu einem Pixel animiert. Hier habe ich keine Lösung bei Google gefunden, weil ich nicht wusste, wonach ich suchen sollte. Also habe ich mich mit dem Firebug auf die Lauer gelegt und das Problem in der beschriebenen Form analysieren können. Ich weiß nicht, ob das ein Bug ist oder volle Absicht, aber ich kann mir nicht wirklich eine Situation vorstellen, wo dieses Verhalten gewünscht wäre. Die Lösung dafür liegt aber auf der Hand: Ein unscheinbares height('auto') vor der ausklappenden Animation behebt das Problem sehr zuverlässig.

So sieht nun also das komplette Menüscript aus, das sich endlich so verhält, wie man es auch erwartet:

$('#mainMenu>li>ul').hide(); // needed to prevent CSS-only behaviour on first contact
$('#mainMenu>li').hover(
  function() {
    $(this).find('>ul').stop().height('auto').slideDown(150); // the height('auto') prevents the menu from memorizing an incorrect height-value forever when leaving the menu while the animation is running
  },
  function() {
    $(this).find('>ul').stop().slideUp(50);
  }
);

An anderer Stelle half mir height('auto') aber nicht weiter, was also tun? Die Lösung lag zunächst auch hier auf der Hand: Beim Laden der Seite müssen die initialen Werte des Elements in einer Variablen gespeichert werden, zu denen die Animation dann jeweils zurückkehren kann. Das schien mir immens unelegant, weil ich nicht den globalen Scope mit solcherlei Variablen vollmüllen wollte. Mein Bruder brachte dann den entscheidenden Tipp: Man kann die Werte prima als Attribute des Elements im DOM ablegen. Beliebige Attribute sind in HTML zwar nicht erlaubt, aber wenn das Dokument erst mal ins DOM eingelesen wurde, sind die Limitierungen von HTML völlig gleichgültig. Kurz gesagt: Ist das Ding im DOM, ist es kein HTML mehr. Die Denke muss man sich erst mal klar machen. Gut, also schreibe ich die Werte in $(document).ready() fix als Attribute ins DOM und alles wird gut. Doch da hatte ich nicht mit der strengen, aber korrekten Auslegung des ready()-Events in Opera gerechnet: Dort stehen zu diesem Zeitpunkt die gewünschten Werte nicht zur Verfügung, weil es sofort gefeuert wird, sobald das DOM fertig eingelesen wurde, aber eben noch bevor die Engine irgendetwas rendern konnte. Abmessungen sind also nicht bekannt. Die Lösung lautet hier $(window).load(). Dieses Event wird gefeuert, sobald die Seite gerendert wurde, mithin also auch alle Abmessungen bereit stehen. So sind die Events spezifiziert, aber Opera scheint der einzige Browser zu sein, der sie auch so handhabt. Die komplette Lösung für dieses Problem lautet also in etwa so:

$(window).load(function(){
  $("#elementId").attr('origHeight', $("#elementId").height());
});

Ausgelesen wird auf die gleiche Weise, also $("#elementId").attr('origHeight').

Nachtrag 05.07.2010: Wo ich den alten Beitrag gerade noch mal lese, fällt mir auf, dass Doku lesen oft hilft. Der letzte Punkt wird natürlich viel eleganter gelöst, wenn man einfach die data()-Methode von jQuery benutzt. Also wie immer: Augen auf und Hirn an.