Archiv

Archive for November 2012

RavenDB: Eine Einführung

27. November 2012 5 Kommentare

RavenDB ist eine dokumentenorientierte Datenbank. Dies bedeutet das man nicht einzelne Zeilen speichert, sondern ganze Dokumente (im Sinne von JSON und nicht eines Word-Dokuments).

RavenDB ist nicht die erste solche Datenbank. Ganz bewusst spricht man hier von einer 2. Generation. Die Vorteile von Produkten die den Begriff Dokumentenorientierte Datenbank begründeten (wie MongoDB) wurden aufgenommen und gleichzeitig hat man die grössten Probleme und Unschönheiten behoben.

Mit RavenDB steht einem ein ausgereiftes Produkt zu Verfügung das hervorragend mit .Net zusammen spielt. Mit zahlreichen Strategien hilft einem RavenDB eine performante Anwendung zu schreiben. Das dazu nötige Wissen sammelte der Hauptentwickler Ayende Rahien bei Projekten wie NHibernate und dem NH- und EF-Profiler.

Für OpenSource-Projekte kann man RavenDB kostenlos nutzen. Das Lizenzierungsschema für ClosedSource-Projekte ist recht umfangreich und hilft einem das zum Projekt passende Modell zu finden. Die Preise starten bei moderaten 7$ pro Monat mit die Basic-Version und steigen je nach Funktionsbedarf an.

 

Installation der Datenbank

Um den Server-Teil von RavenDB zu installieren gibt es 2 Wege:

  1. Der Download einer Zip-Datei
  2. Das NuGet-Paket RavenDB.Server

Für den Server ist die Option 1 der bevorzugte Weg. Nach dem Entpacken der Zip-Datei startet man das Programm start.cmd und RavenDB kümmert sich um den Rest. Die webbasierte Administrationsoberfläche ist von nun an über http://localhost:8080 (oder dem ersten freien Port darüber) erreichbar:

Bevorzugt man lieber die Variante mit NuGet muss man für den Server-Teil ein eigenes Projekt anlegen. Dieses Paket ist nicht dazu gedacht mit Visual Studio verwendet zu werden und man braucht dieses separate Projekt einzig als Installationscontainer. Die Startdatei heisst in diesem Fall Raven.Server.exe und liegt im zur Solution gehörenden Verzeichnis packages\RavenDB.Server.1.0.960\. Abgesehen davon gibt es keine Unterschiede zwischen den beiden Ansätzen.

Versucht man den Server im gleichen Projekt zu installieren wie den Client wird dies in nicht auflösbaren Abhängigkeiten enden. Daher die beiden Teile unbedingt trennen!

 

Installation des Clients

Hier sollte man aufs NuGet-Paket setzen. Neben dem Client selber werden so auch gleich alle Abhängigkeiten aufgelöst. Die Installation des Paketes RavenDB.Client erfolgt entweder über die grafische Oberfläche oder mit diesem Befehl in der Package Manager Console:

Install-Package RavenDB.Client

Sofern man keine speziellen Einstellungen machen will ist die Installation damit abgeschlossen.

 

Daten speichern

Mit RavenDB lassen sich Daten ganz einfach speichern. Damit IntelliSense bei Abfragen helfen kann sollte man erst einmal eine Klasse definieren:

public class Book
{
    public string Id { get; set; }
    public string Title { get; set; }
    public string ISBN { get; set; }
    public int Pages { get; set; }

    public override string ToString()
    {
        return String.Format("{0} '{1}' ({2}) has {3} pages", Id, Title, ISBN, Pages);
    }
}

Um Objekte vom Typ Book zu speichern genügt es die Main-Methode einer Konsolenapplikation mit diesem Code zu erweitern:

using (var ds = new DocumentStore { Url = "http://localhost:8081/" }.Initialize())
using (var session = ds.OpenSession())
{
    var book = new Book() { Title = "RavenDB Intro", ISBN = "123-4-5678", Pages = 200 };
    session.Store(book);
    session.SaveChanges();
    Console.WriteLine(book.Id);
// => books/1 'RavenDB Intro' (123-4-5678) has 200 pages
}

Alles was man braucht um mit RavenDB Objekte zu speichern ist eine laufende Datenbank, eine Session und das zu speichernde Objekt. RavenDB nutzt für alle Operationen das Unit of Work Pattern. Bei so kleinen Demo-Anwendungen mag dies übertrieben erscheinen. Will man RavenDB aber produktiv einsetzen wird man sehr schnell die damit verbundenen Vorteile (wie Batch-Operationen) zu schätzen lernen.

 

Abfragen mit LINQ

RavenDB arbeitet sehr gut mit .Net zusammen. Dies wird nicht zu Letzt bei den Abfragen mittels LINQ deutlich. Möchte man alle Bücher die mit „Raven“ beginnen kann man diese ganz gewöhnliche LINQ-Abfrage schreiben:

using (var ds = new DocumentStore { Url = "http://localhost:8081/" }.Initialize())
using (var session = ds.OpenSession())
{
    var book = session.Load<Book>("books/1");
    Console.WriteLine(book);

    var ravenBooks = from books in session.Query<Book>()
            where books.Title.StartsWith("Raven")
            select books;

    foreach (var foundBook in ravenBooks)
    {
        Console.WriteLine(foundBook.Id + ": " + foundBook.Title);
        // => books/1 : RavenDB Intro
    }
}

Die Abfragen können beliebig verfeinert werden. Alles was man sonst so von LINQ kennt und schätzen gelernt hat funktioniert auch mit dem Provider für RavenDB.

Wenn man die ID eines Objektes kennt kann man auf LINQ verzichten und es direkt über die Session laden:

    var book = session.Load<Book>("books/1");

 

Verändern oder Löschen

Daten können ganz einfach verändert werden. Und werden die Daten nicht mehr benötigt lassen sie sich auch ohne grossen Aufwand löschen. Zum Editieren erzeugt man jeweils erst eine Abfrage die einem die gewünschten Objekte holt. Nach dem Verändern müssen die Änderungen der Session bekannt gemacht werden – auch hier nutzt man ja das Unit of Work Pattern.

using (var ds = new DocumentStore { Url = "http://localhost:8081/"}.Initialize())
using (var session = ds.OpenSession())
{
    var book = session.Load<Book>("books/1");
    Console.WriteLine(book);

    book.Title = "Another Book about RavenDB";
    session.Store(book);
    session.SaveChanges();

    var renamedBook = session.Load<Book>("books/1");
    Console.WriteLine(renamedBook);
    // => books/1 'RavenDB Intro' (123-4-5678) has 200 pages
    // => books/1 'Another Book about RavenDB' (123-4-5678) has 200 pages
}

Zum Löschen eines Objektes beginnt man ebenfalls mit einer Abfrage und markiert das Objekt als gelöscht:

using (var ds = new DocumentStore { Url = "http://localhost:8081/" }.Initialize())
using (var session = ds.OpenSession())
{
    var book = session.Load<Book>("books/1");
    Console.WriteLine(book);

    session.Delete(book);
    session.SaveChanges();

    var renamedBook = session.Load<Book>("books/1");
    if (renamedBook == null)
    {
        Console.WriteLine("Book with id 1 not found");    
    }
    // => books/1 'RavenDB Intro' (123-4-5678) has 200 pages
    // => Book with id 1 not found
}

Vergisst man das Objekt erst zu holen wirft RavenDB eine entsprechende Exception. Der Vorteil davon ist man löscht auch wirklich nur das gewünschte einzelne Objekt.

 

Fazit

Mit RavenDB kommt man ohne grosse Vorbereitung schnell zu einer Dokumentendatenbank. Die Standardeinstellungen sind Ideal um sich ins Thema NoSQL einzuarbeiten. Und auch das Unit of Work Pattern kann man ohne grossen Aufwand in Aktion erleben.

Will man RavenDB produktiv einsetzten wird man aber noch ein wenig mehr Aufwand treiben müssen als für diese Demobeispiele. Zu vielen Bedürfnissen einer Produktionsumgebung bietet einem RavenDB eine optimale Unterstützung. Diese Teile werde ich in einem eigenen Blogeintrag genauer beschreiben.

Schlagworte: ,

Mein neues Phone

20. November 2012 1 Kommentar

Mein Windows Phone 7 Gerät (ein LG E900 Optimus 7) begleitete mich nun für 2 Jahre. Ich kann mich noch gut erinnern wie gespannt ich auf den Neustart von Microsofts mobiler Plattform war. Seit ich zum ersten Mal vom „Silverlight-Phone“ hörte wollte ich so ein Gerät haben.
Die Alterserscheinungen wie Probleme mit dem Akku, einem äusserst mühsamen ruckeln in der Twitter-Anwendung und den spontanen Neustarts wurden leider immer mehr. Zeit also für ein neues Gerät. Aber welches?

 

Ein Neustart mit Windows Phone 8?

Ende Juni 2012 wurde Windows Phone 8 zum ersten Mal konkret erwähnt. Die 10 neuen Plattformfeatures die vorgestellt wurden zeigten mir 2 Dinge:

  1. Microsoft hat sich viele Gedanken gemacht und steht vor einem Neuanfang
  2. Die Windows Phone 7.x Reihe ist tot.

Über den zweiten Punkt wurde ja mittlerweile überall breit diskutiert. Wie weit sich dies bewahrheiten wird können wir erst sagen wenn der Funktionsumfang von 7.8 offengelegt wird.

Die lange Funkstille und die Geheimniskrämerei rund um die Details von Windows Phone 8 haben mich genervt. Während Windows 8 über ein Jahr vor dem Release durch die Entwickler getestet werden konnte gab es das SDK für Windows Phone 8 erst nach der Veröffentlichung. Verschiedener könnte man ein neues Produkt wohl kaum einführen.

Nun liegt dies aber hinter uns und es wird Zeit zu schauen wie sich diese „geheimen“ Features in der Praxis bewähren.

 

Neue Plattform-Features

Nachdem ich nun eine Woche lang die 4 Anwendungen pro Zeile nutzen konnte will ich dieses Feature nicht mehr missen. Dies verwunderte mich sehr, da ich dieses Feature im Juni noch als „das ist doch kein Plattform-Feature“ betitelt hatte. In dem Punkt traf ich ein vorschnelles Urteil.

Die Lockscreen-Meldungen sind ein weiteres Feature das äusserst praktisch ist. Nun genügt mir ein Klick auf den Power-Knopf und ich sehe was für Meldungen auf mich warten – ganz ohne vorher einzuloggen.

Die Geschwindigkeit der neuen Hardware ist bemerkenswert. Während Angry Birds auf WP 7.x dermassen ruckelte das man damit nicht spielen wollte läuft nun alles flüssig. So gehört sich das.

Äusserst gelungen finde ich die Integration des Systems mit DropBox. Will ich dort eine Datei öffnen die der DropBox-Viewer nicht kennt wird mir die Möglichkeit geboten eine passende Anwendung auszuwählen. Diese Inter-App-Kommunikation macht aus den Insellösungen der einzelnen Apps endlich eine brauchbare Einheit.

OneNote zeigt mir nun endlich auch Tabellen so an wie ich diese auf dem Desktop erfasst habe. Unter Mango war ein Herauszoomen um einen Überblick zu bekommen nicht möglich. Nun sehe ich beim Start die ganze Tabelle und kann bei Bedarf hineinzoomen. Da liegen wirklich Welten in der Benutzerfreundlichkeit.

Im neuen Store finde ich mich endlich zurecht. Während ich unter Mango noch endlos scrollen musste werden meine Suchanfragen nun so beantwortet das ich die gewünschte Anwendung unter den ersten 3 Treffern habe. Mir erscheint der Store zudem viel aufgeräumter und man nutzt endlich jede Chance um einem gute und passende Anwendungen zu verkaufen – also genau das wozu man den Store geöffnet hat.

In-App Käufe sind gut gelöst und ermöglichen nicht nur bei Spielen schneller vorwärts zu kommen. Mir gefällt das alle meine Einkäufe über ein Konto laufen können und ich nicht bei jedem Anbieter meine Kreditkarten-Informationen hinterlegen muss.

Und da wir gerade beim Einkaufen sind: Die Ticket-Anwendung ist eine tolle Ergänzung. Bei Eventbrite ein Ticket für eine Veranstaltung kaufen oder bei Booking.com ein Zimmer reservieren: Das nötige Ticket landet an einem definierten Ort und ist ohne grosses suchen auffindbar. Damit es noch schneller geht kann man diese auch auf dem Lockscreen anzeigen.

Screenshots lassen sich ebenfalls machen. Dazu genügt das gleichzeitige Drücken von Power und dem mittleren Knopf unten am Gerät.

Mit der Sprachsteuerung konnte ich mich noch nicht anfreunden. Noch bin ich schneller wenn ich mich durch die Menüpunkte klicke als den Befehl zu diktieren. Es ist aber wohl nur eine Gewöhnungssache.

 

Was mir besonders gut gefällt

Die vielen kleinen Verbesserungen wie die Lupe um den Cursor punktgenau zu platzieren oder der automatische Wechsel auf Grossbuchstaben nach einem Leerzeichen zur Namenseingabe sind eine echte Erleichterung. Auch wenn dies alles Kleinigkeiten sind, so summieren sich diese schnell und bieten eine tolle Benutzerführung.

Mein Top-Feature ist aber die Podcast-Anwendung. Wie habe ich es gehasst wenn ich wegen einem Neustart alle bereits gehörten Folgen einzeln durchspulen musste, nur damit ich den Status korrekt setzen konnte. Nun genügt mir ein einziger Klick und ich kann zwischen Neu und Abgespielt hin und her wechseln. Zudem bleibt der Podcast an der Stelle wo ich aufgehört hatte – dies trotz Restart oder wenn der Akku leer war.

Ob Systemupdates, Downloads von Musik oder Podcasts: Alles geht ohne eine Desktop-Software benutzen zu müssen. Die Daten kommen so aufs Gerät wie ich dies will und ich werde nicht durch eine Software gegängelt die mir beim Speichern noch gerne schnell die Songtitel überschreibt (was Zune ja mehrmals fertig brachte…).

Die Kamera bietet eine sehr gute Bildqualität. Gerade bei diffusem Licht in der Dämmerung oder bei Nebel liefert die Kamera scharfe Bilder. Grosse Helligkeitsunterschiede werden ebenso gemeistert wie schnelle Bewegungen. Wenn es auch nicht an meine PowerShot herankommt, so ist die Kamera für ihre Grösse doch top.

Für definitive Angaben zur Akkuleistung ist es noch zu früh. Die ersten Tests sind aber äusserst positiv und spielen in einer anderen Liga als das WP 7 Gerät.

 

Was fehlt

Leider fehlt bei meinem Phone gleich wie bei der Top-Linie von Nokia die Möglichkeit eine SD-Karte als Speichererweiterung zu verwenden. Da wird hoffentlich bei der nächsten Generation noch nachgebessert.

Und für NFC müsste ich erst noch einen Adapter kaufen. Dies stört mich im Moment noch nicht, da NFC sich erst einmal durchsetzen muss und ich keine NFC-fähigen Geräte habe. Ich bin gespannt ob ich in einem Jahr diesen Adapter besitze oder ob ich darauf verzichten kann.

 

Schlussworte

Es ist erstaunlich wie sich die Smartphones in 2 Jahren weiterentwickelt haben. Mir war wichtig dass mein neues Phone gut mit Windows zusammenspielt und ich die angekündigten Plattformfeatures auch wirklich nutzen kann. Daher kaufte ich mir ein iPhone 5.

 

Schlagworte:

Kopierten Code finden mit der Code Clone Analyse

14. November 2012 Kommentare aus

Code wird gerne kopiert. Was einem zuerst hilft schnell ähnliche Anforderungen zu erfüllen wird in kurzer Zeit zu einem Problem. Nun ist es nicht mehr damit getan eine Stelle im Code zu korrigieren und der Fehler ist behoben – man muss jetzt immer auch noch alle Kopien korrigieren.

Das Problem dabei ist das man nicht weiss was für Code kopiert wurde und wo der in Modul X aufgetretene Fehler noch alles drin ist. Als Folge davon bleiben die Fehler meist unentdeckt und die Kunden fragen sich wieso sie immer wieder die gleichen Probleme melden müssen.

Seit Visual Studio 2012 hat man beim Aufstöbern dieser Klone eine Hilfe. Die Analysefunktionen wurden um die Funktion Code Clone Detection erweitert. Wie der Name vermuten lässt wird damit kopierter Code aufgespürt.

Führt man diese Auswertung aus muss man sich erst einmal gedulden. Der ganze Code wird in Tokens unterteilt und dann analysiert. Der erstmalige Durchgang ist je nach Codebasis und Geschwindigkeit des Rechners eine gute Gelegenheit für eine ausgedehnte Kaffeepause.

 

Nicht nur 1:1 Kopien

Code der 1:1 kopiert wurde wird von Code Clone als „Exact Match“ gefunden. Damit gibt sich Code Clone aber nicht zufrieden. Kleinere Anpassungen wie umbenannte Variablen werden ebenfalls erkannt und als „Strong Match“ oder als „Medium Match“ klassifiziert.

Richtig interessant wird es bei grösseren Änderungen die als „Weak Match“ eingestuft werden. Hier ist die Chance auf falsch erkannte Klone entsprechend grösser. Dafür findet man hier aber auch die Stellen, die man auf den ersten Blick nicht als Klon erkennen würde:

public void MethodA(string input)
{
    Console.WriteLine("input => ", input);

    string a = input.Trim().ToLower();
    string b = input.Trim().ToLower();
    string c = input.Trim().ToLower();
    string d = input.Trim().ToLower();
    string e = input.Trim().ToLower();

    Write(a);
    Write(a);
    Write(a);
    Write(a);
}

public void MethodB(string input)
{
    string b = input.Trim().ToLower();
    Write(b);
    Write(b);
    Write(b);

    string a = input.Trim().ToLower();
        
    string c = input.Trim().ToLower();
    Console.WriteLine("input => ", input);

    string e = input.Trim().ToLower();
    string d = input.Trim().ToLower();
    Write(b);
}

In diesem Beispiel wurde der gleiche Code anders aufgebaut. Gerade bei solchen Klonen spielt Code Clone seine Stärken aus und erweist sich als äusserst hilfreich.

 

Nebeneffekte

Nutzt man Code Clone in einem realen Projekt kann man damit noch mehr Probleme aufdecken als nur kopierten Code. Sind Methoden inhaltlich identisch aber mit ganz anderen Namen versehen (wie beispielsweise GetOrder und GetPerson) gibt es wohl grössere Probleme beim Verstehen der Domäne.

Im besten Fall löst sich das Problem mit einer genaueren Erklärung der Domänenbegriffe. Es kann aber gerade so gut auch ein Warnzeichen für eine falsche Abstraktion oder gröbere Architekturfehler sein.

 

Einschränkungen

Code Clone hat 2 wichtige Einschränkungen:

  1. Diese Analyse benötigt die Premium und der Ultimate Version von Visual Studio 2012.
  2. Es werden nur Code-Teile berücksichtigt die aus 10 oder mehr Befehlen bestehen.

 

Fazit

Mit der Code Clone Analyse kann man ohne grossen Aufwand kopierte Codestücke auffinden. Dabei werden nicht nur 1:1 Kopien gefunden, sondern auch Teile die ähnlich sind. Die so gewonnenen Erkenntnisse sind eine gute Ausgangslage für ein Refactoring oder eine teamweite Code Review.

Schlagworte: ,

MiniProfiler für Ruby

7. November 2012 Kommentare aus

MiniProfiler ist ein äusserst hilfreicher Profiler für Webanwendungen, den ich hier schon vorgestellt habe. Hat man sich erst einmal an den immer verfügbaren Profiler gewöhnt will man nicht mehr ohne dieses Werkzeug entwickeln. Und man will es auch für alle anderen Plattformen nutzen.
Wie sich zeigt geht dies nicht nur mir so. MiniProfiler wurde auf Ruby portiert und bietet einem dort den gleichen Funktionsumfang.

 

Installation und Konfiguration

Die Installation und Konfiguration ist unter Ruby deutlich einfacher als in .Net. Es genügt das Gemfile seiner Rails-Anwendung um einen Eintrag zu Miniprofiler zu ergänzen:

gem 'rack-mini-profiler'

Nach einem bundle install kann man die Anwendung starten und MiniProfiler sofort nutzen:

Will man wissen wie viel Zeit man für eine Methode benötigt übergibt man diese in einem Block an MiniProfiler:

  def index
    Rack::MiniProfiler.step("fetch items") do
      @items = Item.all
    end 
    ....
  end

Die Auswertung unterscheidet sich nicht gross von der aus .Net bekannten Darstellung:

 

MiniProfiler in der Produktion

Standardmässig wird die Rack-Middleware nur in der Entwicklungsumgebung aktiviert. Da Rails in diesem Modus keine Optimierungen macht variieren die Werte recht stark. Dieses Problem lässt sich lösen in dem man MiniProfiler auch in der Produktion aktiviert.

Dazu erweitert man am besten die Datei application_controller.rb um einen Before-Filter:

before_filter :miniprofiler

private
def miniprofiler
  Rack::MiniProfiler.authorize_request 
  # Optional mit Einschränkung der Sichtbarkeit: 
  # if user.developer?
end

 

Fazit

Mit dem portierten MiniProfiler kann man die unter .Net schätzen gelernten Möglichkeiten auch für Rails-Anwendungen nutzen. Die Konfiguration ist durch die Implementierung als Rack-Middleware sogar noch einfacher als im Original. Somit gibt es keinen Grund auf MiniProfiler zu verzichten nur weil man Rails nutzt.

Schlagworte: ,

Unterlagen zu “Ruby und Rails für .Net Entwickler”

4. November 2012 Kommentare aus

Am 31. Oktober durfte ich den Vortrag “Ruby und Rails für .Net Entwickler” bei der .Net User Group Bern präsentieren. Auf den ersten Blick mag die Themenwahl für eine User Group die sich mit .Net beschäftigt erstaunen. Schaut man sich all die neuen und praktischen Werkzeuge (wie zum Beispiel NuGet) an, so geht erstaunlich vieles auf Ruby und Rails zurück.

 

Unterlagen

Die Präsentation findet sich auf Speakerdeck und kann dort auch als PDF heruntergeladen werden.

 

Beispiele

Der Code und die Befehle für die Beispiele mit Rails für die alltäglichen Arbeiten liegen im Git-Repo DNUGBE_RailsDemo. Die darin liegende Anleitung führt die Liste der nötigen Befehle und weist mit einem / auf notwendige selbst zu machende Anpassungen hin.

Wer gerne damit experimentieren möchte kann sich den Code direkt auf GitHub.com anschauen oder den Windows-Client GitHub for Windows verwenden.

 

Weiterführende Informationen

Damit man sich die Links nicht aus den Folien zusammensuchen muss:

Webseiten & Tools

Tools für Windows

Podcasts

Screencasts & Videos

Bücher

In meinem Blog sind alle Beiträge zu Ruby & Rails mit dem Tag Ruby versehen.

 

Nachlieferung der Antwort zum Umgebungswechsel

Um zwischen den einzelnen Umgebungen von Rails hin und her zu wechseln kann man das Environment setzen. In der Kommandozeile geht dies so:

rake environment RAILS_ENV="test" db:migrate
rake RAILS_ENV="production" RAILS_GROUPS="assets" assets:precompile
rails server -e production

Falls noch weitere Fragen offen sind bitte einen Kommentar hinterlassen.

 

Danke

Als Abschluss möchte ich mich nochmals bei der .Net User Group Bern und den Teilnehmern bedanken. Es freut mich das man auch für Präsentationen einen Platz findet die keine reinen .Net-Themen behandeln.

Schlagworte: ,
Folgen

Erhalte jeden neuen Beitrag in deinen Posteingang.

Schließe dich 297 Followern an