Für und Wider Microservices

Serviceorientierte Architektur – das Buzzword ist in alle Munde. Auch ich darf mich regelmäßig im Rahmen meiner Arbeit mit diesem Architektur-Typ auseinander setzen.

Die Idee an und für sich ist ja schon interessant: Funktionen werden über wohldefinierte Schnittstellen (z.B. REST) angeboten, wie die Antwort zu einem Request entsteht ist dann völlig unerheblich – das reicht von einer anderen Programmiersprache bis hin zu einem vollständig anderen physikalischen System. Modularisierung auf die Spitze getrieben. Eigentlich der Traum eines jeden Entwicklers sollte man meinen. Minimale Kopplung, wenn ein Service ersetzt werden soll, muss nur noch die Schnittstelle erhalten bleiben, und man kann es sogar ganz einfach umstellen.

Klingt ja erst mal alles vernünftig, aber jede Medaille (und jede Technik) hat bekanntlich zwei Seiten. Wo ist die Schattenseite der Service-Orientierung?

Ein kurzer Ausflug in die Historie hilft uns das Konzept besser zu verstehen. Schon seit geraumer Zeit haben wir uns an eine Art Gewaltenteilung gewöhnt: Daten “leben” in der Regel in einem eigenen Umfeld, das unterschiedlich ausgestaltet sein kann – sei es eine relationale Datenbank (die es wiederum in verschiedensten Geschmacksrichtungen gibt: MySQL, MariaDB, Postgreß, DB2, etc), in Dateien oder auch in den modernen NoSQL-Datenbanken. Wichtig dabei ist nur: Man sollte die Datenhaltung so wählen, dass sie zum Anwendungszweck passt. Der Blick über den Tellerrand hat auch hier noch nie geschadet: Nur weil man bisher alles in ein relationales Schema gepresst hat, muss das für eine (neue) Anwendung noch lange nicht eine gute Wahl sein.

Ohne es sich groß bewusst zu machen, haben wir hier die erste Stufe einer Service-Orientierung eingeführt – angesprochen wird der Service über eine definierte Schnittstelle. In ganz vielen Fällen ist die Schnittstelle in der Sprache der eigentlichen Applikation bereits etwas abstrahiert um sie leichter nutzen zu können (auch bekannt als “Connector”). Ein ähnliches Konstrukt mit einem anderen Focus hat bereits Dan Bernstein für qmail verwendet. Triebfeder dort war die Sicherheit – auch das bietet eine definierte, gekapselte Schnittstelle.

Ist die Sache mit den Services also nur “neuer Wein in alten Schläuchen”? Ganz so einfach ist es nicht, es hat sich doch einiges geändert – die Schnittstellen haben sich verändert – weg von festen Techniken wie etwa einem MySQL-Adapter – hin zu gerneralisierten Schnittstellen wie SOAP oder JSON als Transport-Kappsel. Das hat natürlich Vorteile – man kann die Services etwas weiter auseinander ziehen, z.B. auf spezielle Server mit angepasster Hardware oder etwa einen zentralen Authentifizierungs-Server für Single-Sign-On.

Ein weiterer oftmals genannter Vorteil ist die Skalierbarkeit: Wenn mehrere Rechner den gleichen Service anbieten, dann kann man die Last darauf gleichmäßig verteilen. Besonders sinnvoll ist es wenn man die Server-Funktion dann noch fachlich genauer eingrenzen kann. So kann man sich vorstellen, dass man mehrere Server aufsetzt und dann alphabetisch anhand der Nutzernamen aufteilt – natürlich so, dass jeder Server im Zweifel die Aufgaben eines anderen nutzen kann – aber durch die Spezialisierung wirken Cache-Mechanismen um ein Vielfaches besser.

Soweit die vielen positiven Aspekte (es gibt noch einige mehr). Aber jede Medaille hat ja zwei Seiten. Was sind Nachteile einer derartigen Struktur?

Ausfallsicherheit gibt es nicht ohne Preis – es müssen ggf. mehrere Server gestartet werden, auch wenn das heute durch Container und Virtualisierungslösungen einfacher geworden ist, man muss sich im administrativen um eine ganze Menge mehr Maschinen kümmern.

Die nächste Stelle an der man mehr Aufwand hat, ist der Aufruf und die Kodierung der Daten. Hier handelt man sich bei Netwerkaufrufen gleich einmal den vollständigen TCP/IP-Stack ein, mit allen seinen sieben Schichten. Das mag nicht übermäßig viel sein, aber es kommt definitiv etwas Latenz hinzu – wenn der entfernte Server dann noch weiter weg steht und womöglich etwas knapp angebunden ist, merkt man das sehr schnell. Besonders heftig ist es, wenn man dann noch (ohne es zu wissen oder zu wollen) eine ganze Kette solcher Services lostritt, weil der abgefragte Server wiederum andere Services anstößt…

Ein weiteres oftmals vernachlässigtes Problem ist die Datenkonsistenz und Datenaggregation: Liegen die Daten alle in einer Datenbank gehört es zum guten Ton Fremdschlüssel zu verwenden und so etwaige Inkonsistenzen zu vermeiden. So kann man beispielsweise sicherstellen, dass mit jeder Veränderung eines Datensatzes der aktuell angemeldete Benutzer mitgeschrieben wird, und dass dieser gültig ist (also zum Beispiel seine ID in der Benutzertabelle existiert). Ändert sich nun der Benutzername, ist das alles kein Drama, die Datenbank bleibt in sich konsistent. Das Löschen einen Benutzers mit noch vorhandenen Datensätzen lässt sich ebenfalls unterbinden. Will man etwas in dieser Form mit getrennten Services realisieren hat man sehr schnell eine Synchronisationshölle geschaffen. Im besten Fall kann man noch eine ID des Benutzers oder dessen Login-Namen als String speichern. Wird dieser dann auf dem Authentifikationsserver gelöscht, bekommt die eigene Anwendung davon gar nichts mit. Der Benutzer kann sich zwar nicht mehr anmelden, aber die Tatsache, dass dieser Datensatz gelöscht wurde (was ggf. für die Applikation sehr interessant sein könnte) wird nicht weiter propagiert. Besonders heftig trifft es wenn Veränderungen am Login-Namen vorgenommen werden. Das passiert häufiger als man denkt: Ein Benutzer heiratet und schwupps ändert sich in vielen Firmen der Login, da er an den Nachnamen gekoppelt ist. Für das aufrufende System ist es ein neuer Benutzer. Der Benutzer kann seine Datensätze vom Vortag nicht mehr editieren, weil er ist ja nicht der Autor. Die Szenarien in dieser Hinsicht sind vielfältigst. Will man diesen Problemen Herr werden benötigt man wieder zusätzliche Services die einen Rückschluss auf die Veränderung zulassen (also z.B. die Frage: Wurde Benutzer x irgerndwann einmal umbenannt?)

Der Weg zu einer “hippen” Microservice-Architektur will also gut überlegt sein. Es kommt sehr auf den Anwendungsfall an und ob es mir im gegebenen Kontext überhaupt möglich ist einzelne Services so heraus zu lösen, dass sie vollständig eigenständig sind. Praktischerweise ist die Architekturwelt an dieser Stelle nicht vollständig digital bzw. schwarz/weiß, es gibt beliebig viele Abstufungen die man wählen kann und die alle legitim sind. Weder ist ein monolithische Architektur per se falsch und böse, noch sind Microservices das allein seelig machende Allheilmittel. Es hilft, sich über die Rahmenbedingungen im Klaren zu sein:

  • Habe ich tatsächlich unabhängige fachliche Teilbereiche?
  • Wie groß ist die Entwickler-Gruppe – lohnt es sich mehrere Teams zu bilden?
  • Gibt es eine hohe Abhängigkeit von Daten zwischen Anwendungen / Prozessen?

Man kann noch eine Reihe weiterer Fragen stellen um ein genaueres Bild zu erhalten.

Zum Abschluss noch ein kurzer Blick zurück in die Geschichte bzw. ältere Software-Architekturen. Modularisierung von Software gab es ja bereits schon früher. Dort hat sich der Ansatz “high cohesion, loose coupeling” bewährt. Wenn man es genau betrachtet, sind Mikroservices eine logische Weiterentwicklung dieses Ansatzes. Innerhalb eines Sources-Code-Repositories kann man diese Vorgabe nur als Regel für die Entwickler vorgeben: Es ist zu vermeiden, dass man von jeder beliebigen Stelle im Code andere Funktionen aufruft. Der Ansatz der Objektorientierung hat hier bereits wichtige moderierende Funktion. Ebenso kann man durch den Einsatz von Modulen das Bewusstsein schärfen, wenn ein (fachlicher) Bereich verlassen wird. Microservices schließlich erzwingen das Konzept durch weitere Hürden, wie das Verpacken in universelle Pakete (JSON, SOAP siehe auch oben). Ob derartige Zwänge immer zu besserer Software führen ist jedoch fraglich. Zudem gibt es in jedem Projekt doch immer wieder Funktionen die gleichartig sind – mit Mikroservices nimmt man bewusst in Kauf, dass ggf. Funktionalität zweimal ausprogrammiert wird. Ob das dann gute Architektur ist, darf sich jeder selbst überlegen.

 

 

DeveloperCamp 2016 Würzburg

Den Horizont erweitern, einfach auch einmal über den Tellerrand hinaus blicken und noch dazu jede Menge coole Leute mit Ähnlichen Interessen treffen. All diese Erwartungen wurden für mich durch das Developer Camp 2016 in Würzburg erfüllt.

Die Veranstaltung ging über zwei Tage Freitag und Samstag, wobei mein Arbeitgeber so freundlich war die Kosten für diese ungewöhnliche und erstmalig stattfindende Fortbildung und die Übernachtung zu übernehmen. Für die ein oder andere aktuelle Problemstellung gab es dann auch jede Menge Hinweise und Ideen zur Lösung. Details folgen weiter unten.

Um nichts zu verpassen bin ich mit meinem Kollegen Sebastian sehr früh in Mannheim aufgebrochen auch weil die Strecke nach Würzburg voller Baustellen und Staugefahren ist – Ergebnis: wir waren etwas vor der Zeit am Veranstaltungsort, aber es hat sich gleich die lockere Atmosphäre und die professionelle Organisation des Camps gezeigt – man war bereits auf Frühankommer eingestellt – inklusive “Laufzettel mit Gewinnspiel” und dem wichtigsten für den Informatiker: frischer Kaffee.

Continue reading

MySQL und Barrakudas

Eigentlich sollte man sich um einen Datenbankserver möglichst wenig kümmern müssen. Regelmäßige Updates zur Sicherheit sind auch kein Thema. Bei der Konfiguration sollte man in der Regel auch nicht alle Tage was neues ausprobieren.

Spannend wird das nur, wenn dann etwas nicht funktioniert und man auf die Suche geht. So etwas ist mir heute einmal wieder passiert. Auslöser war eigentlich eine harmlose Sache: Vor kurzem gab es eine Fehlermeldung, dass ein Datensatz eines Benutzers nicht gespeichert werden konnte – mit dem Hinweis:

MySQL Error 1118 (Row size too large)

Soweit so ärgerlich – ich habe da erst ein wenig gesucht, aber nichts gefunden – da der Fehler sich auch irgendwie nicht adhoc reproduzieren lies habe ich mich erst mal um das Tagesgeschäft gekümmert. Bis mir das gleiche Problem heute selbst auf die Füße gefallen ist, allerdings nicht an ursprünglicher Stelle sondern bei einer ganz anderen Aktion: Eigentlich wollte ich nur “mal eben schnell” feststellen ob die Performanceprobleme einer neuen Funktion nur darauf zurück zu führen sind, dass unser Entwicklungssystem schon etwas älter ist und damit nicht immer gerade als Vergleich herhalten kann (es hat gewisse Vorteile ein solches System zu verwenden: Was da schon nicht prickelnd läuft, ist in der Regel ein Hinweis, dass man sich die Programmierung nochmal anschauen sollte).

Nunja in diesem Fall hat die Analyse der Programmierung leider nicht so recht gefruchtet – daher wollte ich einen Versuchsballon starten und die aktuelle Entwicklung auf unserem Produktiv-System in einer Spielwiese testen. Normalerweise ist das kein Problem und wenn die Performance dort dank mehr Rechenleistung ausreichend ist, kann man es ja erst mal so lassen. Ich nehme also meinen Entwicklungs-Dump und versuche diesen in die Spielwiese zu laden. Aber – oh Wunder – ich renne genau in den Fehler von oben hinein. Allerdings mit einem Dump, den ich aus einer bestehenden Datenbank extrahiert habe – die Größe müsste also ja passen, denn sonst wäre es ja gar nicht erst reingekommen.

Aber der Reihe nach: Ich suche natürlich erst einmal nach einem Problem mit der Größe, dabei stoße ich darauf, dass es eine Veränderung an der Art und Weise gab, wie die Datenbank mit ihrer InnoDB-Engine die Daten ablegt – das neue Format wurde “Barracuda” getauft. Dieses soll unter anderem effizienter mit dem Speicher haushalten, bzw. man kann festlegen wie ggf. gespeichert werden soll. Generell gilt für die InnoDB: Nur große Objekte (also TEXT, BLOB und Consorten) werden außerhalb der Seite abgelegt, alles andere bleibt in der Page. Das kann zu dem oben genannten Fehler führen. Allerdings muss man es da schon recht dicke treiben, denn die Blattgröße ist maximal 8126 Bytes bezüglich der Daten. Selbst wenn ich nun vom absoluten Worst-Case für meine Datenbank ausgehe und für jedes VARCHAR-Feld pro Zeichen von maximal für Bytes (weil wir mit UTF-8 arbeiten) ausgehe, komme ich auf etwas mehr als 600 Bytes. Also kann das nicht der Grund sein… ebenfalls würde das noch nicht erklären, warum es mit dem früheren Speicherformat (names “Antelope”) bisher funktioniert hat.

Auch wenn es auf den ersten Moment komisch erscheint, habe ich dann im Testsystem mal nach einem weiteren StackExchange-Eintrag experimentiert, und ins Schwarze getroffen. Mit der veränderten Einstellung lief der Import plötzlich sauber durch. Ganz wichtig dabei ist, dass man es wie hier beschrieben macht. Also erst den Server-Prozess sauber beenden, damit wirklich alle Änderungen aus dem Log geschrieben sind. Dann zusätzlich die Index, Log und Cache-Files für die InnoDB aus dem Weg räumen, dann umstellen und den Serverprozess wieder starten. Der kümmert sich dann darum, dass die notwendigen Verwaltungs-Dateien automatisch wieder erzeugt werden und diesmal die neue Größe haben.

Problem gelöst, nur weshalb trat der Fehler eigentlich auf? Denn man möchte ja etwas dabei lernen. Die Ursache ist in der Art und Weise zu suchen, wie der MySQL-Dump funktioniert: Im Prinzip ist die Datei nur eine große Sammlung von Statements, die nacheinander ausgeführt werden. Dabei wird natürlich auch Rücksicht auf Abhängigkeiten genommen, z.B. die Fremdschlüssel – denn es kann ja passieren, dass Tabelle “A” auf eine Spalte in der Tabelle “Z” referenziert, die Tabelle “Z” aber noch nicht erzeugt wurde, wenn “A” rekonstruiert wird. Die Daten werden dabei (wie man es auch ganz regulär machen würde) als Insert-Statements in die Tabellen geschrieben. InnoDB beachtet das ACID-Prinzip, jedes Statement wird daher als atomare Operation betrachtet. Um effizienter zu arbeiten, verwendet der Dump folgendes Konstrukt

insert into table a values ('a','b','c'), ('d','e','f'), .... ('xyz','aa','cc');

Das ist völlig legitim. Man kann alternativ auch folgende Statements ausführen.

insert into table a values ('a','b','c');
insert into table a values ('d','e','f');
....
insert into table a values ('xyz','aa','cc');

Das Ergebnis ist das Gleiche. Nur intern ist es ein kleiner aber feiner Unterschied. Um die ACID-Kriterien zu erfüllen, wird im zweiten Fall nach jedem einzelnen Statement ein Commit durchgeführt (was etwas Performance kostet), für InnoDB ein Zeichen, dass man die Log-Datei “wegschreiben” kann und damit dann auch wieder leeren kann, es ist also Platz für neue Daten in der Datei vorhanden. Passiert das nicht (wie im ersten Fall, in dem InnoDB davon ausgehen muss, es handelt sich um ein atomares Statement) kann die Log-Datei zu klein sein, was dann zur Fehlermeldung führt. Warum dann aber eine völlig fehlweisende Fehlermeldung auftaucht, die keinen Hinweis auf das Logfile enthält, bleibt vorerst noch Sache der jeweiligen Entwickler. Ich habe mal einen Bug-Report ausgefüllt, mal sehen ob das behoben werden kann (oder ob ich selbst einmal die Zeit finde mich dem Problem zu widmen).

 

 

Weihnachtsbastelei – Treiber für ein ASUS Pro70U Laptop

Alle Jahre wieder ist nach Weihnachten Chaos – auch bei diversen Freunden und Verwandten. Eigentlich mache ich das ja ungern während der Feiertage, aber wenn man als Experte schon mal vor Ort ist, dann packt man irgendwann dann doch an – auch wenn man nicht unbedingt Lust hat. Sollte ja auch nur eine Kleinigkeit sein, der Rechner an sich läuft ja schon, nur die Webcam mag nicht…

Gesagt getan, man schaut sich das Ding einmal an: Ein Asus Laptop Modell Pro70U – na das sollte doch eine machbare Größe sein. Sollte … Zu dem Gerät findet man bei Asus schon einmal keine Information, was irgendwie verdächtig ist. Wie ich dann heraus gefunden habe, ist das ein Gerät was ursprünglich einmal in den Niederlanden verkauft wurde – aber auch auf der niederländischen Seite von Asus findet sich nichts wirklich aussagekräftiges. Also nichts mit mal eben schnell.

Das Gerät ist schon durch mehrere Hände gegangen – es hat also auch schon ein paar Jahre auf dem Buckel. Das merkt man auch am Prozessor und an den Treibern – ein Athlon X2 als Prozessor ist noch dazu nicht gerade ein gängiges Modell geworden. Wenn man die Performance anschaut die das Gerät hinlegt, wundert einen das auch nicht mehr.

Mit etwas Glück habe ich dann herausgefunden, dass es sich wohl um ein umgelabeltes Gerät handelt was mal als Asus A7U verkauft wurde. Ich vermute, dass es sich ein Gerät handelt, das bei einem Discounter verkauft wurde, dort zwar als Asus beworben werden sollte, aber man nicht offen eingestehen wollte, was für ein Gerät man da eigentlich verkauft. Die Webcam ist dann auch nicht gleich installierbar – denn es gibt wieder einmal mehrere Sub-Modelle des Geräts, die unterschiedliche Peripherie installiert haben. Mit dem letzten Treiber funktioniert das Gerät dann auch endlich. Was für ein Krampf – aber: Andere sitzen nach Weihnachten über ihren Bausätzen und Modellen – der typische Nerd bastelt eben an unwilligen Rechner – und man braucht doch auch immer mal wieder eine Herausforderung.

Nur noch eine Kleinigkeit zusätzlich, um die man mich bittet: Da man leider nicht 10-Finger schreiben kann – der Aufdruck auf der Tastatur passt leider nicht zum gewählten Layout im Windows-Betriebssystem. Also nochmal raten was das genau ist – in meinem Fall sind wir am Ende mit einer amerikanischen Tastaturbelegung erfolgreich.

Jetzt bleibt nur zu hoffen, dass ich das Gerät nicht so schnell wieder in den Fingern habe, denn das eben schnell mal einen Treiber installieren hat dann doch einige Stunden gedauert. Das liegt auch daran, dass das Gerät leider nicht wirklich eine ansprechende Performance abliefert – zumindest nicht unter Windows 7. Zwischenzeitlich war ich derart frustriert, dass ich beinahe zum USB-Stick mit einem Linux gegriffen hätte.

IPv6 – das “neue” Internet-Protokoll und der steinige Weg dorthin

Nun habe ich am 22. und 23.05.2014 die Möglichkeit bekommen am IPv6-Kongress in Frankfurt teilzunehmen. So langsam aber sicher wird es Zeit sich um das neue Internet-Protokoll zu kümmern und damit vertraut zu werden. In erster Linie ist es natürlich ein berufliches Interesse, hier am Ball zu bleiben. Aber auch für mich privat als “digital Native” bis “Nerd” – irgendwo dazwischen liege ich wohl – ist es natürlich interesant zu wissen was als nächstes kommt.

Nun ersteinmal: Warum das ganze? Nun, das Internet ist langsam aber sicher gewachsen, schneller als man es ursprünglich einmal gedacht hat und noch dazu in Ausdehnungen die sich früher kein Mensch so recht vorstellen konnte. Wichtigstes Prinzip war immer die sogenannte Ende-zu-Ende Kommunikation nach dem Best-Effort-Prinzip: Jeder leitet alle Daten zielführend und so gut es geht weiter, die kleinste Einheit dafür sind sogenannte Pakete. Egal was man an Daten im Internet verschicken möchte, alles wird in kleine Häppchen zerlegt und vom Sender zum Empfänger transportiert. Dabei ist es (fast) unerheblich was transportiert wird: Sprache, Text, Bilder, Videos, Dateien etc.: Alles wird auf die Pakete verteilt – man kann es wie das Versenden einer umfangreichen Lieferung sehen: Was auf einen LKW passt wird auf einen geladen und verschickt, wenn es mehr wird, teilt man es auf. Vorteil: Wenn mal tatsächlich etwas nicht ankommt, muss man nur den fehlenden Teil der Daten nachschicken (da wird es dann mit den LKWs ggf. etwas schwierig).
Was braucht man um Pakete zu verschicken? Richtig, eine Adresse damit der Postbote oder Paketdienst weiß wohin mit der Lieferung. Dazu wurde das Internet-Protokoll entwickelt, kurz IP. Derzeit werden Adressen mit 32 bit Länge verwendet, geschrieben in 4 Blöcken zu je 8 Bit. Das gibt dann Angaben wie 192.168.10.74. Diese Adressen werden gemäß ihrer Historie als IPv4 (vierte Revision des Protokolls in Verbindung mit TCP) bezeichnet.

Nun funktioniert das ja momentan schon, weshalb also ein neues Protokoll einführen? Never touch a running system bzw. never change a winning team…. Nun es gibt gute Gründe dafür, denn das Netz ist seit der letzten Protokollversion immens gewachsen. Niemand hätte anfänglich davon zu träumen gewagt, dass IP derartig populär und weltweit im Einsatz sein würde. Auch waren 32 Bit zu dem Zeitpunkt ein nahezu unvorstellbar großer Zahlenbereich.
Heute hat fast jeder mindestens einen PC, Laptop und ein Smartphone ggf. noch weitere Geräte wie Netzwerkdrucker, IP-Telephone, IP-Webcams, Internetfähige Fernseher etc. Für jedes Gerät wird eine eigene Adresse benötigt… Wenn jeder Mensch auf der Erde ein Gerät hat, dann reicht es schon nicht mehr…
Für den Gebrauch in abgeschlossenen Netzwerken gibt es Adressen, die nicht weltweit eindeutig sind – so lange die Netzwerke nicht miteiander kommunizieren müssen ist das auch legitim. Die bekannstesten Adressen für diesen Fall sind die der Class C: 192.168.x.y, für größere gibt es die Class b (172.16.0.0 bis 172.32.255.255), in großen Unternehmen gibt es meist Class A (10.x.y.z).
Schon früh hat man Methoden entwickelt um Internet-Anschlüsse für mehrere Rechner auf einmal nutzbar zu machen. Einige alte Hasen erinnern sich unter Linux noch an ipfwadm, später ipchains und heute iptables. Die Werkzeuge können noch viel mehr aber eben auch IP Masquerading bzw. Network-Address-Translation (NAT). Noch heute kommen genau die gleichen Mechanismen zum Einsatz, meist hübsch verpackt in einem Multifunktionsgerät das viele als Router bezeichnen (was technisch nur teilweise korrekt ist). Netter Nebeneffekt: ohne besondere Einstellungen (z.B. Portweiterleitungen) sind die Geräte im Netz auch erst mal vor Zugriffen von außen geschützt.
Im öffentlichen Internet dürfen die oben genannten Bereiche nicht verwendet werden, sie fallen (wie einige andrere Bereiche mit speziellen Funktionen) aus den zur Auswahl stehenden IP-Adressen heraus. Es wird also noch knapper.
Nun kann man ja sagen: was einmal klappt, geht auch zweimal… Also schachteln wir doch ein Netz mittels IP Masquerading in ein anderes. Das funktioniert (leider) recht gut. Zudem erhöht es die Sicherheit, sollte man meinen. Schwierig wird es dann aber Geräte in der zweiten Ebene anzusprechen: am eigenen Router kann man noch Portweiterleitungen einrichten, ein Provider mit mehreren tausend kunden kann das nicht. Insgesamt wird also das Ende zu Ende Prinzip ausgehebelt. Im kleinen ist das ja noch ok, aber weltweit wird es schwierig… Denn ein Fernzugriff aus die zentrale Dateiablage daheim ist sehr praktisch (dann muss man die Dateien nicht irgendwelchen Clouddiensten anvertrauen). Genau das klappt dann aber eben nicht mehr.
Es gibt noch einige gute Gründe mehr weshalb IPv4 ersetzungsreif ist, aber das würde den Rahmen hier sprengen.

Nun gut, ich bin technisch ja durchaus interessiert, also würde ich IPv6 dann auch gerne baldest möglich nutzen. Zumal ein Parallelbetrieb ja sogar explizit vorgesehen und möglich ist. Das brauche ich beispielsweise für meinen gut gedienten Netzwerkdrucker, für diesen wird es keine Softwareaktualisierung geben, die ihn  IPv6 fähig macht. Aber der Rest meines Geräteparks ist soweit eigentlich fit. Bis auf … wer hätte es gedacht? Den Router. Nun gut, der hat auch schon einige Jahre auf dem Buckel und es gab ihn bereits bei Vertragsabschluss als Endgerät.

Also frage ich erst mal bei meinem Provider nach, wie es denn aussieht mit IPv6 und vor allem ob es eine Möglichkeit wieder ein subventioniertes Gerät zu erhalten. Fragen kostet nichts und man kann nur Erkenntnis gewinnen. Prompt habe ich die Antwort, das er Ersatz des Routers wahrscheinlich möglich sei, aber ich möge doch bitte nochmal in der Technik anrufen. Gesagt getan. Dort verweißt man mich dann aber doch in die Vetragsbetreuung. Dort heißt es dann, dass ein Upgrade des Routers nur gegen Zuzahlung von 90 EUR möglich ist, was mir für das kleinste Gerät mit Branding dann doch etwas viel Geld ist. Ich lehne das Angebot also erst einmal ab und schaue mich derweil bei den Gerbauchtgeräten um.

Am nächsten Tag erfolgt ein weiterer Anruf, man signalisiert beim Router Entgegenkommen und senkt die Hürde auf 49 EUR – immer noch zu viel wie ich finde – die Geräte gehen bei ebay für um die 35 EUR über den virtuellen Tresen und Versandkosten hätte ich in beiden Fällen. Also ordere ich erst mal eine FritzBox mit IPv6-Fähigkeit – immer in dem Glauben, dass dies das Tor zur IPv6-Welt aufstoßen wird.

Einige Tage vergehen, ich bin auch sonst gut ausgelastet, aber einige Wochen danach komme ich dann endlich dazu die Box anzuschließen. Erste Ernüchterung bei den Fähigkeiten: Bisher gab es zwei normale analaoge Anschlüsse intern, jetzt nur noch einen, der andere ist für ein Fax reserviert (TAE-N-Anschluss) – die Software lässt sich auch nicht überreden den Anschluss zweckentfremdet zu nutzen. Das ist ärgerlich, denn mittlerweile haben wir ja zwei Telefone die wir auch beide parallel nutzen möchten und bisher konnten. Aber egal: Jetzt will ich erst einmal wissen wie es um IPv6 steht und für einen Test ist das Setup ja durchaus geeignet.

Doch was muss ich feststellen: Ich bekomme keine IPv6-Adresse bzw. ein entsprechendes Präfix zugeteilt. Das ist ein Problem des Providers, weshalb ich den wieder kontaktiere. Die Antwort ist diesmal ernüchternd: IPv6 gibt es nur für einige Kunden mit V-DSL und in einem Pilotprojekt. Ein allgemeiner Start ist noch nicht in Aussicht.

Also wird es erst mal nichts mit IPv6 bei mir. Auf eine Lösung mit Tunnel möchte ich eigentlich ungern setzen, die Option Dualstack-Lite wäre für mich ja auch noch OK gewesen. Was bleibt ist ein schaler Beigeschmack über das Verhalten meines Providers bezüglich des Routers – wollte man mir hier einfach nur ein Neugerät verkaufen oder ist das nur ein Kommunikationsproblem gewesen. Ersteres fände ich reichlich dreist, letzteres ist wohl aber in modernen Unternehmen immer wieder der Fall. Warten wir also ab, was kommen wird – vielleicht auch irgendwann IPv6.

 

Modularer Querbaukasten in PHP: Traits

Objektorientierte Entwicklung ist mittlerweile der Standard wenn es um Geschäftslogiken geht. Für verschiedene weitere Anwendungszwecke gibt es auch immer noch gute Funktionale Programmiersprachen. Jede Herangehensweise hat ihre Vor- und Nachteile.

Wie immer sind Programmierer komische Wesen und würden an einigen Stellen gerne das Beste aus beiden Welten haben, auch wenn diese sich eigentlich gegenseitig ausschließen.

Aktuell hatte ich mal wieder einen solchen Fall: Es gibt eine “fertige” PHP-Bibliothek zum Erzeugen von PDF-Dokumenten (diese eigenen sich in der Regel besser zum Ausdrucken als HTML-Seiten) – etabliert hat sich hier FPDF bzw. dessen Fork TCPDF. TCPDF ist die aktuellere und modernere Fassung, sie unterstützt unter anderem die Verwendung von UTF-8-Zeichensätzen. Daher musste ich mich auch “mal wieder” mit schon lange gepflegten und eigentlich abgeschlossenen PDF-Routinen beschäftigen: FPDF kann mit UTF8 nicht richtig umgehen, somit sehen die erzeugten PDFs aus wie Kraut und Rüben sobald Umlaute oder Sonderzeichen im Spiel sind.

Beim Umstellen gibt es ein paar Feinheiten, aber nichts was einen wirklich davon abhält die Umstellung halbwegs zügig durchzuführen. Die meisten Probleme erkennt man einmal und kann sie dann in den Folgedateien direkt korrigieren.

In diesem Zusammenhang habe ich mich mal wieder etwas geärgert: Viele unserer Dokumente enthalten Tabellen. Soweit so langweilig. Aus Mangel an Alternativen haben wir häufig den Code einfach von der einen eigenen Klasse in die nächste mit kopiert. Das Ergebnis ist altbekannt. Wenn man einen Fehler beseitigen will, muss man alle Kopien mit durcharbeiten. Effizient ist das nicht gerade.

Eine mögliche Option ist es eine eigene Klasse dazwischen zu setzen, die solche Funktionen realisiert. Aber was ist mit den Dokumenten wo man dann gar keine Tabelle braucht – da hat man Pech gehabt? Fazit das geht, aber richtig schön finde ich das auch nicht. Mehrfach-Vererbung kennt PHP nicht – aus gutem Grund (Diamond-Problem). Für meinen Fall hätte ich mir etwas gewünscht wie eine Art Plugin oder von mir aus auch eine Art “include” das entsprechende Funktionen einbindet wenn sie benötigt werden. Vergleichbar mit dem was ein Präprozessort für C erreichen kann: Macro-mäßig das einfügen was gerade gebraucht wird – bei compilierten Sprachen eine sehr feine Sache, bei Skripten leider kein gangbarer Weg.

Was braucht man eigentlich genau? bzw. was wünsche ich mir? – Das waren meine Fragen. Damit man eine Tabelle einfach einbauen kann braucht man Zugriff auf einige Klassenvariablen – man könnte sich ggf. behelfen, eine Referenz an eine Tabellenklasse zu übergeben und dort den notwendigen Code zu schreiben. Aber eine Tabelle ist ja auch nur wieder eine Sammlung von einfacheren PDF-Elementen – würde also auch wieder aus der TCPPDF-Klasse erben müssen, davon den Code in die andere Klasse zu übergeben mal ganz abgesehen. Eine Art “Nachbau” des Präprozessors wäre es wenn man hergehen könnte und an der benötigten Stelle in der Klasse einfach per include die Funktionen einbaut die man braucht. Das geht natürlich so nicht, auch weil es im Tabellencode ja durchaus sinnvoll ist, diesen strukturiert zu halten und keinen Spaghetti-Code zu erzeugen, den keiner mehr durchschaut. Auch die Nutzung von Klassenvariablen innerhalb der Tabelle wäre doch praktisch. Kurzum: ein simples Include kann das nicht leisten und sollte es auch nie.

Nun ist es ja aber bei weitem kein super exotisches Problem, mit dem wir hier konfrontiert sind: Modulbauweise mit Blackboxes die nur definierte Schnittstellen haben ist ja auch in anderen Bereichen üblich: Keiner entwickelt heute mehr für jedes Auto Standard-Komponenten vollständig neu – vielmehr werden Grundelemente mit einen neuen Aufsatz versehen oder neu miteinander kombiniert. PHP löst das Dilemma mit sogenannten Traits – ich vergleiche das gerne mit Matrix-Vererbung – um ein Gesamtpaket zu erhalten markiert man einfach die Zusatzfunktionen die das Ergebnis haben soll. Klingt kompliziert – ist es aber nicht.

Einen Trait programmiert man fast wie eine ganz normale Klasse – abgesehen, davon dass sie keinen eigenen Konstruktor enthält, gibt es alles was man sonst auch kennt: Funktionen, Zugriffsbeschränkungen (public,private,protected) und Klassenvariablen. Kurzum man kann alles was man immer wieder braucht damit sauber realisieren – in meinem Fall, habe ich alles was ich für eine Tabelle benötige im Trait verpackt. Man hat sogar Zugriff auf die Methoden und Variablen der Klasse in der man den Trait am Ende einsetzen will – hier ist die Unterstützung der Entwicklungsumgebung natürlich nicht so gut wie in einer vererbten Klasse, denn der Trait kann ja in jeder beliebigen Klasse verwendet werden – von daher etwas mehr Denkarbeit. Ich habe vieles direkt aus der bisherigen Realisierung übernehmen können, das macht es etwas leichter.

Was man noch beachten muss: Gleichnamige Funktionen in der übernehmenden Klasse “überdecken” bzw. überschreiben die Funktionen des Traits (vergleichbar mit dem was man aus der Vererbung kennt: Es wird immer die “nächstliegende” Funktion genommen, es sei denn man gibt den Namespace bzw. die Elternklasse mit an (parrent::) . Für mich hat es sich bewährt im Trait die Funktionen als solche entsprechend zu bennen – sie bekommen alle den Prefix “pdf_table_trait_” – die Wahrscheinlichkeit, dass man somit ungeplant etwas überschreibt ist vergleichsweise gering. Die Programmiersprache nimmt einem eben nicht alles ab und etwas Coding-Disziplin hat noch keinem Entwickler geschadet.

Insgesamt habe ich nun mit dem Trait das was ich gesucht habe: Einen Code-Block, den ich separat warten kann – wenn ich einen Fehler in der Tabellenerzeugung beseitige, dann muss ich das nur noch an einer Stelle tun, nicht mehr in jedem Dokument. Zudem habe ich es so realisiert, dass ich den Code sogar innerhalb einer Klasse mehrfach aufrufen kann um verschiedene Tabellen zu zeichnen (das hatte ich vorher mit etwas Verrenkungen unsauber gelöst). Man sollte natürlich jetzt nicht alles und jedes zwingend in einen Trait auslagern, nur weil es geht – mit Maß und Ziel das richitige Werkzeug an der richtigen Stelle ansetzen. Traits gehören dabei eindeutig in die Kiste mit der Aufschrift “Spezialwerkzeuge” – man braucht sie nicht all zu häufig, aber wenn man weiß dass es sie gibt und wie man sie richtig einsetzt, geht vieles sehr elegant zu lösen.

Vom Himmel hoch da komm ich her – Skydrive-Schwachsinn zur Weihnachtszeit

Vor einigen Tagen hatte ich mal wieder ein absolutes Schlüsselerlebnis, das mich in meiner Skepsis gegenüber Windows 8 und Microsoft-Produktem im Allgemeinen deutlich bestärkt hat. Sicher sind die Produkte von Microsoft in vielen Fällen ein gewisser Standard, aber es gibt immer wieder Ecken und Kanten an denen ich mich einfach nur ärgere wie etwas gelöst ist.

Windows Vista ist ebenso eine Ladenhüter wie es schon seinerseits Windows ME war – viele Feautres gut gemeint und gewollt, aber die Realisierung war nicht der Knaller. Ähnliches sehe ich gerade bei Windows 8 – auch hier hakt es an vielen Stellen und das Betriebsystem hat sich meilenweit von dem entfernt was es eigentlich machen sollte – Ressourcen des Rechners bündeln und allen Anwendungen zur Verfügung stellen, auf Basis einer einheitlichen Schnittstelle. Das Fehlen des Startmenüs mit der Suchfunktion ist eines, aber eine komplette Touch-Bedienung für einen Desktop-PC oder Laptop an dem Maus und Tastatur angeschlossen sind – das kann in meinen Augen nicht hinhauen. Ironie dabei ist der Werbesong “Everything at once” von “Lenka” – dort werden verschiedenste nicht miteinander vereinbare Gegensätze postuliert, welche die Sängerin alle doch erfüllen möchte. Wer das mal probiert hat, weiß: Manche Dinge schließen sich einfach gegenseitig aus … Ich bin gespannt wann sich diese Erkenntnis auch in Firmen herum spricht (und das betrifft leider nicht nur Microsoft, auch andere Firmen verwenden “Standard-Software” für Zwecke, für die sie nie gedacht war und wundern sich dann noch über “komische” Ergebnisse).

Was war das konkrete Problem diesmal? Ein Kunde wollte wie bisher unter Windows verschiedene Bild-Dateien per e-mail verschicken. Soweit nichts wirklich Spannendes oder Nerviges. Da es bequem und auch legitim ist, markierte er die Bilder seiner Wahl und wählte im Kontext-Menü: Senden an … => e-mail-Empfänger. Nun ging auch brav das eingerichtete (und mitgelieferte) Windows Live Mail auf (oder wie ich es nach der Erfahrung wohl eher nenne: “Windows Live Quäl” – es quält dich ggf. ein Leben lang…). Interessanterweise wollte das System jedesmal einen Hotmail-Account einrichten, obwohl bereits eine e-mail-Adresse konfiguriert war. Klickte man den Dialog einfach weg und schaute in die e-mail so wurde vom Mailprogramm angestrebt, die Bilder nur als Thumbnails in die e-mail einzubetten und die Originale zu Skydrive für eine bestimmte Zeit hochzuladen und per Link oder Bildergalerie verfügbar zu machen. Natürlich ist das nicht das was der Anwender eigentlich wollte, nämlich die Bilder einfach an die e-mail anhängen.

Was ist der Hintergrund? Generell bietet e-mail die Möglichkeit Anhänge mit zu versenden, so wie man es auch von klassicher Snail-Mail her kennt. Einfach etwas mehr in den Umschlag packen und im Anschreiben darauf verweisen. Mit HTML-Mails sind auch direkte Anzeige-Referenzen möglich, aber im Prinzip ist es jedesmal ein elektronisches Kuvert mit dem Inhalt, mal nur reiner Text, mal eben mit Anlagen. Problematisch ist die Mailbox-Größe der Empfänger bzw. Restriktionen der e-mail-Server aus Performance und Sicherheitsgründen: Oftmals sind hier Limits für eine Nachricht vorhanden und oft sind die recht knapp bemessen (es sei denn man ist sein eigener Mail-Admin und stellt sich die Einschränkungen entsprechend ab oder zumindest mal hoch ein). Daher ist es bei größeren Dateien oder Datenmenge oftmals ratsam auf Alternativen auszuweichen, also zum Beispiel den Upload der Datei auf einen Webserver und dem Empfänger nur einen Link (genauer einen URL) zuzuschicken damit er die Datei bei Bedarf herunter laden kann. In Etwa kann man es mit dem Angebot eines Webshops vergleichen bei dem man online bestellt und dann die Info bekommt: “Ihre Ware können Sie in Warenhaus XYZ in ihrer Nähe abholen, sie ist dort für sie bis zum soundsovielten reserviert).

Daher ist das Ansinnen von Live-Mail ja ganz gut gemeint, bewahrt es doch den Nutzer vor etwaigen e-mail-Rückläufern wenn die e-mail nicht zugestellt werden kann. Aber will ich wirklich jedes Bild in die Cloud eines amerikanischen Konzerns auslagern? Gerade im Blick auf die NSA-Affaire halte ich den Vorschlag für nicht zielführend und gelinde gesagt für Irreführung des Benutzers. Es wird eine Notwendigkeit vorgegaukelt die es schlichtweg nicht gibt.

Ich selbst verwende schon seit sehr langer Zeit alternative e-mail-Programme wie Pegasus-Mail (früher) und Mozilla Thunderbird (aktuell). Thunderbird macht hierbei vor wie man es besser machen kann: Hängt man Attachments einer bestimmten Größe an, gibt es einen Hinweis auf einen Cloudservice, der darauf hinweist, dass es problematisch sein könnte eine derat “dicke” e-mail zu versenden, und ob man diesen nutzen möchte. Man hat also definitiv die Wahl was man machen möchte, etwas was mit Live Mail leider nicht geht – zumindest habe ich auf die Schnelle keine passende Option gefunden und diverse Foren-Einträge im Netz schildern ähnliche Erfahrungen. Von daher kann ich leider als ITler keinem Menschen mehr die Benutzung von Live-Mail auch nur nahelegen als Alternative, sondern kann nur auf externe Programme verweisen die dem alten Unix/Linux-Mantra der Software treu geblieben sind “do one thing and do it right” – auf gut deutsch: Mache eine Sache, die aber dafür richtig und nicht alles nur so halb und dafür auf einmal (everything at once). In der Linux-Welt gibt es viele spezialisierte Programme für genau einen Zweck, weitere Funktionen, die nichts mit der eigentlichen Aufgabe zu tun haben, sucht man aber (zu Recht) vergeblich. Sicherlich ist das nicht immer und überall bis ins Letzte sinnvoll, aber es hat sich als gute Richtlinie für die Modularisierung von Programmen erwiesen: Für jeden Zweck das passende Werkzeug. Man versucht doch auch nicht, Schrauben mit einem Hammer “einzuschrauben”…

Einen Würg-Around gibt es dann dennoch für Windows Live Mail und das Kontext-Menü:

  1. Im Ordner, in dem sich die Bilddateien befinden eine leere Textdatei erzeugen (z.B. bla.txt), diese muss noch nicht einmal Inhalt haben
  2. Zusätzlich zu den Bildern die gerade erzeugte Dummy-Datei anwählen
  3. Kontextmenü => Senden an e-mail-Empfänger
  4. In Windows Live-Mail wird nun eine e-mail mit regulären Attachments erzeugt (es geht also …)
  5. Aus der Attachmentliste und der Auflistung im Text die leere Textdatei wieder rauswerfen
  6. Voila!

Das so ein Murks notwendig ist, zeugt davon, dass man scheints noch nicht gelernt hat, auf einen Anwendungsfall wirklich passende Lösungen zu liefern – das Gängeln des Benutzers hat ja aber auch eine jahrzehnte lange Tradition bei Microsoft. Warum das wissen wohl nur die Marketing-Menschen aus Redmond.

In diesem Sinne erst mal frohe Weihnachten und viel Spaß beim Verschicken von e-mails mit handelsüblichen Attachments.

Umstellung von Webprojekten auf UTF-8

Im letzten Artikel habe ich die Grundlagen zusammengefasst, mit denen ich mich beschäftigen musste um mein aktuelles Projekt voran zu bringen. Das Problem war ursprünglich die nicht einheitliche Handhabung diverser Zeichenketten, was bei Benutzer-Inhalten und Sonderzeichen zum berühmten Mojibake führen konnte (aber eben nicht zwingend muss). Nun denn, gehen wir ans Eingemacht und stellen das Projekt auf UTF-8 um, damit habe ich hoffentlich dann einen wichtigen Schritt in Richtung Zukunftsfähigkeit getan. Außerdem bietet sich UTF-8 wegen seiner Kompatibilität zu ASCII an – Programmcode wird dadurch nicht angetastet und PHP ist dankenswerter Weise sehr einfach gestrickt war Text-Ausgaben mittels “echo” oder ähnlichen Befehlen betrifft: Was hintendran als Argument kommt wird genauso wiedergegeben wie es reingekommen ist – Byte für Byte. Damit hat man wenig Probleme, auch wenn eine Seite eben mal doch Sonderzeichen enthält (wie es im Deutschen leider häufiger der Fall ist). Dieser Post kann als grundlegendes Howto verwendet werden, es gilt jedoch immer: “Keine Garantie” und “your milage may vary”

Erster Schritt – Anpassen der Entwicklungsumgebung

Damit man in Zukunft mit der Entwicklungsumgebung weiterhin einfach arbeiten kann, ohne sich jedesmal Gedanken über irgendwelche Sonderzeichen machen zu müssen – wenn man mal eben drei Zeilen Kommentar schreibt, sollte man sich auf dessen Inhalt konzentrieren können. Je nachdem was man verwendet gibt es da verschiedene Stellen die eingestellt werden müssen. Ich verwende Eclipse, dort kann man das Encoding einmal generell (unter Window -> Preferences -> General -> Workspace:  Text-File-Encoding) einstellen.  Zudem sollte man für die verschiedenen Einträge unter “Content Types” sicherstellen, dass per default dort auch UTF-8 genommen wird. Unter Linux habe ich festgestellt, dass es meistens schon vorab eingestellt ist, denn die meisten aktuellen Linux-Distris sind vom System aus schon löblicherweise auf UTF-8 als Standard umgestellt. Ein Blick in die Äste Web -> CSS Files und Web -> HTML-Files schadet auch nicht. Im Ast XML sollte es per Default auch schon passen, aber Nachgucken schadet auch hier nicht.

Nun muss man noch die Projekt-Einstellungen anpassen (wenn man bestehende Projekte hat) – wenn man den Fehler gemacht hatte und ein neues Projekt angefangen hat ohne sich vorher über die Verwendung von Zeichensätzen Gedanken zu machen (sowas sollte auf jeder Checkliste für Projekte stehen, aber wer achtet da schon drauf wenn es mal eben um eine kleines Projekt geht …. das dann später wächst …). Wenn man die Umstellung gemacht hat, kann man einmal Buchstabensuppe sehen, indem man eine Datei öffnet die Sonderzeichen enthält … die sehen nun etwas komisch aus. Alle händisch ersetzen ist nur was für Hartgesottene oder sehr sehr kleine Projekte.

Zweiter Schritt – Datein umwandeln / umcodieren

Es gibt ein praktisches Tool zum Umwandeln <code>iconv</code> das Werkzeug gibt es auch für Windows, aber so richtig mächtig und scharf wird das erst in Kombination mit ein wenig Scripting (bei mir in Bash)


#!/bin/bash

for file in $(find . -type f -name ‘*.php’)
do
iconv -f iso88591 -t utf8 -o $file.utf8 $file
if [ $? -eq 0 ]
then
#echo “$file erfolgreich”
mv $file.utf8 $file
else
echo $file geht nicht $?
fi
done

Was machen wir und warum mache ich da so? Ersteinmal suche ich alle betroffenen Dateien heraus, da ich mit PHP arbeite sind das alle Dateien die auf <code>.php</code> enden. Jede dieser Dateien lasse ich durch Iconv laufen und als neue Datei abspeichern. Man sollte nicht auf die Idee kommen <code>iconv -f iso88591 -t utf8 -o $file $file</code> zu verwenden. Das klappt nur bei kleinen Dateien. Wenn das nicht der Fall ist, hat man evtl. unvollständige Dateien und wundert sich was passiert ist, denn <code>iconv</code> gibt in diesem Fall keine Fehlerme. Mit dem Speichern in eine separate Datei bleibt das Original erst einmal unberührt und man kann sich ggf. auf die Fehlersuche machen, denn: Wenn beim Konvertieren selbst etwas schiefgeht gibt es einen exit-Code > 0. Wo es geklappt hat, überschreibe ich das Original. Ansonsten ein kleines <code>echo</code> das mir die fehlerhaften Dateien angibt damit man dort nachsuchen kann, meistens hat man schon irgendwo mal etwas als UTF8 gespeichert oder die Zeichensätze verbeult, das findet sich aber meist recht schnell. Bei mir waren es von 500 Dateien zwei Stück die etwas Handarbeit erforderten. Das gleiche Schema kann man auf alle reinen Textdateien anwenden, wenn man es braucht, z.B. reine HTML-Dateien (Endung htm oder html) oder auch JavaScript-Code. Wichtig ist noch dass man seinem Webserver ggf. beibringt, per default auch in UTF-8 auszuliefern. Dazu sucht man in den Konfigurationsdateien die folgende Zeile:

AddDefaultCharset UTF-8

Nach einem Neustart des Daemons wird das dann als default verwendet. Warum aber nur im default-Fall? Klar es gibt noch ne Möglichkeit das einzustellen und zwar in den ganzen HTML-Headern. Dort gibt es das META-Tag mit dem man Vorgaben machen kann auch für den Fall, dass man auf dem Server keinen Zugriff auf die Einstellungen des Apache oder wie auch immer sonst gearteten Webserver-Prozess hat.

&lt;meta equiv="content-type" content="text/html; charset=utf8"&gt;

Damit sollte jeder aktuelle und die allermeisten der älteren Browser in der Lage sein zu erkennen: Jetzt kommt was in UTF8.

Wenn man nur eine statische Website hat, ist man jetzt schon fertig – nur wer hat das schon heute noch?

Datenbankumstellung (MariaDB/MySQL)

Die Website an sich sollte nach der Umstellung weiterhin funktionieren, denn der eingebettete PHP-Code ist besteht nur aus Zeichen des ASCII-Repertoires und ist somit nicht verändert. Über das was zwischen Klammern steht oder einfach “unverdaut” ausgegeben wird, macht PHP sich praktischerweise keine Gedanken sondern gibt es einfach aus, egal wie viel Bytes das sind und ob das nun ein besonderes Zeichen ist oder nicht.

Unlustig sind die Dinge die jetzt noch dynamisch aus der Datenbank nachgeladen werden. Wenn man es bisher (wie häufig bei Standardinstallationen) versäumt hatte auf UTF8 umzustellen, dann muss das jetzt auch noch erfolgen. Ich halte nichts davon die Daten bei jeder Ausgabe in UTF8-Strings zu konvertieren – das ist viel zu viel Aufwand wenn das Projekt eine gewisse Größe erreicht hat. Im übrigen haben viele Leute noch per default den Zeichensatz auf “latin1-swedish” stehen, ein Hinweis woher MySQL denn ursprünglich mal kam. Im 0815-Tagesgeschäft fällt das aber in Europa meist niemandem auf.

Praktischerweise gibt es die Funktion
ALTER TABLE xyz CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]

Damit kann man jeweils eine ganze Tabelle umstellen und eine Collation vorgeben, wir erinnern uns: Collations regeln die Sortierreihenfolge je nach dem wie es gehandhabt werden soll.

Das klingt nicht schlecht und klappt im Allgemeinen auch ganz hervorragend, wenn da nicht einige Fallstricke wären.

Der erste ist ja noch gut gemeint seitens der Engine-Designer: Möglicherweise zu kleine Felder werden in das nächstgrößere Format überführt, wenn der Ausgangszeichensatz einer mit nur einem Byte pro Character ist, der Zielzeichensatz aber mehrere hat oder zumindest haben kann. So werden Textfelder mit bis zu 256 Zeichen zu Mediumtext umgewandelt. Das ist von der Auswirkung her eigentlich zu verschmerzen, aber in meinem Fall habe ich das hinteher wieder manuell korrigiert. richtig problematisch wird das wenn man über die entsprechenden Spalten Indizes angelegt hat, denn Textspalten lassen sich nicht indizieren.

Womit wir beim nächsten Fallstrick wären: An einigen Stellen funktioniert das mit der Umstellung nicht wie geplant, Ursache sind die Foreign-Keys. Ich habe an einigen Stellen “sprechende” Schlüssel anstelle von numerischen verwendet. Gerade dann wenn man in den referenzierten Tabellen wirklich nur Sateliten-Informationen stehen, wie etwa ein Icon und eine ausführliche textuelle Beschreibung zu einem bestimmten Zustand. Einige werden jetzt die Hände über dem Kopf zusammen schlagen, aber ich habe bisher keine negativen Auswirkungen auf die Performance feststellen können, eher positive Effekte bei der Fehlersuche. Wenn man schon anhand des Eintrags in der Tabelle selbst weiß was Sache ist, kann man sich einen zusätzlichen Join sparen. Das hat ja auch seine Vorteile.

Was also tun? Im Netz findet man praktische Anweisungen, die gesamte DB einmal per  mysqldump in eine Textdatei zu konvertieren, dort dann mit iconv das Gleiche zu veranstalten wie mit den Code-Files, danach noch die Tabellen-Definitionen automatisiert anpassen und den Dump wieder in die Datenbank kippen. Das funktioniert, ist aber bei größeren Datenmengen unhandlich.

Stattdessen habe ich mir die Information-Schema-Tabellen zu Nutze gemacht: dort stehen die Meta-Informationen zu den Tabellen in Tabellen, die man wie gewohnt mit SQL-Befehlen lesen kann – schreiben leider nicht, aber immerhin etwas. Dort sucht man sich nun die betroffenen Spalten und Tabellen heraus (Varchars und Texte), zudem schaut man auf die Foreign-Keys und merkt sich diese. Dann schmeißt man die Foreign Keys weg, führt die Veränderungen an den Tabellen durch (das geht ja dann). Wenn das durchgelaufen ist, kann man noch die vergrößerten Spalten wieder auf die Original-Größe zurück setzen (also Mediumtext => Text usw). Zu guter Letzt schaltet man die Foreign-Keys die man sich gemerkt hat wieder scharf. Fertig ist die Laube. Ganz so einfach ist es im Detail nicht, denn man muss stets vollständige Spaltendefinitionen verwenden, einfach nur den Typ ändern geht so leider nicht, auch wenn das eine praktische Sache wäre.

Jetzt hat man das gesamte Projekt umgestellt – zumindest was die Datenbasis und was die HTML-Seiten und den eingebetteten JS-Code betrifft. Das ist in aller Regel alles was man braucht.

Was noch an Problemen auftreten kann, beschreibe ich in einem weiteren Artikel. Stichwort sind hier externe Libraries und Frameworks.

Mojibake – Buchstabensuppe

Na da hatte ich mir doch eine lange währende Aufgabe ausgesucht, die ich in der aktuellen Pflegephase meines Softwareprojekts endlich einmal angehen wollte. Aktuell läuft das Produkt soweit zufriedenstellend, nur an einigen kleiner Ecken knackt und knirscht es immer mal wieder. Unter anderem das leidige Thema “Sonderzeichen und deren Darstellung” – da nicht absolut zwingend für die Funktionsfähigkeit habe ich das längere Zeit nicht großartig beachtet.

Nun gut, was ist das eigentliche Problem und woher kommt es? Die Ursachen liegen in der Historie des PCs ver- oder besser begraben: Da Speicher und Datenverarbeitung teuer war, hat man so sparsam wie möglich gearbeitet. Man stellte dabei fest: Inklusive aller wichtigen Zeichen der englischen Sprache und allem was man als Steuerzeichen (Zeilenumbruch, Tabulator, etc.) benötigt, bekommt man in 7 Bit unter. Das ist schon mal etwas krumm, denn gängig ist bei allem was Rechner betrifft doch eigentlich etwas eine Potenz von 2. Die ersten Rechner die ich verwendet habe (mit einem Intel 8088 als Unterbau) konnten nur 8 Bit parallel verarbeiten – immer mehr als die 7. Schon wenig später gab es 16Bit als Standard und mit der großen Verbreitung des PCs in die Büros war der Standard 32 Bit erreicht. Heute findet der sich bereits größtenteils in Ablösung durch 64Bit-Systeme. Was war der Sinn des 8. Bits? Man konnte es je nach Gusto verwenden: Entweder bohrte man damit den Zeichenvorrat auf, oder man konnte es zur Fehlererkennung und Korrektur einsetzen. Insgesamt muss man sagen: Alles mit Hand und Fuß.

Nur leider waren Rechner damals noch nicht gängigerweise vernetzt und die Standard-Definitoren etwas kurzsichtig – erst einmal wurde nur an die eigene Heimat gedacht, dass es möglicherweise andere Sprachen gibt, die nicht Englisch sind und einige Zeichen mehr mitbringen – wer konnte das schon ahnen? So kam was kommen musste: Einschränkungen bei diversen Dingen wie dem Betriebssystem: Umlaute oder Sonderzeichen in Dateinamen waren einfach nicht vorgesehen oder führten zu unvorhergesehenen Ergebnissen. Für das Verfassen und Verarbeiten von Texten war das natürlich keine Option, wer in Deutschland einen Text schreiben wollte, der sollte das auch tun können. Daher erweiterte man den Zeichensatz auf das 8 Bit und schon hatte man jede Menge Möglichkeiten auch Sonderzeichen abzuspeichern. Wichtig war nur, das jeder die gleiche Zuordnung traf und nicht einer ein ü für ein ö verwendete was die binäre Darstellung betraf. Soweit so gut oder auch schlecht.

Nun gehen leider bei verschiedenen Betrachtungen immer wieder einige Dinge durcheinander, auch ich habe hier am Anfag so meine liebe Mühe gehabt alles richtig zu verorten, daher hier einmal die Kurzfassung, zu allem was notwendig ist bzw. was sich auf die Darstellung und Handhabung von Texten am Rechner auswirken kann.

Binärer-Code

Eine Abfolge von 0en und 1en die irgendetwas darstellen – was ist für den Rechner erstmal unerheblich, dafür bedarf es einer Zuordnungs oder Code-Tabelle oder eines Algorithmus, der den Binärcode in etwas umsetzt, das dem Benutzer eher vertraut ist (leider sind wir Menschen nicht sonderlich gut binär veranlagt).

Code-Tabelle/Zuordnung/Algorithmus

Je nachdem was für eine Datentyp abgebildet werden soll, gibt es verschiedene Methoden dies zu tun. Am einfachsten sind ganze, positive Zahlen. Diese lassen sich aus der Abfolge von 0en und 1en entsprechend “errechnen” – man muss nur noch wissen wo man anfangen muss (little endian vs. big endian). Für positive und negative Ganzzahlen hat sich das Zweierkomplement bewährt, für Fixkomma und Gleitkomma gibt es entsprechende Standards. Alles ein Thema für sich, denn wir wollen ja Texte bzw. Strings beleuchten. Hier hat sich eine Übersetzungstabelle als Mittel der Wahl erwiesen – sie ordnet jeder möglichen Abfolge von 0en und 1en eine menschenlesbare Bedeutung zu. So wird z.B aus der binären Folge 0110 1101  = 0x6D = O155 = “m”. Die Zuordnung an und für sich ist reine Willkür – man hat sich mal auf gewisse Standards geeinigt bzw. diese festgelegt, damit eben auf allen Rechner ein “m” ein “m” ist und nicht aus der “e-mail” durch Willkür eine “e-nail” wird. Der Urvater aller Standards dazu heißt ASCII (America Standard Code for Information Interchange) – wie der Name schon sagt ein nationales Standardformat. Auch bekannt ist diese Tabelle als Character-Set.

Windows-Codepages und Nornumg

Für verschiedene Regionen wurden verschiedene Verwendungen des verbliebenen 8. Bits (siehe oben) standardisiert – leider teilweise recht unterschiedlich, zum Teil nur an wenigen Stellen. Ziel war es, die in der jeweiligen Region verwendeten Sprachen möglichst gut abzubilden. Leider gab es da erst sehr spät eine Einigung auf einheitliche Standards, so dass zeitweise unterschiedliche Hersteller unterschiedliche Zuordnungen trafen. Ganz genauso wie wenn man Dateien ohne Angabe des verwendeten Zeichensatzes weitergab konnte es also passieren, dass der Zielrechner die Bit-Folge unterschiedlich interpretierte, weil bestimmte Bitfolgen eben etwas unterschiedliches bedeuteten. Dankenswerterweise hat man dabei die sichtbaren Zeichen (leider nicht so bei den Steuerzeichen) aus dem Urvater ASCII gleich belassen (das hatte sich ja bewährt, und für den internationalen Textaustausch reichte dieser kleinste gemeinsame Nenner auch aus). Gängig sind in der westlichen Welt die Standards der ISO 8859 in den Varianten 1-16, unter Windows die Codepage 1250 und unter DOS die Codepage 850.

Unicode

Mit der steigenden Internationalisierung und der immer stärker zunehmenden Vernetzung von Computern ist das mit den Nachschlagetabellen so eine Sache – man muss immer wieder etwas anderes berücksichtigen: Das Betriebsystem und die Region bzw. die Regionaleinstellungen des Anwenders – nur damit Text auch so ankommt wie er einegeben wurde. An einigen Stellen hat man sich beholfen oder die Probleme durch menschliche Intuition überbrückt – durch die Redundanz in der menschlichen Sprache kann man viele Worte ja auch lesen wenn Buchstaben vertauscht wurden oder nicht lesbar sind. Jeder Mensch der Lesen lernt kann das mehr oder weniger: Wenn aus einen Königreich dann plötzlich ein K$nigreich wird, dann wird der geneigte Leser das immer noch erkennen, auch wenn so ein Text etws mühsamer zu lesen ist. Ohnehin: wenn es international wird, dann ist die Sprache der Wahl in aller Regel doch Englisch und somit problemfrei. Aber wäre es nicht toll, wenn jemand eine Lösung hätte, damit ich auch chinesische Texte richtig angezeigt bekomme? Oder auch mal einen arabischen Text im Original anschauen? Das klingt weit hergeholt, aber diese Anwendungsfälle gibt es häufiger als man denkt. Die ursprüngliche Idee mit 32Bit und somit 4 Bytes pro codiertem Zeichen zu arbeiten (UTF-32) ist zwar einfach zu realisieren, aber ein wenig “over the top” ist das schon: Wer überträgt schon gerne 3 komplett genullte Bytes wenn die Info doch nur in einem steht? Außerdem ist der Standard nicht abwärtskompatibel, er bricht mit den alten Vorgaben von ASCII, was bei älterer Software oder inkompatibler Software Ärger machen kann. Daher gibt es verschiedene Methoden mit variabler Anzahl von Zeichen, sozusagen das Beste aus beiden Welten: UTF-16 oder UTF-8 sind hierbei die bekanntesten Möglichkeiten.

Schriftarten und Glyphen

Wir haben uns nun langsam von der Bits & Bytes-Ebene nach oben gearbeitet hin zum abstrakten Begriff eines “characters”. Es gibt aber noch eine Ebene obendran – die Schriftarten oder auch Glyphen. Das ist im Prinzip eine weitere Tabelle die festlegt wie ein abstraktes Zeichen auf dem Ausgabemedium dargestellt werden soll. Jeder der sich einmal durch den Schriftenkatalog einer gängigen Office-Sammlung gewühlt hat, weiß das ein A ein A bleibt, auch wenn es etwas unterschiedlich geformt ist. Das beste Beispiel ist noch immer die eigene Handschrift im Vergleich zu einem beliebigen, gedruckten Werk. So lange eine gewisse Basis-Form erhalten bleibt, erkennt jeder Leser darin auch weiterhin ein A. Es gibt natürlich auch wieder Spezielle Schriftarten die als Darstellungvon Buchstaben Symbole haben, die nichts mit dem eigentlichen Zeichen zu tun haben – das bekannteste dürfte die Schriftarte Wingding oder auch Webdings sein. Besonders unpraktisch fällt mir diese immer wieder in e-mails aus Outlook auf, wenn man diese als Text ließt. Dort wird der Smily 🙂 automatisch in ein J umgewandelt und mit der Schriftart Wingdings formatiert – sieht zwar im ersten Moment richtig aus, aber mancher hat sich schon gewundert wo das “J” denn nun herkommt. Ich merke es mir immer so: Ein Glyph macht aus einer Bit-Folge mittels einer Tabelle eine ganz bestimmte Grafik. Das ist zwar etwas vereinfacht, denn Schriftarten machen manchmal noch mehr, aber um den Überblick zu behalten reicht es allemal.

Collations

Was nochwas? Haben wir nicht alles endlich abgehandelt? Leider noch nicht ganz: Es gibt nämlich noch etwas was man mit Zeichenketten gerne macht: Aufreihen und Sortieren. Kling trivial, und es gibt doch Sortieralgorithmen wie Sand am Meer. Könnte man meinen, leider ist dem nicht ganz so (und das ist mit ein Grund weshalb man Sortieralgorithmen am besten an Zahlen erklärt …), denn auch wenn es im ersten Moment verlockend sein mag zu sagen: Man sortiert einfach nach der Größe der entsprechenden Ganzzahl der Bitfolge, das bringt leider nicht das gewünschte Ergebnis, denn schon bei ASCII haben wir ja große und kleine Buchstaben, ordnet man nun nach der errechneten Wertigkeit, so würde das folgende Sortierreihenfolge ergeben A,B,C…..,X,YZ,a,b,c – für die alphabetische Auflistung eines Materialkatalogs nicht das gewünschte Ergebnis – auch im Telefonbuch sucht man die Leute mit “von” im Vornamen ja nicht unter “v” sondern unter “V” und dort irgendwo nach “Voldemort”…. und nun wirds ganz interessant: Wo ordne ich denn die Sonderzeichen wie Ä,Ö,Ü ein … sind das separate Zeichen am Ende? Oder soll ich sie behandeln wie “Ae”,”Oe” und “Ue”? Das ganze nun noch auf die internationale Ebene gehoben und es wird ganz spannend: Je nach Land gibt es gleiche Zeichen, aber die werden unterschiedlich einsortiert, aber der Rechner soll es dennoch richtig machen. Das kann nur bedingt funktionieren, alles weitere regelt man über die Collation, die kann man zur Not auch bei der Sortierung mit angeben, und dem Sortierprogramm somit die Regeln vorgeben.

So jetzt habe ich einmal die Grundlagen zusammengefasst, die Auswirkungen und Mittel die man braucht um das alles umzusetzen behandle ich in einem separaten Artikel.

 

 

Die andere Seite der Laufveranstaltung – Herbstlauf 2013

An einer Laufveranstaltung teilnehmen ist eine Sache – je nach Streckenlänge auch entsprechend anstrengend aber jedesmal ein tolles Erlebnis für mich. Auch nicht zu verachten ist aber der Schritt auf die andere Seite, hinter die Kulissen. Mit der Organisation des Herbstlaufs 2013 der DJK habe ich auch dieses Jahr den Schritt wieder getan. Mittlerweile liegt die Veranstaltung etwas mehr als eine Woche zurück – Zeit ein wenig zurück zu blicken.

Nach dem Lauf ist vor dem Lauf – so ungefähr war das Credo nach der ersten Durchführung des Herbstlaufs 2012 – zum ersten Mal hatte die Triathlon-Abteilung die Organisation vollständig übernommen, zudem wurde erstmals eine Chipzeitmessung eingesetzt. Klar das da einiges noch nicht flüssig lief und die eine oder andere Erkenntnis mühsam gewonnen werden musste. Somit begann es bereits nach der ersten Nachbesprechung mit konkreten Beschaffungen – in diesem Jahr erleichterte uns schon ein Gabelhubwagen an vielen Stellen die Arbeit erheblich. Zudem wurde die Markierung der Strecke optimiert. Auch die Erfahrungswerte in Sachen Software und Hardware zahlten sich dieses Jahr aus: WLAN im Feld ist zwar nett, aber nicht zuverlässig genug. Daher diesmal gleich Kabel, das dauert auch nicht viel länger im Verlegen, wenn alles vorbereitet ist.

Die richtig heiße Phase ab Freitag beim Aufbau verlief denn auch entsprechend kühl, innerhalb weniger Stunden stand die IT-Infrastruktur vollständig zur Verfügung und der Annahmebereich für Nachmeldungen und die Abholung war eingerichtet. Auch der restliche Aufbau war sehr bald abgeschlossen. Einzig die Reinigung der Strecke zog sich etwas in die Länge, beim Herbstlauf hat man nunmal mit etwas Laub zu tun, sonst wäre es ja kein Herbstlauf. Die Beschaffung von Getränken und Werbematerial war auch flugs erledigt und so konnten wir deutlich vor der geplanten Zeit in die letzte Nachtruhe vor dem Lauf gehen. Abgesehen von einer Back-Aktion, der Kuchen für den Verkauf sollte ja frisch sein – aber auch das ist ja kein Drama, so ein Blechkuchen ist ja flugs gemacht und gebacken.

Da dieses Mal die Online-Voranmeldung recht gut lief, hatten wir deutlich weniger Nachmeldungen, und auch zusätzliches Personal bei der Eingabe – somit entfiel ein erkannter Flaschenhals. Auch der Trouble-Desk war diesmal auffällig ruhig, bis auf einige kniffelige Spezialfälle war nichts spektakuläres dabei, die üblichen defekten Startnummern aber alles sehr entspannt.

So konnte ich am Hauptlauf sogar noch fleißig Bilder machen, insgesamt etwas mehr als 2300 mal habe ich abgedrückt. Deutlich zu oft wie ich im Nachinein feststellen muss, dazu weiter unten etwas mehr. Schon sehr bald nach dem letzten Zieleinlauf konnte der Abbau hinter den Kulissen beginnen – wie üblich verlief das nochmals schneller als der Aufbau. Innerhalb weniger Stunden war alles Material verladen, verräumt und teilweise sogar schon retourniert. Durch die Verlegung des Erfassungsrechners in den Anmeldebereich konnte direkt in der Nähe des Druckers weitergearbeitet werden, während gleichzeitig der Abbau der Verkabelung am Zielkanal erfolgen konnte. Bis das demontiert war, konnte das Netzwerk schon wieder ein Stück weiter abgeschmolzen werden – so lange bis am Ende ein simples Cross-Over-Kabel für zwei Rechner erhalten blieb an denen noch gearbeitet wurde. Sämtliche anderen aktiven Komponenten wie Switches und APs konnten derweil schon abgebaut werden. Auch der Backup-Drucker war zu Hochzeiten zwar hilfreich, konnte aber für die wenigen Korrekturdrucke abgezogen werden. Nach und nach stapelten sich diverse Kisten für die Verladung ins Auto. Alles noch einladen – fertig.

Ebenso fix waren die Kollegen an anderer Stelle – nur noch wenige Einzelteile galt es zu verladen oder ins Lager zu schaffen. Somit konnte bereits deutlich vor der geplanten Zeit mit den Helferfeierlichkeiten begonnen werden. Natürlich freut das die Helfer, wenn sich nicht alles ewig hinzieht.

Etwas “Nachwehen” gab es denn doch noch – das IT-Material musste ich bei mir auch wieder verräumen, auch wenn dank Vorsortieren das recht bald als “erledigt” abgehakt werden konnte. Zudem noch den geliehenen Anhänger zurück bringen, aufgrund des matschigen Geländes musste der aber auch noch geschrubbt werden. Mein Auto hat dafür auch gleich eine Reinigung erfahren, damit es sich wenigstens lohnt.

Erstaunlich aufwändig gestaltete sich die Auslese der Bilder bzw. deren weitere Verwendung. Einerseits war es das schiere Datenvolumen, dass alleine anderthalb Tage Dauerlast am DSL-Anschluss benötigte um die Bilder auf einen Server zu übetragen. Ferner bringen Bilder einer Laufveranstaltung nichts, wenn sie nicht nach Startnummern gefiltert werden können. Mit meiner Erfahrung habe ich kurzerhand eine kleine Software in PHP geschrieben, die sich der Verwaltung und Ausgabe der Bilder annimmt. Auch dabei habe ich wieder etwas gelernt – diesmal über automatische Nachbearbeitung von Bildern auf der Kommandozeile, also praktisch im Blindflug. Mit einigen Hilfsmitteln kann man Bilder gleich passend rotieren lassen (ohne alles nochmal durch die JPEG-Mühle zu drehen). Die Verwaltung übernimmt dann eine Datenbank in der ich die Bilder direkt als Datensatz abgelegt habe, das erspart Probleme bei doppelten Dateinamen und die Verwaltung von Meta-Informationen ist auch deutlich leichter. Dennoch habe ich die folgenden Abende damit zugebracht die 2300 Bilder mit Nummern zu versehen, eine Multi-User-Fähigkeit muss ich noch einbauen, Ideen dazu habe ich schon. Auch am Layout muss ich noch ein wenig was machen, aber die Funktionalität stand ja erst einmal im Vordergrund.

Insgesamt wieder eine tolle Erfahrung die mein Leben bereichert hat, auch ich habe wieder einiges dazu gelernt – vor allem werde ich nächstes Mal weniger Bilder und dafür besser komponierte machen, Qualität schlägt Quantität. Wer Interesse an der Software hat,  kann sich ja einmal bei mir melden – ich denke wir sind nicht der einzige Verein, der viele Leute mit Kameras hat, aber keinen professionellen Bilderdienst engagiert.