Die Kombination von funktionalen und objektorientierten Sprachelementen mit F# und C#

Die Seite wird erstellt Hortensia Böhme
 
WEITER LESEN
Die Kombination von funktionalen und objektorientierten Sprachelementen mit F# und C#
Die Kombination von funktionalen
                 und objektorientierten
         Sprachelementen mit F# und C#

                   Bachelorarbeit

                     zur Erlangung
               des akademischen Grades
            BACHELOR OF SCIENCE (B.SC.)
          im Studiengang Allgemeine Informatik

          vorgelegt an der Fachhochschule Köln
                    Campus Gummersbach
    Fakultät für Informatik und Ingenieurwissenschaften

                    ausgearbeitet von:
                   Michael Morbach

Erstprüfer/in: Prof. Dr. Erich Ehses (Fachhochschule Köln)
  Zweitprüfer/in: Prof. Dr. Victor (Fachhochschule Köln)

               Gummersbach, im Juli 2013
Die Kombination von funktionalen und objektorientierten Sprachelementen mit F# und C#
I                                         Kurzfassung

    Kurzfassung
    Die vorliegende Bachelorarbeit beschäftigt sich vorwiegend mit der Fragestellung in-
    wieweit sich die Paradigmen der funktionalen und der objektorientierten Programmie-
    rung in der heutigen Softwareentwicklung im .NET Umfeld kombinieren lassen und wie
    sie sich bereits darin äußern. Eine ausführliche Einführung in die funktionale Program-
    mierung soll dazu beitragen, einen Einblick in die Konzepte und die Sichtweise des
    funktionalen Entwickelns und Denkens zu erlangen. Diese Einblicke werden durch den
    Entwicklungsprozess einer Anwendung bestärkt, der praxisnah darstellt, in welchen
    Bereichen sich die beiden Paradigmen ergänzen können.

    Abstract
    This bachelor thesis deals mainly with the question how far it is practically possible to
    combine the paradigms of functional- and object oriented programming in a .NET envi-
    ronment and how they do manifest themselves already. A detailed introduction to
    functional programming should help to gain an insight into the functional concepts and
    thinking. These insights are strengthened by the development process of an application,
    which demonstrates where functional and object oriented programming complement
    each other.
Die Kombination von funktionalen und objektorientierten Sprachelementen mit F# und C#
II                                                        Inhaltsverzeichnis

     Inhaltsverzeichnis

     Kurzfassung ...................................................................................................................... I

     Abstract............................................................................................................................. I

     Inhaltsverzeichnis .......................................................................................................... II

     Abbildungsverzeichnis................................................................................................... V

     Abkürzungsverzeichnis ................................................................................................ VI

     1         Einleitung ............................................................................................................. 1

     2         Grundlagen der funktionalen Programmierung .............................................. 2
     2.1       Was ist funktionale Programmierung? .................................................................. 2
     2.2       Funktionale Programmierung produktiv einsetzen ............................................... 3
     2.2.1     Paradigma der funktionalen Programmierung ....................................................... 3
     2.2.2     Deklarativer Programmierstil ................................................................................ 3
     2.2.3     Verstehen was ein Programm tut ........................................................................... 5
     2.2.4     Nebenläufigkeit ..................................................................................................... 6
     2.3       Beispiele funktionaler Programmierung................................................................ 7
     2.3.1     Das Verarbeiten von Daten mit LINQ ................................................................... 7
     2.3.2     Beschreibung einer Benutzeroberfläche mit XAML ............................................. 8
     2.3.3     Komposition .......................................................................................................... 9

     3         Kernkonzepte von F# ........................................................................................ 11
     3.1       Auswertung funktionaler Programme ................................................................. 11
     3.1.1     Verwenden von unveränderlichen Datenstrukturen ............................................ 11
     3.1.2     Den Zustand eines Programms durch Rekursion verändern ............................... 12
     3.1.3     Verwenden von Ausdrücken an Stelle von Anweisungen .................................. 13
     3.2   Schreiben von deklarativem Code ....................................................................... 14
     3.2.1 Funktionen als Argumente .................................................................................. 14
     3.2.2 Funktionen höherer Ordnung .............................................................................. 15
     3.3       Typen in der funktionalen Programmierung ....................................................... 16

     4         Anwendungskonzept Pixxler ............................................................................ 18
     4.1       Serviceorientierte Architektur ............................................................................. 18
     4.2       WCF Service Pixxler ........................................................................................... 19
     4.3       Pixxler API .......................................................................................................... 19
     4.4       Clientanwendung Pixxler .................................................................................... 20
     4.5       F# Bibliothek ....................................................................................................... 20
Die Kombination von funktionalen und objektorientierten Sprachelementen mit F# und C#
III                                                        Inhaltsverzeichnis

      5         Implementierung des Pixxler Services............................................................. 21
      5.1       Was ist ein WCF Service ..................................................................................... 21
      5.2       Einrichten der Datenbank .................................................................................... 22
      5.3   Ansteuerung der Datenbank aus dem Code......................................................... 23
      5.3.1 Einsatz des Entity Frameworks zur Abbildung des Datenbankmodells im
            Code ..................................................................................................................... 24
      5.3.2 Was ist LINQ? ..................................................................................................... 25
      5.4       Authentifizierung eines Benutzers ...................................................................... 27
      5.4.1     Annotation von Klassen und Methoden .............................................................. 27
      5.4.2     Schnittstellendefinition zum Authentifizieren ..................................................... 28
      5.4.3     Abfragen von Daten aus der Datenbank mit LINQ ............................................. 29
      5.4.4     Das Repository Entwurfsmuster .......................................................................... 29
      5.4.5     Validieren eines Benutzers .................................................................................. 30

      6         Funktionale Bibliothek mit F# ......................................................................... 33
      6.1   Parallelisierungstechniken ................................................................................... 33
      6.1.1 Parallelisieren von kleinen Codesegmenten ........................................................ 33
      6.2       Implementierung der grafischen Effekte ............................................................. 34
      6.2.1     Berechnungen von Farben ................................................................................... 35
      6.2.2     Implementieren und Anwenden von Farbfiltern ................................................. 36
      6.2.3     Implementieren eines Unschärfeeffekts .............................................................. 39
      6.3       Was kann F# einem C# Entwickler bieten? ........................................................ 40

      7         Implementierung des Pixxler WPF Clients ..................................................... 41
      7.1       Warum WPF? ...................................................................................................... 41
      7.2       Architektur der Anwendung ................................................................................ 42
      7.2.1     PRISM ................................................................................................................. 42
      7.2.2     Das Architekturmuster MVVM ........................................................................... 44
      7.2.3     Dependency Injection .......................................................................................... 45
      7.3       Struktur der Anwendung (Shell) ......................................................................... 46
      7.4       Implementierung der Module .............................................................................. 48
      7.4.1     Anmeldung am Service ....................................................................................... 48
      7.4.2     Übersicht über die Alben ..................................................................................... 49
      7.4.3     Bearbeiten von Bildern ........................................................................................ 52

      8         Fazit .................................................................................................................... 53
      8.1       Zusammenfassung ............................................................................................... 53
      8.2       Wie hat sich die funktionale Programmierung eingebracht ................................ 54
      8.2.1     LINQ zur Abfrage von Datenstrukturen.............................................................. 54
      8.2.2     WPF & XAML zur Gestaltung von Oberflächen ................................................ 55
      8.2.3     F# zur Implementierung von Kernfunktionalitäten ............................................. 56
Die Kombination von funktionalen und objektorientierten Sprachelementen mit F# und C#
IV                                                 Inhaltsverzeichnis

     8.3   Persönliches Fazit ................................................................................................ 56

     9     Literaturverzeichnis .......................................................................................... 58
Die Kombination von funktionalen und objektorientierten Sprachelementen mit F# und C#
V                                              Abbildungsverzeichnis

    Abbildungsverzeichnis
    Abbildung 1: SOA (Crofton, 2010) ................................................................................ 18
    Abbildung 2: WCF - ABC Prinzip ................................................................................ 22
    Abbildung 3: ER Modell der Datenbank ........................................................................ 23
    Abbildung 4: EF Modell der Datenbank im Code .......................................................... 25
    Abbildung 5: Definition des Interfaces für den BenutzerService ................................... 28
    Abbildung 6: Das Repository Entwurfsmuster .............................................................. 30
    Abbildung 7: Das BenutzerRepository ........................................................................... 30
    Abbildung 8: Die DataContracts..................................................................................... 32
    Abbildung 9: Modell des PRISM Frameworks ............................................................. 44
    Abbildung 10: Modell des MVVM Entwurfsmusters ................................................... 45
    Abbildung 11: Struktureller Aufbau des WPF Clients ................................................... 46
    Abbildung 12: Login am Service .................................................................................... 48
    Abbildung 13: Login Sequenzdiagramm ........................................................................ 49
    Abbildung 14: Inhalte eines Albums darstellen.............................................................. 50
    Abbildung 15: Ein Bild im Detail aufrufen .................................................................... 51
    Abbildung 16: Ein Bild bearbeiten ................................................................................. 52
Die Kombination von funktionalen und objektorientierten Sprachelementen mit F# und C#
VI                            Abkürzungsverzeichnis

     Abkürzungsverzeichnis
     API     Application Programming Interface

     CLR     Common Language Runtime
     DI      Dependency Injection

     EF      Entity Framework (5.0)

     GUID    Globally Unique Identifier

     IoC     Inversion of Control
     LINQ    Language Integrated Query

     MVVM    Model-View-ViewModel

     SOAP    Simple Object Access Protocol
     SoC     Separation of Concerns

     UI      User Interface

     WCF     Windows Communication Foundation
     WPF     Windows Presentation Foundation

     XAML    Extensible Application Markup Language
Die Kombination von funktionalen und objektorientierten Sprachelementen mit F# und C#
1                                             Einleitung

    1      Einleitung
    Die letzten Jahrzehnte hat die objektorientierte Programmierung den Markt in der Soft-
    wareentwicklung dominiert, indem sie es erreichte, die Komplexität einer Anwendung
    mit Struktur zu versehen und Sprachen für Entwickler intuitiv einsetzbar zu machte.

    Doch nicht jede Art von Komplexität lässt sich mit Hilfe von Objekten abbilden. Einige
    Bereiche, die z.B. Berechnungen, Analysen oder Transformationen betreffen, ziehen
    keinen Nutzen aus Objekten. Somit stehen Entwickler in der heutigen Zeit neuen Her-
    ausforderungen gegenüber. Es müssen Programme entwickelt werden, die eine große
    Menge an Daten schnell und sparsam verarbeiten können und gleichzeitig auf mehrere
    Prozessoren zugeschnitten sind.

    Aus dem Schatten der wissenschaftlichen Institutionen haben sich die funktionalen und
    deklarativen Techniken der Softwareentwicklung in den vergangenen Jahren mehr und
    mehr auch in der Wirtschaft bewährt. In C# wurden generics, anonyme Funktionen und
    Ausdrücke zur Abfrage von Daten eingebaut. Eine ausgereifte kommerzielle funktionale
    Sprache blieb allerdings bisher aus. Mit F# entwickelte Microsoft seit 2002 eine Spra-
    che die sowohl funktional ist, zudem aber über das .NET Objektmodell ebenso Zugriff
    auf objektorientierte Bereiche besitzt.

    Programmiersprachen in der heutigen Zeit sind multiparadigmatisch. Objektorientierte
    und funktionale Programmierung geht mehr und mehr in einander über und bietet somit
    eine weitläufige Liste von einsetzbaren Möglichkeiten bei der Entwicklung von An-
    wendungen. So kann bereits jetzt in C# auf viele funktionale Techniken zurückgegriffen
    werden..

    Funktionale Programmierung jedoch beschränkt sich nicht nur auf die Art und Weise
    wie Code geschrieben wird. Mehr ist es eine andere Sichtweise wie Probleme gelöst
    werden können. In dieser Arbeit sollen diese Betrachtungsweise und einige anwendbare
    Techniken bei der Entwicklung einer Software, die sowohl das objektorientierte als
    auch das funktionale Paradigma nutzt, aufgezeigt werden.
Die Kombination von funktionalen und objektorientierten Sprachelementen mit F# und C#
2                             Grundlagen der funktionalen Programmierung

    2          Grundlagen der funktionalen Programmierung
    Funktionale Sprachen sind Ausdrucksstart und erledigen sogar große Aufgaben, obwohl
    der dazu geschriebene Code meist minimalistisch ist. Funktionaler Code wird ergebnis-
    orientierter verfasst und die Art und Weise wie Anweisungen ausgeführt werden, kann
    besser vor den Entwicklern versteckt werden. Es ist insgesamt unwichtiger worden wie
    die Ergebnisse erreicht werden, denn dieser Weg zur Ergebnisfindung muss nur ein ein-
    ziges Mal spezifiziert werden.

    2.1        Was ist funktionale Programmierung?

    Es existiert eine ganze Reihe von unterschiedlichen funktionalen Sprachen und es gibt
    keine Funktionalitäten die eben jede dieser Sprachen besitzen müsste. Daher ist es
    schwierig eine allgemeingültige Definition, die auf die funktionale Programmierung
    zutrifft, zu finden. Was die Sprachen miteinander verbindet sind eher allgemeine As-
    pekte. Dennoch hat jede dieser Sprachen einen eigenen Stil, um Lösungen für Probleme
    zu schaffen. Funktionale Programmierung lässt sich daher wohl am besten im Vergleich
    zur imperativen Programmierung beschreiben.

    „Functional programming is a style of programming that emphasizes the evaluation of
    expressions, rather than execution of commands. The expressions in these languages
    are formed by using functions to combine basic values“ 1

    Der funktionale Ansatz wird aus dem ersten Satz gut ersichtlich. Die „Auswertung von
    Ausdrücken“ repräsentiert den funktionalen Aspekt und die „Ausführung von Anweisun-
    gen“ den imperativen Aspekt.

              Ausführung von Anweisungen – Ein Programm wird als eine Verkettung von Be-
               fehlen ausgedrückt. Die Befehle beschreiben wie das Ende des Programms er-
               reicht wird und was für Objekte während dieses Prozesses erstellt und verändert
               werden.
              Auswertung von Ausdrücken – Ein funktionales Programm entspricht eher einem
               Ausdruck der beschreibt wie z.B. die Eigenschaften von einem Objekt aussehen

    1
        (Hutton, 2002) http://www.cs.nott.ac.uk/~gmh/faq.html
Die Kombination von funktionalen und objektorientierten Sprachelementen mit F# und C#
3                        Grundlagen der funktionalen Programmierung

           sollen nachdem es erstellt wurde. Es werden keine einzelnen Schritte vorgege-
           ben, die besagen wie das Objekt zusammengebaut wird und es besteht keine
           Möglichkeit die Erzeugung eines Objektes zu beeinflussen, bevor es nicht er-
           stellt wurde. Sollte also z.B. eine Tasse Kaffee mit Zucker erstellen werden, so
           könnte der Kaffee nicht getrunken werden bevor der Zucker enthalten ist, denn
           wenn das Objekt erstellt ist enthält es den Zucker bereits.

    Der wesentliche Unterschied ist also der, dass bei der funktionalen Programmierung
    Code in Form von Ausdrücken anstatt in einer Reihe von Anweisungen geschrieben
    wird. Aus diesem Grund wird Code in der funktionalen Programmierung auf eine ganz
    andere Art und Weise verfasst und gekapselt.

    2.2    Funktionale Programmierung produktiv einsetzen

    Entwickler schätzen die funktionale Programmierung oft durch ihre ausdrucksstarke
    und lesbare Art. Dies ist jedoch noch lange kein Grund es auch wirklich zu praktizieren.
    In diesem Kapitel soll der Nutzen und die Vorteile der funktionalen Programmierung
    herausgestellt werden.

    2.2.1 Paradigma der funktionalen Programmierung

    Funktionales Programmieren ist ein Programmierparadigma. Das bedeutet, dass es
    Konzepte definiert, die genutzt werden können um bestimmte Probleme zu lösen. In der
    Objektorientierten Programmierung wird über Problemlösungen in Form von Objekten
    nachgedacht. Jede Sprache ist im speziellen etwas anders. So bietet C++ die mehrfache
    Vererbung und JavaScript die Prototypen. Funktional zu programmieren bedeutet je-
    doch nicht gleichzeitig auf das jeweils andere Paradigma zu verzichten. So bietet die
    Sprache C#, welche eine im Kern objektorientierte Sprache ist, seit der Version 3.0 auch
    einige funktionale Möglichkeiten die ausgenutzt werden können. Auf der anderen Seite
    ist F# eine funktionale Sprache, die jedoch das vollständige .NET Objektmodell unter-
    stützt. Es kann also in beiden Fällen genau das Paradigma für ein Problem gewählt wer-
    den, welches für die Lösung am besten geeignet ist.

    2.2.2 Deklarativer Programmierstil

    Beim deklarativen Programmierstil wird die Logik eines Programmes ausgedrückt, ohne
    auf konkrete Implementierungsdetails näher einzugehen. Diese Beschreibung könnte
4                       Grundlagen der funktionalen Programmierung

    zwar auch auf die Definition der funktionalen Programmierung passen, jedoch ist die
    Idee der deklarativen Programmierung sehr viel weitläufiger und kann mit vielen unter-
    schiedlichen Technologien umgesetzt werden. Da sich diese Arbeit unter anderem auf
    die funktionale Programmierung konzentriert, wird im Folgenden demonstriert wie an-
    hand einer funktionalen Sprache deklarativer Code geschrieben werden könnte.

    Anwendungen werden implementiert, indem einem Computer die Ziele anhand eines
    vorgegebenen Vokabulars, welches dieser interpretieren kann, beschrieben werden. Bei
    der imperativen Programmierung besteht dieses Vokabular aus einzelnen Befehlen. Es
    besteht allerdings immer die Möglichkeit neue Befehle, wie z.B. „Zeige Kundende-
    tails“, hinzuzufügen. Das gesamte Programm ist jedoch lediglich eine Aneinanderrei-
    hung von einzelnen Schritten, die beschreiben wie eine Gesamtaufgabe erledigt werden
    soll. Eine Aufgabe könnte zum Beispiel wie folgt lauten:

    „Nimm den nächsten Kunden aus der Liste. Wenn der Kunde in Deutschland wohnt,
    dann zeige seine Details. Wenn mehrere Kunden in der Liste vorhanden sind gehe zum
    Anfang“

    Sobald ein Programm wächst, wird die Anzahl an Befehlen in dem Vokabular schnell
    größer und es wird immer schwieriger dieses zu verwenden. Der objektorientierte An-
    satz erleichtert dies, weil dieser eine Ordnung und Organisation in die anlaufenden Be-
    fehle bringt. So könnten alle Befehle, die mit Kunden zu tun haben, in einer Klassen-
    struktur unterbringen. Das Programm selbst wäre jedoch immer noch eine Sequenz aus
    Befehlen.

    Funktionale Programmierung bietet einen ganz anderen Ansatz dieses Vokabular zu
    erweitern. Anstatt sich darauf zu beschränken nur neue Befehle zu erstellen, wird darauf
    gesetzt neue Kontrollstrukturen zu erzeugen – Primitive die beschreiben wie Befehle
    miteinander verknüpft werden können. In imperativen Programmen wird eine Sequenz
    von Befehlen zusammengestellt, die eine beschränkte Anzahl von eingebauten Kontroll-
    strukturen wie z.B. Schleifen nutzt. Wenn jedoch ein typisches Programm betrachtet
    wird, so lässt sich beobachten, dass sich die meisten Strukturen wiederholen. Einige
    dieser Strukturen sind bekannt und werden Entwurfsmuster genannt.

    In dem Kundenbeispiel lässt sich ebenfalls ein Muster erkennen. „Führe den ersten
    Befehl für jeden Kunden aus bei dem der Zweite Befehl ‚wahr‘ zurückgibt“. Diesen
    Ausdruck kann man auch simplifizieren zu „Zeige die Kundendetails für jeden Kunden
5                         Grundlagen der funktionalen Programmierung

    aus Deutschland“. In diesem Satz ist „Zeige Kundendetails“ das erste Argument und
    „aus Deutschland“ das Zweite.

    Beide Sätze zur Lösung desselben Problems werden nun gegenübergestellt:

             Nimm den nächsten Kunden aus der Liste. Wenn der Kunde in Deutschland
              wohnt, dann zeige seine Details. Wenn mehrere Kunden in der Liste vorhanden
              sind gehe zum Anfang
             Zeige die Kundendetails für jeden Kunden aus Deutschland

    Es lässt sich klar erkennen, dass im ersten Satz genau beschreiben wird wie das Ziel
    erreicht werden kann, während der zweite Satz beschreibt was genau erreicht werden
    soll. Dies ist auch gleichzeitig der essentielle Unterschied zwischen imperativer und
    deklarativer Programmierung.

    2.2.3 Verstehen was ein Programm tut

    Ein gewöhnliches Programm besteht aus allerhand Objekten die einen internen Zustand
    haben, der entweder direkt oder durch Methodenaufrufe verändert werden kann. Das
    bedeutet, dass es sehr schwierig sein kann zu erkennen welche Eigenschaften sich durch
    einen Methodenaufruf verändert haben. Folgendes Beispiel verdeutlicht dies:

     Ellipse und Rechteck (C#)

     Ellipse el = new Ellipse( new Rectangle( 0, 0, 100, 100 ) );
     Rectangle rc = el.BoundingBox;
     rc.Inflate( 10, 10 );
     return el;

    Bei diesem Ausschnitt kann man nicht wissen, welchen Zustand die zurückgegebene
    Ellipse haben wird, ohne den Code auszuführen. Besitzt die BoundingBox eine Rückre-
    ferenz zur Ellipse und verändert die Methode Inflate(x,y) das Rechteck oder gibt es
    ein neues Rechteck zurück? Wäre letzteres der Fall, so hätte die dritte Zeile keinerlei
    Effekt.

    Bei der funktionalen Programmierung sind die meisten Datenstrukturen nicht veränder-
    lich. Somit kann eine erzeugte Ellipse nach ihrer Erzeugung nicht mehr verändert wer-
    den. Das einzige was getan werden könnte, wäre eine neue Ellipse zu erzeugen und mit
    anderen Parametern zu initialisieren. Das erleichtert das Lesen von Quelltext erheblich
    wie im nächsten Beispiel leicht zu erkennen ist.
6                              Grundlagen der funktionalen Programmierung

        Ellipse und Rechteck (C#)

        Ellipse el = new Ellipse( new Rectangle( 0, 0, 100, 100 ) );
        Rectangle rc = el.BoundingBox;
        Rectangle rcNew = rc.Inflate( 10, 10 );
        return new Ellipse( rcNew );

    Beim Schreiben von funktionalen Programmen mit unveränderlichen Typen ist das Ein-
    zige, was eine Methode tun kann, ein Rückgabewert liefern. Wie man im Beispiel er-
    kennen kann gibt die Methode Inflate(x,y) ein neues Rechteck zurück. Dies ist keine
    neue Idee in der .NET Welt, denn es existieren auch andere Typen die genauso funktio-
    nieren, wie z.B. der Typ DateTime oder String.

    Die Lesbarkeit des Quellcodes wird durch diese Variante maßgeblich verbessert. Die
    Lesbarkeit ist jedoch nicht der einzige Grund für diesen Ansatz. Ein weiterer Grund ist
    die Entwicklung von Anwendungen mit Unterstützung für mehrere Kerne.

    2.2.4 Nebenläufigkeit

    Möchte man in der traditionellen imperativen Programmierung eine nebenläufige An-
    wendung entwickeln, so stößt man auf folgende Probleme:

              Es ist schwer, existierenden sequenziellen Code in parallel ablaufenden Code
               umzuwandeln, da eine große Menge an Code explizit so umgeschrieben werden
               muss, dass Threads verwendet werden.
              Es muss sehr genau geprüft werden, dass beim Zugriff auf Objekte keine Dead-
               locks auftreten können und dennoch muss genügend Spielraum zur parallelen
               Ausführung bestehen bleiben.

    Die Funktionale Programmierung hat darauf folgende Antworten:

              Bei Verwendung des deklarativen Programmierstils kann Nebenläufigkeit in be-
               stehenden Code eingeführt werden. Durch Ersetzen der Primitive, die bestim-
               men wie Befehle kombiniert werden, ist dies jederzeit möglich.
              Dank der Unveränderlichkeit von Objekten ist es unmöglich, dass race
               conditions2 oder deadlocks3 auftreten. Es ist außerdem direkt ersichtlich, welche
               Teile des Programms unabhängig laufen.

    2
        Eine Konstellation in der das Ergebnis einer Operation durch andere Einzeloperationen beeinflusst wird
    3
        Ein Zustand, bei dem mehrere Prozesse auf die Zustandsänderung eines anderen warten und sich gegen-
          seitig behindern
7                        Grundlagen der funktionalen Programmierung

    Durch diese beiden Aspekte wird das Design einer Anwendung maßgeblich beeinflusst,
    was zu einer Erleichterung beim Schreiben von parallel ausführbarem Code führt wo-
    durch auch der Vorteil von Mehrkernprozessoren ausgenutzt werden kann. Es sollte
    jedoch beachtet werden, dass die Parallelisierung von Code nicht allein durch den Ein-
    satz von nicht veränderlichem Code eintritt, sondern lediglich erleichtert wird.

    2.3    Beispiele funktionaler Programmierung

    Im Folgenden soll anhand einiger kleinerer Beispiele gezeigt werden, dass funktionale
    Programmierung nicht nur in der Theorie einsetzbar ist. Es wird außerdem auf die de-
    klarative Programmierung sowie ihre Vorteile anhand von LINQ und XAML eingegan-
    gen.

    2.3.1 Das Verarbeiten von Daten mit LINQ

    LINQ wurde von Microsoft entwickelt, um ein einheitliches Verfahren für den Zugriff
    auf Datenstrukturen verschiedener Arten bereitzustellen. Im Folgenden soll anhand ei-
    nes Codebeispiels gezeigt werden, welche Vorteile sich durch den deklarativen Pro-
    grammierstil ergeben.

     Imperative Datenverarbeitung (C#)

     public IEnumerable GetExpensiveProducts()
     {
         List filteredInfos = new List();
         foreach ( Product product in this.Products )
         {
             if ( product.UnitPrice > 75.0M )
             {
                 filteredInfos.Add( String.Format( "{0} - €{1}",
                   product.ProductName, product.UnitPrice ) );
             }
         }
     }

    Dieses Codebeispiel ist als eine Sequenz von Befehlen im imperativen Stil geschrieben.
    Es wird eine neue Liste erzeugt, danach über alle bestehenden Produkte iteriert und an-
    schließend werden die Produkte, die einen bestimmten Preis übersteigen, in eine neue
    Liste eingefügt. Beschreiben wir das Problem etwas abstrakter, so wird klar, dass ledig-
    lich eine Auflistung von Produkten gefiltert werden soll.
8                        Grundlagen der funktionalen Programmierung

    Mit C#, ab der Version 3.0, kann dieses Problem auch mit Hilfe von LINQ gelöst wer-
    den. Das folgende Codebeispiel beschreibt wesentlich anschaulicher und lesbarer, wel-
    ches eigentliche Ziel erreicht werden soll.

     Deklarative Datenverarbeitung mit LINQ (C#)

     public IEnumerable GetExpensiveProducts()
     {
            return from product in this.Products
                   where product.UnitPrice > 75.0M
                   select String.Format( "{0} - €{1}", product.ProductName,
                                                       product.UnitPrice );
     }

    Dieser einzelne zusammenhängende Ausdruck besteht aus elementaren Operatoren wie
    z.B. select und where. Diese Operatoren nehmen wiederum andere Ausdrücke als
    Argumente, um zu ermitteln was gefiltert werden soll und welches Ergebnis zurückge-
    geben werden soll. Diese Operatoren geben dem Entwickler also eine Möglichkeit, ver-
    schiedene Teile des Codes zu kombinieren, ohne dabei mehr Code schreiben zu müssen.
    Ein weiterer interessanter Aspekt ist, dass dieser Ausdruck wesentlich einfacher zu le-
    sen ist, da die konkrete Implementierung der elementaren Operatoren vor dem Entwick-
    ler versteckt wird. Es wurde eine Lösung geschaffen, die einerseits einfacher von der
    Implementierung, als auch flexibler in der Anwendung ist. In Kapitel 6.1 wird außer-
    dem ersichtlich, dass es so einfacher ist, Code zu parallelisieren.

    2.3.2 Beschreibung einer Benutzeroberfläche mit XAML

    Die Gestaltung von Benutzeroberflächen hat sich in den vergangenen Jahren gerade
    durch den Einsatz von Designern innerhalb den Entwicklungsumgebungen stark verbes-
    sert. Code wird immer häufiger von Generatoren automatisiert erzeugt, da dieser, gerade
    bei komplexen Oberflächen, für Entwickler kaum noch überschaubar ist.

    Die Windows Presentation Foundation (WPF) und ihre enthaltene deklarative Sprache
    XAML gehen dabei einen Schritt weiter. Seit der Version 3.0 sind beide ein fester Be-
    standteil des .NET Frameworks und bringen neben dem Compiler auch einen Laufzeit-
    parser für XAML mit.

    XAML ist eine allgemein einsetzbare deklarative Sprache und besonders geeignet um
    Benutzeroberflächen zu gestalten. Sie ermöglicht die Trennung zwischen dem Teil, der
    die Ansicht der Oberfläche beschreibt und dem Teil, der die konkrete Programmlogik
9                        Grundlagen der funktionalen Programmierung

    enthält. Genau wie bei XML wird die Beschreibung der Oberfläche in einer Baumstruk-
    tur repräsentiert. Dadurch werden eine wesentlich schlankere Form der Oberfläche so-
    wie eine bessere Lesbarkeit gewährleistet. Einen Designer gibt es nach wie vor, jedoch
    sind Anpassungen an automatisch generierten Code einfacher möglich.

     Erzeugung eines UI im deklarativen Stil (XAML)

    Der XAML Code beschreibt die Benutzeroberfläche durch den Einsatz elementarer
    Schlüsselworte und das Festlegen von bestimmten Eigenschaften, so dass der gesamte
    Code zu einem einzigen Ausdruck wird. Auch hier wird wieder sehr deutlich, dass le-
    diglich festgelegt wird was das Ergebnis sein soll und das wie in einer Blackbox vor den
    Entwicklern versteckt wird.

    2.3.3 Komposition

    Es wurde bereits gezeigt, dass es möglich ist, viele Probleme durch den deklarativen Stil
    einfacher zu lösen, wenn zu diesem Zweck zuvor die nötigen Bibliotheken erstellt wur-
    den. Datenstrukturen können mit Hilfe von LINQ einfach abgefragt und Benutzerober-
    flächen mit XAML leicht verständlich erstellt werden.

    Für die spezifischeren Probleme, die einen eigenen Bereich betreffen, gibt es jedoch
    meist keine vorgefertigten Bibliotheken. Die Funktionalität, die vor den Entwicklern in
    einer Blackbox versteckt wird, entsteht jedoch nicht auf magische Weise, sondern muss
    zunächst einmal implementiert und in einer Bibliothek gekapselt werden. Im Folgenden
    wird beispielhaft gezeigt wie solch eine Bibliothek entstehen könnte.

     Erstellen einer funktionalen Animation (C#)

     var green = Anims.Circle(Brushes.OliveDrab, 100.0f.Anim());
     var blue = Anims.Circle(Brushes.SteelBlue, 100.0f.Anim());
     var animatedPos = Time.Wiggle * 100.0f.Anim();

     var greenMove = green.MoveXY(animatedPos, 0.0f.Const());
     var blueMove = blue.MoveXY(0.0f.Const(), animatedPos);
     var animation = Anims.Compose(greenMove, blueMove);
10                       Grundlagen der funktionalen Programmierung

     Es ist nicht wichtig das Beispiel im Detail zu verstehen. Im Grunde genommen werden
     lediglich 2 Kreise erzeugt, eine Bewegung mit Hilfe der MoveXY Methode erzeugt und
     durch die Compose Methode in eine einzelne Animation gekapselt.

     Ein wichtiger Aspekt von deklarativen Bibliotheken ist die Tatsache, dass sie kombi-
     nierbar eingesetzt werden können. In diesem Beispiel ist eine solche Komposition z.B.
     durch das Erstellen einer einzelnen Animation aus mehreren einzelnen Bewegungen
     deutlich geworden. Ein anderes Beispiel wäre LINQ, wo komplexe Abfragen aus meh-
     reren einzelnen kleineren Abfragen erstellt werden können. Somit könnten z.B. auch
     eigene Primitive erzeugt werden, um damit Animationen zu erstellen.
11                                            Kernkonzepte von F#

     3          Kernkonzepte von F#
     Der Fokus in diesem Kapitel liegt darauf, die Kernkonzepte der Sprache F# kennenzu-
     lernen und einen Einblick in allgemeine Ideen sowie elementare Techniken der funktio-
     nalen Programmierung zu bekommen.

     3.1        Auswertung funktionaler Programme

     Im vorherigen Kapitel wurde bereits angedeutet, dass funktionale Programme unverän-
     derliche Datenstrukturen nutzen. Man mag sich nun fragen, wie ein Programm über-
     haupt etwas tun kann, wenn alles unveränderlich ist. Die Antwort ist kurz wie auch ein-
     fach. Ein funktionales Programm wird nicht als eine Verkettung von Ausdrücken be-
     schrieben die den Zustand verändern sondern mehr als eine systematische Anwendung
     von Regeln.4

     3.1.1 Verwenden von unveränderlichen Datenstrukturen

     Wird innerhalb eines funktionalen Programmes von Datenstrukturen gesprochen, so
     sind im allgemeinen Werttypen oder Klassen, wie sie aus C# bekannt sind, gemeint.
     Diese Datenstrukturen sind in F# unveränderlich, sobald sie zum ersten Mal initialisiert
     wurden. In C# können einzelne Daten mit Hilfe des Schlüsselwortes readonly eben-
     falls als unveränderlich gekennzeichnet werden. Ebenso ist es auch möglich in F# ver-
     änderliche Typen zu erzeugen, jedoch ist der Standard, dass Typen nicht veränderlich
     sind. Das bedeutet auch, dass Methodenaufrufe nicht den Zustand einer Struktur verän-
     dern, sondern stets einen Rückgabewert besitzen der weiter verarbeitet werden muss.
     Das kann bei der Initialisierung einer Liste z.B. wie folgt aussehen.

         Erstellen einer Liste

         var list = ImmutableList.Empty().Add(1).Add(3).Add(5).Add(7);

     Dieses Beispiel ist jedoch extrem simpel und sobald darüber nachgedacht wird ein
     komplexeres Problem auf dieselbe Weise anzugehen, kann es schwierig werden.

     4
         Vgl. computation by calculation (Hudak, 2000)
12                                              Kernkonzepte von F#

     3.1.2 Den Zustand eines Programms durch Rekursion verändern

     Um aufzuzeigen wie komplexere Probleme gelöst werden können, wird im Folgenden
     eine Funktion implementiert, die die Zahlen x bis y aufsummiert, ohne dabei auf lokale
     Variablen zurückzugreifen. Im einfachsten Sinne und durch Verwendung lokaler Vari-
     ablen könnte diese Funktion wie folgt aussehen:

         Aufsummieren von Zahlen mit lokaler Variable (C#)

         int SumNumbers( int from, int to )
         {
             int res = 0;
             for ( int i = from; i        to ) return 0;
             int sumRest       = SumNumbers( from + 1, to );
             return from       + sumRest;
         }

     Dieses Beispiel ist funktional, da es lediglich mit Wertzuweisungen und Rückgabewer-
     ten arbeitet. Die Rekursion wird hier durch einen Selbstaufruf und eine Abbruchbedin-
     gung innerhalb der Funktion repräsentiert. Der Zustand der Berechnung wird nun nicht
     mehr in einer lokalen Variablen festgehalten, sondern wird durch die Rekursion selbst
     ausgedrückt. Den rekursiven Teil einer Berechnung jedes Mal selbst zu schreiben wäre
     jedoch aufwändig und auch hier gibt es wiederum einen Weg den schwierigen Teil zu
     verstecken und Probleme zu lösen ohne explizit auf Rekursionen zurückzugreifen.

     5
         Eine Technik, in der eine Funktion sich selbst über den Aufruf von selbst definiert
13                                     Kernkonzepte von F#

     3.1.3 Verwenden von Ausdrücken an Stelle von Anweisungen

     Bei der imperativen Programmierung ist ein Ausdruck ein einfaches Stück Code, wel-
     ches ausgewertet wird und dann ein Ergebnis liefert. So ist z.B. ein Methodenaufruf
     bzw. die Verwendung eines booleschen- oder Zahlenoperators ein Ausdruck. Eine An-
     weisung hingegen ist ein Stück Code welches den Zustand des Programms verändert.
     Eine Anweisung wäre somit z.B. der Aufruf einer Methode, die keinen Rückgabewert
     besitzt oder die Zuweisung eine Wertzuweisung zu einer Variablen.

     Bei funktionalen Sprachen wird der Zustand durch das Ergebnis einer Funktion reprä-
     sentiert und weitergegeben. Wird diese Logik weiter verfolgt, so lässt sich sagen, dass
     in der funktionalen Sprache alles als Ausdruck bezeichnet werden kann. Betrachtet man
     nochmals das Beispiel aus dem vorherigen Abschnitt, in welchem Zahlen aufaddiert
     wurden, so lässt sich feststellen, dass es nicht vollkommen funktional ist, da es in einer
     Folge von drei Anweisungen geschrieben ist. Mit Hilfe einer kleinen Anpassung lässt
     sich dieses Beispiel jedoch auf eine vollständig funktionale Version verbessern.

      Aufsummieren von Zahlen durch Rekursion (C#)

      int SumNumbers( int from, int to )
      {
          return ( from > to ) ? 0
                               : { int sumRest = SumNumbers( from + 1, to );
                                   from + sumRest; }
      }

     Der Methodenkörper ist jetzt rein funktional, da er nur noch aus einem einzelnen Aus-
     druck besteht. Dies ist in der Sprache C# nur in relativ seltenen Fällen möglich, da in-
     nerhalb von konditionellen Auswertungen keine lokalen Variablen verwendet werden
     können. Obwohl dieses Beispiel sehr minimalistisch gehalten ist, gibt es einen Hinweis
     darauf, was man in der funktionalen Sprache alles schreiben kann:

           Der Methodenkörper ist ein einzelner Ausdruck. In C# bedeutet das auch, dass
            der Körper mit dem Schlüsselwort return beginnt.
           Da If-Then-Else ebenfalls eine Anweisung ist, muss man auf den konditionel-
            len Operator (?:) zurückgreifen.
           Der Ausdruck im else Block enthält eine Variablendeklaration gefolgt von ei-
            nem Ausdruck. Es wird eine lokale Variable sumRest deklariert welche im rest-
            lichen Codeblock verfügbar bleibt. Variablendeklarationen in F# funktionieren
            auf dieselbe Art und Weise. Die Deklaration ist zwar kein Ausdruck aber ein
14                                   Kernkonzepte von F#

            syntaktisches Hilfskonstrukt welches an einen Ausdruck angehangen werden
            kann.

     3.2    Schreiben von deklarativem Code
     Bisher wurde lediglich beleuchtet, welche Auswirkungen die deklarative Programmie-
     rung hat und in wie weit die Anwendung dieses Programmierstils das Entwickeln er-
     leichtern kann. Die folgenden Kapitel sollen zeigen, wie dies auf der technischen Seite
     überhaupt möglich gemacht wurde.

     Aus der technischen Sicht deuten zwei Aspekte besonders auf den deklarativen Stil hin.
     Der Erste von beiden wurde zuletzt behandelt – nämlich das jedes Sprachkonstrukt ein
     Ausdruck ist. Es wird kein genaues Wissen mehr über einzelne Anweisungen benötigt,
     da sich ein Programm aus Ausdrücken zusammensetzt die miteinander kombiniert wer-
     den. Der Zweite Aspekte beschäftigt sich mit dem Problem, dass Funktionen für unter-
     schiedliche Zwecke eingesetzt werden können.

     3.2.1 Funktionen als Argumente

     Wird der zweite Aspekt aus Kapitel 3.2 betrachtet, so stellt kommt folgende Fragen
     zustanden: „Wie lässt sich der variable Teil einer Methode von dem immer gleichblei-
     benden Teil separieren?“. Die Antwort auf diese Frage ist relativ einfach: „Der gleich-
     bleibende Teil bildet den Körper der Methode und die Parameter bilden den variablen
     Teil, den die Methode ausführen soll“.

     Eine Modifikation, an dem Beispiel SumNumbers aus Kapitel 3.1.2, könnte so aussehen,
     dass diese die Funktionalität erhält sämtliche Aggregationen durchzuführen, anstatt le-
     diglich Zahlen aufzuaddieren. Folgendes Beispiel demonstriert dies:

      Aggregieren von Zahlen durch Rekursion (C#)

      public int AggregateNumbers( Func op, int init, int from,
      int to )
      {
          if ( from > to ) return init;
          int sumRest = AggregateNumbers( op, init, from + 1, to );
          return op( from, sumRest );
      }

     Zur ursprünglichen Funktion sind zwei weitere Parameter hinzugekommen – der Initiale
     Wert (init) und eine Operation die beschreibt wie die kommenden Zahlenwerte trans-
15                                        Kernkonzepte von F#

     formiert werden sollen. Die Operation wird in Form eines delegates übergeben, wel-
     cher spezifiziert, dass er eine Funktion mit zwei Parametern vom Typ int ist und auch
     den Typ int als Rückgabewert besitzt.

     Die Idee Funktionen als Argumente zu nutzen ist eines der nützlichsten funktionalen
     Konzepte. Wird angenommen, dass eine bestehenden Kundenliste sortiert werden soll,
     so wäre der klassische objektorientierte Lösungsweg die Sort Funktion einer Liste zu
     nutzen und eine eigene Sortierklasse, die das IComparer Interface implementiert, mit zu
     übergeben. Diese Klasse würde bestimmen wie zwei Elemente miteinander verglichen
     werden können. Ein nicht ganz unerheblicher Aufwand, wenn bedacht wird, dass eine
     Klasse für diesen Vorgang geschrieben, diese zum Einsatz instanziiert und abschließend
     als Argument übergeben werden müsste. Ganz davon abgesehen, dass die Lesbarkeit
     des eigentlichen Zieles nicht deutlich zu erkennen ist.

     3.2.2 Funktionen höherer Ordnung

     Inzwischen wurde gezeigt, dass Funktionen wie Werte gehandhabt werden können und
     sogar als Parameter für andere Funktionen dienen können. Es gibt zwei wichtige Begrif-
     fe die oft genutzt werden, wenn über diese Art von Funktionen gesprochen wird:

               Funktion erster Klasse (First-class function) ist eine Funktion in Form eines
                Wertes. Man kann diese also beispielsweise als Argument für eine andere Funk-
                tion weiter nutzen. Als Ergebnis haben diese Funktionen auch einen Typ, der in
                C# als delegate ausgedrückt wird. Beim Aufruf der Funktion greift diese auf
                ihren Erstellungskontext zurück. 6
               Funktion höher Ordnung (Higher-order function) bezieht sich auf eine Funkti-
                on, die wiederum eine Funktion als Argument nimmt oder als Rückgabewert be-
                sitzt. Das Beispiel aus Kapitel 3.2.1 ist beispielsweise eine Funktion höherer
                Ordnung. Diese Art der Parametrisierung wird in funktionalen Sprachen sehr
                häufig eingesetzt und hilft dabei Quellcode deklarativer zu gestalten. 7

     Mit einem weiteren Beispiel in der Sprache F# sollen diese Aspekte verdeutlicht wer-
     den. Zunächst werden aus einer Liste die ungeraden Zahlen herausgefiltert und an-
     schließend das Quadrat der jeweiligen Zahlen gebildet.

     6
         Vgl. (Microsoft, 2012)
     7
         Vgl. (Lorenz, 2009)
16                                    Kernkonzepte von F#

      Verarbeiten einer Zahlenliste mit Funktionen höherer Ordnung (F#)

      > let numbers = [1..10]
        let isOrdd(n) = n % 2 = 1
        let square(n) = n * n
        ;;

      val numbers : int list
      val isOdd : int -> bool
      val square : int -> int

      > List.filter isOdd number;;
      val it : int list = [1; 3; 5; 7; 9]

      > List.map square (List.filter isOdd numbers);;
      val it : int list = [1; 9; 25; 49; 81]

     Nachdem eine Liste mit den Zahlen von 1 bis 10 erzeugt wurde, werden zwei weitere
     Funktionen gestellt. Die Erste Funktion gibt zurück, ob der übergebene Wert (n) durch
     zwei teilbar und somit gerade oder ungerade ist. Die zweite Funktion bildet aus dem
     übergebenen Wert das Quadrat.

     Nach der Definition der Funktionen, wird eine Funktion höherer Ordnung,
     List.filter, genutzt, die wiederum als erstes Argument eine Funktion und als zweites
     Argument eine Liste einfordert. Wie anhand der folgenden Zeile zu erkennen ist, wird
     als Rückgabewert eine Liste mit ungeraden Zahlen geliefert.

     Das darauffolgende Beispiel gibt noch eine weitgehendere Idee. Es wird die Funktion
     List.map aufgerufen und als erstes Argument die zuvor geschriebene Funktion square
     übergeben. Als zweites Argument wird aber nicht etwa eine gewöhnliche vorgefilterte
     Liste übergeben, sondern wiederum eine Funktion die als Ergebnis eine Liste als Rück-
     gabewert besitzt, nämlich selbige Funktion aus dem ersten Beispiel.

     3.3    Typen in der funktionalen Programmierung
     Da funktionale Sprachen jedes Stück Code als Ausdruck werten, ist es eine eher gewag-
     te Aussage zu sagen, dass jeder Ausdruck einen Typ besitzt. Es bedeutet, dass jedes
     syntaktisch korrekte Stück Code einen bestimmten Typ hat. Dieser sagt aus was für eine
     Art von Ergebnis erwartet wird sobald ein Ausdruck ausgewertet wird und gibt somit
     eine wertvolle Information über einen Ausdruck.

     Typen können als eine Art grammatikalische Regeln für die Zusammensetzung von
     primitiven Ausdrücken gesehen werden. In funktionalen Sprachen haben Funktionen
17                                  Kernkonzepte von F#

     einen Typ, genauso wie die square Funktion aus dem vorherigen Beispiel. Dieser Typ
     bestimmt auch gleichzeitig wie eine Funktion verwendet werden kann. Wird sie mit
     einem Argument vom Typ int aufgerufen, so lautet der Typ des Rückgabewertes auch
     int.

     Wichtiger jedoch ist jedoch die Tatsache, dass der Typ auch vorgibt in wie weit eine
     Funktion mit einer anderen Funktion genutzt werden kann. So kann die Funktion squa-
     re nicht mit der Funktion List.filter verwendet werden, da die Filterung eine Funk-
     tion mit dem Typ boolean erwartet. Genau das beschreibt auch eine grammatikalische
     Regel – die Typen stellen sicher, dass Funktionen stets in einem sinnvollen Kontext
     verwendet werden.
18                                Anwendungskonzept Pixxler

     4      Anwendungskonzept Pixxler
     Um die Kombination von funktionalen und objektorientierten Sprachelementen mög-
     lichst praxisnah zu erproben, wurde im Rahmen dieser Bachelorarbeit ein Konzept für
     eine Anwendung erstellt, welche für den Rest dieser Arbeit den Arbeitstitel „Pixxler“
     trägt. Die Idee dahinter ist eine multiuserfähige Anwendung die Bilder durch verschie-
     dene Farb- und Bildfilter nachbearbeitet und in der Cloud speichert. Die Bilder werden
     dabei in zuvor, vom Benutzer, angelegten Alben gespeichert. Da die zustande kommen-
     den Daten jedoch nicht lokal beim Benutzer gespeichert werden sollen, sondern in einer
     zentralen Datenbank, korrespondiert die Anwendung mit einem Service innerhalb eines
     Netzwerks. Wichtig bei der Konzeption des Projektes war auch der Gedanke der Erwei-
     terbarkeit. Eine absolute Erweiterbarkeit kann allerdings nicht garantiert werden, denn
     diese ist für einen Entwickler immer mit zusätzlichem Aufwand und erhöhter Komple-
     xität des Programms verbunden. Bei der Abwägung einen Service als Schnittstelle für
     den Datenverkehr und andere Dienstleistungen einzusetzen überwogen die Vorteile je-
     doch dem Aufwand, besonders in Hinsicht der Multiuserfähigkeit und Erweiterbarkeit
     der gesamten Plattform. Weiterhin soll auch die Praxistauglichkeit sowie der moderne
     Ansatz der serviceorientierten Architektur in Hinsicht auf funktionale Eigenschaften
     näher untersucht werden.

     4.1    Serviceorientierte Architektur
                                            Die Idee, die hinter diesem Anwendungskonzept
                                            steckt, nennt sich serviceorientierte Architektur
                                            (SOA). Erreicht wird dadurch, dass ein oder gar
                                            mehrere unabhängige verteilte Services einen
                                            Bestandteil eines Programmes übernehmen. Ei-
                                            ne pragmatische Standardisierung von Schnitt-
                                            stellen sorgt, in Verbindung mit XML als ein-
                                            heitlichem Datenformat, für die notwendige
     Abbildung 1: SOA (Crofton, 2010)
                                            Interoperabilität. Dadurch wird außerdem ge-
     währleistet, dass unterschiedliche Endanwendungen mit Hilfe dieser externen Schnitt-
     stellen auf gleiche Weise funktionieren.
19                               Anwendungskonzept Pixxler

     4.2    WCF Service Pixxler

     Das Speichern von allen gesammelten Daten in der Cloud ist ein zentraler Aspekt in
     diesem Projekt. Alle, von Clients erzeugten Daten, sollen in einer zentralen Datenbank
     gespeichert werden. Um die Datenbank selbst jedoch nach außen hin abzusichern und
     eine komfortable und neutrale Schnittstelle für Clientanwendungen zu gewährleisten
     wird ein Service mit Hilfe der Windows Communication Foundation (WCF) entwickelt.
     Die auf Nachrichten basierte Kommunikation zwischen den Klienten und dem Service
     wird dabei über das Simple Object Access Protokoll (SOAP) realisiert. Diese Nachrich-
     ten werden verschlüsselt über einen Datenstrom versendet und sind somit gegenüber
     Dritten weitestgehend geschützt. Um gespeicherte Daten aus der Datenbank abzufragen
     wird auf einen Objektrelationalen Mapper zurückgegriffen. Dieser Mapper erleichtert
     die Ansteuerung der Datenbank aus dem Quellcode des Services und ermöglicht den
     Einsatz der funktional orientierten .NET Erweiterung LINQ to Entities. Durch den Ein-
     satz von LINQ soll außerdem gezeigt werden, welche Vorteile der funktionale Ansatz
     auch im Bereich der Abfrage von Daten aus einer Datenbank haben kann. Der Service
     dient somit insgesamt sowohl als Vermittlungsstelle zwischen Anwendungen und Da-
     tenbank, als auch als Dienstleister für andere Aufgaben wie die Authentifizierung von
     Benutzern.

     4.3    Pixxler API
     Eine API soll den Zugriff auf den Service als weitere Schicht abstrahieren damit die
     Ansteuerung dessen nicht direkt im Quellcode der jeweiligen Endanwendung imple-
     mentiert werden muss. Diese Bibliothek enthält alle vom Service angebotenen Schnitt-
     stellenmethoden, eine Struktur zur lokalen Datenhaltung sowie eine lokale Implementie-
     rung des Authentifizierungsmechanismus. Die Verwendung einer solchen Bibliothek
     hat den Vorteil, dass die Ansteuerung des Services auch von anderen Endanwendungen
     auf gleiche Weise wiederverwendet werden kann und nicht im Quellcode mehrerer
     Endanwendungen erneut implementiert werden muss. Es kann im späteren Verlauf so-
     gar in Betracht gezogen werden, diese API öffentlich zugänglich zu machen und Dritt-
     anbietern von Software einen Zugriff auf den Service zu gewähren. Die API wird als
     eigenständiges Modul in die Endanwendung eingebunden.
20                                      Anwendungskonzept Pixxler

     4.4       Clientanwendung Pixxler
     Da auch die Vorteile der deklarativen Programmierung näher vorgestellt werden sollen,
     wird die Benutzeroberfläche der Clientanwendung mit der, XML ähnlichen, deklarati-
     ven Sprache XAML gestaltet. Sie ist fester Bestandteil der Windows Presentation
     Foundation (WPF) und wird eingesetzt um grafische Elemente, Benutzeroberflächen,
     Verhaltensweisen, Animationen, Transformationen, Darstellung von Farbverläufen und
     weitere mediale Inhalte zu definieren.

     Die möglichst hohe Flexibilität der Anwendung wird durch eine modulare Architektur
     gewährleistet. Die Modularisierung der Endanwendung wird dabei durch den Einsatz
     der .NET Bibliothek PRISM, sowie den modernen Ansatz der Dependency Injection
     möglich gemacht, um auch in der Zukunft eine leichte Erweiterbarkeit möglich zu ma-
     chen. Sogenannte Softwaremodule bilden dabei die eigentliche Funktionalität der End-
     anwendung. Folgende Module sind für die Anwendung vorgesehen:

              Modul für den Login
              Modul zur Navigation der Bilderalben und deren Inhaltsanzeige
              Modul zur Anzeige von Bildern und deren Bearbeitung

     Bei der Entwicklung der Clientanwendung wird C# als Sprache für die Anwendungsar-
     chitektur sowie alle anderen objektorientierten Bereiche verwendet.

     4.5       F# Bibliothek

     Die Anforderung ist, dass der mit F# implementierte funktional orientierte Teil als Bib-
     liothek in der Clientanwendung bzw. im Service ansprechbar sein sollte. In dieser Bibli-
     othek sollen sämtliche Funktionalitäten bereitgestellt werden, um Bilder mit verschie-
     denen Farb- und Effektfiltern neu berechnen zu lassen. Da der F# Code beim Kompilie-
     ren, genau wie C# Code, in den Zwischencode für die CLR8 umgewandelt wird, ist eine
     Verwendung dieser Bibliothek aus einer .NET Anwendung bzw. dem Service problem-
     los möglich. Voraussetzung dafür ist allerdings die Einbindung der allgemeinen F# Bib-
     liothek aus dem .NET Framework in das jeweilige Projekt.

     8
         Dies ist die Laufzeitumgebung von .NET
21                                  Implementierung des Pixxler Services

     5          Implementierung des Pixxler Services
     Der Pixxler Service stellt eine zentrale Anlaufstelle für ausgelagerte Aufgaben aller Art
     dar. Er ist ein elementarer Baustein für sämtliche Endanwendungen und muss somit
     auch als erstes konzipiert und implementiert werden. Folgende Aufgaben soll der Ser-
     vice in der ersten Version übernehmen:

               Authentifizierung der Benutzer
               Vermittlungsstelle für Daten aus der Datenbank

     Da es sich um eine multiuserfähige Anwendung handeln soll, wird eine Authentifizie-
     rung am Service notwendig. Die Abfrage benutzerbezogener Daten muss dabei inner-
     halb einer Sitzung ablaufen um sicher zu stellen, dass jedem Benutzer die passenden
     Daten zur Verfügung gestellt werden können. Nach der erfolgreichen Anmeldung soll
     dem Benutzer eine SessionID 9 vergeben werden, mit welcher dieser dann weitere Leis-
     tungen des Services nutzen kann. Die SessionID wird in Form einer GUID repräsentiert
     um die weltweite Einmaligkeit der Sitzung zu gewährleisten.

     Bei den Leistungen des Services handelt es sich sowohl um die Abfrage von Bildern
     und Alben die einem Benutzer zugeordnet sind als auch um Routinen, die zum Spei-
     chern neuer Bilder und Alben dienen.

     Um die Ansteuerung des Services nicht für jedes unterschiedliche Endgerät neu zu ent-
     wickeln und ggf. sogar später eine öffentliche Ansteuerung zu ermöglichen, wird für
     den Service eine API in Form einer .NET Bibliothek entwickelt um die Datenstrukturen,
     Konnektivität und das Handhaben der Sitzung für die Anwendungsentwicklung bereit-
     zustellen.

     5.1        Was ist ein WCF Service
     Die Windows Communication Foundation (WCF) ist eine von Microsoft entwickelte
     Technologie, die es Entwicklern ermöglicht Kommunikationsplattformen zu erstellen
     die mit standardisierten Protokollen (TCP, HTTP) arbeiten. Die WCF ist somit beson-
     ders dazu geeignet um serviceorientierte Anwendungen zu entwickeln.

     9
         Eine eindeutige alphanumerische Zeichenfolge die dazu dient den Klienten wiederzuerkennen
22                                  Implementierung des Pixxler Services

     Ein WCF Dienst ist dabei in folgende Bereiche unterteilt:

               Eine Adresse die den Ort der Erreichbarkeit in Form einer URI beschreibt
               Die Bindung, welche die Form der Kommunikation sowie eingesetzte Kommu-
                nikationsprotokoll beschreibt. Verschlüsselung fällt ebenfalls in diesen Bereich.
               Ein Vertrag, der beschreibt welche Dienstleistungen in Form von Methoden der
                Service anbietet.

     Abbildung 2: WCF - ABC Prinzip 10

     Dieses ABC (Address, Binding, Contract) Prinzip abstrahiert somit das Konzept des
     Endpunktes.

     5.2        Einrichten der Datenbank

     Die Daten der Benutzer müssen in einer Datenbank persistent gespeichert werden. Als
     Speicherort für diese Daten dient ein Microsoft SQL Server 2008 R2 mit einer Stan-
     darddatenbank. Die zu speichernden Daten sind zu Anfang sehr überschaubar und wer-
     den auf folgende Strukturen projiziert:

               Benutzer
               Alben und ihre Zugehörigkeit zum Benutzer
               Zugriffsrechte auf Alben anderer Benutzer
               Bilder und ihre Zugehörigkeit zum Album

     Da die Anwendung darauf ausgelegt ist von mehreren Benutzer genutzt zu werden,
     muss die Tabellenstruktur in der Datenbank ebenfalls benutzerbezogen gestaltet werden.
     Jeder Benutzer soll X Alben anlegen können und in diesen alle gewünschten Bilder an-
     ordnen können. Es soll außerdem berücksichtigt werden, dass in einer späteren Version

     10
          (Beaulieu, 2010)
Sie können auch lesen