Random-Access und UTF-8

English

Es ist eine schöne Sache, dass man „Random-Access-Dateien“ verwenden kann und die Möglichkeit hat, effizient zu einer beliebigen Byteposition zu springen, um ab dort zu lesen oder zu schreiben.

Das gilt auch für Textdateien, bei denen pro Zeichen eine feste Anzahl Bytes verwendet wird, z.B. immer genau ein Byte oder immer genau zwei Bytes pro Zeichen.

Nun ist aber der neue Standard für Text-Dateien UTF-8. Da funktioniert das auch fast so, weil bei vielen Sprachen die Zeichen immer noch meistens ein Byte groß sind.
Aber wenn man zu einer bestimmten Byte-Position springt, kann es passieren, dass man mitten zwischen den Bytes eines Zeichens („Code Point“) landet und nicht am Anfang eines Zeichens. Woher soll man das erkennen, wenn man nicht den Effizienzgewinn von Random-Access wegwirft und die Datei Byte für Byte und Zeichen für Zeichen liest, bis man an der betreffenden Stelle ist?
Nun lässt sich das aber finden, da UTF-8 Self-synchronizing ist. Man weiss, dass das erste Byte einer Bytesequenz, die ein Zeichen beschreibt, entweder mit 11 oder mit 0 anfängt. Alle weiteren Bytes fangen mit 10 an. So lässt sich vorwärts oder rückwärts an den Anfang eines Zeichens springen, das zumindest so nahe wie möglich an der gewünschten Position beginnt.
Schwieriger wird es, wenn man nicht an eine bestimmte Byte-Position, sondern an eine bestimmte Zeichenposition springen will.
Man kann das zwar schätzen, aber man weiß nie genau, wie lang die Zeichen in dem übersprungenen Bereich als Bytesequenz sind. Das lässt sich mit einer Indexstruktur in einer zweiten Datei oder in einem dafür abgestellten Bereich der Datei lösen, wo vermerkt ist, an welcher Byteposition man jeweils den Beginn von Zeichen k*b findet, wobei b eine „Blockgröße“, z.B. 1024 Zeichen, ist. Solange man nur hinten anhängt und nicht mitten in der Datei etwas überschreibt, sollte das möglich sein.

Share Button

GNU-Emacs und Unicode

Heute sollte man Text-Dateien bevorzugt in Unicode erstellen und speichern. Natürlich braucht man nur englische Texte, deshalb reicht ISO-646 (ASCII) aus, aber ein paar Umlaute kommen doch noch rein, allein wegen Eigennamen und so kann man ISO-8859-1 oder ISO-8859-15 nehmen und hat die Umlaute auch dabei. Praktisch mit demselben Aufwand kann man stattdessen UTF-8 verwenden. Das erlaubt es, die Umlaute zu haben, aber auch alle anderen Unicode-Zeichen. Und die seltenen Umlaute sind zwei Bytes statt einem groß, was in aller Regel vernachlässigbar ist. Eine andere Frage ist es aber, wenn man z.B. Russisch, Griechisch, Japanisch oder Chinesisch schreibt. utf-8 führt dazu, dass die griechischen und russischen Buchstaben mindestens zwei Bytes brauchen und die chinesischen und japanischen noch mehr. Bei diesen Sprachen ist zugegebenermaßen der Anreiz, eine Codierung zu verwenden, die auf diese Sprache zugeschnitten ist, größer, weil man so die Textdateien um Faktor 1.5 oder 2 kleiner machen kann. Weiß jemand, wie das heute praktiziert wird? In welcher Codierung speichert man üblicherweise Textdateien bei Sprache, die nicht auf lateinischen Buchstaben basieren?

Nun hat GNU-Emacs leider vor vielen Jahren seine eigene Idee statt Unicode entwickeln wollen, wie man die Zeichen der verschiedenen Sprachen codiert. Wer das noch weiß, wird vielleicht dem ganzen Werkzeug misstrauen, aber das ist nicht nötig.
Man kann eine einzelne Datei als Textdatei in utf-8 markieren, indem man in der ersten Zeilen einen Kommentar hat, der etwa so aussieht:

// -*- coding: utf-8-with-signature-unix -*-
// -*- coding: utf-8-with-signature -*-
// -*- coding: utf-8-unix -*-
// -*- coding: utf-8 -*-

Ab dann wird die Datei als Unicode gespeichert und auch beim nächsten öffnen interpretiert.
Das „-unix“ erzwingt einen Zeilenwechsel nur aus „ctrl-J“ (LF), statt „ctrl-M ctrl-J“ (CR LF), was in der Regel besser funktioniert, wenn man sowohl auf Win64/Win32 als auch auf Linux/Unix-Plattformen unterwegs ist.
Das -with-signature führt dazu, dass am Anfang der Datei eine „Signatur“ aus drei Bytes eingefügt wird, die ausdrückt, dass die Datei utf-8 ist. Leider wird diese Signatur nicht von allen Werkzeugen verstanden, aber wenn sie verstanden wird, ist das eigentlich der richtige Ansatz, weil man so wirklich utf-8 erkennen kann, ohne die ganze Datei vorher zu lesen.

Das läßt sich auch pro Endung festlegen, wenn man in .emacs so etwas schreibt:

(defvar utf8-suffix-regex nil "describes suffixes of files that are always utf8")

(setq utf8-suffix-regex "\\.\\(cs\\|scala\\|java\\|groovy\\)$")

(defun choose-encoding-by-suffix ()
  "Choose the encoding based on suffix"
  (interactive)
  (when (and (stringp buffer-file-name)
             (string-match utf8-suffix-regex buffer-file-name))
    (set-buffer-file-coding-system 'utf-8-unix nil t)))

(add-hook 'find-file-hook 'choose-encoding-by-suffix)

Wenn bei diesen impliziten Konvertierungen etwas schiefgeht, z.B. weil iso-8859-1 nach utf-8-Konvertierung zweimal statt einmal gelaufen ist, dann hilft recode. Man kann im Emacs die geöffnete Datei mit recode konvertieren:
Ctrl-X h ESC 1 ESC | recode utf8..latin1
Es empfiehlt sich, vorher eine Sicherungskopie anzulegen.

Dieselben Fragestellungen tauchen mit anderen Editoren und Entwicklungsumgebungen auch auf. In Eclipse und Netbeans kann man die Codierung von Dateien nach Endung, Projekt und auch für einzelne Dateien festlegen. Sicher wissen die vi-Spezialisten gut Bescheid, wie es mit vi geht.

Entscheidend ist, dass man sich bewusst für eine Codierung entscheidet. In Sprachen mit lateinischer Schrift dürfte das fast immer utf-8 sein, wenn man nicht „Altlasten“ hat. Das lässt sich mit geeigneten Editoren in den Griff bekommen.

Share Button

Warum Baumstruktur

Für Dateiverzeichnisse (Filesysteme) hat sich eine Baumstruktur etabliert. Wir haben uns daran gewöhnt und für die meisten Zwecke ist das auch eine sinnvolle Strukturierung.

Relativ oft wird man aber mit dem Problem konfrontiert, daß es zwei oder mehr Aspekte gibt, nach denen man seine Dateien oder Unterverzeichnisse gruppieren will. Machen wir es mal abstrakt mit Farbe, Form und Größe.

Dann kann man etwa so etwas haben wie

$MAINDIR/rot
$MAINDIR/blau
$MAINDIR/gruen
$MAINDIR/gelb

und in der nächsten Ebene dann jeweils so etwas wie

$MAINDIR/rot/quadrat
$MAINDIR/rot/kreis
$MAINDIR/rot/dreieck
$MAINDIR/rot/sechseck
$MAINDIR/blau/quadrat
$MAINDIR/blau/kreis
...
$MAINDIR/gelb/dreieck
$MAINDIR/gelb/sechseck

und darunter jeweils

.../klein
.../mittel
.../gross

Aber manchmal möchte man es genau anders haben haben, also zuerst nach Form differenzieren, dann nach Größe und zuletzt nach Farbe.
Und es kann oft sehr unpraktisch sein, wenn Dinge, die eigentlich zusammengehören und die man zusammen bearbeiten will, verstreut über das Verzeichnissystem herumliegen.

Es hilft sicher, daß man sich vorher gut überlegt, wie man seine Verzeichnisstruktur aufbaut, so daß es zumindest in möglichst vielen Situationen einigermaßen paßt. Es gibt sicher Möglichkeiten, damit umzugehen. Man könnte zum Beispiel alle sechs Verzeichnisbäume anlegen und via Hardlinks oder Softlinks die Dateien, die man im ersten Verzeichnisbaum richtig eingetragen hat, von den anderen Verzeichnisbäumen jeweils passend verlinken (Softlink) oder dort auch eintragen (Hardlink). Das geht unter Linux und Unix mit deren eigenen Dateisystemen gut, es kann aber eine Herausforderung sein, das konsistent zu halten.

Man kann auch die Daten auf Dateisystemebene irgendwie ablegen, vielleicht sogar in einer der möglichen Strukturierungen, aber den Zugriff über eine Applikation anbieten, die es ermöglicht, so darauf zuzugreifen, als wären sie in einer der anderen fünf Arten strukturiert. Ein typisches Beispiel sind Musikprogramme (Player), die es ermöglichen, die Musikstücke nach Genre, Sänger, und vielen anderen Kriterien zu strukturieren und dann mit diesen Daten darauf zuzugreifen. Es gibt dann typischerweise irgendwo Metadaten, die diese Zusatzinformationen enthalten. Hier hat man noch den Zugriff über das Dateisystem, was sehr praktisch ist, gerade bei Musik, aber die Applikation muß Änderungen erkennen und gegebenenfalls die Metadaten anpassen oder sogar interaktiv abfragen und ergänzen.

Noch weiter geht es, wenn die Datenspeicherung völlig intransparent ist, im Extremfall sogar unter Benutzung sogenannter „Raw-Devices“, und wenn man dann nur noch über so eine Applikation an die Daten herankommt. Im Grunde genommen sind alle Datenbanken in dieser Rubrik angesiedelt, aber auch die Repositories vieler Versionsverwaltungssysteme oder auch Content-Management-Systeme, die natürlich wiederum eine Datenbank verwenden können. Eine Folge davon ist, daß man an diese Daten nur noch mit der Applikation oder deren Hilfsprogrammen herankommt und nicht mehr wirklich auf Dateisystemebene damit arbeiten kann. Eine kleine Anzahl von Datenbankprodukten und das zugehörige Knowhow leistet man sich gerne, denn das braucht man und es lohnt sich. Aber wenn jetzt Software unnötigerweise ihr eigenes Repository-Format statt einer einfachen Dateispeicherung verwendet, kann es schon schwieriger werden, die ganzen Daten im Griff zu behalten.

Das Problem ist also in der Praxis dort, wo es eine große Rolle spielt, häufig irgendwie gelöst. Trotzdem wäre es manchmal schön, wenn die Verzeichnisstruktur nicht wie ein Verzeichnisbaum aufgebaut wäre, sondern zumindst in manchen Teilbäumen wie ein dünn besetzter Hyperquader, wo man nach einer Reihe von Kriterien die passenden Dateien suchen und in einem temporären virtuellen Verzeichnisbaum zugänglich machen könnte. Diese Mehrfachindizierung war übrigens auch in Datenbanken vor etwa 30 Jahren eine Herausforderung, wenn die einzelnen Indizes für sich genommen nicht selektiv genug sind. Man hat wohl das Konzept des Z-Index (oder der Z-Kurve) entwickelt, womit eine Verflechtung von verschiedenen Indizes möglich ist, die für sich genommen nicht selektiv genug sind, um für einen bestimmten Indexwert nur noch eine so kleine Menge von Daten zurückzuliefern, daß eine erschöpfende Suche in diesen Daten unproblematisch wäre.

In der Systemadministration stellt sich diese Frage häufig. In der Linux- und Unix-Welt ist es üblich, größere Applikationen so zu installieren, daß etwa 4-6 Orte im Verzeichnissystem verwendet werden:

  • ausführbare Programme in /usr/bin oder /usr/local/bin oder /bin o.ä.
  • Bibliotheken und statische Hilfsdaten dazu in /usr/lib oder /usr/local/lib oder /opt. Zum Teil architekturunabhängige statische Hilfsdaten und Bibliothken auch in /usr/share. Oft ist die ganze Applikation unter /opt installiert und es gibt softlinks nach /usr/local/bin
  • Man-Seiten unter /usr/man, /usr/local/man, /opt/man o.ä.
  • Konfiguration unter /etc
  • Variable Daten (z.B. Tablespaces für Datenbanken) unter /var/lib, /var/opt o.ä.
  • logs unter /var/log

Das ist das, was sich eigentlich etabliert hat und wie die Software, die mit Linux-Distributionen mitkommt, üblicherweise installiert wird. Man hat so nicht die ganze Applikation zusammen in einem Verzeichnis, aber dafür hat man eine Trennung in statische und dynamische Daten und kann auf Servern viel gezielter Entscheidungen darüber treffen, welche Daten in welches Backup kommen, welche Raid-Konfiguration man verwendet, ob man die Daten lokal oder remote hält, ob man sie mit anderen Servern teilen kann und ob man SSDs einsetzt oder auch wer Schreib- und Leseberechtigungen hat. Diese Fragen wird man eher für alle Daten in /var/lib gleich beantworten als für alle Daten unter /tomcat.
So wird die zweitbeste Vorgehensweise, eben alles, was zu einer Applikation gehört, komplett in einem Unterverzeichnis zu halten, trotz ihrer offensichtlichen Reize, eher selten gewählt. Hier wäre so eine Matrixstruktur für das Dateisystem schön, man könnte also Zeilen für die Applikationen haben und Spalten für die Art der Daten (lib, bin, share, var, log, conf, man,…).

Share Button

Unicode, UTF-8, UTF-16, ISO-8859-1: Warum ist das so schwierig?

English

Seit etwa 20 Jahren schlagen wir uns mit der Umstellung auf Unicode herum.

Warum ist das so schwierig?

Das größte Problem ist, dass man Dateien nur sehr begrenzt ansieht, wie ihr Inhalt zu interpretieren ist. Wir haben letztlich ein paar Tricks, mit denen man es oft erkennen kann:
Die Endungen funktionieren für häufige und gut definierte Dateitypen, z.B. .jpg oder .png recht gut. In anderen Fällen wird der Inhalt der Datei untersucht und zum Beispiel am Anfang der Datei so etwas wie

#!/usr/bin/ruby

gefunden, woraus geschlossen werden kann, dass das mit ruby ausgeführt werden soll und zwar mit dem Ruby, das unter /usr/bin/ruby steht. Wenn man sich lieber nicht festlegen will und das Ruby haben will, das zuerst im Pfad ( $PATH ) kommt, dann kann man stattdessen

#!/usr/bin/env ruby

verwenden. Das geht leider unter MS-Windows nur unter cygwin, wenn man das cygwin-Ruby verwendet, nicht aber mit dem nativen Win32-Ruby (oder Win64-Ruby).

Nun kommt aber der nächste Schritt und der ist einfach ärerlich. Welches „encoding“ wird für diese Datei verwendet? Man kann sich auf UTF-8 oder ISO-8859-1 einigen, aber sobald einer im Team vergisst, seinen Editor entsprechend zu konfigurieren, ist Durcheinander abzusehen, weil dann Dateien entstehen, die UTF-8 und ISO-8859-1 (oder noch andere Encodings) miteinander mischen, was dann irgendwann zu obskuren Fehlern führt.

Es war ein großer Fehler, dass bei der Entwicklung von C, Unix und vor allem der libc ein Verständnis von Dateien definiert wurde, das keine Typ-Information für den Dateiinhalt erlaubt. Im Internet haben wir Mime-Header für EMail und WWW-Seiten und alles mögliche andere. Dadurch weiß der Empfänger der Kommunikation stets, wie die empfangen Daten zu interpretieren sind. Ich denke, dass Dateien solche Metainformationen haben sollte, die etwa dem Mime-Header entsprechen. Dann könnte man Dateien beliebig umbenennen, sogar die Endung, ohne dass die Datei dadurch unlesbar würde. Aber als Unix und C entwickelt wurde, wurde auch die libc und die Filesystemkonzepte definiert. Daran haben sich alle Unixe seither gehalten und auch Linux folgt diesen Vorgaben. Aber auch in der MS-Windows-Welt hat man die Betriebssysteme wahrscheinlich in C entwickelt und dabei diese Eigenschaften oder deren Fehlen geerbt. Ich weiß nicht, bis wann man versucht hat, MS-Windows-NT/2000/XP/Vista/7/8… noch auf FAT-Dateisystemen lauffähig zu halten, dabei hätte NTFS mit den multiplen Streams pro Datei eine Werkzeug geschaffen, mit dem man so einen Mime-Typ im zweiten Stream und den eigentlichen Inhalt im ersten Stream speichern könnte. Was aber fehlt ist ein allgemein anerkanntes Regelwerk, das die Nutzung des zweiten Streams für Typinformationen festlegt Aber man verwendet weiterhin Endungen, hofft auf gutes Glück bei Textdateien und analysiert magic-bytes innerhalb der Dateien, um den Typ der Datei und das Encoding zu raten.

Natürlich haben XML und HTML die Möglichkeit, das Encoding innerhalb der Datei zu definieren. Dummerweise muss man aber das Encoding der Datei schon kennen, um die Zeilen zu lesen, wo drinsteht, welches Encoding die Datei hat. Das ist nicht so schlimm, denn letztlich steht diese Information jeweils am Anfang der Datei und man kann ein paar Encodings durchprobieren, und jeweils unter dieser Annahme anfangen, die Datei zu lesen, bis man es richtig weiß.

Am gefährlichsten ist es, UTF-8 und ISO-8859-1 (oder ähnliche Encodings) zu verwechseln. Da die unteren 128 Zeichen bei beiden gleich sind und zumindest im deutschen Sprachraum doch die überwältigende Mehrheit von Text-Inhalten darstellen, sticht das Problem nicht gleich ins Auge, sondern schleicht sich eher ein, wenn man nicht sauber arbeitet und Dateien mit verschiedenen Encodings zusammenkopiert oder die Dateien den falschen Konversionen aussetzt. Nun werden aber die Umlaute in UTF-8 durch zwei Zeichen codiert, in ISO-8859-1 durch eines. Beim Lesen der Datei unter der falschen Annahme bekommt man also irgendwann mal Zeichenfolgen, die in dem Encoding eigentlich gar nicht vorkommen dürften. Bei UTF-16 ist das einfacher, weil die Dateien dort jeweils mit FFFE oder FEFF anfangen, so dass man einigermaßen sicher UTF-16 an sich und die Bytefolge (niedriges zuerst oder hohes zuerst) erkennen kann.

In der MS-Windows-Welt kommt noch als weiteres Ärgernis hinzu, dass zwar das ganze System mit modernen Encoding arbeiten kann, aber diese schwarzen CMD-Fenster kommen immer noch mit CP-850 oder CP-437 hoch, enthalten also in etwa dieselben Zeichen wie ISO-8859-1, aber an anderen Positionen. Da bekommt man dann schon einmal ein Sigma-Zeichen statt einem „ä“ zu sehen. Diese Incompatibilität innerhalb desselben Systems bringt natürlich Nachteile mit sich.

Share Button

Die kleinen Hürden der Interoperabilität

Heute hat sich in der IT-Landschaft vieles vereinheitlicht, so daß Interorabilität besser geworden ist als vor 20 Jahren.

Ein paar Beispiele:

  • Netzwerktechnologie: Heute hat sich TCP/IP als Netzwerktechnologie durchgesetzt. Sogar die Verkabelung mit RJ45/Ethernet und die Funknetze (WLAN) sind standardisiert und passen zwischen verschiedensten Geräten zusammen. Vor ein paar Jahren gab es beliebig viele proprietäre Netzwerktechnologiene, die nicht miteinander kompatible waren, z.B. BitNet (IBM), NetBios (MS), DecNet (DEC), IPX (Novell),….
  • Zeichensätze: Heute haben wir Unicode und ein paar standardisierte Zeichensätze und Codierungen und zumindest für Web und EMail Wege, diese Metainformation zur Verfügung zu stellen. Dieser Bereich ist noch nicht problemfrei, aber im Vergleich zu früheren Jahren, wo verschiedene EBCDIC-Codierungen regierten oder wo Zeichensätze üblich waren, die keine Umlaute enthielten, haben wir hier auch große Fortschritte in der Standardisierung erlebt.
  • Zahlen: Es hat sich für Fließkommazahlen und für Ganzzahlen eine gewisse, relativ kleine Menge von numerischen Typen etabliert, die immer wieder benutzt werden und die sich überall (fast) gleich verhalten. Problematisch bleibt der Integer-Überlauf.
  • Software: Früher hat man Software für eine spezifische Maschine entwickelt, also eine CPU-Architektur mit einem Betriebssystem. Heute hat man die Möglichkeit, einheitliche „Plattformen“ auf verschiedenester Hardware zu haben: Linux läuft auf fast jeder physikalischen und virtuellen Hardware vom Mobiltelefon bis zum Supercomputer und es ist praktisch derselbe Kernel, läßt sich also gleich nutzen. Java, Ruby, Perl, Scala und andere Programmiersprachen sind auf verschiedensten Plattformen vorhanden und bieten sozusagen ihre eigene abstrakte Plattform. Und das Web ist eine einfache und sinnvolle Möglichkeit, Applikationen für verschiedenste Geräte nur einmal zu entwickeln.
  • Dateisysteme: Es hat sich ein einigermaßen einheitliches Verständnis dafür, wie ein Dateisystem aussehen soll, entwickelt, mit einigen betriebssystemspezifischen Besonderheiten. Für Datenhaltung lassen sich Dateisysteme aber gemeinsam für verschiedene Betriebssyteme nutzen, zum Beispiel mit Samba.
  • GNU-Tools: Die GNU-Tools (bash, ls, cp, mv,……..) sind unter Linux zum Standard geworden und ihren traditionellen Unix-Pendents, wie man sie noch heute z.B. unter Solaris findet, haushoch überlegen. Man kann sie aber auf praktisch jedem Unix installieren und es gibt mit cygwin sogar eine Portierung für MS-Windows.

Interoperabilität ist heute für viele Interoperabilität zwischen Linux (oder anderen Posix-Systemen) und Win32/Win64 (MS-Windows).

Erfahrene Linux-Anwender sind es gewohnt, als Trennzeichen für Pfade diesen Schrägstrich „/“ (forward slash) zu verwenden. Der umgekehrte Schrägstrich „\“ wird benötigt, um Sonderzeichen zu „escapen“. In der MS-Windows-Welt sieht man häufig, daß der umgekehrte Schrägstrich „\“ (backslash) als Trennzeichen verwendet wird. Das ist nötig im CMD-Fenster, weil dieses den normalen Schrägstrich „/“ nicht durchläßt. Meine Erfahrung ist aber, daß die low-level-Win32-Bibliotheken beide Varianten verstehen. Sowieso werden die normalen Schrägstriche „/“ von cygwin, ruby, perl, java u.s.w. verstanden. Man kann sich also fast immer die Mühe sparen, hierfür Fallunterscheidungen zu machen, außer man schreibt cmd-Skripte. Und wer will sich das schon für mehr als fünf oder sechs Zeilen antun. Ich empfehle also für Java-, Perl- und Ruby-Entwickler auch unter MS-Windows ausdrücklich immer den normalen Schrägstrich „/“ als Trenungszeichen in Pfaden zu verwenden. Das ist lesbarer, schon weil man den umgekehrten Schrägstrich „\“ oft verdoppeln muß, und es erleichtert die Portablität auf Linux oder Posix.

Tückischer ist die Sache mit dem Zeilenwechsel. In der Linux- und Unix-Welt ist in Textdateien ein „Linefeed“ („\n“=Ctrl-J) als Zeilenwechsel üblich. In der MS-DOS und MS-Windows-Welt hat sich dagegen „Carrige-Return+Linefeed“ („\r\n“=Ctrl-M Ctrl-J) etabliert. Die meisten heutigen Programme stören sich nicht daran und kommen unter beiden Plattformen mit beidem klar. Wer unter MS-Windows Notepad verwendet, wird mit Linux-Zeilenenden keine Freude haben, aber Notepad muß man wirklich unter MS-Windows nicht benutzen, da es dort bessere Editoren (gvim, emacs, ultraedit, scite, …) gibt. Umgekehrt führt der MS-Windows-Zielenwechsel bei ausführbaren Skripten unter Linux zu Probleme. Skripte enthalten normalerweise in der ersten Zeile so etwas wie „#/usr/bin/ruby“. Das nimmt das Betriebssystem als Hinweis, daß man das Programm /usr/bin/ruby verwenden soll, um dieses Skript auszuführen. Wenn aber die Zeile mit Ctrl-M Ctrl-J endet, dann wird nach einem Programm „/usr/bin/ruby^M“ gesucht (^M = Ctrl-M = „\r“) gesucht, das es natürlich nicht gibt und man erhält eine unverständliche Fehlermeldung.

Ad hoc kann man die Umwandlung schnell so machen:

$ perl -i~ -p -e ’s/\r//g;‘ script

Oder für die Umgekehrte Richtung:

$ perl -i~ -p -e ’s/\n/\r\n/g;‘ textfile

Wer noch Subversion verwendet, sollte Skripte dort so einstellen, daß sie immer nur mit „LF“ als Zeichenwechsel gespeichert werden und Textdateien vielleicht jeweils mit der Konvention des Betriebsystems, unter dem der Client läuft.

Share Button

Apps oder HTML5

English

Die Idee mit den Apps für Mobiltelefone ist nicht sehr neu. Schon recht einfache Telefone konnten so etwas und man entwickelte die Apps oft mit Java ME, einem verkleinerten Java. Das ist vielleicht nicht die beste Lösung, aber hatte immerhin den Vorteil, daß man eine Entwicklung für eine Vielzahl von Mobiltelefonen machen konnte und nur beim Testen dann alle möglichen Geräte durchprobieren mußte.
Dann kam bei den Nokia-Smartphones Qt mit C++ als Basis für die Entwicklung von Apps auf. Das versprach immer noch geräteunabhängig zu sein, weil Qt OpenSource ist und auf verschiedene gängige Desktop-Betriebssysteme sowie Symbian und Maemo/Meego portiert worden ist. Wirklich verbreitet waren die Qt-Apps auf Symbian und Maemo/Meego. Heute wird Qt von Digia entwickelt und soll in Zukunft unter anderem auch für Android verfügbar sein.
Nun kamen mit der Verbreitung von Apple-iphone und Android neue Varianten auf, deren Apps man mit Dalvik schreiben soll. Microsoft versucht auch noch ein Mobiltelefon-OS zu verbreiten, das dessen Apps wieder anders, vielleicht mit C#, entwickelt werden sollen.
So stellt sich für App-Entwickler heute das Problem, daß man Apps mit einer bestimmten Funktionalität wirklich ca. 6-8 Mal komplett neu entwickeln muß, wenn man einen großen Teil der Anwender erreichen will. Für sehr wichtige Apps mag das schon eine vertretbare Investition sein, aber es stellt sich doch schnell die Frage, ob der Aufwand vertretbar ist. Außerdem wissen wir nicht genau, welche Systeme außer Android in ein paar Jahren verbreitet sein werden oder zumindest relevante Nischen besetzen. Vielleicht wird sich bei neuen Systemen zumindest eine Android-Kompatibilität durch eine angepaßte Dalvik-Umgebung für diese Systeme etablieren, aber sicher ist auch das nicht. Mit Web-Applikationen ist man aber schon ab dem ersten Tag auf dem neuen Smartphone, von dem man heute noch nichts weiß. Den Browser wird niemand weglassen wollen.

Die Idee, mit den Prozenten aus dem Verkauf von Apps über die jeweiligen App-Stores Geld zu verdienen war sicher vor ein paar Jahren mal Gold wert. Heute gibt es aber für viele Systeme eine riesige Vielfalt von Apps und wenn da noch eine dazustellt, ist es schon ungewöhnlich, noch auf so hohe Download-Zahlen zu kommen, daß die paar Cent pro Download alleine schon den Aufwand finanzieren könnten.
Bis vor gar nicht so langer Zeit hatten die Apps noch eine Existenzberechtigung alleine schon wegen der Möglichkeiten Client-seitig, also auf dem Mobiltelefon, bessere interaktive Funktionalität aufzubauen als dies mit HTML und einer Webapplikation möglich wäre.
Das hat sich aber inzwischen sehr relativiert. Mit HTML5, JavaScript, Ajax, Websockets und einigen anderen Neuerungen der klassischen Web-Applikations-Technologie kann man heute praktisch alles machen, was diese Apps konnten. Und man muß es nur einmal entwickeln. Ich gehe daher davon aus, daß sich diese Apps nur für einige wenige spezielle Anwendungen halten werden, die so bedeutend sind, daß die Mehrfachentwicklung nicht weh tut und die mehr Interaktion brauchen als mit Web-Applikationen üblich ist. Es wird immer schwieriger, solche Fälle zu finden. Was einem spontan einfällt:

  • Anwender soll für Verwendung der Funktionalität bezahlen. Das gibt es im Internet an viele Stellen. Die Bezahlmechanismen sind noch nicht optimal, aber weit verbreitet und etabliert, wenn es um Einkaufen im Web geht. Sogenannte „Paywalls“ für Bereiche einer Webseite oder -applikation, die nur zahlenden Kunden zugänglich sind, gibt es. Vorteil: Kein app-Store zieht seine Prozente ab.
  • Spiele sollten doch auch offline funktionieren, zum Beispiel im Ausland (solange Dataroaming teuer ist) oder im Tunnel. Das verspricht HTML5 mit dem lokalen Speicher („local storage“) aber zu lösen
  • Aussehen: Kann man mit HTML5 ziemlich beliebig schaffen.
  • Interaktivität: Mit JavaScript, Ajax und HTML5 kann man sehr gute Applikationen bauen.

Kurz gesagt, das Geschäft mit den App-Stores dürfte in ein paar Jahren zum Auslaufmodell werden oder als Nische für eine kleine Anzahl von Apps überleben.

Share Button

Datumsformate

English

Es kommt recht oft vor, dass man bei einer Software ein Datum eingeben oder ablesen muss, oft gepaart mit einer Uhrzeit. Das kann ja so etwas erfreuliches wie ein Geburtstag sein oder aber ein Termin, den man lieber vergessen würde, weil er sowieso mal wieder viel zu früh kommt.

Bei Datums- und Uhrzeitformaten in Softwareapplikationen sollte man zwischen der internen Darstellung und der angezeigten Darstellung unterscheiden.
Wenn nicht irgendwelche Altlasten dem entgegenstehen, sollte man für eine interne Darstellung unbedingt ISO 8601 beachten, wenn nicht eine rein numerische oder binäre Darstellung zur Anwendung kommt. Wenn dem Altlasten entgegenstehen, ist das ein guter Anlass, diese Altlasten zu entsorgen.

ISO 8601 ist dieses Datumsformat: <Jahr>-<Monat>-<Tag>, z.B. 2012-11-16 (Varianten: 20121116 121116 12-11-16). Ich benutze das schon seit 20 Jahren praktisch überall, auch in Papierform. Mir gefällt daran, dass man bei dieser Schreibweise sofort weiß, was das Jahr, der Monat und der Tag ist. Diese Reihenfolge ist konsequent, denn man schreibt ja bei Zahlen auch die größeren Tausender vor den Hundertern, also sollten die Jahre zuerst stehen. Vor allem entfällt die Frage, ob jetzt der Monat oder der Tag zuerst kommt, was ja bei einem Datum wie 06/07/08 nie ganz klar ist. Wenn man eine Datei sortiert, in der solche Datumsangaben am Anfang der Zeilen stehen, stimmt die Sortierung. Ein weiterer Vorteil ist, dass dieses Format international (und damit neutral) ist, also nicht ein bestimmtes Land bevorzugt, so dass es auf die Dauer universell verstanden und akzeptiert werden wird. Inzwischen hat wohl jeder dieses Datumsformat oft genug gesehen, um es zu verstehen, weil immer mehr Webseiten das verwenden. Die Schreibweisen ohne Bindestrich und mit zweistelliger Jahreszahl finde ich übrigens nicht so brauchbar, weil sie für menschliche Leser nicht so schnell als Datum erkennbar und zerlegbar sind.

Für die Darstellung gegenüber dem Benutzer kann man in guten Applikationen die Präferenzen des Benutzers berücksichtigen. Es gibt eine kleine Unstimmigkeit, weil seit einigen Jahren in der Schweiz, Deutschland und Österreich das ISO 8601-Format das offizielle Standardformat für die Schreibweise eines Datums geworden ist. Ja, darüber freue ich mich. Aber diese Konvention verbreitet sich erst langsam, so dass übliche Locale-Einstellungen an Rechnern meistens noch auf das eigentlich veraltete Format Tag.Monat.Jahr gehen, immerhin mit einer vierstelligen Jahreszahl. So wie auf Wochenmärkten noch lange Pfund verwendet wurde, obwohl das kg schon seit Jahrzehnten galt. Ich würde mir wünschen, daß man als Anwender die Wahl hat, welches Datumsformat Software verwendet, insbesondere sollte ISO 8601 immer als eine Möglichkeit zur Verfügung stehen. Im Prinzip gibt es die Mechanismen, aber sie sind in vielerlei Hinsicht unzulänglich implementiert:
– Es ist mühsam, die Datumseinstellung zu ändern.
– Die meiste Software ignoriert diese Locale-Einstellungen
– Ein großer Teil der Software verwendet fälschlicherweise lokalisierte Datumsformate auch intern, verträgt also nur eine bestimmt oder einige bestimmte Einstellungen.

Ich empfehle hier, Software mal mit Einstellung für weit entfernte Sprache wie z.B. „Usbekisch“, „Chinesisch“ oder „Arabisch“ zu testen, um solche Abhängigkeiten zu erkennen, selbst wenn vorerst (und für „alle Zeiten“) nur eine deutschsprachige und eine englischsprachige Version zum Einsatz kommt.

Für Datumseingaben hat sich bewährt, dass man einen kleinen Kalender einblenden kann und sich dort im richtigen Monat den richtigen Tag auswählen kann. Aber auch hier sollte für denjenigen, der weiß, was er oder sie will, die Eingabe des Datums als Zeichenkette ohne Wechsel zur Mausbedienung möglich sein. Und das ISO-8601-Format sollte dabei immer verstanden werden, gerne zusätzlich auch das Format der aktuellen Locale-Einstellung, also z.B…

Auf jeden Fall muß aber das Datum nach der Eingabe in ein kanonisches Format übersetzt werden, um sicherzustellen, dass 2012-11-16 und 16.11.2012 gleich sind.

Ein Vorschlag zu den Posix-, Unix- und GNU-Tools: Das Progamm „date“ ist seit Jahrzehnten in der Unix- und Linux-Welt etabliert und gibt leider ein Datum in einem obskuren US-Format aus. Ich glaube, daß man das nicht ändern kann, aber man sollte diesem Daten konsquent einen Begleiter „idate“ („international date“) geben, der ohne Parameter aufgerufen ein ISO-8601-Datumsformat verwendet, in diesem Fall zusammen mit der Zeit, also z.B.

$ idate
2012-11-16T17:33:12

Vielleicht schlage ich das den Entwicklern der core-Utils, zu denen die unter Linux übliche GNU-Variante von Date gehört, einmal vor. Immerhin versteht das GNU-date beim Setzen des Datum schon lange das ISO-Format. Bis dann kann man sich ganz gut behelfen, wenn man folgendes in die .bashrc einträgt:
export TIME_STYLE=long-iso
alias idate=’date „+%F %T“‚
Oder für tcsh in die .tcshrc:
setenv TIME_STYLE long-iso
alias idate ‚date „+%F %T“‚

Share Button