The horrors of PHP

Wenn herauskommt, dass ich tatsächlich noch PHP bei manchen Kunden einsetze, bin ich vermutlich bald arbeitslos. Aber ich kann alles erklären!!! Das hat.. historische Gründe. Und für manche Zwecke ist das Framework tatsächlich ziemlich brauchbar, vor allem aus dem Preis-Leistungswinkel heraus betrachtet.

Heute ein kleines Schmankerl, das mich einen halben Tag gekostet hat und mit einem Schlag gegen die Stirn endete, den ich heute noch spüre. Ausgangssituation ist die Befüllung eines Array mit weiteren Strukturen (auch assoziative Arrays). Dabei werden manchmal neue Einträge erzeugt, während in anderen Fällen ein bereits bestehender Eintrag ergänzt wird.

Consider this code:

$main = array();

$first = array(); // erster Eintrag
$first["bla"] = "blup";

$main[] = $first;

// wenn man diesen Eintrag noch ändern will
$change_it = end($main);
$change_it["bla"] = "blip";

// schaun wir mal
print_r($main);

Huch, immer noch "blup"! Ist klar, end() liefert nur eine Kopie. Man muss sich also eine Referenz holen. Dies gelingt mit dieser ziemlich "eingängigen" (höhö) Syntax:

end($main);
$change_it = &$main[key($main)];
$change_it["bla"] = "blip";

Jetzt ist es fein, in "$main" ist des nun korrekt mit "blip" überschrieben. Doch damit nicht genug. Jetzt kommen wir zum eigentlichen Spezialisteneinsatz.

// Ein weiteres Element hinzufügen
$change_it = array();
$change_it["bla"] = "blop";
$main[] = $change_it;
// schaun wir jetzt mal
print_r($main);

Ach du Sch****! Was ist denn hier passiert?


Array
(
    [0] => Array
        (
            [bla] => blop
        )

    [1] => Array
        (
            [bla] => blop
        )
)

Meine Erwartungshaltung wäre gewesen, dass durch die Zuweisung der Neuanlage des Arrays der Referenz-Bezug aufgehoben ist. Aber das ist nicht der Fall! Füge ich folgendes ein:

unset($change_it);

funktioniert es wie erwartet:

Array
(
    [0] => Array
        (
            [bla] => blip
        )

    [1] => Array
        (
            [bla] => blop
        )
)

Man darf also nie vergessen, dass die Normalität nur ein dünner Schleier vor der Anarchie und dem Chaos ist.. ne quatsch, ich meine natürlich PHP nur ein Wrapper über eine C-Libary ist, deren haarige Knochen immer mal wieder hier und dort herausgucken. Musch halt wissa! Meine Güte.

SVN to Git (Part III)

Keine weiteren Details, nur ein kleines Addendum. Eine Info, die ich immer wieder vergesse und hier (auch für euch) aufbewahre. Hin und wieder kommt es vor, dass man ein neues Repository anlegen möchte. Ja, sogar bei mir gibt es gelegentlich neue Projekte ;-) Diese entstehen nun normalerweise nicht auf dem Server sondern auf der Arbeitsstation oder dem Laptop, den man unterwegs dabei hat. Um so ein Projekt remote zu tracken (und vor allem zu sichern) legt man ein remote repository auf dem Server an. Ich habe dazu ein Wurzelverzeichnis für alle serverseitigen Git-Repositories. Das ist praktisch, weil man diese so einer einfachen Datensicherung zuführen kann. Man kann dann folgendermaßen vorgehen:

cd /usr/local/git_root
mkdir git_newProject
git init git_newProject
cd git_newProject
git config --bool core.bare true

Nach "git init" muss man ggf noch (rekursiv) die Berechtigungen des Folders anpassen. Wenn man (wie ich) git mit ssh verwendet, sollten alle Anwender die auf das Verzeichnis zugreifen Schreibberechtigungen haben.

Jetzt kann man das lokale Repository in das eben angelegte leere Repository pushen:

git push --set-upstream origin master

Da noch keine Tracking-Informationen vorhanden sind müssen diese per upstream Option gesetzt werden. Jetzt sind beide Repositories in Sync und man kann mit dem bekannten push/pull Verfahren Änderungen übertragen.

SVN to Git (Part II)

Das SVN Repository nach Git zu überführen ist schon nicht schlecht, nur reicht das in vielen Fällen nicht ganz aus. In "klassischen" VCS Systemen sind häufig mehrere Projekte enthalten, wie auch in meinem SVN Repository. In Git empfiehlt es sich jedoch, für jedes Projekt ein eigenes Repository anzulegen. Der Hintergrund ist, dass es nicht möglich ist, Branches und Merges nur auf einem Teil des Repositories auszuführen. Wenn z.B. in einer Struktur "Projekte" Unterverzeichnisse mit den Projekten "A", "B" und "C" existieren, kann in git nicht z.B. "C" master nach "C" v. 1.0 gebrancht werden. Durch die "leichte" Bauart der Repositories ist es aber kein Problem, für die Unterprojekte jeweils eigene Repositories anzulegen. Ein weiterer Vorteil ist, dass damit auch Abhängigkeiten offensichtlicher werden, was zu sauberem Arbeiten verleitet.

Was kann man also machen? Die Vorgehensweise ist grob die: Das von SVN im ersten Teil erzeugte "große" Repository wird zunächst noch einmal geklont. Dann werden die unerwünschten Teilprojekte herausgetrennt, so dass nur noch das relevante Projekt übrig bleibt. Dieses Repository wird dann noch einmal sauber in ein neues, endgültiges Repository geklont.
Zu meinem Beispiel soll ein Repo erzeugt werden, dass nur das Projekt "C" enthält.

Das von SVN erzeugte Repository in ein temporäres Repository klonen und in das Verzeichnis wechseln

 git clone git_svn/ git_svn.tmp/
 cd git_svm.tmp

Abtrennen der Projekte A und B

git filter-branch --prune-empty --index-filter 'git rm --cached --ignore-unmatch A/* B/*' HEAD

Der jetzt entstandene "Rest" wird zu einem neuen Repository. Das Zwischen-Repository kann danach gelöscht werden. Bitte beachten: Ab jetzt ist ein Update per git svn fetch nicht mehr möglich, da die remote Beziehung nicht mehr besteht.

cd ..
git clone git_svn.tmp/ new/path/to/C
rm -rf git_svn.tmp/

In diesem Zusammenhang möchte ich auf das neue schöne Syntax-Highlighting ab diesem Post aufmerksam machen, das durch das Plugin Syntax Highlighter Evolved erzeugt wird. Das klappte erst durch die Umstellung auf den neuen WordPress-Editor, mit dem ich bis heute nicht zurecht kam. Grund war, dass der Schalter für das Hinzufügen von Blocks immer ausgegraut war. Ärger! Die Lösung ist einfach wie idiotisch: In den User Einstellungen " Disable the visual editor when writing " erst deaktivieren, speichern und dann wieder anhaken und speichern. Dann funktioniert es. Das liegt vermutlich an einem etwas defekten zurückliegenden WordPress-Update.

SVN to GIT (Part I)

Late to the party, ich weiß. Aber wenigstens bin ich irgendwann doch noch angekommen. Beflügelt durch eine wirklich gute Schulung die ich bei einem Kunden genießen durfte habe ich beschlossen, mein ziemlich umfangreiches SVN Repository nach git zu migrieren. Dabei kann man gleich aufräumen und "sinnvolle" Repositories erzeugen von Dingen, die zusammengehören. Ich habe mein SVN allein verwendet und auch fast keine Branches erzeugt, so dass die Migration ziemlich leicht ist. Für jeden SVN Benutzer legt man ein Eintrag in einer Mapping-Datei an, damit die in git übliche Benutzername / Email Konstruktion zugeordnet werden kann. Beispiel:
hmueller = Hans Müller
Dann erzeugt man z.B. in einem Verzeichnis git_svn ein SVN Repo mit folgendem Kommando
git svn clone svn://lager/project --no-metadata -A author.txt git_svn/
Auf den Parameter --stdlayout habe ich verzichtet, da mein SVN Repo keine trunk/branches Struktur hat. Wenn "git svn" nicht funktioniert ist es wahrscheinlich nicht installiert. Auf einem Raspberry Pi ist das per default so. Man kann dann das Paket mit sudo apt-get install git-svn nachinstallieren.
Nicht verzagen, das dauert (auf dem Raspberry Pi) je nach Repository-Größe ewig. Das Ergebnis ist ein Git-Repo, in der die komplette Versionshistorie enthalten ist. Und das Beste: Die Verknüpfung zu SVN ist nach wir vor erhalten. Kommen noch Änderungen in SVN an, können diese mit einem
git svn fetch nachgezogen werden, ohne das man das Repository erneut klonen muss. Sehr praktisch! Jetzt gibt es die Situation, dass ggf. der HEAD Pointer irgendwo hinzeigt bzw. die Git Revisions zu den SVN Revisions gemappt werden. Das passiert immer nach einem fetch. Mit
git update-ref refs/heads/master refs/remotes/git-svn
kann man eine Aktualisierung durchführen.

await!

Bisher habe ich um das async/await Pattern in C# eher einen Bogen gemacht. Grundsätzlich war mir mehr oder weniger klar, was da vor sich geht, aber wozu syntaktischer Zucker, wenn es auch so geht? Es sieht schöner aus. Zumindest für diejenigen, die "Schönheit" für uns festlegen. Aber inzwischen trifft man auf Konstellationen, in denen man gar nicht mehr drumherum kommt, z.B. wenn eine Bibliothek, die man verwenden möchte nur noch LalaBlaBlubAsync(...) Aufrufe hat, wobei die Vorversion noch mit LalaBlaBlub(...) auskam. Tja.

Ich wollte dann doch mal etwas tiefer gehen und stieß auf diesen interessanten Artikel (Achtung MSDN Link). Ich finde, das Konzept wird hier wirklich schön erklärt. Das Beste daran ist jedoch dieses herrliche Zitat:

“Asynchronous code reminds me of the story of a fellow who mentioned that the world was suspended in space and was immediately challenged by an elderly lady claiming that the world rested on the back of a giant turtle. When the man enquired what the turtle was standing on, the lady replied, “You’re very clever, young man, but it’s turtles all the way down!”

Better late than never!

errorMode Custom

Hier eine kleine Anmerkung zu einem kleinen Ärgernis, AKA ungooglebarer Fehler:

Man betreibt man eine Site oder einen Webservice mit dem IIS (Version 7 in meinem Fall) möchte man in seltenen Fällen im Code explizit den StatusCode setzen. Das kann z.B. so aussehen:

WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.ServiceUnavailable;

Diese Zeile führt dazu, dass der Aufrufer 503 Busy zurückerhält. Neulich hatte ich die Situation, dass der Client stattdessen immer 500 bekam und die betr. Zeile ignoriert wurde. Weshalb? Es war zum Verrücktwerden. Offensichtlich war folgender Abschnitt in der web.config dafür verantwortlich:

<system.webServer>
<httpErrors errorMode="Custom" />
<system.webServer>

Heart failure

Gestern habe ich die OpenSSL Lib in unserer iOS App gepatcht. Die verwendete Version hatte den Heartbleed.

Am Tag 2 fragen sich jetzt alle wie das nur sein kann, daß so ein eklatanter Bug jahrelang unentdeckt in einer Open Source Software versteckt bleibt. Und .. ogott jaaa.. wer den wohl schon alles für seine finsteren Machenschaften ausgenutzt hat?!

Open Source muss doch sicher sein, es ist offener Quellcode, jeder kann reinschauen und damit sollten Fehler doch sofort entdeckt werden! Das klappt aber nur dann wenn es eine kritische Masse Leute gibt, die das auch tun und die verstehen, was sie dort vorfinden. Und das ist im Fall von OpenSSL sicherlich nicht so ganz leicht. Jeder der diese Lib schon verwendet hat weiß, wie gräßlich kompliziert das Ding ist. Und ich spreche hier nur von der korrekten Verwendung, vom Griff in den Code selbst ist das meilenweit entfernt. Das ist auch, was man z.B. bei Fefe lesen kann. Der sich selbst nicht zutraut, das Ding zu auditieren, weil, tja, einfach zu kompliziert das Ganze. Lieber selbst schreiben(!). Ich nehme zwar an, daß das ironisch gemeint war aber das ist eher einer der Cracker auf dem Gebiet.

Ich stelle dasselbe Phänomen auch bei uns fest: Je komplizierter ein Code-Komponente aufgebaut ist, desto länger halten sich darin die haarsträubendsten Fehler. Sitzen einem direkt vor der Nase, aber man kann sie nicht erkennen, weil man vor lauter Bäumen den Wald nicht sieht. Aus diesem Grund kann ich immer wieder nur eins meiner Dauer-Mantras wiederholen. Warum einfach, wenns auch kompliziert geht! Ne halt, das war jetzt nicht ganz richtig..

Wer wissen will wie Heartbleed funktioniert klickt einfach mal hier.

Codekicker: Was gut ist muss auch teuer sein?

Seit den Anfängen bin ich Fan und Mitglied von stackoverflow. Das ist eine Webseite, auf der Entwickler ihre Fragen loswerden können, die dann von anderen Entwicklern und Fachleuten beantwortet werden. Dafür bekommen sowohl Fragesteller als auch Beantworter Punkte, sogenanntes Karma. Das Karma vergibt nicht die Administration, sondern die anderen Benutzer, die ihre Stimme abgeben können, wenn ihnen eine Frage oder Antwort besonders gut gefällt. Für eine falsche Antwort oder eine nicht fachlich passende Frage kann sogar Karma abgezogen werden. Und weil die Menschen so fürchterlich angeben, wie toll sie sind funktioniert das Ganze ausgezeichnet. Stellt man eine Frage stürzen sich sogleich zig eifrige Karmajäger drauf und fabrizieren mehr oder weniger sinnvolle Antworten. Das Ganze kostet nichts - die Betreiber leben allein von der hohen Besucherzahl von ausgewiesenen Profis des Fachs und den dabei dezent (und vermutlich ziemlich teuer) geschalteten Anzeigen. Stackoverflow ist wirklich der Fundus bei Schwierigkeiten rund um die Entwicklung. Unsere firmeneigene iOS Anwendung hätte ohne diese Site eine zig-mal höhere Entwicklungszeit benötigt.

Benutzerprofil von puls200Seit ein paar Wochen gibt es jetzt den (wohl unvermeidlichen) Klon auf deutsch: Das Ganze nennt sich codekicker (wer hat sich nur den Namen ausgedacht?) und verfolgt genau dasselbe Geschäftsmodell. Dabei wurde sogar das Layout fast 1:1 übernommen, wer stackoverflow kennt fragt sich wo eigentlich die Unterschiede sind. Ich habe mich angemeldet und seit ein paar Tagen fröhlich mitgepostet. Das geht noch ganz gut, da die Menge der Teilnehmer noch etwas überschaubar ist. Mein erstes Fazit:

  1. Sehr .NET-lastig, kaum Fragen zu Java, Webentwicklung und Mobilem
  2. Wie bei stackoverflow gibt es die unvermeidlichen Dauer-Antworter, die zu jeder Frage ihren mehr oder weniger qualitativ wertigen Senf abgeben und das Karma horten
  3. Das Niveau der Fragen ist nicht besonders hoch. Ich vermute, dass diejenigen dann eher bei stackoverflow posten, des Englischen ohnehin besser mächtig
  4. Einige sinnvolle Features von stackoverflow wurden kurioserweise weggelassen, z.B. die Moderation und Überarbeitung von Fragen, die Acceptance-Rate, usw.
  5. Der speziell in deutschen Foren oft anzutreffende rechthaberische Ton ist gottseidank nur sehr selten zu vernehmen

Ich denke wenn sich die Gefolgschaft von dotNetPro geschlossen anmeldet besteht eine konkrete Überlebenschance. Ich werde die Site definitiv noch eine Weile aktiv begleiten.

Kleiner Test

Nachdem ich herausgefunden habe, dass in der Welt der Webprogrammierung seit Jahren tolle Sachen passieren ohne dass ich etwas davon mitbekomme habe ich beschlossen, mich ein bisschen kundig zu machen. Ein Kollege macht interessante Dinge mit html5 und jquery, das gefiel mir. Nachdem ich Raphael entdeckt habe, eine vielversprechende Bibliothek für Zeichnen in 2D musste ein kleiner Test sein. Hier gehts hin, ein Aufguß von Conway's Game of Life. Ich gebe es ja zu, noch was altbackeneres hätte ich kaum aus dem Hut zaubern können, aber der Programmieraufwand sollte sich in Grenzen halten. Wir kennen sie, die sympathischen Blinker ;-)
Interessant war in diesem Zusammenhang die deutlich unterschiedliche Performance auf verschiedenen Browsertypen. Speziell wenn ein Objekt semi-transparent wird habe ich den Eindruck findet im Firefox ein Software-Rendering statt, denn dann bricht die Leistung komplett ein. Im IE ist es zwar besser aber weit entfernt von akzeptabel. Hier fehlt m.E. der Anschluß an die Hardware der Plattform. Oder ich bin nur einfach zu blöd die richtigen Einstellungen zu finden ;-)
Ich werde das Skript demnächst noch ein bisschen erweitern, so dass man die wichtigsten Optionen einstellen kann.

Ich werd langsam zu alt für so einen Mist ;-)

Ich schreibe hier nicht gern von meiner Arbeit. Mich versteht ja doch keiner. Aber manchmal ist es einfach zu schrill. Heute zum Beispiel fand ich einen wunderbaren Fehler leider erst nach über zwei Stunden. iPad Anwendung. Folgende Situation:
Ich habe ein UIView, das mit einer bestimmten Größe initialisiert wird. In dieses View werden im Nachhinein dynamisch Subviews und Controls hinzugefügt. Das View ist in einem SplitviewController eingebettet.
Damit das Ganze schön skaliert habe ich außerdem folgendes gemacht:

searchView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
searchView.autoresizesSubviews = YES;

und danach die Subviews hinzugefügt. Wenn man die Anwendung startet sieht optisch alles gut aus, die Controls sind am richtigen Fleck. Aber das Event-Handling funktionierte nicht mehr. Ich habe wirklich alles ausprobiert, bis ich testweise einen Button hinzugefügt habe. Dabei fiel mir auf, dass die Events doch ausgelöst wurden .. allerdings nur in einem sehr schmalen Streifen am oberen Ende des Button. Gottseidank habe ich überall rumgeklickt ;-) Danach habe ich das Flag UIViewAutoresizingFlexibleHeight weggelassen und siehe da, alles funktioniert wie erwartet. Wie es scheint, wird der View tatsächlich flexibel skaliert, seine Kind-Elemente jedoch nicht. Skaliert wird nur der Bereich in dem Events ausgewertet werden. Wir haben also zwei Views, eins mit den tatsächlichen Controls und eins mit den Grenzen des Event-Handlings. Die andere Erklärung ist die, dass Kind-Elemente einfach aus ihrem Parent herausragen können. Was auch immer passiert war, es war nicht auf Anhieb zu erkennen. Eher so auf Siebt- oder Achthieb.
Was lernen wir daraus?
- Öfter einchecken um funktionsfähige von kaputten Sourcecodeteilen besser unterscheiden zu können
- sich von der Annahme verabschieden, alles müßte so funktionieren wie man es sich gedacht hat
- manuelles Resizing muss in allen Ebenen der Viewhierarchie implementiert werden damit es zuverlässig funktioniert
- es ist verblüffend wieviel Zeit man in API-Spezialskills investieren muss, die man hinterher auf keiner anderen Plattform mehr gebrauchen kann