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

iPhone und Apple

In meinem “offiziellen” Job bin ich nun seit 8 Wochen (mit einigen Unterbrechungen) mit Softwareentwicklung für das iPhone beschäftigt. An dieser Stelle möchte ich kurz meine bisherigen Erfahrungen resümieren. Vorausschickend noch anzumerken ist, daß sich vieles wie Meckerei anhört. Das sollte nicht so sein. Ich bin dem Apple-Virus nicht anheim gefallen, verwende die Geräte privat nicht und habe daher einen neutralen Standpunkt. Es geht nicht darum, ob iPhones cool oder praktisch sind. Eher, was passiert wenn man dafür Software entwickelt.

iPhone Entwicklung – lohnt sich das denn?
Die Frage aller Fragen. Angesichts der unüberschaubaren Flut an Apps im Apple Store kann das Gefühl entstehen, daß dieser Markt komplett gesättigt ist. Das stimmt allerdings nicht, denn es werden immer noch Neugeräte (und damit Apps) verkauft. Allerdings – um “entdeckt” zu werden muß man entweder kostenlos (Blödsinn, wir wollen Geld verdienen) oder sehr gut sein. Wer früh kommt, verdient allerdings auch mit simpelsten Anwendungen Geld. Inzwischen geht das aus meiner Sicht für den Apple-Store / Consumermarkt nur dann, wenn es nur wenig Konkurrenz für die “Idee” gibt. Man muss berücksichtigen: Wenn man, sagen wir, in 2 Wochen eine sehr einfache App entwickelt (ganz optimistisch gerechnet) bei einem hiesigen, sehr konservativen Tagessatz von 500€ und noch die Hardwareeinstiegskosten (iMac Mini + iPod = 1.000€) + 100€ Entwicklerlizenz dazunimmt, liegt man bei einer initialen Investition von 6.100 €. Setzt man 1€ an muss die App 8.714-mal heruntergeladen werden (Apple Steuer: 30%), bevor man den break even erreicht. Ab diesem Zeitpunkt verdient man Geld. Aber nicht vergessen: Das ist der Consumer-Markt. Man ist zum Support verpflichtet. Bekommt man von nur einem Promille aller Anwender eine E-Mail (ganz dolle optimistisch), muß man bis zu diesem Punkt schon 8 Supportanfragen bearbeiten. Oh, lala. “Läuft” es einmal, wird die Anwendung in der Regel sehr schnell gecrackt und Plagiate tauchen auf, wie Kollegen von mir schon erfahren haben. Die Verkaufskurve zeigt dann unwillkührlich wieder nach unten. Ein großer Vorteil soll natürlich nicht verschwiegen werden. Als Entwickler im stillen Kämmerlein hat man mit dem AppStore eine fantastische Vertriebskette zur Verfügung. Die Kunden müssen nicht mehr gefunden oder geworben werden. Falls, tja, falls sie einen innerhalb der derzeit rund 200.000 angebotenen Apps selbst finden. :-)
Jetzt entwickeln wir nicht für den Consumer-Markt. Wir haben Geschäftskunden, die Masse ist nicht entscheidend. Allerdings bleibt die Gerätevielfalt dieselbe. Zur Anwendungsentwicklung auf einem Endgerät existiert eine preiswerte Alternative, und zwar die Implementierung einer für mobile Geräte optimierten Webseite. In vielen Fällen müssen ohnehin online auf Geschäftsdaten zugegriffen werden, eine Internetverbindung ist also erforderlich. Und ob HTC/Android, Berry oder iPhone, es läuft überall (mehr oder weniger ansehnlich) gleich. Im Funkloch tut sich dann nichts mehr, aber das ist dann vom Anwendungsfall abhängig. Man prüfe also, ob man sich das antun will ;)

Restriktionen
In der Apple-Welt lebt man auf einer Insel. Das ganze System ist darauf ausgelegt, dass der Anwender und der Entwickler ausschließlich Apple-Komponenten verwenden. Das fängt schon bei Kleinigkeiten an, wie dem Anschluß einer herkömmlichen PC Tastatur an einem Mac mini. Oder die Darstellung der Apple-Dokumentation in anderen Browsern außer Safari. Oder der Verbindung zu Windows Shares im Finder. Lauter kleine Ärgernisse, die man zwar irgendwann durch Googelei lösbar sind, aber trotzdem nerven, weil es sich um bewußt ausgelegte Stolpersteine handelt. Wer will sich schon gern die Arbeitsweise vorschreiben lassen. Ganz extrem ist natürlich dann die Entwicklungsumgebung fürs iPhone, ausschließlich mit XCode auf einem Mac Betriebssystem. Das hat keine technischen Gründe. Besonders zynisch dabei ist aus meiner Sicht, daß die darunterliegenden Komponenten aus der Unix-Welt stammen und wie der GCC beispielsweise der GPL unterliegen. Alles sicherlich rechtens, komisch riechen tut es trotzdem.

Entwicklung
Wie entwickelt man denn nun? XCode entpuppt sich als vollwertige und moderne Entwicklungsumgebung. In der Produktivität bleibt das Programm trotzdem meilenweit hinter Visual Studio zurück, was an dem umständlichen Debugger und am Fehlen von Funktionen wie “Edit & Continue” und der etwas zähen Intellisense Unterstützung liegt. Objective-C hätte ich mir schlimmer vorgestellt, ich habe mich trotz meines etwas vorgerückten Alters relativ schnell damit zurechtgefunden. Aber die Bibliotheksfunktionen! Immer wieder herrlich, wenn man selbst primitive Dinge wie das Zusammenfügen von Strings in der Doku nachschlagen darf, nur weil man den Funktionsnamen wieder vergessen hat. Man merkt auch, daß die Programmiersprache nur auf C übergestülpt ist. Probleme wie die Korruption des Speichers oder Stacks, Zugriff auf de-allokierte Objekte und ähnliche Schweinereien die ich schon ziemlich verdrängt hatte sind wieder an der Tagesordnung. Mit den damit verbundenen Programmabstürzen. Es ist problemlos möglich, eine Maske im Interface Builder so zu konfigurieren, daß das Programm an einer vollständig irreführenden Stelle einfriert. Nicht falsch verstehen. Das ist alles lösbar, nur würde man seine Zeit gern für andere Dinge verwenden. Im Grunde wird man ständig daran erinnert, daß man nicht wiederverwendbare Fähigkeiten für eine Insellösung aufbaut. So könnte man natürlich auch bei .NET, Java und ähnlichem argumentieren, nur sind die Inseln dort eher.. Kontinente.

Lernen
Wie ein guter Student habe ich mir zunächst ein Buch bestellt. “iPhone SDK Application Development” von Jonathan Zdziarski. Ein ehemaliger iPhone Hacker, ich dachte, das ist ganz sinnvoll. Leider erfüllte es nicht ganz meine Erwartungen. Die API hat sich inzwischen etwas verändert, so daß viele Beispiele etwas veraltet sind. An vielen Stellen hätte ich mir auch etwas mehr Tiefe gewünscht, dafür dann evtl. andere Bereiche wie Audio weggelassen. Auch der Index hilft nur begrenzt bei Problemen. Ein Buch im Sinne eines “Cookbook”, wie es für viele anderen Sprachen gibt ist sicherlich sinnvoller für den Einsteiger. Für Detailfragen muß man ohnehin auf Google zurückgreifen. Ich frage mich inzwischen ernsthaft, ob Bücher in dieser Form überhaupt noch einen praktischen Nutzen haben, außer auf der Biographie des Autors einen äußerst positiven Eindruck zu hinterlassen. (SterneSterneSterneSterneSterne).