Saturday, December 29, 2007

Playing around with NBehave

As I said recently I'm still exploring tdd and its capabilities. The next evolutionary step could be bdd. Therefore I downloaded NBehave and I tried to write one story with it. Passive View is my preferred playground and thats how it goes with NBehave and TypeMock.NET:

First the declaration of the View, the Presenter and a Service-Gateway that is used by the Presenter to retrieve some information.
protected IView _view;
protected Presenter _presenter;
protected EventHandler _updateRequestedEvent;
protected IServiceGateway _serviceGatway;

The setup of the this objects is not showed here. It simples instantiates mocks for the View and the ServiceGateway and injects it into the Presenter using Constructor-Injection. The _updateRequestedEvent is a mocked event on the view and is also used later in the example.

First I have to specify a story. This is done like that:

[TestFixtureSetUp]
public void FixtureSetup()
{
_getCurrentTimeStory = new Story("Getting the current service time");
_getCurrentTimeStory.AsA("User").IWant("to update the displayed current time")
.SoThat("I can see what time is on the serivce side");
}

And that's one scenario that came in my mind:

[Test]
public void HelloNTServiceIsNotAvailable()
{
using (RecordExpectations recorder = RecorderManager.StartRecording())
{
_view.ShowMessageBox("The Service is currently not available");
recorder.CheckArguments();
}
_getCurrentTimeStory.WithScenario("Service is not available")
.Given("the Service returns an exception", new Exception("Error"), e =>
{
using (RecordExpectations recorder = RecorderManager.StartRecording))
{
recorder.ExpectAndThrow(_serviceGatway.GetTime(), e);
}
})
.When("I update the current time", () => _updateRequestedEvent(this, EventArgs.Empty))
.Then("a message box should display", "The Service is currently not available", m =>
{
MockManager.Verify();
})
;
}

Looks quite chaotic and a developer not used to NUnit,TypeMock and NBehave might not understand it at first glance. I also think the combination of NUnit,TypeMock and NBehave is a little bit strange as they do not integrate very well. Maybe there is another way how to combine those frameworks?

But what I like is the overall structure that it gives to the tests and the readable test output that can be interpreted by a product owner. Here are now the scenario above and another scenario that I could present to him:

Story: Getting the current service time

Narrative:
As a User
I want to update the displayed current time
So that I can see what time is on the serivce side

Scenario 1: Service is not available
Given the Service returns an exception: System.Exception: Error
When I update the current time
Then a message box should display: The Service is currently not available

Scenario 2: Service is available
Given the Service returns the time: 01.01.2000 12:24:23
When I update the current time
Then the label on the view should display: 12:24

Sunday, December 16, 2007

Evaluating a dependency injection framework

I heard the first time about tdd in the year 2002 when a colleague of mine introduced me to a tool called 'NUnit'. I found tdd very helpful from the beginning and I was always one of them that pushed that paradigm and mindset. I learned like a lot of the other tdd enthusiasts, that 'test first' is good, that 'test isolation' is really necessary, that a 'mocking framework' helps a lot, and that it's all about a good design. On this journey I'm now at a point where I question: could a 'dependency injection framework' help?

That is what I tried to find out today and what this post is about. I wrote a simple application including:
  • a wpf client with one window called Window1
  • a wcf service called Service with one Methode GetDate() that returns the current date and time
  • one assembly testing the wpf-presentation and wcf-service (just unit-tests)

Introducing a DI-Framework

One trying to write tests in such an environment knows that integrating the real wpf- and wcf-environment into the tests is a bad idea. Instead it's better to stub and mock those environments to get easier, more stable, and faster tests. This means we usually want a test-configuration where the most external dependencies (like wpf or wcf) are mocks or stubs. On the other hand we want to have a configuration on a deployed system that utilizes the real dependencies. So it's something about configuration and that's where the DI-frameworks come into play.

I decided to give Jeremy's StructureMap a try because it doesn't look so overloaded like Sprint.NET or Windsor.

Following code shows my wcf-service IService that I include in the presentation-layer as a Service-Gateway (see also ServiceStub-Pattern):


[ServiceContract]
public interface IService
{
[OperationContract]
DateTime GetTime();
}
/// <summary>
/// Gateway to intercept for testing
/// </summary>
public interface IServiceGateway : IService
{
void Close();
}
/// <summary>
/// Real gateway using the wcf generated ServiceClient class
/// </summary>
public class ServiceGateway : IServiceGateway
{
private readonly ServiceClient _service;

public ServiceGateway()
{
_service = new ServiceClient();
}

public void Close()
{
_service.Close();
}

public DateTime GetTime()
{
return _service.GetTime();
}
}
/// <summary>
/// Stub for testing
/// </summary>
public class ServiceGatewayStub : IServiceGateway
{
public void Close()
{
}

public DateTime GetTime()
{
return new DateTime(2000, 1, 1, 12, 34, 55, 12);
}
}
Step 1:
Using the following code to resolve the reference to the external wcf-service

IServiceGateway gateway = ObjectFactory.GetInstance<IServiceGateway>()
and using the following configuration for the tests

<StructureMap>
<DefaultInstance PluginType="HelloNTPresentation.IServiceGateway,HelloNTPresentation" PluggedType="HelloNTService.ServiceGatewayStub,HelloNTTests" Scope="Singleton"/>
</StructureMap>
I could wire the code during the tests to the ServiceGatewayStub instead of the real ServiceGateway.

Step 2:
I didn't like that because it meant that we have to setup a configuration for the real (not test) environment like:

<StructureMap>
<DefaultInstance PluginType="HelloNTPresentation.IServiceGateway,HelloNTPresentation" PluggedType="HelloNTPresentation.ServiceGateway,HelloNTPresentation" Scope="Singleton"/>
</StructureMap>
After I have had read how to build an IoC container in 15 lines of code I thought that DI can't be so difficult and I tried to build my own DI-framework. I liked very much that I could configure the DI in the code now and eliminate the file-based configuration:
      ObjectFactory.Register<IServiceGateway>(() => new ServiceGatewayStub());
IServiceGateway gateway = ObjectFactory.Create<IServiceGateway>();
All tests were green and I was happy to start the refactored sample application first time after. But there was big surprise when it crashed. I had forgotten to configure DI for the wcf-service and wpf-service. But where should I put that configuration? Both of them run in some kind of hosted environment and I wasn't able to find a nice place to put that configuration-code. So I realized that it's a little bit harder than I thought to write an own DI-Framework.

Step 3:
Back to StructureMap I found a way to minimize the file-based configuration. The solution was to use the attributes PluginFamily and Pluggable that define default behaviour. In this case the class ServiceGateway is the default implementation of IServiceGateway and there is no need to configure it for the wcf-service and the wpf-client anymore.

    [ServiceContract]
public interface IService
{
[OperationContract]
DateTime GetTime();
}
[PluginFamily("ServiceGateway")]
public interface IServiceGateway : IService
{
}
[Pluggable("ServiceGateway")]
public class ServiceGateway : IServiceGateway
{
}
Step 4:
Now let's have a look to following the presenter (presenter is what is responsible for the presentation-logic):

    public class Presenter: IDisposable
{
readonly IView _view;
readonly IServiceGateway _service;

public Presenter(IView view, IServiceGateway service)
{
_view = view;
_service = service;
}
}
That presenter shows all internal dependencies on its constructor. This enables us to use constructor injection when writing tests with a Mock-Framework (e.g. TypeMock)
     _serviceGatway = RecorderManager.CreateMockedObject<IServiceGateway>();
_view = RecorderManager.CreateMockedObject<IView>();
_presenter = new Presenter(_view, _serviceGatway);
But what's about the others that don't want to bother about providing those dependencies to the constructor? And that's where the DI-framework gets really valueable because it enables us to instantiate concrete classes without providing the needed arguments to the constructor. Following code is from the wpf-client and shows how this is done:

    Presenter presenter = ObjectFactory.FillDependencies<Presenter>();
Just for completeness, I have to mention how I configured IView:

    [PluginFamily("Window1")]
public interface IView
{
}
[Pluggable("Window1")]
public partial class Window1 : Window, IView
{
}
Summary

  • I always used constructor injection but with a DI-framework it gets easier because the client code doesn't need to manage the dependencies anymore.
  • I like StructureMap because it looks simple and it works.

Tuesday, December 11, 2007

Offline data synchronization

I wrote a few days before that it looked like I would get involved in a SOA-project. Today it looks like I will get involved in another project! This new project could have following technical characteristics:
  • said to be a rich-client-project
  • support for offline disconnected scenarios (offline agents)
  • distributed application (Internet, intranet or some kind of private network)
  • integration with a backend system (no idea what kind of interface that would be)

Sounds interesting .... So I bought yesterday something about WPF to update myself with 'state of the art rich client development'.

Maybe the new Microsoft Synch Framework could be interesting in that context too. I watched this and it looks promising. I have to admit that I hate that kind of presentations but it looks that it's flexible and can be extended. I'm not yet sure about that but at least the synch-runtime can be instantiated in a object-oriented manner and that's always a good sign. Would be great if it could be connected to a service instead of a database.

Sunday, December 9, 2007

WCF puts all together

I was supposed to get involved into a SOA-project therefore I started to read about WCF. In the meanwhile it turned out that I might not be involved in that project, however I kept on doing my reading on this issue. I went through the following two books:


  • Pro WCF Practical Microsoft SOA Implementation was a good introduction with a lot of code and examples. I liked it as a brief introduction into how WCF 'feels like'. But I switched to the other book soon after since I got more interested in the overall concepts than in the details.

  • I liked Programming WCF Services because it talks in more details about advanced stuff like Instance Management, Faults, Transactions, Concurrency and Security.

Below is what I think about WCF: I think theres is nothing new but that all comes together in a nice consistent way. WCF helps much if an application is more than a monolithic web or rich-client application. I'd like to mention two personal highlights:


Saturday, December 1, 2007

excpetion handling could be easy

We have been doing a major refactoring in our project trying to get rid of the legacy exception handling. As we went through our code we had some good laughs (we shouldn't have laughed as we still have to maintain that for a long time) and it was obvious that some developers had no clue about how to deal with exceptions or were too lazy to implement a more sophisticated handling. It seemed that some developers didn't miss any opportunity to get rid of that nasty exceptions. It seemed that we were fighting a .NET-bug called 'Exception'.

We also had a lot of discussons about exceptions, especially because we wanted to eliminate exception swallowing but not to change the user experience! Our product manager stated that it's better to have an obscure behaviour that the users knows than a new fancy error dialog that indicates problems at the root. (Users don't like fail fast!)

I didn't want to talk about that stuff but I have just come across some similar thoughts:

http://grabbagoft.blogspot.com/2007/11/stop-madness.html (see Try Catch Publish Swallow)
http://grabbagoft.blogspot.com/2007/06/swallowing-exceptions-is-hazardous-to.html
http://grabbagoft.blogspot.com/2007/06/re-throwing-exceptions.html

Tuesday, November 27, 2007

consistency, integrity and exceptions

I was blaming myself today talking about consistency and integrity without remembering the exact definitions of it. I just remembered that there are some interesting differences between them. What I meant was a definition like Consistency and Integrity.

My point was that exception handling and especially the concept of design by contract could be seen in a similar context. I tried to argue that violating a design by contract-rule(pre/post/invariance) is like violating the 'programs internal consistency'.

But as Consistency and Integrity is just clearly defined in the context of data it seems that my derivation doesn't make sense.

In personally would say a 'program consistency' is maintained as long it's internal state doesn't contain any contradictions. Furthermore a 'program integrity' is maintained as long as the programs internal state does reproduce all related external state correctly.

Following that definition one could say that 'program consistency' can be checked by the design by contract-technique but 'program integrity' cannot. 'program integrity' cannot be checked at all by a program.

Tuesday, November 20, 2007

Expresso - Regextool and others

I used Expresso first time today and I liked it much more than the Regulator that I've used up to now . The 'Regex Analyzer'-View and the 'Search Result'-View display the Regex and the matches as a tree and this helps me a lot in understanding Regex's.

I've always wanted to mention that I'm using a visual studion plugin named Cool Commands. I'm using just one command of it: 'Collapse All Projects' . It collapses my 20 projects in a solution with one click! Will the brand-new visual studio 2008 support that out of the box?

Sunday, November 11, 2007

Scrum and xp from the trenches

I've just finished reading Scrum and xp from the trenches. To see that everybody trying to adapt Scrum is running into the same kind of problems perks me up. Scrum like its written in the books is quite dogmatic but this book gives some good pragmatic advices.

Two remarks about what I've read related to the project I'm currently working on:
  1. We are trying to adapt a simple estimation method where we compare the complexity of use-cases choosing a number from 1,2,3,5,8,13 ... One use-cases is randomly chosen as a 'reference use-case' and all other use-cases are estimated by comparing it with the 'reference use-case'. Estimating use-cases is a reoccurring activity in our project and the problem is that every team member has always to remember a 'reference use-case' in its details to be able to give an estimate to another use-case. Using that method we had a kind of 'currency' to determine the real value in time (how many hours is one point?). Calculating 'Total Points in a Sprint' * 'currency' gives us the total amount of working hour of the team in a Sprint.
  2. Maybe we should switch over to a system where 1 Point is '1 ideal programming day'. We could still use an exponentially growing number like 0.25, 0,5, 1,2,3,5,8,13... to address the growing uncertainty. The drawback is that we might have to deal now with number less than 1 but on the other hand it gives us a better feeling on how much work is related to one certain number. Furthermore our 'currency' gets a 'focus factor' and that's easier to understand by managers and addresses directly the question why we cannot deliver as fast as in an 'ideal environment'. I guess comparing use-cases according to their complexity is a good choice for a single 'planning-meeting'. However in our case where we estimate a small number of use-cases monthly, it's better to pin the points to '1 ideal programming day'.

Sunday, October 28, 2007

Patterns 4 - Domain Driven Design

Im vorläufig letzten Beitrag zu Patterns möchte ich einige Patterns aus dem Buch Domain Driven Design von Evans auflisten. Leider sind die Patterns nicht Online verfügbar, doch gehört dieses Buch sowieso zur Pflichtlektüre wenn mit Domain Model's gearbeitet wird. Wer es weniger theorietisch mag und sehe möchte wie sich das Arbeiten mit DDD 'anfühlt' dem sei Applying Domain-Driven-Design and Pattern von Nilson empfohlen.

Supple Design
Unter dieser Überschrift sind Patterns enthalten welche die Absicht und Wirkung von Code möglichst transparent darstellen lassen sollen. Idee ist dass die Struktur des Code die Funktionalität möglich klar darstellt.
  • Side-Effect-Free-Functions: Mit diesem Pattern können, auch in Kombination mit unveränderbaren 'Value Objects', einfach verständliche und testbare Funktionen realisiert werden. Für das Verständnis und das Testen müssen nur Inputparameter und der Resultatwert der Methode berücksichtigt werden da keine Seiteneffekte vorhanden sind. Weiter wird empfohlen Commands (Methoden welche beobachtbaren Zustand verändern) in sehr einfache Operationen zu gliedern welche keine Domäneninformationen retournieren.
  • Assertions: Im Code sollen Pre-/Postcondition und Invarianzen definiert werden. Damit sollen auch Seiteneffekte explizit spezifiziert werden damit für das Verständnis einer Methode nicht alle Ausführungspfade analysiert werden müssen.
  • Intention-Revealing Interfaces: Hier gehts es darum dass Klassen- und Methodenamen gefunden werden welche die Funktionalität und Verantwortlichkeit klar ausdrücken. Es sollte nicht nötigt sein dass daneben noch dokumentiert werden muss, unter welchen Umständen eine Klasse und Methode wie funktioniert. Auch sollten im Namen Begriffe aus der 'Ubiquitous Language' auftauchen.
  • Standalone Classes: Gelingt es eine völlig losgelöste Klasse, ohne Abhängigkeiten auf andere Klassen zu entwickeln, reduziert man die konzeptionelle Komplexität massgeblich. Lose Kopplung kann eingesetzt werden um die Komplexität von Code zu reduzieren.
  • Closure of Operations: Dieses Konzept hält uns an Operationen wie mathematische Operationen aufzubauen da diese ein einfaches Konzept ist. Dabei sollen Eingabeparameter und Rückgabwert vom gleichen Typ sein. Ein solches Interface ermöglicht das Zusammenbauen von komplexeren Operationen aus einfacheren Primitiven.
  • Specification: Ein Value Object welches als Predicate bestimmt ob ein anderes Objekt ein bestimmtes Kriterium erfüllt.
  • Ubiquitous Language: Dabei sollen Begriff und Konzepte aus der Problemdomäne von den Entwicklern übernommen werden. Diese Begriff und Konzepte haben ein starken Einfluss auf den Design und sind einer der wichtigsten Treiber für den Design.

Building Blocks
Hier haben wir Patterns welche unter DDD häufig vorkommen.

  • Layered Architecture: Schlägt vor im allg. eine Applikation in Presentation, Application, Domain und Infrastruktur Layer zu schichten. Dies ermöglicht einen ausdrucksstarken Domainlayer zu erhalten da dieser nicht mit Anzeige-, Speicher-oder Berechtigungsaufgaben usw. überladen wird.
  • Entities und Value Objects: Wichtige Konzepte zum Unterscheiden von Klassen mit Identitäten (z.B: eine Person mit einer ID) und Klassen deren Identität durch die Werte der Klasse bestimmt ist (z.B eine Farbe identifizierbar durch ihre RGB-Werten). Es wird empfohlen Value Objects als unveränderbare Klassen zu designen.
  • Modules: Gibt Anleitunng nach welchen Aspekten Code modularisiert werden sollten. Dabei sollte auf geringe Kopplung und hohe Kohäsion geachtet werden. Modulnamen sollten Teil der Ubiquitous Language werden. "If your model is telling a story, the Modules are chapters".
  • Services: Im allg. sollte für jeden Service gelten: 1.) Die Operation auf dem Service ist Teil des Domänenkonzept welches aber nicht als Entitiy oder Value Object ausgedrückt werden kann. 2.) Die Service-Schnittstelle nimmt Bezug auf das Domänenmodell. 3.) Die Operation ist zustandslos. Desweitern kann ein Service in verschiedenen Schichten realisiert werden (Application-, Domain-, Infrastructure-Service) wobei sich die Verantwortlichkeiten je nach Schicht stark unterscheiden können.
  • Factories: Erzeugt in einer Operation ein konsistentes Objekt oder Aggregate (Invarianzen müssen erfüllt sein). Dieses Pattern wird wichtig sobald ein Objekt nicht mehr mit einem einfachen Konstruktoraufruf erzeugt und in einen konsistenen Zustand überführt werden kann.
  • Repositories: Lädt Objekte oder Aggregates von einem tieferen Infrastrukturlayer in den Speicher (z.B von der Datenbank) und erzeugt die Illusion dass die Objekte immer im Speicher vorhanden sind. Repositories werden spezifisch für Klassen von Objekten und Aggregates realisiert und zeigen auf ihren Schnittstellen die Designentscheidung bezüglich Objektzugriff.
  • Aggregates: Damit werden eine Anzahl von Entities oder Value Objects logisch gruppiert um die Kopplung zwischen Teilen des Modells zu reduzieren. Pro Aggregate wird eine Klasse als Aggregate-Root definiert und der Zugriff auf das Aggregate darf nur noch über diesen Root erfolgen.
Strategic Design
Hier sind Patterns aufgelistet welche helfen in einem grösseren, komplexen System das Domänenmodell und verschiedene Teile davon herauszubilden.
  • Core Domain: Definiert die wichtigste Domain in einem Projekt. Für diese wird mit grosser Sorgfalt das Modell gefunden und ständig verfeinert. Jegliche Art von Entscheidungen können nun so gefällt werden dass es zuerst der Core Domain zu Gute kommt.
  • Generic Subdomain: Eine Subdomain ist nicht der Hauptgrund weshalb eine Software entwickelt wird, doch ist die Subdomain (z.B ein Zeitzonen-Modell) eine wichtige Unterstützung der Core Domain. Solche Domänen sollten aus der Core Domain gelöst werden um diese nicht unnötig komplex zu machen. Auch können Generic Subdomain häufiger als Core Domains wiederverwendet oder auch eingekauft werden. Vor und Nachteile beim Einkaufen von Sumdomänen sind in diesem Kapitel auch erläutert.
  • Domain Vision Statement: Schlägt vor dass die Coredomäne und ihr Wert zu Projektbeginn beschrieben wird um dem Entwicklungsteam eine gemeinsame Richtung zu geben.
  • Segregated Core: Beschreibt den Vorgang wie aus einem System ohne Core Domain eine solche gebildet werden kann.

Large-Scale Structure ist ein Kapitel in welche einige Patterns enthalten sind welche helfen ein Struktur für grosse Systeme zu finden.

Maintaining Model Integrity beschreibt Ansätze wie Modelle zwischen unterschiedlichen Systemen synchron gehalten werden oder wie mit den Unterschieden umgegangen werden kann.

Thursday, October 18, 2007

Patterns 3 - Enterprise Application Architecture

Wie der Titel dem geneigten Leser andeutet möchte ich in diesem Beitrag das Standardwerk Patterns of Enterprise Application Architecture, kurz EAP, von Martin Fowler zitieren. Im Gegensatz zu den GoF-Patterns aus meinem ersten Beitrag zu Patterns sind die EAP-Patterns recht spezifisch mit einer Anwendung verbunden. Im folgenden werde ich eine Auswahl von Patterns aus dem Buch auflisten indem ich die Zusammenfassung aus dem Buch pro Pattern zitieren und wo es für mein Verständis wichtig war habe ich noch Kommentare hinzugefügt. Für Details sei an das Buch verwiesen. Nicht erwähnte Patterns sind nicht weniger wichtig, doch haben sie in meinem Umfeld weniger Bedeutung da die Problemstellung nicht vorhanden ist oder ich diese bis heute durch ein Framework lösen lies.

Domain Logic Patterns
Domain Model: 'An object model of the domain that incorporates both behavior and data.' Wegen Domain Driven Design ist dieses Pattern für mich ein Muss.

Service Layer: 'Defines an application's boundary with a layer of services that establishes a set of available operations and coordinates the application's response in each operation.' Für den Service Layer gibt es die Variation 'Domain Facade' und 'Operation Script'. Da ich den Domain Model-Ansatz bevorzuge habe ich hier auch eine Bevorzugung für die 'Domain Facade'. Die Eigenschaften eines einzelnen Service hat Evans auch hier beschrieben.

Data Source Architectural Patterns
Active Record: 'An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data.' Dieses Pattern kann zu einer Vereinfachung in der Implementation eines Domain Model führen indem die Datenbankstruktur und die Domain Model-Stuktur gleich gehalten werden.

Data Mapper: 'A layer of Mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself.' Im Gegensatz zum Active Record wird das Mapping hier in den Data Mapper ausgelagert. Der Data Mapper wird in der Regel nicht selbst implementiert da dies ein komplexes Unterfangen ist (z.B kann für ein objekte-relationales Mapping NHibernate verwendet werden). Auch wird ein Data Mapper oft zusammen mit einem Domain Model verwendet. (siehe auch Mapper)

OR Behavioral Patterns
Unit of Work: 'Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.' Unit of Work sollte in der Regel zusammen mit einem Data Mapper implementiert werden.

Identity Map: 'Ensures that each object gets loaded only once by keeping every loaded object in a map. Looks up objects using the map when referring to them. ' Identity Map muss im Zusammenhang mit einem Data Mapper implementiert werden.

Lazy Load: 'An object that doesn't contain all of the data you need but knows how to get it.' Wichtiges Pattern in Zusammenhang mit Data Mapper und Domain Model um zu steuern wann welche Daten von einer Datenquelle geladen werden.

OR Metadata Mapping Patterns
Query Object: 'An object that represents a database query.' Das Specification Pattern ist mit Query Object verwandt. Der Unterschied ist dass das Query Object auf technischer Ebene ein Query beschreibt. Das Specification Pattern selbst kann Begriffe aus der ubiquitous Language verwenden und bilden und ist Teil der Geschäftslogik.

Repository: 'Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects'. Ich war hier immer unsicher was der Unterschied zwischen einem Repository und einer Factory ist. Aber in Domain Driven Design von Evans wird klar definiert: 'The Factory makes new objects; the Repository finds old objects' und in Applying Domain-Driven Design and Patterns wird dargestellt dass das Repository für die Persistierung von neu erzeugten Objekten zuständig ist. Ein Repository befindet sich auf einer höheren Ebene als ein Data Mapper indem es Query Object oder Specifications auswertet und Objekte mit Hilfe eines Data Mapper erzeugt.

Web Presentation Patterns
Model View Controller: 'Splits user interface interaction into three distinct roles. (View, Controller, Model).' Siehe auch MVP unter welche das Pattern weiter verfeinert dargstellt wird.
Page Controller: 'An object that handles a request for a specific page or action on a Web site'. Ich sehe im Page Controller eine Anpassung des Model View Controller an das Web-Umfeld wo es die View einmal auf dem Client als HTML-Seite und einmal auf dem Server als Server-Seite gibt. Dies ist auf jeden Fall der Grund weshalb im Unterschied zum Model View Controller die View keine Abhängigkeit auf den Page Controller hat. Die clientseitige HTML-Seite hat nämlich eine Abhängigkeit auf den Page-Controller indem diese Web-Requests übermittelt.

Front Controller: 'A controller that handles all requests for a Web site'. Der Controller instanziert abhängig vom Request Commandos welche die weiteren Verarbeitungen vornehmen.

Template View: 'Renders information into HTML by embedding markers in an HTML page.' Das ist wie eine ASP-Serverseite.

Application Controller: 'A centralized point for handling screen navigation and the flow of an application'.

Distribution Patterns
Remote Facade: 'Provides a coarse-grained facade on fine-grained objects to improve efficiency over a network.' Wichtig ist, als Unterschied zum Service Layer, dass die Remote Facade grob-strukturierte Methoden aufweist.

Data Transfer Object: 'An object that carries data between processes in order to reduce the number of method calls.' Kann zusammen mit Remote Facade zur Datenübertragung verwendet werden. In .NET werden so oft DataSet's oder XML-Serialisierte Objekte als DTO über Webservices verwendet.

Offline Concurrency Patterns
Optimisitc Offline Lock: 'Prevents conflicts between concurrent business transactions by detecting a conflict and rolling back the transaction.'

Pessimistic Offline Lock: 'Prevents conflicts between concurrent business transactions by allowing only one business transaction at a time to access data.'

Coarse-Grained Lock: 'Locks a set of related objects with a single lock'. Damit verwaltet ein Optimisitc Offline Lock oder ein Pessimistic Offline Lock die Locks auf höherer Ebene (z.B: Aggregate) um den Lockingaufwand zu verringern und die Konsistenzsicherheit zu erhöhen.

Implicit Lock: 'Allows framework or layer supertype code to acquire offline locks.' Stellt sicher dass das Locking implizit ist und somit vom Client-Code weder vergessen noch umgangen werden kann.

Session State Patterns
Client Session State: 'Stores session state on the client.' Wird z.B von ASP.NET-Seiten als ViewState implementiert. Kann aber auch für alle Arten von Sessions verwendet werden.

Server Session State: 'Keeps the session state on a server system in a serialized form'. Wird z.B von ASP.NET-Seiten auf dem System.Web.HttpContext.Session -Property implementiert.

Database Session State: 'Stores session data as committed data in the database.' Kann bei ASP.NET via Konfiguration für den Server Session State eingeschaltet werden.

Base Patterns
Gateway: 'An object that encapsulates access to an external system or resource.' Vereinfacht ein komplexes externes Inteface und stellt evtl. die Basis zur Verfügung um einen Service Stub anlegen zu können. Noch ein paar Erklärungen: Ein Gateway wird für externe Komponenten geschrieben während eine Facade von einer externen Komponente zur Verfügung gestellt wird. Ein Adapter wiederum ist eine technische Möglichkeit wie ein Gateway umgesetzt werden kann.
Mapper: 'An object that sets up a communication between two independent objects.' Ist komplexer zu implementieren als ein Gateway. Der Mapper kann als Zwischenschicht gesehen werden welche die zwei angrenzenden Schichten aufeinander abbildet. Beide angrenzenden Schichten bleiben dabei unabhängig und nur der Mapper hat eine Abhängigkeit auf diese.

Layer Supertype: 'A type that acts as the supertype for all types in its layer.' Mag ich persönlich nicht da dadurch schnell das Single Responsibility Prinzip verletzt wird. (z.B Domain Model hat Subertype für Persistenz).

Separated Interface: 'Defines an interface in a separate package from its implementation.' Die Konfiguration der konkreten Instanz (welche das Interface implementiert) kann danach von einem dritten, von beiden Packages abhängigen Komponente oder per Plugin zur Laufzeit erfolgen.

Registry: 'A well-known object that other objects can use to find common objects and services.'

Plugin: 'Links classes during configuration rather than compilation.' Dafür gibts heute eine Anzahl Frameworks (z.B Spring.NET). Plugin wird häufig auch im Zusammenhang mit dem Dependency Inversion Principle und Separated Interface verwendet.

Service Stub: 'Removes dependence upon problematic services during testing.'

Record Set: 'An in-memory representation of tabular data.' = DataSet in .NET

Sunday, October 14, 2007

Patterns 2 - Prinzipen

Im zweiten Beitrag zu Patterns möchte ich einige Prinzpien ansprechen welche helfen einen ausgereiften und qualtitativ guten Softwaredesign zu finden. Diesen Prinzipien zu folgen ist nicht immer ganz einfach, aber sie machen schlussendlich den Unterschied zwischen einer längerfristig wartbaren und qualtitativ hochstehenden Software und einem Hack aus.

DRY: Das Prinzip 'Don't repeat yourself' besagt dass in der Programmierung keine Duplikationen und Redundanzen enthalten sein sollen. Dies gilt für den Programmcode, für Datenbankdefinitionen usw... Das befolgen dieses Prinzips erhöht die Wiederverwendung von Programmcode enorm und ist Ausdruck einer sauberen Programmierung schlechthin.

Law of Demeter: Vereinfacht gesagt definiert das Gesetz von Demeter die Regel 'Sprich nur mit deinen engsten Freunden'. Damit wird erreicht dass eine Klasse sich nur an das nächste Umfeld koppelt (die engsten Freunde) und nichts über die Struktur des weiteren Umfelds wissen muss. Das Gesetz definiert formal für die Methode M auf dem Objekt o:
  1. o.M() -> darf auf Methoden von o zugreifen (z.B mit this.X())
  2. o.M(a) -> darf auf Methoden von a zugreifen (z.B mit a.X())
  3. 0.M() -> darf auf Methoden von selbst erzeugten Objekten zugreifen (z.B a = new A() wird in der Methode M() angelegt, dann darf o.M() -> a.X() aufrufen)
  4. o.M() -> darf auf Methoden von direkt aggregierten Objekten zugreifen(z.B a = new A() wird im Konstruktor angelegt, dann darf o.M() -> a.X() aufrufen)
Open/Close Principle: Das Prinzip verlangt dass eine Softwarekomponente (Module, Klasse, Methode usw...) erweitert werden kann ohne dass die Komponente in ihrer inneren Struktur angepasst werden muss. Der Sinn dahinter ist dass eine Komponente ihre Verantwortlichkeit (gemäß Single Responsibilty Principle sollte da nur eine sein) erfüllt ohne sich um die entsprechenden Variationen kümmern zu müssen. Für die Variation sollte die Komponente aber entsprechende Erweiterungpunkte mittels Delegation an Abstrakte Interfaces oder Vererbung durch Abstrakte Methoden gegen aussen zur Verfügung stellen. Auf der anderen Seite sollte die Komponente auch ihre interne Struktur gegen aussen verbergen. Dies ermöglicht dass die Komponente ihre Implementation ändern kann, ohne dass Erweiterung und Variationen davon betroffen wären.

Single Responsibilty Principle: Das Prinzip besagt, dass ein Komponente (Module, Klasse, Methode usw..) genau eine Verantwortlichkeit haben soll. Eine Komponente sei somit nur anzupassen, wenn bezüglich dieser Verantwortlichkeit die Anforderungen ändern. Um dies erreichen zu können müssen folgende wechselwirkenden Aspekte betrachtet werden.

  1. Es sollte eine hohe Kohäsion erreicht werden. Eine Komponente hat ein hohe Kohäsion falls sie eine wohldefinierte Aufgabe abschliessend und vollständig löst (siehe auch Link)

  2. Durch lose Kopplung sollen Komponenten über ein wohldefinierte und möglichst kleine Schnittstelle miteinander verbunden werden

  3. Mit Separation of Concerns sollen die Verantwortlichkeiten in einer Software systematisch aufgeteilt werden. Dabei werden die Verantwortlichkeiten eindeutig an ein Module, Klasse oder Methode übergeben.
Liskov Substitution Principle: "Methoden welche Basisklassen (auch Abstrakte Klassen oder Interfaces) als Parameter haben müssen diese Objekte benutzen können ohne die konkrete Klasse zu kennen". Dies bedeutet für die Überschreibung einer Methode oder die Implementierung einer Methode aus einem Interface:

  1. Vorbedingung dürfen nicht verschärft werden
  2. Nachbedingungen dürfen nicht abgeschwächt werden
  3. Es dürfen nur Klassen von Exceptions geworfen werden welche auch von der Basis-Methode geworfen werden oder als mögliche Exception dort dokumentiert wurde. Es dürfen auch Ableitungen von diesen Exceptions geworfen werden
Eine Verletzung des Liskov Subsitution Principle führt zu einer schlecht funktionierenden Umsetzung des Open/Close Principle da sich die Erweiterung instabil verhalten wird.

Dependency Inversion Principle: Das Prinzip hat zum Ziel einen flexiblen und somit wartbaren Design zu finden. Die Regeln besagen:
  1. Übergeordnete Komponenten (Module, Klasse, Methode usw...) und untergeordnete Komponenten sollten nicht direkt voneinander abhängig sein. Beide sollten nur von Abstraktionen abhängig sein.
  2. Abstraktionen sollten nicht von den Details abhängig sein. Details sollten von den Abstraktionen abhängig sein.

Das Prinzip ist auch für den TDD Entwicklungsansatz enorm wichtig, da dadurch das mocken und stubben von untergeordneten Modulen ermöglicht wird. So gesehen stellt TDD einen flexible Design sicher, da der übergeordnete Code im Unitest mit Mocks und Stubs und in der laufenden Applikation mit den konkreten untergeordneten Modulen arbeitet.

Noch was vergessen?

Monday, September 24, 2007

Patterns 1 - Gang of Four

Seit ich mich mit Entwurfsmuster, oder eben Patterns wie ich normalerweise sage, beschäftige haben sich einzelne Steine zu einem grösseren Mosaik zusammengefunden. Das Mosaik hat noch viele Lücken, aber ich möche hier alle mir wichtig erscheinenden und von mir verstandenen Patterns zusammenfassen. Dies ist mein aktuelles "Weltbild" des objektorientierten Software-Designs. Noch ein Wort zu meiner Welt. Meine Welt ist die der grösseren datenzentrierten Geschäftsanwendungen, mit einer Rich-Client Benutzeroberfläche.

In der Folge möchte ich in mehreren Beiträge diese Patterns auflisten und zusammenstellen. In einem ersten Beitrag gehts es um die 'Gang of Four - Patterns' welche eine Ansammlung von systemnahen, technisch orientierten Patterns darstellen.

Abstract Factory: Erzeugt eine Familie von Objekte unterschiedlicher Typen ohne dass man bei der Benutzung gegen eine konkrete Familie programmiert. Als Beispiel dient hier eine IDbFactory welche IConnection, ITransaction für den Datenbankzugriff erstellt. IDbFactory kann nun konkrete für SQL-Server oder Oracle implementiert werden ohne dass es für den Benutzer von IDbFactory einen Unterschied ausmacht.

Builder: Abstrahiert den Konstruktionsprozess für komplexe Objekte. Falls erforderlich kann der Konstruktionsprozess für andere Typen wiederverwendet werden. So kann zum Beispiel das abstrakte Erstellen einer Rechnung mit einer Anzahl Rechnungspositionen mit einem abstrakten Builder realisiert werden. Als Varianten für konkrete Builder wäre ein KreditorenrechnungsBuilder und ein DebitorenrechnungsBuilder möglich

Factory Method: Erzeugt ein Objekt wobei die implementierende Subclass über den konkreten Typ des erzeugten Objekts entscheidet. Ist mit dem Abstract Factory-Pattern dadurch verwandt, dass dort eine Familie von Objekten und hier nur ein Objekt erzeugt wird.

Singleton: Stellt sicher, dass eine Klasse nur einmal instanziert ist und global zugegriffen werden kann. Damit kann zum Beispiel eine Infastrukturdienst wie die Protokollierung einfach für alle Programmstellen zugreiffbar gemacht werden. Das Pattern sollte aber sehr bedacht eingesetzt werden, da man sich damit sehr einfache versteckte Abhängigkeiten baut, welche die Flexibiltät und Wartbarkeit von Programmcode stark einschränken.

Adapter: Ermöglicht den Zugriff auf eine Klasse via ein Interface welches die Klasse selbst aber nicht unterstützt. Als Beispiel könnte man damit in einer Windows.Forms-Anwendung Controls über eine Interface IControl ansprechen obwohl die Windows.Forms-Library kein solches Interface unterstützt. Ein ControlAdapter würde dann Control auf IControl adaptieren.

Composite: Ist eine Datenstruktur in Form eines Baumes mit Vater-Kind-Beziehungen. Jeder Knoten im Baum ist wieder ein Composite mit weiteren enthaltenen Composites oder dann ein Leaf (Blatt) ohne weiteren Composites.

Decorater: Damit kann zur Laufzeit ein Objekt dynamisch erweitert werden. Bestehende Methoden können erweitert werden und auf dem Decorater können neue Funktionalitäten für das Objekt realisiert werden. Als Beispiel könnte man damit eine Klasse Strassenverbindung abhängig von der Strassensituation als GesperrteStrasse oder als StrasseMitStau instanzieren was dann das Verhalten der Strassenverbindung zur Laufzeit beeinflusst.

Chain of responsibilty: Ermöglicht dass eine Anforderung oder eine Meldung von einer Anzahl Objekten verarbeitet werden kann, wobei jedes Objekt eine spezifische Aufgabe wahrnimmt und die Meldung an ein nächstes weiterleitet. Als Beispiel kann das Verarbeiten einer Meldung in verschiedenen Schritten angesehen werden: 'Dekomprimieren der Meldung' -> 'Authentizität der Meldung prüfen' -> 'Meldung interpretieren' usw....

Command: Bildet eine Anfrage an ein Objekt ab und erlaubt damit Transport, Protokollierung, Persistierung usw. der Anfrage. Zum Beispiel kann damit ein Command in einer Queue gespeichert und zu einem späteren Zeitpunkt ausgeführt werden.

State: Ermöglicht einem Objekt sein Verhalten abhängig von einem Zustand zu ändern. Die Implementation des Verhalten wird an den State delegiert.

Strategy: Kapselt einen Algorithmus in einer Klasse und ermöglicht damit eine allgemeine Verarbeitung mit spezifischen Strategien zu parametriesieren. So könnte damit die Berechnung einer Strassenverbindung mit der 'KuerzesterWegStrategie' oder mit der 'SchnellsterWegStrategie' parametrisiert werden. Der darunterliegende Berechnungsalgorithmus ist somit unabhängig und kann mit verschiedenen Strategien kombiniert werden.

Template Method: Kapselt Teile eines Algorithmus in Methoden und erlaubt Subklassen diese Teile zu implementieren. Somit realisiert eine Basisklasse das Grundgerüst eines Algorithmus und die Subklassen können einzelne Verarbeitungsschritte verfeinern.

Sunday, September 9, 2007

IO und funktionale Programmierung in C#

Zusammenfassung
Das seiteneffektfreie Programmieren ist in der funktionalen Programmierung ein wichtiger Grundsatz, welcher in der imperativen Programmierung (z.B C#) oft vernachlässigt wird obwohl dadurch höhere Nachvollziehbarkeit, Wiederverwendbarkeit und Testbarkeit erreicht werden kann. Im folgenden wird Anhand eines Beispiels gezeigt wie eine Konsolenausgabe seiteneffektfrei realisiert werden kann.

Einleitung
In der funktionalen Programmierung werden Seiteneffekte und Zustände wie der Teufel das Weihwasser gescheut. Leicht passiert es dass durch Seiteneffekte Methoden und Klassen, bei entsprechend ungeeignetem Design, ein nicht deterministisches Verhalten zeigen, was Zuverlässigkeit, Stabilität und Fehleranalyse von Programmen umgemein behindert. IO-Operationen können als Beispiel für Funktionalitäten dienen welche gezwungenermassen Seiteneffekte aufweisen.
string line = System.Console.ReadLine();


Wartet das Programm im Methodenaufruf ReadLine() auf eine Benutzereingabe, so ist nicht sicher ob der Aufruf jemals einen Wert zurückliefert (z.B falls der Benutzer am Bildschirm eingeschlafen ist und somit keine Eingabe macht). Weiter liefert der Aufruf ReadLine() bei jedem Aufruf unter Umständen einen anderen Wert zurück, obwohl aus Sicht des Programmes nichts geändert hat. Dieses Verhalten ist in der imperativen Programmierung (C#) normal, in der funktionalen Programmierung aber verpönnt da in dem darunterliegenden mathematischen Verständnis der Programmierung kein Platz für Nichtdeterminismus und Zufall ist. Auch die Methode System.Console.WriteLine() macht aus mathematischer Sicht wenig Sinn da sie keinen Rückgabewert hat und den Zustand des Programmes nicht verändert.

Beispiel
Wie könnte man nun die Seiteneffekte für folgendes Beispiel beheben?
static void Main(string[] args)
{
int index = 0;
var numbers = new int[] { 1, 3, 7, 10 };
foreach (var number in numbers)
{
System.Console.WriteLine("Index {0}: {1}", index++, number);
}
System.Console.ReadLine();
}

Lösung

Die Seiteneffekte können zwar nicht ganz eliminiert werden da eine Ausgabe auf die Console nun mal erwünscht ist. Die Idee ist es den Seiteneffekt an eine unkritische Stelle zu verschieben und den Zustand der gewünschten Ausgabe explizit abzubilden (wie dies ein Monad in der funktionalen Programmierung macht).

static void Main(string[] args)
{
System.Console.Write(
new int[]{1,3,7,10}
.Select( (number,index)=> string.Format("Index {0}: {1}{2}", index,number,Environment.NewLine))
.Aggregate( (lines,line) => lines + line));
System.Console.ReadLine();
}

Unter Verwendung von LINQ wird mit Select und string.Format() jedes Listenelement in eine Ausgabenzeile projiziert. Danach werden alle Zeilen mit Aggregate und 'lines + line' in einen einzigen String aggregiert welcher am Schluss auf die Konsole ausgegeben werden kann.

Da unsere Funktion nun die Ausgabe explizit abbildet, können wir Tests schreiben und prüfen ob die Ausgabe korrekt ist:


[TestMethod]
public void TestOutput()
{
string output = new int[]{1,3,7,10}
.Select( (number,index)=> string.Format("Index {0}: {1}{2}", index,number,Environment.NewLine))
.Aggregate( (lines,line) => lines + line);
Assert.AreEqual( "Index 0: 1" + Environment.NewLine +
"Index 1: 3" + Environment.NewLine +
"Index 2: 7" + Environment.NewLine +
"Index 3: 10" + Environment.NewLine , output);
}



Sunday, August 26, 2007

C# 3.0 vs. Haskell und das 'Countdown-Problem'

In 'Programming in Haskell' wird eine Lösung für das Countdown-Problem in Haskell vorgestellt. Im folgenden wurde diese Lösung in C# 3.0 übersetzt und der Unterschied zwischen Haskell und C# 3.0 analysiert.

Das Countdown Problem
Das Countdown Problem lautet wie folgt: Gegeben seien eine Folge positiver ganzer Zahlen, die Quellzahlen, und eine positive ganze Zahl, die Zielzahl. Gesucht wird ein arithmetischer Ausdruck, in dem jede der Quellzahlen höchstens einmal auftritt und der als Ergebnis die Zielzahl liefert. Als Operatoren können in dem Ausdruck +, -, * und / verwendet werden, wobei jedes Zwischenergebnis ebenfalls eine positive ganze Zahl sein muss. Zum Beispiel löst für die Quellzahlen [1; 3; 7; 10; 25; 50] und die Zielzahl 765 der Ausdruck (1 + 50) * (25 - 10) das Problem. [Referenz: http://www.mathematik.uni-marburg.de/~loogen/Lehre/ws06/Konzepte/Uebungen/u6.pdf]

Unter diesem Link kann die Lösung in C# heruntergeladen werden.
Die C#-Lösung unterscheidet sich zu der Haskell-Lösung vorallem dadurch, dass in C# objektorientierte Konstrukte eingeführt wurden. Nachfolgend eine Auflistung der Haskell-Features welche nur erschwert in C# abgebildet werden konnten



  • Rekursive Typen wurden als Klassenhierarchien abgebildet. Folgender Haskell-Code
    data Expr = Val Int  App Op Expr Expr

    wurde in C# zu
    public interface IExpression{}
    public struct Value : IExpression
    {
    public Value(int value){}
    }
    public abstract class Operation : IExpression
    {
    protected Operation(IExpression l, IExpression r){}
    }
    public class Add : Operation
    {
    public Add(IExpression l, IExpression r) : base(l, r) { }
    }
    public class Sub : Operation
    {
    public Sub(IExpression l, IExpression r) : base(l, r) { }
    }
    public class Mul : Operation
    {
    public Mul(IExpression l, IExpression r) : base(l, r) { }
    }
    public class Div : Operation
    {
    public Div(IExpression l, IExpression r) : base(l, r) { }
    }


    Während der Haskellausdruck an Produktionsregeln erinneren und somit eine internal DSL bilden, fehlt in C# 3.0 eine solche Möglichkeit. In C# wurde der dieser Ausdruck als ein Expression-Tree abgebildet. Die Anwendung des rekursiven Typs sieht in Haskell wie folgt aus:
    evaluate( App Add( Val 2 ) ( Val 3 ))

    während in C# der Expression-Tree wie folgt instanziert und evaluiert würde:
    new Add(new Value(2), new Value(3)).Eval();

    Das Problem an der objektorientierten Lösung in C# ist, dass in der Anwendung immer Objekte erzeugt werden müssen. Dies verlangt das Schlüsselwort 'new' welches im Gegensatz zum Haskell-Beispiel, den Ausdruck verschleiert. Auch ein FluentInterface bringt in diesem Fall nichts, da damit keine Ausdrücke verschachtelt werden könnten.

  • Lazy-Evaluation wird für die Lösung des Countdown-Problem benötigt, ansonsten alle Lösungskandidaten am Anfang der Berechnung in den Speicher geladen werden müssten. Lazy-Evaluation ermöglicht die Berechnungsfunktionen so zu kaskadieren, dass nur immer die gerade benötigten Resultat ermittelt werden und dass nicht mehr benötigte Zwischenresultat sofort im Speicher freigegeben werden können.
    Während in Haskell diesbezüglich keine Vorkehrungen nötig sind muss in C# explizit jede Berechnung und Berechnungsschlaufe über IEnumerable erfolgen. Verwendet man LINQ und Extension-Methods so können alle Haskell-Lösungen in die entsprechende LINQ-Lösung übersetzt werden. Aus der Haskell-Funktion

    solutions :: [Int] -> Int -> [Expr]
    solutions ns n = [e ns' <- choises ns,
    e <- exprs ns',
    evaluate e == [n]]

    wird in C# 3.0 zu
    public static IEnumerable<IExpression> GetSolutions(IEnumerable<int> values, int result)
    {
    return values.Choises().SelectMany(choise => choise.Exprs()).Where( exp => exp.IsValid() && exp.Eval() == result);
    }


  • Pattern-Matching ist ein Konstrukt um die Komplexität pro Funktion oder Methode zu reduzieren. Die Haskell-Funktion
    perms :: [a] -> [[a]]
    perms [] = [[]]
    perms (x:xs) = concat (map (interleave x)(perms xs))

    behandelt den Fall der leeren Liste und den Fall der nicht leeren Liste in zwei getrennten Funktionsimplementionen. Da C# Pattern-Matching nicht kennt müssen dort die beiden Fälle in der Methodenimplementation durch eine if-Anweisung explizit behandelt werden:
    public static IEnumerable<IEnumerable<int>> Perms(this IEnumerable<int> list)
    {
    if (list.Count() == 0)
    {
    return new int[][] { new int[] { } };
    }
    else
    {
    return list.Skip(1).Perms().SelectMany(subList => subList.Interleave(list.First()));
    }
    }


  • Listen sind in Haskell tief in die Sprache eingebettet. Folgendes Beispiel
    perms :: [a] -> [[a]]
    perms [] = [[]]
    perms (x:xs) = concat (map (interleave x)(perms xs))

    ist im starken Kontrast mit C# 3.0:
    public static IEnumerable<IEnumerable<int>> Perms(this IEnumerable<int> list)
    {
    if (list.Count() == 0)
    {
    return new int[][] { new int[] { } };
    }
    else
    {
    return list.Skip(1).Perms().SelectMany(subList => subList.Interleave(list.First()));
    }
    }

    Folgendes kann beobachtet werden:
    - x in Haskell entspricht list.First() in C#
    - xs in Haskell entspricht list.Skip(1) in C#

    Listen haben unter C# einen langen Leidensweg hinter sich:
    - .NET 1.0 kennt untypisierten Listen aus System.Collections
    - .NET 2.0 unterstützte typisierte Listen aus System.Collections.Generic
    - ab Visual Studio 2008 wird nun LINQ eingeführt

    LINQ ist grossartig doch leider kommt es sehr spät. Eine grosse Erneuerung ist die Erkenntnis dass man anstellen von Listen nun mit IEnumerable's arbeitet. Während Listen (z.B List) in .NET die Eigenschaft der Eager Evaluation haben, wird mit IEnumerable Lazy-Evaluation erreicht (siehe auch oben). Leider muss man sich in Zukunft immer explizit für 'Eager' oder 'Lazy'-Evaluation entscheiden und es wird immer einen konzeptionellen Bruch zwischen den beiden Ansätzen geben. Die Verwendung von IEnumerable (Lazy-Evaluation) ist auf jeden Fall der Verwendung von IList,ICollection usw. (Eager-Evaluation) vorzuziehen.

Zusammenfassung
Mit C# 3.0 lassen sich einige Konzepte aus der funktionalen Programmierung anwenden. Diese Konzepte sind allerdings in einer funktionalen Sprache wie Haskell eleganter umgesetzt. Dagegen steht im Kontrast dass in Haksell objektorientierte Konzepte fehlen, welche vorallem für den Bau von grossen und komplexen Softwaresystemen benötigt werden (z.B Abstrakte Datentypen)

Friday, August 17, 2007

Domain-Driven Design von Eric Evans. Kapitel 1-2

Nachfolgend fasse ich die Kapitel 1-2 vom Buch Domain-Driven Design von Eric Evans aus meiner Sicht zusammen. Folende Patterns zeigten für mich neue Aspekte auf und werden meine Arbeit in Zukunft beeinflussen.

Layered Architecture: In diesem Kapitel werden die verschiedenen Schichten wie 'Infrastructure Layer', 'Domain Layer', 'Application Layer' und 'Presentation Layer' konkret im Zusammenhang mit Domain-Driven Design beschrieben. In Kombination mit dem Pattern Model-View-Presenter habe ich nun eine Idee, wie ein Model darin aufgebaut werden könnte.

Modules: Das Kapitel zeigt mir auf, dass bei der Auftrennung von Modules (Namespaces,Assemblies) eher Grenzen zu wählen sind welche in der Fachdomäne auch vorhanden sind. So macht es zum Beispiel eher Sinn anhand von Begriffen wie 'Kundenverwaltung' oder 'Rechnungmodul' Module aufzuteilen, als anhand von Begriffen wie 'DomainLogic', 'DataServices' usw. Die führt dazu dass die Module eine geringe Kopplung aufweisen und eine abgeschlossene Einheit bilden.

Aggregates: Das Pattern hilft durch seine Regeln das Domänenmodell auf einfache Art und Weise übersichtlich und somit auch wartbar und einfach verständlich zu halten. Hätte ich früher noch über Module nachgedacht um die Kopplung zwischen Teilen des Domänenmodels zu reduzieren, geht das nun mit Aggregates deutlich einfacher und flexibler. Mir hatte immer eine Element im Design gefehlt wo spezielle Verantwortlichkeiten wie z.B Validierung und Konsistenzprüfung untergebracht werden konnten. Dies kann nun einfach im Domänenmodell selbst im Aggregateroot untergebracht werden. Allerdings habe ich auch schon gesehen, dass im Aggregateroot Infrastrukturdienste wie die Persistierung untergebracht wurden. Hier muss man sich aber strikte an die Verantwortlichkeiten des Domänenmodells und somit eines Aggregates erinnern und nur Domänenlogik implementieren.

Factories und Repositories: In beiden Kapitel wird konkret erläutert was die Verantwortlichkeiten von Factories und Repositories sind. Während Factories für das Erstellen von neuen Objekte und neuen Aggregates zuständig sind, behandeln Repositories das Auffinden und Instanzieren von persistierten Objekten und Aggregates. Mir werden diese Kapitel in Zukunft helfen, unabhängig von dem unterliegenden Datenzugriffsmechanismus einen einheitlichen, objektorientierten Design für die Persistenzschicht zu finden.

Sunday, July 29, 2007

Programming in Haskell (durch die C#-Brille gesehen)

Während des letzten Monats habe ich das Buch 'Programming in Haskell' durchgearbeitet. Es hat mir einen guten Einblick in die Welt der funktionalen Programmierung ermöglicht. Obwohl ich mir nicht die Zeit nahm jedes Beispiel und jede Übung bis ins letzte Detail zu verstehen, habe ich doch einige Konzepte verstanden welche meine Arbeit als Softwareentwickler in Zukunft beeinflussen werden. Folgende Punkte waren für mich neu und haben mich beeindruckt:

Abstraktion auf Ebene von einzelnen Funktionen und Operationen
Folgender C#-Code berechnet die laufende Summe über einen Array von Integers:
 public static int[] GetLaufendeSumme(int[] values)
{
int[] summierung = new int[values.Count()];
int sum = 0;
for( int i=0; i<values.Count(); i++ )
{
sum = values[i] + sum;
summierung[i] = sum;
}
return summierung;
}

In Haskell habe ich nun mit Hilfe der Funktion foldl folgende Lösung gefunden:

getLaufendeSumme :: [Int]->[Int]
getLaufendeSumme = foldl (
\summen wert -> case summen of
[] -> [wert]
otherwise -> summen++[wert + last summen] ) []


Da foldl das Iterieren und Berechnen von neuen Werten aufgrund der iterierten Werten abstrahiert ist der Haskellcode im Vergleich zum C#-Beispiel ausdruckstärker. foldl ist somit ein Pattern welches in ähnlichen Situation wieder angewendet werden kann. Im Gegensatz zu einer for-Schleife in C# ist mit foldl die Absicht und das Funktionieren des Codes klar.

Lazy Evaluation
Mit Layz Evaluation sorgt der Intepreter dafür, dass ein Ausdruck erst dann ausgewertet wird wenn der Wert des Ausdrucks benötigt wird. Bei Haskell werden alle Ausdrücke standardmässig mit 'Lazy Evaluation' aufgelöst. Nur Dank dieser Technik ist es möglich mit unendlichen Listen zu arbeiten. Im folgenden Bespiel definiert die Funktion fibs alle Fibonacci-Zahlen. Mit der Funktion fibGT kann dann die erste Fibonacci-Zahl, welche grösser als ein bestimmter Wert ist, gefunden werden.
fibs :: [Integer]
fibs = [0,1]++[ a+b (a,b) <- zip fibs (tail fibs) ]

fibGT :: Integer -> Integer
fibGT n = head (dropWhile (\a->a<n) fibs)

Bei C# werden standardmässig alle Ausdrücke sofort evaluiert und das Arbeiten mit z.B unendlichen Listen ist nur durch die explitzite Verwendung eines Iterators (IEnumerable, IEnumerator, etc.) möglich.

Pattern Matching
'Pattern Matching' hilft dabei, eine Funktion für verschiedene Fälle getrennt zu implementieren. So entscheidet der Haskell-Interpreter aufgrund der Argumente welche Funktionsimplementation für den aktuellen Fall herbeigezogen werden muss. So sind zum Bespiel folgende Funktionsdefinitionen für sumInt und sumInt2 gleichwertig:

sumInt :: [Integer] -> Integer
sumInt (n:ms) = n + sumInt ms
sumInt [] = 0

sumInt2 :: [Integer] -> Integer
sumInt2 ns = if ns == [] then 0
else (head ns) + sumInt2 (tail ns)

Während in der Funktion sumInt für den Fall '(n:ms)' und den Fall '[]' zwei Implementationen gemacht wurden, wird in der Funktion sumInt2 alles innerhalb einer Implementation mit Hilfe von if-Entscheidungen behandelt.



Induktives Denken

Folgender Haskell-Code berechnet die Fibonacci-Zahlen (0,1,1,2,3,5,8,13,21...)


fibs :: [Integer]
fibs = [0,1]++[ a+b (a,b) <- zip fibs (tail fibs) ]

Mich fasziniert an dieser Lösung, dass der Code nicht 'imperativ' als Anweisung verstanden werden kann. Der Haskell-Code oben lässt mich folgendes denken:
  1. fibs liefert mir alle Fibonacci-Zahlen
  2. Die Fibonacci-Zahlen beginnen mit 0 und 1
  3. Die weiteren Zahlen berechne ich indem ich die Fibonacci-Reihe mit der um eins verschobenen Fibonacci-Reihe pro Zahl kombinieren und pro Kombination die Zahlen zusammenzähle.

Für mich ist diese Denkweise ungewohnt, da die Definition der Funktion fibs davon ausgeht dass fibs (bereits) die korrekten Fibonacci-Zahlen zurückliefert. Auch hat die Funktion deklarativen Charakter. Es werden nämlich nur die Berechnungsregeln beschrieben. Wie und wann welche Berechnung erfolgt ist nicht ersichtlich.

Saturday, June 9, 2007

Model-View-Presenter (MVP) und seine Geschmacksrichtungen

Neulich hat Jeremy D. Miller in seinem Blog die verschiedenen Ausprägungen des Model-View-Presenter Patterns erörtert. Hier ein kurze Zusammenfassung dessen was mir wichtig erscheint:

Dem MVP liegen im allgemeinen folgende Definitionen zu Grunde:
  • Model ist eine Abbildung dessen was dargestellt wird.
  • View ist die Darstellung.
  • Presenter bringt das Model auf der View zur Darstellung und aktualisiert das Model aufgrund von Benutzereingaben.

The Autonomous View

Das 'Anti-Pattern'. Model-View-Presenter sind in einer Klasse vereint.

Supervising Controller
  • Presenter: Übergibt das Model (oder Teile davon) der View zur Darstellung. Der Presenter wird von der View aufgerufen um auf Benutzereingaben zu reagieren.
  • View: bringt das vom Presenter an die View übergebenen Model zur Darstellung (z.B mit Databinding). Leitet Benutzereingaben an den Presenter weiter.

Die View ist somit direkt vom Modell abhängig.

Passive View
  • Presenter: Kapselt das Model gegenüber der View. Übernimmt das Databinding indem die dargestellten Werte (nicht das Model) explizit der View zur Darstellung übergeben werden. Der Presenter wird von der View aufgerufen um auf Benutzereingaben zu reagieren.
  • View: Stellt die vom Presenter übermittelten Werte dar und leitet Benutzereingaben an den Presenter weiter.

Gegenüber dem Supervising Controller Pattern hängt die View hier nicht vom Modell ab.

Presentation Model
  • Presentation Model: Das Model und der Presenter sind hier zusammengeführt. Das Presentation Model zeigt gegenüber der View die darzustellenden Werte und reagiert falls ein solcher Wert verändert wird. Das Presentation Model wird von der View aufgerufen um auf Benutzereingaben zu reagieren.
  • View: Bindet das Presentation Model direkt für die Darstellung.

Für die Kommunikation zwischen View und Presenter gibt es bei allen Pattern zwei Möglichkeiten:

  1. Direkt: Die View ruft den Presenter direkt und explizit via Methoden auf (z.B im Eventhandler in der View).
  2. Indirekt: Der Presenter abonniert Events welche die View zur Verfügung stellt.

Zur Zeit verwende ich meistens das Passiv View Pattern um eine höchstmögliche Testabdeckung in den Unittests zu erreichen.