So bitte nicht – bad / worse practices – ein Kessel Buntes

Das die Welt nicht grau in grau ist (oder zumindest aktuell sehr zügig endlich der Frühling mit seiner Blüten und Farbenbracht Einzug hält), erfreut das Gemüt. Anders geartet ist da der Datenbank-Entwickler – wie jeder Informatiker ist er „kühl und dunkel“ zu lagern und zu halten, damit er optimal arbeitet.  Somit einher geht eine verstärkte Reaktion auf Restlicht (auch das des Monitors), allerdings messerscharf in schwarz/weiß oder zumindest in Graustufen. Spaß beiseite: „Ein Kessel Buntes“ ist eine finde ich recht treffende Umschreibung für das was landläufig oftmals als „Datenbank“ verkauft und verstanden wird. Leider wieder eine Praxis die auf Dauer nicht tragfähig ist.

Was ist der „Kessel Buntes“ und warum ist er keine gute Idee? – Generell bezeichne ich mit diesem Ausdruck nicht richtig getrennte und beschriebene Entitäten. Teilweise trifft das auch nicht richtig spezialisierte Entitäten. Immer wieder trifft man auf diese Art des Datenbank-Designs: Oftmals wird sie aus der Not heraus geboren, oder aus dem Missverständnis, dass eine Datenbank doch nur eine etwas bessere Excel-Tabelle sei. Eine Excel-Tabelle per se ist ja nicht einmal schlecht – sie bringt immerhin etwas Ordnung ins Chaos und ist für viele tagtägliche Anforderungen das flexible Werkzeug, wenn man mal eben eine Analyse machen muss, oder einfach nur eine „Kleinigkeit“ visualisieren soll. Eine Tabellenkalkulation ist hierzu sehr flexibel und bietet alle Möglichkeiten die man sich wünschen kann – von Layout bis hin zur Berechnung – nichts ist beschränkt. Genau diese Flexibilität ist es jedoch die bei größeren Projekten schnell vom Vorteil zum Hindernis werden kann. Mit der Flexibilität einer Tabellenkalkulation kann man sich oftmals die doch eher lästige tiefgehende Analyse eines Sachverhaltes für eine Datenbank sparen. Problematisch wird es, wenn Tabellenkalkulationen dann zum Allheilmittel erkoren werden. Ehe man es sich versieht werden da komplexe Matrizen aufgestellt, die dem menschlichen Benutzer die Information schön handlich aufbereiten. Nur die Maschinenlesbarkeit ist dann nicht mehr unbedingt gegeben, und selbst einfach Analysen im Datenbestand arten zur Sisyphus-Arbeit aus, vor allem wenn die Flexibilität voll genutzt wird und jede Matrix ein klein wenig anders aussieht.

Besonders ärgerlich aus Datensicht ist hierbei die Verquickung von Äpfeln und Birnen zu Obstsalat. Ich selbst durfte hierzu ein sehr schönes Beispiel einer gewachsenen Datenbank erleben: In einem Unternehmen gibt es verschiedene Aufträge, mit unterschiedlichen Qualitäten und Eigenschaften. So gibt es Aufträge die intern erzeugt werden und nur innerhalb von Abteilungen verrechnet werden, wenn überhaupt, zudem gibt es Aufträge, welche mit externen Elementen (auch als Kunden bezeichnet) abgewickelt werden. Nun war der Entwickler etwas faul oder es hat sich erst im Laufe der Zeit ergeben: Für die beiden Typen sind unterschiedliche zusätzliche Informationen notwendig. Initialer Weg um Zeit und Arbeit zu sparen: „Es ist ja nicht viel was da dazu kommt, wir fügen einfach Spalten an“. Recht zügig kann man in einer Datenbank der Einsteigerklasse (die sich tatsächlich auch noch als Datenbank bezeichnet) solche Änderungen realisieren. Die Rede ist hier von einem recht bekannten Produkt aus dem Hause „Winzig-Weich“. Problematisch ist bei diesem Produkt schon die Tatsache, dass Datenhaltung und Repräsentation scheinbar nahtlos ineinander übergehen. Für Anfänger ohne große Vorkenntnisse senkt das die Hemmschwelle doch ganz erheblich. Auch das ist ja für sich genommen eine löbliche Sache, nur auch dieses Produkt hat einen Einsatzbereich (der ist zugegebener Maßen recht breit) – wenn man über diesen hinaus wächst (und viele Projekte haben die Tendenz dazu), merkt man irgendwann recht heftig, wo es zwickt und kneift.

Nun haben wir eine aufgebohrte Datenbank-Tabelle – etwas, dass man mit ein klein wenig Aufwand auch in anderen Datenbanksystemen machen kann. Aus Erfahrung weiß ich nur zu gut, dass es immer wieder Fälle gibt, in denen man sich aus gutem Grund dafür entscheidet eine Spalte „Overhead“ zu spendieren, die nicht immer gefüllt wird, oder sogar nur in wenigen Fällen einen von NULL unterschiedlichen Wert hat. Man hat zwar dabei ggf. ein leichtes Bauchgrimmen, aber es gibt durchaus Szenarien in denen es weniger auf die Performance im Speicherverbrauch oder die absolute Performance ankommt, es aber mit den zusätzlichen Spalten recht schnell greifbare und brauchbare Ergebnisse gibt.

Das Ganze kann man jetzt noch weiter auf die Spitze treiben, in verschiedenen, nicht gegenseitig-exklusiven Geschmacksrichtungen (oder vielleicht doch besser Geschmacksverirrungen):

Man nehme einen weiteren Auftragstyp dazu, weil das aktuelle Projekt es erfordert: Da man in der Tabellen-Ansicht ja jetzt Felder hat die unbelegt sind und man die spezifischen Daten des neuen Typs ja auch noch speichern muss, fängt man kurzerhand an zu Tricksen und zu sparen: Bestehende Felder werden je nach Auftragstyp umgewidmet. Je nachdem was für einen Auftrag man gerade hat, bekommen die Felder jetzt eine Abhängigkeit, eine Semantik. Das macht die Arbeit bei den Masken recht einfach, auch eine tabellarische Übersicht ist kein Problem  – man muss nur wissen wie die einzelnen Felder jetzt zu interpretieren sind. Besonders spaßig ist dann natürlich die Verwendung falscher Datentypen, weil es halt doch nicht mehr so recht gepasst hat: Man kann auch ein varchar-Feld dazu verwenden um Datumsangaben oder Integerwerte zu speichern. Typecast gemäß Semantik und die Sache ist geritzt…

Die Performance und Wartbarkeit dieses Konstruktes kann sich der geneigte Leser dann mal selbst überlegen – vom Wechsel des Datenbank-Unterbaus hin zu einem professionellen Server mit ggf. sehr scharfer referenzieller Integrität wollen wir lieber einmal gar nicht träumen, diese wird dann oftmals auch einfach „geopfert“.

Zweite besonders zu empfehlende Möglichkeit die Performance noch weiter zu minimieren und dem ganzen ein unbeschreibliches „Geschmäckle“ zu verpassen: Die Unterscheidung der Typen ist nicht eindeutig oder klar umrissen, sondern kann womöglich sich zur Laufzeit noch ändern. Viel Spaß schon einmal beim Umsortieren und uminterpretieren der oben missbrauchten/umgewidmenten Felder. Auch Typecast-Mortale genannt (nicht unmöglich und bei heutiger Rechenpower fällt es nicht mal so sehr auf, zumindest für kleinere Datenmengen). Damit die Änderung leicht fällt bzw. weil man sich diesmal um die Felder und die notwendigen Anpassungen des semantischen Codes drücken will (wir erinnern uns: Das ist so sonderlich gut wartbar), macht man es wie in der Realität so häufig auch: Man verwendet „sprechende Schlüssel bzw. sprechende Identifikatoren“. Man kennt diese zur Genüge au vielen Bereichen – so lange der Benutzername beschränkt war auf 8 Zeichen, hat man einfach den ersten Buchstaben des Vornamens plus die 7 ersten des Nachnamens genommen. Wenn es doch mal zu Überscheidungen kommt, gab es eben fortlaufende Endziffern. Nicht schön aber es funktioniert. Ähnliches kann man teilweise bei Dokumenten aus Buchhaltungs-Systemen beobachten: Die ersten Zeichen definieren den Typus des Dokuments, die weiteren sind ggf. noch an das Datum gekoppelt oder gleich einfach fortlaufend. Gängig sind Angaben wie „ANG-xyz“ für Angebot Nr. xyz odr der LS-4711 für den Lieferschein mit der Nummer 4711. Weitere Beispiele kann man sich leicht vorstellen.

Die Performance wird allerdings besonders grottig, wenn man diese Typ-Information aus bestimmten Gründen nicht in einer separaten und indizierten Spalte (sehr einfach und dennoch effektiv sind z.B. Enumerations sofern die Datenbank mit dieser „Mini-Foreign-Key-Lösung“ umgehen kann) sondern einfach die gesamte Nummer in ein Varchar-Feld packt. Wenn man nun nach unterschiedlichen Typen filtern möchte, muss man doch nur die ersten Zeichen betrachten (vorzugsweise noch unterschiedliche Längen wie etwa: ANG und LS von oben, zusammen mit ANS für Kostenvoranschläge…). Mit dieser Technik bekommt man jede Datenbankengine ins Trudeln. Anti-Performance ist at its best …

Nun gut, genug gemault und Augen verdreht – woher der Ausdruck „Kessel Buntes“ kommt dürfte nun jedem klar sein: Man hat verschiedenste Obst (und ggf. auch Gemüse)-Sorten (im Datenbank-Bereich auch Entitäten genannt) in einer Tabelle zusammengeführt und über die Zeitachse das ganze gut durchgerührt und etwas ziehen lassen … Zeit dafür Lösungen zu präsentieren wie man es besser macht.

Oberstes Gebot bei der Modellierung bzw. dem Abbild der Realität: Entitäten trennen, wie Eiweiß und Eigelb. Beides gehört zwar zur Entität „Ei“ aber die Eigenschaften unterscheiden sich schon von der Farbe und dem weiteren Verwendungszweck beim Backen 😉 Daher: Wenn sich zeigt, dass eine weitere, vielleicht auf den ersten Blick sehr ähnliche Entität hinzugenommen werden soll, sehr sehr kritisch prüfen ob man diese unbedingt in das bestehende Schema „pressen“ muss. Im ersten Moment mag es zwar mehr Arbeit sein separate Entitäten zu verwalten, aber die Erfahrung zeigt: Jedes Datenbankschema hat auf die mittlere bis lange Frist die Tendenz sich weiter auszudifferenzen und detaillierter zu werden. Also besser gleich von Anfang an verschiedene Tabellen verwenden (ich werde auch noch einen ausführlichen Beitrag zum Thema „one true lookup table – OTLT“  verfassen) – diese im Zweifel per UNION erst einmal wieder zusammen zu führen (was nicht immer vermeidbar ist, oder zumindest für einen Teil der Daten sinnvoll sein kann) ist der bessere Weg.

Im letzten Absatz ist es schon angeklungen, ein Problem das man häufiger hat: „Aber die Dinger aus der Realität sind doch zu 80% ident …“ – in der objektorientierten Programmierung ist das ein klarer Fall für die Verwendung von Vererbung ggf. in Kombination mit abstrakten Klassen. Die übergeordnete Klasse stellt die gemeinsame Basis samt Funktionen bereit, und die spezialisierten Klassen kümmern sich um die 20 verblieben Prozent der Details. In einer relationalen Datenbank klappt dieser Ansatz nicht direkt. Hier muss man auf die Kombination von Geschäftslogik und einzelnen Tabellen zurück greifen: In der Geschäftslogik verwendet man den objektorientierten Ansatz wie gerade beschrieben, in der Datenbank führt man Surrogate ein, die es erlauben vom Kleinen auf das Größere zu schließen – dabei muss man ggf. aufpassen, dass keine Doppeldeutigkeiten entstehen (teilweise sind diese jedoch auch wünschenswert, das muss man situativ entscheiden) gibt. Auch bekannt ist das Konzept unter dem Namen „Vererbung für Arme“. So bekommt man zwar auch ein wenig Overhead, aber die Struktur bleibt klar erkennbar und man braucht nicht erst noch eine Tabelle die einem sagt, wie jetzt welcher Wert zu interpretieren ist.

Was auf keinen Fall eine Option sein darf, ist die Integration von Typinformationen in ein anderes Feld – diese Information muss man wo immer möglich in separate Felder auslagern, die man im besten Fall noch mit einer Referenz (Fremdschlüssel) auf eine andere Tabelle mit entsprechenden Meta-Informationen absichert. Sonst passiert es leicht, dass der Benutzer (aus Schusseligkeit oder gar mit Intention) einen neuen Typ einführt der gar nicht definiert ist (z.B. ein Tippfehler der Form „AND“ anstelle „ANS“) – welche Semantik dann greift bzw. welch kuriose Fehlinterpretationen und Fehlermeldungen dann auftreten können liegt im Bereich der Spekulation und der Admin-Belustigung. Über die notwendigen Operationen der String-Extraktion denkt man in diesem Fall auch besser nicht nach, geschweige denn daran wie häufig diese Operation angewandt werden muss…

Fazit: Es mag verlockend sein, eine Datenbank möglichst flexibel und „platzsparend“ zu gestalten, wie man es auch in einer Tabellenkalkulation machen würde. Aber die gewonnene Sicherheit ist absolut trügerisch und der Performance und Wartbarkeit tut man sich mit einem Kessel Buntes mit absoluter Sicherheit keinen Gefallen. Besser gleich überlegen ob das wirklich notwendig und sinnvoll ist, so klein das Problem aktuell auch sein mag – die Wahrscheinlichkeit, dass man irgendwann einen großen Scherbenhaufen hat ist erheblich vergräßert und dann ist nichts gewonnen, aber viel verloren.

Update-Erfahrungen DELL Streak

Nun habe ich mein geschätztes DELL Streak als Smartphone ja schon eine ganze Weile … liebevoll auch Backstein, Army oder „back to the roots-phone“ genannt. Immerhin ist das Ding nicht gerade ein Leichtgewicht, aber es hat schon seit Beginn einen schönen großen Bildschirm. Anfänglich war das etwas arg groß, aber im Vergleich zu den aktuellen Geräten braucht es sich nun nicht mehr zu verstecken – auch die Geräte von Samsung sind ja deutlich größer geworden (Websites im Miniformat lassen sich nunmal schlecht lesen).

Einziger Wermutstropfen: Es gibt keine offiziellen Updates mehr für das Gerät und die Bedienung des alten Androids 2.2.2 war doch reichlich hakelig, von diversen unmotivierten Abstürzen in der letzten Zeit einmal ganz zu schweigen. Ein neues Gerät wäre eine Lösung, zumal es ja mehr Leistung bieten würde…. auf der anderen Seite: Warum ein neues Gerät wenn ich für das bestehende doch die ganze Infrastruktur samt Ladekabel und Fahrzeug-Halterung habe …

Schon länger steckte mir ja die Idee in den Fingern das Ding software-mäßig aufzubohren – also ein Jailbreak oder ein Rooting zu machen. Nun habe ich mir endlich einmal die Zeit genommen. Das Ergebnis ist noch nicht ganz das was ich erwartet habe – immerhin war die alte Version schön deutsch und ich hatte mich an diverse Dinge gewöhnt.

Mit ein wenig Geduld bekommt man über ein Recovery-Image der Version 350 (so etwas wie ein Live-Linux nur für Android, das aber fest auf das Gerät geflasht wird) auch die Möglichkeit das letzte offizielle Update von DELL zu installieren. Soweit zumindest die Theorie – in der Praxis sind die Ergebnisse interessanter: Das Update wurde für den Koreanischen Markt (passenden zu den aktuellen politischen Spannungen dort …) vor etwas mehr als einem Jahr veröffentlicht … Leider ohne Support für die Deutsche Sprache und mit der Installation komplett in Koreanisch! Mit ein wenig Mühen bekommt man es dann auch wieder zumindest auf Englisch – da finde ich mich dann ohne Probleme zurecht …

Für alle die wie ich immer ein wenig Scheu vor den etwas technischen Beschreibungen in den diversen Foren haben: Wenn man sich einmal ein wenig mit dem Ablauf auseinander gesetzt hat ist alles halb so wild: Auf dem Telefon befinden sich mehrere „Betriebssysteme“, ein wenig ist das vergleichbar mit den unterschiedlichen Kerneln die man unter Linux schon beim Start auswählen kann – wer wie ich noch Kernel selbst kompiliert hat, der weiß was ich meine – nur hatte man beim Rechner etwas mehr Eingriffsmöglichkeiten. Zusätzlich zum „produktiven“ System gibt es noch ein Recovery-System das auf einer separaten Partition vor sich hinschlummert – das braucht zwar Platz, aber Speicherplatz kostet heute ja fast nichts mehr und so ein Rettungsanker macht die Sache in vielen Fällen doch etwas leichter.

Leider sind diese Recovery-Systeme oftmals vom Hersteller vorgegeben und wehren sich auch gerne mal dagegen, dass der Benutzer damit Schindluder treibt. Bei einem Rechner würde man jetzt einfach einen USB-Stick mit alternativem Image verwenden, oder eine andere CD zum Booten (etwa ein PartedMagic oder ein Knoppix) einlegen. Beim Smartphone klappt das nicht … Aber dafür gibt es andere Wege und USB ist auch hier der Schlüssel. Über das Fastboot-Protokoll und dem entsprechenden Tool (gibt es für Windows und für Linux) kann man das Recovery-System von extern ersetzen. Je nachdem welches Recovery-System man installiert, stehen einem unterschiedliche weitere Möglichkeiten offen – bei den Herstellern ist man meist eingeengt, dafür gibt es zumindest während der Garantie auch entsprechend Support. Mit alternativen Revocery-Images lassen sich aber auch ältere Geräte auf Stand bringen.

Die wichtigsten Infos gibt es gesammelt im sehr aktiven xda-devolpers-Forum bzw. deren Wiki. Unter anderem gibt es eine sehr brauchbare Anleitung zum Flashen und den damit verbundenen Startmodi, Angaben zur DELL-spezifischen  Versionierung (ein Kessel Buntes: Für jede Region und für jeden Anbieter gibt es verschiedene modifizierte Systeme, auch Branding genannt – nur ärgerlich, dass man irgendwann keine Updates mehr erhält) und natürlich eine Liste mit offiziellen und inoffiziellen (community-basierten) Versionen.

Nun war ich ja schon mal den Weg des Updates gegangen – und hatte dabei die Klippe mit den koreanischen Zeichen erwischt (man lernt manche Dinge nur auf die harte Tour) – aber so richtig wollte da keine Freude an dem neuen System aufkommen – immerhin war es ja auch schon wieder etwas älter und hatte auch noch ein koreanisches Branding (was unter anderem im App-Store mit deutschen Apps wie Tagesschau.de ein wenig Hindernisse aufwirft). Außerdem waren einige Funktionen verschütt gegangen, etwa die Konfigurierbarkeit des Launchers (DELL Stage) – sicherlich hätte man sich daran gewöhnen können oder irgendwo in den Tiefen des Systems wohl auch die Möglichkeit zur Einstellung gefunden.

Aber mit dem ohnehin angefertigten Backup lag natürlich noch eine andere Option auf der Hand – nachdem es von DELL ohnehin keinen Support mehr geben wird, könnte man ja auch mal nach weitergehenden Alternativen suchen und vielleicht einmal zur aktuellen Generation von Android aufschließen. Der Weg zurück zum Ursprung war ja keineswegs verbaut – vielleicht ein wenig Arbeit, aber im Zweifel hätte man einfach die alte Recovery-Version wieder einspielen können und dann das System wieder in den Ausgangszustand zurück bekommen können.

Also nicht lange fackeln, wenn man schon mal dabei ist. Also habe ich mir gleich mal die aktuelle Entwicklung „Longhorn“ angeschaut. Mit der gewonnen Routine war das Installieren dann bei weitem nicht mehr so aufregend wie das Aufspielen der koreanischen Version, wenn man mal verstanden hat was da grob abläuft, und wo man hinpacken muss ist mir zumindest gleich mal viel wohler. Ausgangspunkt war für mich das Recovery-Image „Streakdroid“ (ganz unten in der Liste). Damit lassen sich noch mal sicherheitshalber Backups anstoßen, bevor man mit dieser Anleitung weiter macht.

Das dauert eine gefühlte Ewigkeit und zwischenzeitlich dachte ich schon ich hätte wohl eine etwas längere Nachtschicht vor mir um wieder ein funktionsfähiges Telefon zu bekommen. Aber Geduld zahlt sich aus, am Ende startet das Gerät doch durch und zeigt den Startbildschirm an. Das wäre mal geschafft. Etwas lästiger ist das Rückspielen der ganzen persönlichen Einstellungen. Praktischerweise funktioniert das mitgelieferte (und vorher natürlich anzuwendende) Backup-Tool von DELL in Kooperation mit Nero auch auf dem modifizierten Gerät. Damit lassen sich unter anderem die Kontakte, SMS-Nachrichten, Hintergrundbilder und einiges mehr nach der notwendigen Totalbereinigung wieder zügig auf das Gerät schaffen. Sowas lob ich mir echt. Mühsam ist hingegen die Installation der verschiedenen Apps diese muss man einzeln wieder anstoßen (ein wenig fühle ich mich wie früher in den Sommerferien, als ich regelmäßig meinen Rechner frisch aufgesetzt habe – genauso wie damals fliegen hier einige Apps aus der Sammlung raus, die ich ohnehin nicht mehr benötigt habe – Frühjahrsputz nennt man das).

Bis jetzt bin ich echt super zufrieden mit der Leistung der modifizierten Software, der HOLO-Launcher gefällt mir mit seinen Einstellmöglichkeiten richtig gut. Ein paar Sachen wie etwa das „Start-Menü“ für wichtige Funktionen des Handys (Kontakte, SMS, AppSammlung/Menü) weiß ich schon jetzt echt zu schätzen – da kann DELL Stage einfach nicht mithalten. Man muss aber auch zu Gute halten, dass mittlerweile einige Jahre Entwicklung im Smartphonebereich ins Land gegangen sind. Jetzt heißt es einfach abwarten wie sich das Gerät im täglichen Leben schlägt. Es war zwar Aufwand und ein wenig Überwindung gefragt um in das Neuland vorzustoßen, aber es gefällt mir deutlich besser als nur wegen einer Software ein neues Gerät zu kaufen.