Externe Datenbanken – Speicherfresser oder Serversparmaßnahme?

02. August 2010 - Kategorie: Computer, Programmiersprachen, Programmierung, Publikationen - Keine Kommentare » -

Vor kurzem habe ich in zwei Foren Verweise auf mehrere Anbieter sogenannter “externer Datenbanken” gefunden, zumeist kostenlose. In diesem Artikel möchte ich nun die Pro- und Kontra-Argumente für/gegen solche Datenbankdienste aus meiner Sicht erörtern.

Warum nutzt man Dienste bei denen man direkt mit einem externen Datenbankserver kommuniziert?
Spontan fällt mir bei Hobbyprojekten eigentlich nur Faulheit des Programmierers ein. Bei kommerziellen Projekten könnten noch Performance-Aspekte hinzukommen, wenn tausende Datensätze gleichzeitig verarbeitet werden müssten, hierzu jedoch später mehr. Im folgenden werde ich mich jedoch v.a. auf den Hobbyentwicklerbereich beziehen, da dieser Artikel an erster Stelle für diese Zielgruppe gedacht ist.

Was spricht gegen die Nutzung von externen Datenbanken in der Desktop-Programmierung?
Bei der Desktopprogrammierung würde eine externe Datenbank ein Sicherheitsrisiko darstellen, da man die Zugangsdaten zum MySQL-Server entweder durch Tools wie .NET Reflector, durch Netzwerksniffer oder durch einfaches Reverse Engineering herausgefunden werden könnten. Die meisten Anbieter bieten nun nicht einmal die Möglichkeit die Rechte der einzelnen Accounts zu verändern und selbst wenn sie es bieten, nur die erfahrensten Hobbyentwickler machen davon Gebrauch. Sobald man jedoch die Zugangsdaten herausgefunden hätte wäre es möglich, selbst Queries zu schreiben, welche an den DB-Server direkt, d.h. ohne vorherige Überprüfung z.B. durch ein Skript, welches den Zugriff regelt, gesendet werden und dort ausgeführt werden. Nun könnten beliebige Datensätze angelegt, manipuliert und gelöscht werden. Die meisten Programmierer kommen erst zuletzt auf den Gedanken, dass jemand direkten Datenbankzugriff haben könnte. Jedoch nützt die beste Eingabeprüfung nichts, wenn eine solche Hintertür zum Datenbanksystem besteht.

Was spricht gegen die Nutzung von externen Datenbanken in der Web-Programmierung?
Bei (fast) allen Webhosting-Packeten sowie bei allen (V-)Server (falls MySQL installiert ist) ist es ohne großen Aufwand möglich eine MySQL-Datenbank aufzusetzen, welche entweder direkt auf der selben Maschine wie der Apache2 liegt oder aber zumindestens im (Hochgeschwindigkeits)Netzwerk des Anbieters.Würde man nun anstelle einer solchen “internen” Datenbank eine externe nutzen, so würde jeder PHP-Request, der eine Datenbankverbindung benötigt aufgrund der Netzwerklatenz wesentlich länger benötigen und desweiteren würde er Traffic erzeugen, was bei datenbanklastigen Applikationen sehr schnell dazu führen würde, dass der Trafficverbrauch pro Request ~2x so groß ist wie bisher.

Was spricht für die Nutzung von externen Datenbankservern?
In meinen Augen das einzige Pro-Argument für die Nutzung externer Datenbankserver ist der Grundgedanke des Cloud Computing. Bei komplexen Datenabfragen und großen Datenmengen, welche anschließend relativ kleine Datenmengen zurückliefern, kann die Nutzung eines externen Dienstes durchaus Vorteile haben. Vor allem wenn der Provider wirklich auf Cloud-/Cluster-Technologien setzt, und die Nutzung in kleineren Intervallen (maximal stündlich) abrechnet, kann dies bei Diensten die mit spontanen Leistungsspitzen zu kämpfen haben, einiges an Geld sparen.

Zusammenfassung
Nur bei großen, gut geplanten, kommerziellen Projekten kann der Einsatz von Outsourcing im Datenbankbereich bei Leistungsspitzen sinnvoll sein. Normalerweise ist man, nicht zuletzt aus Datenschutz- und Performance-Gründen, gut damit beraten, seine Datenbankserver selbst zu hosten.

Coding Guidlines – 10 Vorschläge und einige Zweifel

21. Juli 2010 - Kategorie: Computer, Programmiersprachen, Programmierung, Publikationen - 3 Kommentare » -

In letzter Zeit habe ich mehrfach bei verschiedenen kleineren Projekten, v.a. im PHP-Bereich gelesen, dass sogenannte “Coding Guidlines” entworfen bzw. einfach festgesetzt werden. Ob diese nun jedoch in der Praxis wirklich umsetzbar bzw. sinnvoll sind, darüber machen sich nur die wenigsten Gedanken und wundern sich, warum die anderen Entwickler meckern oder warum sie selbst Probleme bei der Einhaltung haben.

Grundsätzlich lässt sich jedoch sagen, dass Coding Guidlines, d.h. Abmachungen über den für das Projekt einzuhaltenden Programmierstil, äußert sinnvoll sind, da es ja durchaus zu Problemen führen kann, wenn jeder nach seinem Stil arbeitet und nun zwei Personen nacheinander (oder noch schlimmer: nebeneinander) an der gleichen Datei arbeiten sollen.

Auch lassen sich durch einen durchdachten Programmierstil einige Fehler vermeiden, welche jedoch syntaktisch korrekt sind und deswegen nur äußerst schwer zu finden sind. Bei kommerziellen Projekten kann ein solcher Fehler viel Geld kosten!

1. Klammern bei Kontrollstrukturen
Bei vielen Programmiersprachen gibt es die Möglichkeit, z.B. bei if-Anweisungen, welche lediglich einen einzigen Befehl enthalten würden, die Klammern wegzulassen.

if ($user->isAdmin) doSomeAdminThings();

Dieser Code ist syntaktisch korrekt und arbeitet auch so, wie es erwartet wird. Wenn Adminrechte verfügbar sind, dann wird die Funktion doSomeAdminThings() ausgeführt. Wenn wir nun jedoch nach einiger Zeit eine weitere Funktion einfügen, so kann dies zu unersichtlichen Fehlfunktionen führen.

if ($user->isAdmin) doSomeAdminThings(); doSomeAdminWork();

Beim Überfliegen des Quellcodes wird dieser Fehler nur von den wenigsten bemerkt. Jeder erwartet, dass sowohl doSomeAdminThings() als auch doSomeAdminWork() lediglich ausgeführt werden, wenn der Benutzer Administrator ist. Doch kann man nun feststellen, dass die Funktion doSomeAdminWork() immer ausgeführt wird, egal ob der User Admin ist oder nicht. Grund hierfür ist, dass lediglich ein Befehl von der If-Bedingung ohne Klammern umschlossen wird.

if ($user->isAdmin) 
{
       doSomeAdminThings(); 
       doSomeAdminWork();
}

Forderung: Um Probleme im Programmfluss durch fehlerhafte Programmierung zu vermeiden sollten alle Kontrollstrukturen immer mit Klammern versehen werden.

2. Kommentare im Quellcode
Wenn es um das Kommentieren von Quellcode geht, dann scheiden sich die Geister. Manche Projekte fordern, dass alles bis ins letzte Detail beschrieben wird, andere lehnen jegliche Kommentare strikt ab und fordern, dass alles einfach klar ersichtlich sein muss.
Als erstes zum Thema “bis ins letzte Detail” mit Kommentaren versehen.

// Addition von a und b
$c = $a + $b;
// Ausgabe der Summe von $a und $b, repräsentiert durch die Variable $c
echo $c;

Ich denke jedem wird bereits beim ersten Betrachten klar, dass hier eindeutig übertrieben wurde, da hier eindeutig ohne Probleme erkannt werden kann was passiert.

...
for ($i=count($itemsOfVar) - count($itemsOfOthers); $i<count(base::getObj('objects')->userCounter); $i = $i * 2)
...

Eine solche Quellcode-Zeile, welche den Programmierer auf den ersten Blick mit Informationen erschlägt, sollte unbedingt kommentiert werden. Wenn jemand Fremdes diesen Code sieht, so wird er nur mit einem größeren Zeitaufwand erschließen können, was genau geschieht.

Forderung: Beim Kommentieren sollte der gesunde Menschenverstand genutzt werden. Es sollte nicht übertrieben werden, jedoch kann man grundsätzlich sagen, dass eine Kommentarzeile zu viel nicht so sclimm ist, wie eine Kommentarzeile zu wendig!

3. Type-Hints verwenden
In vielen Foren höre ich oft den Kommentar “Ich weiß schon was ich wann und warum meinen Funktionen übergebe” wenn ich zu bedenken gebe, dass in Klassen keine Type-Hints verwendet worden sind. Die meisten sehen Type-Hints als etwas an, dass man lediglich dazu benutzt, um anderen Programmierern eine Hilfestellung zu geben, man selbst habe das anscheinend nicht nötig.

public function addDatabase(abstractDatabaseObject $dbObj) { ... }

Nun können an die Funktion addDatabase nur noch Objekte von Klassen übergeben werden, die von abstractDatabaseObject erben, es ist also sichergestellt, dass es sich um ein DatabaseObject handelt. Natürlich könnte man nun auch innerhalb der Funktion mit if-Abfragen usw. überprüfen ob es sich wirklich um ein solches handelt, der Aufwand wäre jedoch im Vergleich gigantisch. Auch sind Type-Hints sehr nützlich wenn man eine IDE wie etwa NetBeans einsetzt, da nun die Quellcode-Vervollständigung erkennt, von welchem Type eine Variable ist.

Forderung: Type-Hints müssen bei allen Funktionen verpflichtend eingesetzt werden!

4. Verwendung von PHP-Tags
Viele PHP-Programmierer, v.a. Hobbyentwickler, neigen aus Faulheit dazu, lediglich mit Auch bei End-Tags bei Dateien, die lediglich Klassen enthalten gibt es verschiedene Meinungen, notwendig sind diese nähmlich nicht, möglich jedoch schon. Um zu Verhindern, dass eventuelle Leerzeichen o.ä. außerhalb des PHP-Codes ausgegeben werden, empfiehlt es sich bei Klassen, den End-Tag nicht zu nutzen. Grundsätzlich muss aber natürlich immer ein End-Tag verwendet werden, wenn PHP in einer gemischten Umgebung verwendet wird.

Forderung: PHP-Skripte werden immer mit <?php begonnen. Bei Dateien die lediglich Klassen enthalten wird kein abschließender PHP-Tag verwendet.

5. Nomenklatur von Variablen
Innerhalb eines Skripts ist es einer Variable grundsätzlich nicht anzusehen, von welchem Typ sie ist. Auch gibt es bei verschiedenen Programmierern verschiedene Schreibweisen, wie etwa $eineKleineKlasse oder $eine_kleine_klasse. Um ein übersichtliches Skript zu erhalten, sollte hier unbedingt einheitlich gearbeitet werden. Auch Konstante sollten klar als solche erkennbar sein.

Forderung: Temporäre Variablen werden durchgehend klein geschrieben, mehrere Wörter werden mit Unterstrichen getrennt. Klassenvariablen werden beginnen mit einem Kleinbuchstaben wenn sie Private oder Protected sind, ansonsten mit einem Großbuchstaben, mehrere Wörter werden durch Großbuchstaben getrennt. Konstante werden durchgehend groß geschrieben.

6. Getter und Setter
Aus anderen Programmiersprachen wie etwa C# ist das Konzept von Getter und Setter bekannt, welches die beiden Aktionen “Inhalt abrufen” und “Inhalt zuweisen” als Funktionen für eine Eigenschaft einer Klasse vorgibt. Auch in PHP ist diese Funktion sehr sinnvoll, da z.B. durch das fehlen einer Setter-Methode eine Information als Read-Only gekennzeichnet werden kann und zusätzliche Aktionen möglich sind, z.B. das Speichern in der Datenbank beim Setter.

Das folgende Beispiel soll den Nutzen dieser Methode verdeutlichen:

class flugzeug
{
        protected $flugzeugName;
        protected $pilotName;
 
        public function getFlugzeugName()
        {
              return $this->flugzeugName;
        }
 
        public function getPilotName()
        {
              return $this->pilotName;
        }
 
        public function setPilotName($name)
        {
              $this->pilotName = $name;
        }
}

Während der Pilot eines Flugzeuges theoretisch jederzeit wechseln kann (=> Getter und Setter), wird der Name eines Flugzeuges nicht geändert (=> Getter, jedoch kein Setter). Würde man den Flugzeugnamen nun etwa im Konstruktor übergeben so könnte er für die gleiche Instanz der Klasse nicht mehr geändert werden, da keine Setter-Methode existiert.

Forderung: Nutzung von Getter-/Setter-Methoden für den Zugriff auf öffentliche Variablen einer Klasse sowie zur Datenkapselung.

7. Übergabe von Wahrheitswerten als Parameter
Übereifrige fordern manchmal auch, dass keine Wahrheitswerte an Funktionen übergeben werden sollen, sondern dann für jede Wahrheitswertunterscheidung eine extra Funktion eröffnet werden soll. Das hierdurch lediglich Redundanz erzeugt wird, da der Code kopiert werden muss, bedenken jedoch nur wenige!

Forderung: Wahrheitswerte dürfen, soweit nicht der komplette Funktionsablauf ein anderer ist, als Parameter übergeben werden.

8. Aufteilung von Klassen auf Dateien
Vorallem bei Anfänger-Projekten findet man ewig lange PHP-Dateien, manchmal besteht sogar das gesamte Projekt lediglich aus der index.php. Von solchen, in meinen Augen, Angebereien mit Dateien die aus tausenden von Zeilen bestehen ist eindeutig abzusehen, da niemand ernsthaft behaupten kann, dass eine solche “Monsterdatei” noch wartbar ist. Durch klare Strukturierung von Klassen in Dateien ergibt sich zudem der Vorteil, dass einzelne Klassen wesentlich leichter auffindbar sind und auch einfacher hinzugeladen werden können.

Forderung: Für jede Klasse muss eine eigene Datei erstellt werden, welche den gleichen Namen wie die Klasse tragen sollte.

9. Einbinden von Klassen
Die ersten Zeilen der meisten index.php-Dateien größerer Projekte beginnen mit include-Anweisungen. Es gibt Projekte wo die index.php lediglich aus insgesamt mehreren hundert include-Befehlen besteht.

include("aaa.php");
include("aab.php");
...
include("zzz.php");

Nun argumentieren manche Programmierer, dass sie ja jede der eingebundenen Klassen unter bestimmten Umständen benötigen und sie deshalb einbinden müssen. Auch könne man die Klassen nicht erst bei der Benutzung per include einbinden, da es ja so vorkommen könnte, dass eine Datei mehrmals eingebunden wird. Dieses Problem lässt sich jedoch sehr leicht über eine Autoloader-Funktion lösen, wenn man für alle Klassen allgemeingültige Regeln bei ihrer Bennenung und Speicherung einhält. Sollte dies aufgrund zu komplexer Strukturen nicht möglich sein, so könnte man etwa auch mit einer Loader-Klasse arbeiten:

abstract class ClassHelper
{
      private static $alreadyIncluded = array();
 
      public static function includeClass($file)
      {
             if (!array_key_exists($file, self::$alreadyIncluded))
             {
                    include($file);
                    self::$alreadyIncluded[] = $file;
             }
      }
}

Forderung: Klassen sollen erst eingebunden werden, wenn sie vom Skript benötigt werden.

10. Aufteilung auf mehrere Zeilen
Wenn man ein bisher unbekanntes PHP-Skript vor sich hat, dann versucht man i.d.R. erstmal den Ablauf zu verstehen. Je länger nun z.B. die Bedingungen usw. sind, desto schwieriger wird das.

if (($user->isAdmin || $user->isMod) && (!$system->isEnabled && !$user->isLocked)) { }

Wesentlich übersichtlicher wäre es doch nun etwa so:

if ( ($user->isAdmin || $user->isMod)
    &&
    (!$system->isEnabled && !$user->isLocked)) {}

Auch bei Arrays und Funktionen mit vielen Parametern sollte man mehrere Zeilen verwenden um die Übersichtlichkeit zu wahren. (Hinweis: Auch Strings können über mehrere Zeilen gehen!

Forderung: Die Grenze von 80 Zeichen pro Zeile sollte nur in Ausnahmefällen überschritten werden!

CaesarChiffre

02. Juli 2010 - Kategorie: Computer, Programmierung, Snippets - Keine Kommentare » -

Ich habe mir mal eben eine Klasse für die sog. CaesarChiffre geschrieben.

using System;
using System.Collections.Generic;
 
namespace CaesarChiffre
{
    class CaesarChiffre
    {
        private Dictionary intsToChars = new Dictionary();
        private Dictionary charsToInts = new Dictionary();
 
        public CaesarChiffre()
        {
            // Füllen des Dictionaries welches IDs ihre Buchstaben zuordnet.
            intsToChars.Add(0, "a");
            intsToChars.Add(1, "b");
            intsToChars.Add(2, "c");
            intsToChars.Add(3, "d");
            intsToChars.Add(4, "e");
            intsToChars.Add(5, "f");
            intsToChars.Add(6, "g");
            intsToChars.Add(7, "h");
            intsToChars.Add(8, "i");
            intsToChars.Add(9, "j");
            intsToChars.Add(10, "k");
            intsToChars.Add(11, "l");
            intsToChars.Add(12, "m");
            intsToChars.Add(13, "n");
            intsToChars.Add(14, "o");
            intsToChars.Add(15, "p");
            intsToChars.Add(16, "q");
            intsToChars.Add(17, "r");
            intsToChars.Add(18, "s");
            intsToChars.Add(19, "t");
            intsToChars.Add(20, "u");
            intsToChars.Add(21, "v");
            intsToChars.Add(22, "w");
            intsToChars.Add(23, "x");
            intsToChars.Add(24, "y");
            intsToChars.Add(25, "z");
 
            // Füllen des Dictionaries welches Buchstaben ihre IDs zuordnet.
            foreach (int item in intsToChars.Keys)
            {
                charsToInts.Add(intsToChars[item], item);
            }
        }
 
        public String decode(String input, int verschiebung)
        {
            // Wir benötigen nur Kleinbuchstaben!
            input = input.ToLower();
 
            String outp = "";
 
            // Durchlaufen des Input-Strings
            for (int i = 0; i &lt; input.Length; i++)
            {
                // Einzelnes Zeichen
                String c = input[i].ToString();
 
                // Versuch Zeichen zu identifizieren, wenn es sich um keinen Buchstaben handelt, wird das nächste Zeichen aufgerufen.
                int cnr = 0;
                try
                {
                    cnr = charsToInts[c];
                }
                catch (Exception ex)
                {
                    outp += c;
                    continue;
                }
 
                // Durchführen der Verschiebung
                cnr += verschiebung;
                cnr = cnr % 26;
 
                // Hinzufügen zum Ergebnisstring
                outp += intsToChars[cnr];
            }
 
            return outp;
        }
    }
}

Datenspeicherung – Speicherungsmöglichkeiten, Redundanz und Sparmaßnahmen

27. Juni 2010 - Kategorie: Allgemein - Keine Kommentare » -

Bereits mehrmals bin ich in verschiedenen Programmiererforen über so manche Verfehlung im Bereich der persistenten Datenspeicherung gestolpert und habe verzweifelt versucht, die betreffenden User vom Unsinn ihrer Ansätze zu überzeugen. Nun habe ich einen kurzen Artikel zu diesem Thema verfasst, auf den ich in Zukunft verweisen werde.

Dieser Artikel ist unter anderem auch im neuen Menu-Punkt “Publikationen” zu finden.

Der Ubuntumann war da

05. Juni 2010 - Kategorie: Computer, Internet - Keine Kommentare » -

Der Ubuntumann war während der Ferien bei mir da und hat mir was nettes mitgebracht ;)

Ein toller Service für Leute wie mich, die über etwas verfügen, dass den Namen DSL-Anschluss eig. nicht verdient.

PDN-Forum.de – Die Zahlen

05. Juni 2010 - Kategorie: Allgemein - Keine Kommentare » -

Ich muss sagen, die Statistik spricht für sich ;) – Dafür das wir bisher keinerlei Werbung gemacht haben läuft die Community hervorragend.

I’m back – Zurück in der Heimat

04. Juni 2010 - Kategorie: Allgemein - 1 Kommentar » -

Wie im letzten Post geschrieben war ich jetzt zwei Wochen in Italien (Caorle). Nun bin ich seit ca. 5 Stunden wieder zurück in Deutschland und kann sagen, dass ich mich sehr gut erhohlt habe.
Das Wetter war (meistens) traumhaft sonnig, weswegen ich fast die ganze Zeit gejoggt, geschwommen, sparzieren gegangen oder Rad gefahren bin.

Hier in Bayern scheint das Wetter nun auch besser zu werden, wir haben sozusagen die “Regenzeit” in Italien überbrückt.

Während des Urlaubs sind natürlich auch einige tolle Fotos entstanden, von denen ich eine kleine Auswahl in den Anhang anfügen werde.

P.S.: Die Aktivität innerhalb des Blogs und auch innerhalb von New-At-Linux.de wird in den nächsten Tagen wieder steigen ;)

Ich bin dann mal weg!

20. Mai 2010 - Kategorie: Allgemein - Keine Kommentare » -

Vom 21.05.2010 bis zum 06.06.2010 bin ich im Urlaub, d.h. ich bin nicht erreichbar!

PDN-Forum.de – Neustart erfolgreich

17. Mai 2010 - Kategorie: Computer, Internet - Keine Kommentare » -

Vor 5 Tagen, direkt nachdem das Forum für fast eine Woche wegen eines Serverumzugs, welcher leider direkt nach dem Neustart der Community erfolgen musste, habe ich Google Analytics im PDN-Forum.de installiert. Und ich muss sagen: Die Zahlen sprechen für sich!

Diese Daten motivieren natürlich dazu, in Zukunft noch mehr Zeit in die Community zu investieren ;)

Lego NXT – Bau einer Alarmanlage

16. Mai 2010 - Kategorie: Computer, Lego NXT - 1 Kommentar » -

Gestern Abend habe ich mal wieder etwas mit meinem “alten” Lego NXT herumgebastelt, da ich einfach davon begeistert bin, wenn man einfach auf einen Button klickt und sich dann etwas in Bewegung setzt. ;)

Dabei verwende ich seit einiger Zeit die Library AForge.Robotics, welche es  sehr einfach ermöglicht, per C# und Bluetooth mit dem NXT zu kommunizieren.

Mein heutiges Ziel war es, eine Alarmanage unter Verwendung des Lichtsensors zu bauen, welche einen schrillen Alarmton wiedergibt, wenn in einem Zeitraum von 23.00 bis 5.59 das Licht angemacht wird. Ich weiß, dass es dafür bessere Lösungen gibt, wie einen NXT, nähmlich z.B. eine kleine Platine mit Mikrocontroller oder so, aber mir war einfach langweilig und ich wollte es einfach mal ausprobieren.

/// <summary>
/// Verwandelt einen Lego-NXT in eine Alarmanlage, welche bei Helligkeit ein Piep-Geräusch von sich gibt.
/// </summary>
/// <param name="com">COM-Port der NXT-Verbindung</param>
/// <param name="minHour">Zeitpunkt ab dem die Alarmanlage scharf sein soll</param>
/// <param name="maxHour">Zeitpunkt bis zu dem die Alaramanlage scharf sein soll</param>
public void doAlarmanlage(String com, int minHour, int maxHour)
{
    // Neue NXT-Verbindung
    NXTBrick nxt = new NXTBrick();
    // Verbindung aufbauen - COM4 kann u.U. die falsche Adresse sein - Durch eigene Angabe ersetzen
    if (nxt.Connect(com))
    {
        // SensorValues-Variable
        NXTBrick.SensorValues sV;
 
        // Endlosschleife zur Überwachung
        while (true)
        {
            // Frägt den Zustand des Lichtsensors ab (Port: 3)
            Application.DoEvents();
            if (nxt.GetSensorValue(NXTBrick.Sensor.Third, out sV) && sV.Raw <= 700 && (DateTime.Now.Hour > minHour-1 || DateTime.Now.Hour < maxHour))
            {
                // Gibt, wenn es hell ist und die Uhrzeit zwischen 23.00 und 5.59 liegt einen schrillen Ton aus
                nxt.PlayTone(200, 1000);
                nxt.PlayTone(400, 1000);
                nxt.PlayTone(4000, 1000);
                nxt.PlayTone(800, 1000);
                nxt.PlayTone(1200, 1000);
                nxt.PlayTone(4000, 1000);
                nxt.PlayTone(1600, 1000);
                System.Threading.Thread.Sleep(800);
            }
        }
    }
    else
    {
        MessageBox.Show("Verbindung zum NXT nicht möglich!");
    }
}

Für die Nutzung dieses Quellcodes braucht ihr die AForge.Robotics-Library. An sich funktioniert alles so, wie ich es mir vorgestellt hatte, es wäre z.B. nun auch möglich, Log-Einträge zu erstellen und diese in eine Datenbank zu schreiben. Jedoch scheitert die praktische Anwendung schon an dem zu hohen Batterieverbrauch. Trotzdem eine nette Spielerei ;)