Graph databases

My second day at the Spartakiade was dedicated to the subject of graph databases.

In computing, a graph database is a database that uses graph structures for semantic queries with nodes, edges, and properties to represent and store data. A graph database is any storage system that provides index-free adjacency. This means that every element contains a direct pointer to its adjacent elements and no index lookups are necessary. General graph databases that can store any graph are distinct from specialized graph databases such as triplestores and network databases. (source: Wikipedia)

The workshop was led by Stephan (@Piratevsninja) – thank you very much! – and we used Neo4j, the most popular open source graph database. After this day of dive-in I can say I can start to create my first graph database application without asking myself all the time what the hell am I doing 🙂

Also: what is a graph database?

On a very high level we can split the databases into two types: RDBMS and NoSQL. In other words: into relational and nonrelational storages.

NoSQL databases – called by Martin Fowler Not Only SQL have the main focus on the data model and not on the relations between the data. Mostly there isn’t any relation between the entities. They can be differentiated based on the data model they use. Here some examples: Key-value storages (Redis, CouchDB, etc.), Document DBs (Lotus Notes, MongoDB, etc.), Column based DBs (Cassandra, HBase, etc.).

Relational databases (RDBMS) store the data denormalized and define the relations between the data types (also ALL the entries of one type). I don’t think I have to give examples for our plain old databases: if you can join and distinct data you are in the world of relational databases.

Graph databases combine both worlds: they are relational databases with the main focus on the relations between the data (not between the data model) – or like Stephan formulated it: they put data in the context of relationships.

Nodes and relations
Emil knows Ian (source: neo4j.com)

How you define the content ?

A graph database contains nodes (instances like “Emil” and “Ian”) and relations between these nodes (“knows”). One node is defined through some properties and can be grouped through labels. They often have aliases to be easier to work with them:

Emil:Person {name:"Emil", age:"20"}, Ian:Person {name:"Ian"}

One relation is defined through a name, the nodes it connects and the direction of this connection. Relations can also have properties but they should be very carefully chosen. They must describe the relation and not the nodes.

(Emil)-[:KNOWS {certainty:100}]->(Ian)

Now is clear to see what is the difference between a “plain” relational and a graph database: for the former you care always about the data. For the latter the data means nothing without the relation to some other data.

Movies and actors

 

Fine, I can set actors in relations. So what?

The most important point is: think around a corner. The fact that I can report that Ian knows Emil and Johann knows Emil too can be interesting but I don’t think there are any new business ideas in the domain of social connections which weren’t evaluated yet. What about the information that only 20% of the Swedish tourists who visit Germany and are between 18 and 25 do not speak German? This is surely a VERY interesting to know if you sell German dictionaries in the near of Universities…
I just invented this idea – I have no idea how many Swedish guys between 18 and 25 are speaking German 😉 – but this is what I mean with think around a corner!

What else remains to do?

After giving a good thought to the design: the relations and the connected data – like ids and oder characteristics but only if they are must-have – there are only a few things to do. Neo4j just like all the other graph databases have some kind of API to create, insert, update and query data. You only have to save the data across your application and create a UI (or use the one from Neo4j which is one of the coolest UI I ever saw) to create reports. Put this reports in front of the business analyst and you are done!

Wie gesund ist eigentlich mein Code?

 

software quality metric: A function whose inputs are software data and whose output is a single numerical value that can be interpreted as the degree to which software possesses a given attribute that affects its quality.

 Definition nach IEEE Standard 1061 – [Quelle: Wikipedia]

Jede Software, deren Code länger als ein paar hundert Zeilen ist, wird irgendwann den Punkt erreichen, dass man den Code auf Anhieb nicht mehr verstehen kann. Die meisten von uns schreiben Code, der älter als ein paar Monate ist und noch ganz viele Jahre erhalten bleiben soll. (Alle, die das nicht wollen, können hier aufhören zu lesen).

Das Problem, das man früher oder später bekommt, ist die Komplexität unter Kontrolle zu halten. Jeder neuer Kollege hat das Problem, unbekannten, vorhandenen Code so schnell wie möglich zu verstehen. Für beide Fälle ist es sehr hilfreich, wenn man Tools zur Hand hat, die zum Beispiel die Zusammenhänge und Abhängigkeiten visualisieren können.

Als ich bei dem Open Space Karlsruhe die Frage gestellt habe, was die .NET-Community zu diesem Zweck nutzt,war die einstimmige Antwort : NDepend.  Code Metriken sind wichtig, sie sind aber nicht allmächtig. Wenn man allerdings wissen möchte, wie gesund sein Code ist, was sich verschlechtert hat und welche Baustellen aufgeräumt wurden, dann ist NDepend das de facto Standardtool, welches benutzt wird.

Was macht das Tool eigentlich?

Um all die Features zu beschreiben, die NDepend hat, würde man sehr viel Platz und Zeit benötigen – und zum Glück ist dies gar nicht nötig: auf deren Webseite findet man alles, was man braucht: Bilder, Erklärungen, weiterführende Links.

Ich würde hier nur zwei wichtige Funktionalitäten herausheben:

  • Visualisiert

MVC-Runtime Dependency Graph
Abhängigkeiten im MVC-Runtime

 

Auf diesem Bild sieht man, dass man gar nichts sieht 😀

Stellt euch mal vor, ihr müsstet ab sofort an MVC weiterentwickeln. Wo würdet ihr anfangen? Ich würde hiermit beginnen und immer mehr reinzoomen.

Alle Verwender von DotNetOpenAuth.OpenId

 

  • Erklärt

Das coolste für mich bei NDepend ist eigentlich nicht die Tatsache, dass es mir Statistiken und Grafiken liefert, sondern, dass es sie mir Diese auch  erklärt!

 

Interne Abhängigkeiten von DotNetOpenAuth.OpenId

 

Genau so läuft es auch mit den Metriken. Ich will nicht wissen, wie diese berechnet werden – eventuell später –  aber ich will wissen, was es bedeutet, wenn ein Wert zu hoch oder zu klein ist. Und das Tool erklärt dies alles oder leitet mich gezielt dahin weiter, wo es erklärt wird. Und so, ohne es zu merken, habe ich etwas gelernt, was meine Codequalität höchstwahrscheinlich erhöhen wird. Ich kann dadurch ein besserer Programmierer werden.

Es gibt noch sehr viele Gründe, wofür man NDepend ausprobieren bzw. nutzen sollte. Spätestens, wenn ein Team sich für gemeinsame Regeln einigen möchte, sollte man die Einhaltung durch Tools wie dieses und StyleCop and co. absichern. Dadurch wird irgendwann egal, wie ungesund unserer Code heute ist, morgen wird es ihm auf jedem Fall besser gehen – und uns auch.

Templating mit Razor aber ohne MVC

Ich habe unlängst nach einer Möglichkeit gesucht, Seiten schnell und effektiv zu generieren, sowohl für Web als auch für E-Mails als Background-Jobs. Ein Kollege hat mich auf @razorengine aufmerksam gemacht und diese Templating Engine scheint alles zu bieten, was ich gesucht habe.

A templating engine built upon Microsoft’s Razor parsing technology. The RazorEngine allows you to use Razor syntax to build robust templates. Currently we have integrated the vanilla Html + Code support, but we hope to support other markup languages in future.

Die Installation ist so einfach wie möglich:

//mit NuGet:
Install-Package RazorEngine

Man muss danach nur noch die RazorEngine.dll und System.Web.Razor.dll referenzieren und das war’s.

 

Das Generieren von Seiten kann entweder direkt oder mit vorkompilierten Templates erfolgen:

[Test]
public void PageCanBeParsed()
{
   const string template = "Hello @Model.Name! Welcome to Razor!";
   var result = Razor.Parse(template, new {Name = "World"});

   Assert.That(result, Is.EqualTo("Hello World! Welcome to Razor!"));
}
//unterstützt anonyme Klassen
[Test]
public void PageCanBeParsedWithCompiledTemplate()
{
   const string template = "Hello @Model.Name! Welcome to Razor!";
   Razor.CompileWithAnonymous(template, "world");
   var result = Razor.Run(new {Name = "World"}, "world");

   Assert.That(result, Is.EqualTo("Hello World! Welcome to Razor!"));
}
//oder konkrete Typen
[Test]
public void TemplateIsCompiledWithModelType()
{
   const string template = "Hello @Model.Name! Welcome to Razor!";
   var testModel = new TestModel{ Name = "World" };
   Razor.Compile( template, typeof(TestModel), "world2" );
   var result = Razor.Run(testModel, "world2");
   Assert.That(result, Is.EqualTo("Hello World! Welcome to Razor!"));
}

public class TestModel { public string Name; }

Um ehrlich zu sein, ich habe noch keinen Grund gefunden, warum man nicht die vorkompilierte Variante nutzen soll. In diesem Fall wird das Template EIN MAL kompiliert und in Cache abgelegt. Ein Vergleichs- und Stresstest, in dem ich ein halbwegs komplexes Template 500-mal mit Razor.Parse bzw. mit Razor.Compile + Razor.Run aufgerufen habe, hat folgendes geliefert:

   Parse: 03:35.97 min
   Compile+Run: 00:00.63 min

Ich glaube, damit ist alles gesagt. Es sei denn, eine Zeile weniger gilt auch als Argument 🙄

 

RazorEngine unterstüzt fast alles, was Microsoft’s Razor in Views anbietet, wie zum Beispiel Helper-Methoden, Model-Definitionen direkt im Template oder partielle Views:

[Test]
public void EngineSupportsInlineHelper()
{
   const string template = @"@helper MyMethod(string name) {Hello @name}@MyMethod(Model.Name)! Welcome to Razor!";
   var testModel = new TestModel{ Name = "World" };
   var result = Razor.Parse(template, testModel);
   Assert.That(result, Is.EqualTo("Hello World! Welcome to Razor!"));
}

[Test]
public void EngineSupportsInheritsCommand()
{
   const string template = @"@inherits RazorEngine.Templating.TemplateBase
@helper MyMethod(string name) {Hello @name}@MyMethod(Model.Name)! Welcome to Razor!";
   var testModel = new TestModel{ Name = "World" };
   Razor.Compile(template, typeof(TestModel),"testModel");
   var result = Razor.Run(testModel, "testModel");

   Assert.That(result, Is.EqualTo("Hello World! Welcome to Razor!"));
}

[Test]
public void EngineSupportsSubtemplating()
{
    const string masterTemplate = "You are on www.yellow-brick-code.org!";
    Razor.Compile(masterTemplate, typeof(TestModel), "master");

    const string contentView = @"@inherits RazorEngine.Templating.TemplateBase
@helper MyMethod(string name) {Hello @name}@MyMethod(Model.Name)! Welcome to Razor!";
    var testModel = new TestModel{ Name = "World" };

    const string template = contentView + " @Include(\"master\")";

    Razor.Compile(template, typeof(TestModel), "testModelMaster");
    var result = Razor.Run(testModel, "testModelMaster");
    Assert.That(result, Is.EqualTo("Hello World! Welcome to Razor! You are on www.yellow-brick-code.org!"));
}

Und nun sind wir soweit, das Ganze im Web zu testen.

 

Die Engine funktioniert so, dass sie zur Laufzeit aus dem Template eine dll mit einem Zufallsnamen erstellt. Also wenn man die Engine im Web nutzen will, müssen noch ein paar Dinge getan werden:

  1. RazorEngine.Web.dll referenzieren
  2. Ein VirtualPathProvider in Global.asax.cs registrieren
    public class Global : System.Web.HttpApplication
    {
       protected void Application_Start(object sender, EventArgs e)
       {
          HostingEnvironment.RegisterVirtualPathProvider(new RazorVirtualPathProvider());
       }
    ...
    
  3. In Web.Config muss der BuildProvider registriert werden:
    <configuration>
    <configSections>
    <section name="razorEngine" type="RazorEngine.Configuration.RazorEngineConfigurationSection, RazorEngine" requirePermission="false" />
    </configSections>   <razorEngine factory="RazorEngine.Web.WebCompilerServiceFactory, RazorEngine.Web" /><system.web>
    <compilation debug="true" targetFramework="4.0">
    <buildProviders>
    <add extension=".csrzr" type="RazorEngine.Web.CSharp.CSharpRazorBuildProvider, RazorEngine.Web" />
    </buildProviders>
    </compilation>

So aufgerüstet kann man mit den Models und Templates beginnen. Man kann die Templates als html-Dateien speichern. Allerdings wenn man IntelliSense haben möchte, dann muss MVC3 auf den Rechner installiert und die Datei als cshtml gespeichert werden.

 

Das Beispiel hier ist über ein MasterHeader mit dem Anfang der Seite, ein MasterFooter mit dem Ende, beide eingebettet mit " @Include(\"master...\")" in Content. Die ganze Seite bekommt ein Objekt vom Typ Model zum Parsen. Alle Templates werden mit einem ITemplateFinder geladen.

...
ITemplateFinder templateFinder = new TemplateFinder(path);
Razor.Compile(templateFinder.GetTemplate("masterHeader.cshtml"), typeof(Model), "masterHeader");
Razor.Compile(templateFinder.GetTemplate("masterFooter.cshtml"), typeof(Model), "masterFooter");

var model = new Model
{
    PurchaseNo = "011313074142",
    Amount = "270.63",
    Date = "20110121"
};

var template = templateFinder.GetTemplate("Content.cshtml");
Razor.Compile(template, typeof(Model), "content");
var parsedTemplate = Razor.Run(model, "content");
context.Response.ContentType = "text/HTML";
context.Response.Write(parsedTemplate);

Bevor ihr was über Namen oder Verantwortlichkeiten was sagt: das Projekt wurde als Spike erstellt, und als solche hat seine Rolle  perfekt erfüllt 🙂 In Produktion würde ich das Kompilieren von statischen Templates in Application_Start verschieben und das ITemplateFinder sollte auf  jeden Fall Injected werden.

 

Ich muss mich bei den 2 Jungs, die das Projekt entwickeln, sehr bedanken, es war eine super Idee! Schaut es einfach an, die dll kann noch viel mehr.

Kontextabhängige Datenvalidierung

Die Idee stammt von Jimmy Nilsson – Applying Domain-Driven Design and Patterns. Er hat nach einer Möglichkeit gesucht, die immer wiederkehrende Aufgabe, Daten zu validieren, flexibel und kontextabhängig zu gestalten, und zwar so, dass man es nur einmal schreiben muss.

Wie läuft normalerweise so eine Validierung ab? Man will wissen, ob eine Instanz als solche allen Vorschriften entspricht, und wenn nicht, dann welche Felder passen nicht. Jeder, der jemals Webanwendungen geschrieben hat, weiß, wie mühsam und langweilig es ist, jeden Eingabewert auf Gültigkeit zu testen. (Hier geht allerdings nicht unbedingt um Formulare, da kann man ja die Validierung z.B. bei ASP.MVC 2.0 mit Data Annotations durchführen.)

Also zurück zu den Anforderungen: um die verschiedenen Regeln wiederverwendbar zu machen, braucht man diese von einem Interface abzuleiten:

namespace ValidationFramework
{
    public interface IRule
    {
        bool IsValid { get; }
        int IdRule { get; }
        string[] BooleanFieldsThatMustBeTrue { get; }
        string Message { get; }
    }
}

IsValid sagt aus, ob der Regel verletzt wurde. Die IdRule ist dafür da, um diese Regeln einfacher identifizieren zu können. BooleanFieldsThatMustBeTrue kann dafür verwendet werden, um Vorbedingungen zu prüfen. Message braucht wohl keine Erklärung.
Jetzt kann man verschiedene Regeln und eine Basisklasse für gemeinsame Funktionalitäten definieren:

using System.Collections.Generic;
using System.Linq;
using System;

namespace ValidationFramework
{
    public abstract class RuleBase : IRule
    {
        private readonly object m_value;
        private readonly int m_idRule;
        private readonly string[] m_booleanFieldsThatMustBeTrue;
        private readonly object m_holder;

        protected RuleBase(int idRule, string[] fieldsConcerned, string fieldname, object holder)
        {
            m_value = GetPropertyValue(holder, fieldname);
            m_booleanFieldsThatMustBeTrue = fieldsConcerned;
            m_holder = holder;
            m_idRule = idRule;
        }

        private static object GetPropertyValue(object holder, string fieldname)
        {
            return holder.GetType().GetProperty(fieldname).GetValue(holder, null);
        }

        protected object GetValue()
        {
            return m_value;
        }
        protected object GetHolder()
        {
            return m_holder;
        }

        public abstract bool IsValid { get; }
        public int IdRule
        {
            get { return m_idRule; }
        }

        public string[] BooleanFieldsThatMustBeTrue
        {
            get { return m_booleanFieldsThatMustBeTrue; }
        }

        public abstract string Message { get; }

        protected bool BooleanFieldsConcernedAreTrue()
        {
            return
                m_booleanFieldsThatMustBeTrue.Select(a => (bool)m_holder.GetType().GetProperty(a).GetValue(m_holder, null)).
                    Select(b => b).Count() == m_booleanFieldsThatMustBeTrue.Length;
        }
    }

    public class DateIsInRangeRule : RuleBase
    {
        private readonly DateTime m_minDate;
        private readonly DateTime m_maxDate;

        public DateIsInRangeRule(DateTime minDate, DateTime maxDate, int idRule, string fieldName, object holder) : base( idRule, null,fieldName, holder)
        {
            m_minDate = minDate;
            m_maxDate = maxDate;
        }

        public override bool IsValid
        {
            get { 
                var value = (DateTime) GetValue();
                return value >= m_minDate && value <= m_maxDate;
            }
        }

        public override string Message
        {
            get {
                return IsValid
                           ? string.Empty
                           : string.Format("Das Datum ist nicht in gültigen Bereich: {0}-{1}", m_minDate, m_maxDate); }
        }
    }

    public class MaxStringLengthRule : RuleBase
    {
        private readonly int m_maxLength;

        public MaxStringLengthRule(int maxLength, int idRule, string fieldname, object holder) : base(idRule, null, fieldname, holder)
        {
            m_maxLength = maxLength;
        }

        public override bool IsValid
        {
            get { return GetValue().ToString().Length <= m_maxLength; }
        }

        public override string Message
        {
            get {
                return IsValid
                           ? string.Empty
                           : string.Format("Die zugelassene Länge von {0} Zeichen wurde überschritten",m_maxLength); }
        }
    }
}

Jetzt, da die Grundlagen stehen, schauen wir mal, wie man die Validierungsregeln festlegen würde.
Hier ist eine ganz einfache Beispielklasse:

using System;

namespace ValidationFramework
{
    public class Account
    {
        public Account()
        {
            Created = DateTime.Now;
            Address = string.Empty;
        }

        public DateTime Created { set; get; }
        public string Address { get; set; }
        public bool Activated { get; set; }
    }
}

Jetzt definieren wir die Regeln, wonach eine Instanz valide ist oder nicht. Die neue Eigenschaft IsValidated soll diese Information speichern.

    public class Account
    {
        private readonly IList<IRule> m_validationRules = new List<IRule>();

        public Account()
        {
            Created = DateTime.Now;
            Address = string.Empty;
        }

        public DateTime Created { set; get; }
        public string Address { get; set; }
        public bool Activated { get; set; }
        public bool IsValidated { get; set; }

        private void SetupValidationRules()
        {
            m_validationRules.Add(new DateIsInRangeRule(new DateTime(1990,1,1),DateTime.Now,1,"Created",this ));
            m_validationRules.Add(new MaxStringLengthRule(10,2,"Address",this));
        }
    }

Um Regeln auch dynamisch setzen zu können, wird eine Methode AddValidationRule(IRule) definiert

 
    public class Account
    {
...    
        public void AddValidationRule(IRule rule)
        {
            m_validationRules.Add(rule);
        }
...
    }

Nun müssen wir diese Regeln nur noch auswerten. Dafür wird in RuleBase eine statische Methode definiert und in der Beispielklasse die Methode IEnumerable GetBrokenRules()

    public abstract class RuleBase : IRule
    {
...
        public static IEnumerable<IRule> CollectBrokenRules(IList<IRule> rulesToCheck)
        {
            return rulesToCheck.Where(a => !a.IsValid).Select(a => a);
        }
    }
    public class Account
    {
...
        public IEnumerable<IRule> GetBrokenRules()
        {
            SetupValidationRules();
            return RuleBase.CollectBrokenRules(m_validationRules);
        }
...
    }

Um zu beweisen, dass es funktioniert, hier ein Paar Tests:

using System;
using System.Linq;
using NUnit.Framework;

namespace ValidationFramework.Tests
{
    [TestFixture]
    [Category("DateIsInRangeRule")]
    public class If_the_CreationDate_of_the_Account_is_in_range
    {
        [Test]
        public void Then_the_property_Created_is_valid()
        {
            var sut = new Account { Created = DateTime.Now.AddYears(-1) };
            Assert.That(sut.GetBrokenRules().Count(),Is.EqualTo(0));
        }
    }
    [TestFixture]
    [Category("DateIsInRangeRule")]
    public class If_the_CreationDate_of_the_Account_is_to_old
    {
        [Test]
        public void Then_the_property_Created_is_not_valid()
        {
            var sut = new Account { Created = new DateTime(1989,1,1)};
            Assert.That(sut.GetBrokenRules().Count(), Is.EqualTo(1));
            Assert.That(sut.GetBrokenRules().First().IdRule, Is.EqualTo(1));
        }
    }

    [TestFixture]
    [Category("MaxStringLengthRule")]
    public class If_the_Address_of_the_Account_is_to_long
    {
        [Test]
        public void Then_the_property_Address_is_not_valid()
        {
            var sut = new Account { Address = "12345678901"};
            Assert.That(sut.GetBrokenRules().Count(), Is.EqualTo(1));
            Assert.That(sut.GetBrokenRules().First().IdRule,Is.EqualTo(2));
        }
    }
}

Mit den vorhandenen Tests kann man nun refaktorisieren um die Prinzipien der Separation Of Concern einzuhalten. Außerdem ist nun Zeit, auch über die Kontextbezogenheit nachzudenken.
Die Klasse Account wird wahrscheinlich durch irgendeinen ORMapper gefüllt und braucht auf keinem Fall die Verantwortung, die Validierungsregeln zu verwalten. Deshalb kann man das Specification-Pattern von DDD anwenden, und diese Regeln in so eine Spezifikation verschieben:

using System;
using System.Collections.Generic;

namespace ValidationFramework
{
    public interface IValidationSpecification
    {
        IList<IRule> GetValidationRules();
    }

    public class AccountValidationSpecification : IValidationSpecification
    {
        private readonly Account m_objectToValidate;

        public AccountValidationSpecification(object objectToValidate)
        {
            m_objectToValidate = (Account) objectToValidate;
        }

        public IList<IRule> GetValidationRules()
        {
            return new List<IRule>
                       {
                           new DateIsInRangeRule(new DateTime(1990, 1, 1), DateTime.Now, 1, "Created",
                                                 m_objectToValidate),
                           new MaxStringLengthRule(10, 2, "Address", m_objectToValidate)
                       };
        }
    }
}

Die Spezifikationen werden selbstverständlich von einer Factory geliefert und sie werden per Setter Injection gesetzt.

    public  class ValidationSpecificationFactory
    {
        public static IValidationSpecification Create<T>(object objectToValidate)
        {
            if (typeof(T) == typeof(Account))
                return new AccountValidationSpecification(objectToValidate);
            throw new NotSupportedException();
        }
    }
    public class Account
    {
...
        public void SetValidationSpecification(IValidationSpecification specification)
        {
            foreach (IRule rule in specification.GetValidationRules())
                m_validationRules.Add(rule);
        }
...
    }
//Der Aufruf ist dann
var account = new Account();
account.SetValidationSpecification(ValidationSpecificationFactory.Create<Account>(account));

Dadurch ist die Bedingung, Kontextabhängige Validierungsregeln festlegen zu können, erfüllt.

Man kann generische Spezifikationen definieren, die die Regeln für verschiedene Zwecke, z.B. für Persistieren oder auch einfach nur für Akzeptieren definieren:

   
    public interface IValidationSpecification
    {
        IList<IRule> GetValidationRules();
        IList<IRule> GetValidationRulesRegardingPersistence();
    }

Hier der komplette Quellcode zum Herunterladen.