<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-3738779467711724977</atom:id><lastBuildDate>Mon, 07 Oct 2024 03:52:05 +0000</lastBuildDate><category>dotnet</category><category>alt.net</category><category>ddd</category><category>domain driven design</category><category>altnetde</category><category>domainmodel</category><category>netos2008</category><category>patterns</category><category>readability</category><category>tdd</category><category>aosd</category><category>architecture</category><category>archnet09</category><category>asp.net mvc</category><category>maintainability</category><category>nant</category><category>nhibernate</category><category>nunit</category><category>orm</category><category>presentationlayer</category><category>process</category><category>visualstudio</category><title>{ Sebastian Jancke, ein Blog }</title><description></description><link>http://sjancke.blogspot.com/</link><managingEditor>noreply@blogger.com (Sebastian Jancke)</managingEditor><generator>Blogger</generator><openSearch:totalResults>24</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-897824026744406952</guid><pubDate>Wed, 13 May 2009 14:55:00 +0000</pubDate><atom:updated>2009-05-13T17:06:12.980+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">alt.net</category><category domain="http://www.blogger.com/atom/ns#">altnetde</category><category domain="http://www.blogger.com/atom/ns#">architecture</category><category domain="http://www.blogger.com/atom/ns#">archnet09</category><title>Architecture.NET Open Space 2009</title><description>&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://archnet.mixxt.de&quot;&gt;&lt;img style=&quot;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 680px; height: 130px;&quot; src=&quot;http://archnet.mixxt.de/storage/images/css/f/d/2/491cf912b2ffb57eec68db89bca85.jpg&quot; border=&quot;0&quot; alt=&quot;Architecture.NET Open Space&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Am 5. und 6. Juni&lt;/span&gt; veranstalten &lt;a href=&quot;http://www.soptim.de&quot;&gt;SOPTIM&lt;/a&gt;, &lt;a href=&quot;http://www.software-architekten.de/&quot;&gt;Die Software Architekten&lt;/a&gt; und &lt;a href=&quot;http://www.itemis.de/&quot;&gt;itemis&lt;/a&gt; in Düsseldorf einen Open Space zum Thema &quot;Erprobte Konzepte für Unternehmensanwendungen in .NET&quot;.  &lt;br /&gt;&lt;br /&gt;Der Open Space soll Architekten aus der .NET- und Javawelt zusammen bringen um gemeinsam wachsen zu können. Mehr Informationen und die Anmeldung gibt es unter &lt;a href=&quot;http://archnet.mixxt.de&quot;&gt;http://archnet.mixxt.de&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Auslöser für die Idee dieser Veranstaltung waren einige gute Gespräche auf dem &lt;a href=&quot;http://netopenspace.de/&quot;&gt;.NET Open Space 2008 in Leipzig&lt;/a&gt;. Dort (und auch sonst) zeigte sich, das eine spezielle Diskussionsplatform für Architektur jenseits der Blaupause nötig ist.&lt;br /&gt;&lt;br /&gt;Mehr dazu auch auf &lt;a href=&quot;http://twitter.com/#search?q=%23archnet09&quot;&gt;Twitter (#archnet09)&lt;/a&gt;</description><link>http://sjancke.blogspot.com/2009/05/architecturenet-open-space-2009.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-1711793447119876589</guid><pubDate>Sun, 08 Feb 2009 16:57:00 +0000</pubDate><atom:updated>2009-02-10T17:09:55.125+01:00</atom:updated><title>Testing SyntaxHighlighter 2.0</title><description>&lt;pre class=&quot;brush: c#;&quot;&gt;&lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:812469c5-0cb0-4c63-8c15-c81123a09de7:3995cfcf-d4eb-44fe-8f38-62df52c7a60c&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;&lt;pre name=&quot;code&quot; class=&quot;c#:firstline[1]&quot;&gt;namespace Another.Test&lt;br /&gt;{&lt;br /&gt; public class AnotherFoo&lt;br /&gt; {&lt;br /&gt;   public string Bar()&lt;br /&gt;   {&lt;br /&gt;     return &quot;Foo: Bar.&quot;;&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pre&gt;  </description><link>http://sjancke.blogspot.com/2009/02/testing-syntaxhighlighter-20.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-2532227266810436166</guid><pubDate>Thu, 22 Jan 2009 17:38:00 +0000</pubDate><atom:updated>2009-01-22T18:38:13.704+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">alt.net</category><category domain="http://www.blogger.com/atom/ns#">asp.net mvc</category><category domain="http://www.blogger.com/atom/ns#">dotnet</category><category domain="http://www.blogger.com/atom/ns#">readability</category><title>ASP.NET MVC: Keine Präsentations-Belange im Controller</title><description>&lt;p&gt;Als ich heute diesen &lt;a href=&quot;http://code-inside.de/blog/2009/01/22/howto-dynamischen-content-auf-aspnet-mvc-masterpages-bringen/&quot; target=&quot;_blank&quot;&gt;Blogpost&lt;/a&gt; laß, kam mir unweigerlich folgender Gedanke:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font color=&quot;#444444&quot;&gt;Was hat man uns mit den ASP.NET MVC Beispielen angetan?&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Das Problem: Der Titel einer HTML-Seite ist ein Präsentations-Belang der nur durch die View gesteuert und gesetzt werden sollte. Ein Controller sollte nichts darüber wissen. Oren Eini hatte bereits vor einiger Zeit &lt;a href=&quot;http://ayende.com/Blog/archive/2008/12/29/do-not-put-presentation-concerns-in-the-controllers.aspx&quot; target=&quot;_blank&quot;&gt;darauf hingewiesen&lt;/a&gt;. Aber was nützt es, wenn erst einmal ein schlechtes Beispiel von vielen gelesen worden ist. Da heißt es wohl: dagegen anschreiben.&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;Ich gebe zu, dies in ersten Tests auch aus den Beispielen übernommen zu haben. Mittlerweile bin ich aber dazu übergegangen, sämtliche &lt;a href=&quot;http://ayende.com/Blog/archive/2008/12/29/my-baseline-asp.net-mvc-modifications.aspx&quot; target=&quot;_blank&quot;&gt;vorgeschlagenen Modifikationen&lt;/a&gt; umzusetzten. Dies bedeutet, das ViewData.Model passé ist, ViewData der Controller nicht mehr nutzbar ist und Titel durch die View gesetzt werden (durch asp:Content). Somit sind Präsentations- und Kontroll-Belange sauber getrennt und das Modell nur noch streng typisiert verfügbar.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;ViewData.Model.SiteMasterViewData.Title&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;ist jenseits von Clean Code und Lesbarkeit. Letzteres ist es schließlich für mich, was sauberen Code vor allem ausmacht.&lt;/p&gt; &lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:4aaa9836-dc8f-4d50-a018-65f79d1774af&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/alt.net&quot; rel=&quot;tag&quot;&gt;alt.net&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/altnetde&quot; rel=&quot;tag&quot;&gt;altnetde&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/readability&quot; rel=&quot;tag&quot;&gt;readability&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/asp.net+mvc&quot; rel=&quot;tag&quot;&gt;asp.net mvc&lt;/a&gt;&lt;/div&gt;  </description><link>http://sjancke.blogspot.com/2009/01/aspnet-mvc-keine-prsentations-belange.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-7570380493090306604</guid><pubDate>Mon, 12 Jan 2009 12:11:00 +0000</pubDate><atom:updated>2009-01-12T13:18:00.161+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ddd</category><category domain="http://www.blogger.com/atom/ns#">domain driven design</category><category domain="http://www.blogger.com/atom/ns#">dotnet</category><title>ALT.NET DE Online Meeting # 2 - DDD</title><description>Am 26.01.2009 finded das &lt;a href=&quot;http://altdotnet.de/OnlineMeeting_090126.ashx&quot;&gt;zweite Online Meeting&lt;/a&gt; der ALT.NET DE statt (danke &lt;a href=&quot;http://www.der-albert.com&quot;&gt;Albert&lt;/a&gt;!). Albert hat mich gebeten, einen &lt;a href=&quot;http://altdotnet.de/OnlineMeeting_090126.ashx&quot;&gt;Vortrag zum Thema Domain Driven Design&lt;/a&gt; zu halten.&lt;br /&gt;&lt;br /&gt;Diesmal habe ich mir überlegt, weniger Focus auf die Patterns (und ihre wörtliche Repräsentation) zu legen und zunächst mehr Raum für offene Fragen und Probleme rund um die Basis (UL, Domänenexperte) zu haben. Anlass waren die letzten Diskussion auf der DDD-Mailingliste in denen klar wurde, das selbst der &quot;Domänenexperte&quot; an sich nicht immer leicht zu identifizieren ist, geschweige denn jeder Zugang dazu hat.  Im Anschluss an dieses Fundament möchte ich diskutieren, welchen Rahmen Architektur schaffen muss/sollte/kann um die Arbeit mit und an einem Domänenmodell zu erleichtern.&lt;br /&gt;Als Basis soll ein fiktives (aber für mich aktuelles) Beispiel zum Thema &quot;Order Processing&quot; dienen.&lt;br /&gt;&lt;br /&gt;Ich erhoffe mir, dass der Vortrag Anregung zu Fragen und vor allem auch Diskussion des Themas gibt.</description><link>http://sjancke.blogspot.com/2009/01/altnet-de-online-meeting-2-ddd.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-3556161446980873055</guid><pubDate>Wed, 31 Dec 2008 15:51:00 +0000</pubDate><atom:updated>2008-12-31T16:54:08.634+01:00</atom:updated><title>Zum Jahresende: Koordinierte Weltzeit und irdisches Schwanken</title><description>&lt;p&gt;Heute morgen las ich in der &lt;a href=&quot;http://www.sueddeutsche.de/&quot; target=&quot;_blank&quot;&gt;Süddeutschen Zeitung&lt;/a&gt; folgende sehr schöne Formulierung, die in ihrer Wort- und vor allem Namenswahl selten ist:&lt;/p&gt; &lt;p align=&quot;center&quot;&gt;&lt;img title=&quot;schaltsekunde&quot; style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;347&quot; alt=&quot;schaltsekunde&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdQvpbmO4SN8yU1vW1XmZWywdqoJuu3UqfvxTvqmsaz2N75UU1zpH3E2mC_KdOYAMT4Ocv7HmjMQfvmh1wpRYefQU66_2i4AS0cPutVCWWEHgTmFSdGm9mnAYrRCWCuyemJqImC0f0JW_A/?imgmax=800&quot; width=&quot;504&quot; border=&quot;0&quot;&gt; &lt;/p&gt; &lt;p&gt;Dies erinnert mich an den schönen &lt;a href=&quot;http://www.youtube.com/watch?v=NjHp2yw_eRI&quot; target=&quot;_blank&quot;&gt;Werbespot von Monster.de&lt;/a&gt;, indem Menschen mit sehr langen Beinen die Erd-Rotation mit einer Art Fahrrad sicherstellen ;-)&lt;/p&gt; &lt;p align=&quot;center&quot;&gt;&lt;img title=&quot;Monster-de-tv-spot&quot; style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;283&quot; alt=&quot;Monster-de-tv-spot&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1n6A1hYVhgp8uSFQ-E7jjXF7hil_ej-yw3IlrxlCsKLfeRG3C-MHQvY6s4eCUPCS9udQlCnO5Omc4oQ0ZO3LEYsKHtmWHD9dyQmm8u_prLe3Au1lYL2lPme4xjd6dxHNvjGKwvZawZ-qr/?imgmax=800&quot; width=&quot;504&quot; border=&quot;0&quot;&gt;&lt;/p&gt;  </description><link>http://sjancke.blogspot.com/2008/12/zum-jahresende-koordinierte-weltzeit.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdQvpbmO4SN8yU1vW1XmZWywdqoJuu3UqfvxTvqmsaz2N75UU1zpH3E2mC_KdOYAMT4Ocv7HmjMQfvmh1wpRYefQU66_2i4AS0cPutVCWWEHgTmFSdGm9mnAYrRCWCuyemJqImC0f0JW_A/s72-c?imgmax=800" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-7388232032564974164</guid><pubDate>Tue, 30 Dec 2008 10:53:00 +0000</pubDate><atom:updated>2008-12-30T11:53:58.947+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">alt.net</category><category domain="http://www.blogger.com/atom/ns#">altnetde</category><category domain="http://www.blogger.com/atom/ns#">dotnet</category><title>ALT.NET Cologne #4 – Buildmanagement</title><description>&lt;p&gt;&lt;/p&gt; &lt;p&gt;Zum vierten Mal ein ALT.NET Bier im schönen Köln, diesmal zum Thema Buildmanagement (mit &lt;a href=&quot;http://maven.apache.org/&quot; target=&quot;_blank&quot;&gt;Maven&lt;/a&gt;). &lt;a href=&quot;http://www.lieser-online.de&quot; target=&quot;_blank&quot;&gt;Stefan&lt;/a&gt;, &lt;a href=&quot;http://www.shishkin.org&quot; target=&quot;_blank&quot;&gt;Sergey&lt;/a&gt;, &lt;a href=&quot;http://startbigthinksmall.wordpress.com/&quot; target=&quot;_blank&quot;&gt;Lars&lt;/a&gt; und ich hatten dazu Christian Raschka eingeladen. Nach einem kleinen “warm-up” gings ab 19h mit einer Einführung in Maven los. Anschließend diskutierten wir den aktuellen Stand des NPanday-Projektes (früher: NMaven). &lt;/p&gt; &lt;p&gt;Maven ist ein java-basiertes System zum Buildmanagement. Maven ist dabei nur eine sehr kleine Laufzeitumgebung, die erst durch die große Zahl verschiedenster Plugins zum Leben erwacht und arbeitet. Interessant für ALT.NET sind dabei vor allem die Konzeote und Ideen – auch wenn in gemischten Umgebungen ein java-basiertes Buildsystem durchaus pragmatisch erscheint.&lt;/p&gt; &lt;p&gt;Während Ant, NAnt und MSBuild als imperativ aufgefasst werden können, ist Maven rein deklarativ: Man beschreibt was man möchte (Abhängigkeiten, Compiler, Testrunner, Analysen, Reports, …) und Maven kümmert sich um den Rest. Grundsätzlich gilt hier “Convention-over-Configuration”. Es gibt für alles sinnvolle Standardwerte. Zusätzlich sind bestimmte “best practices” als feste Regeln in Maven verbaut. So ist zum Beispiel die Struktur eines Moduls/Projektes immer gleich. Dies hat den Vorteil, dass man darüber nicht mehr nachdenken muss, alle Projekte gleich aussehen und der Standard bereits erprobt ist. Die verschiedenen Bestandteile eines “build” (Phasen!) sind in Maven fest verbaut und entstehen nicht – wie bei Ant – durch das aneinanderreihen von “targets”. Der Vorteil: Eine Phase heißt überall auf der Welt gleich und nicht einmal install, einmal compile und einmal build – hier greifen auch die angesprochenen best practices. Zusätzlich erledigt eine Phase immer die selbe Aufgabe, egal in welchen Projekt (Phasen können trotzdem erweitert werden).&amp;nbsp; &lt;/p&gt; &lt;p&gt;Eine Assembly (oder in Java: JAR) wird in Maven auch Artefakt genannt. Ein Artefakt kann Abhängigkeiten zu anderen, eigenen Modulen haben oder aber auch externe Abhängigkeiten.&lt;/p&gt; &lt;p&gt;Alle Plugins werden genauso wie Abhängigkeiten zu anderen Modulen aufgefasst: Alles ist eine Abhängigkeit des Buildprozesses. Fehlt ein Plugin oder eine Abhängigkeit, so wird dieses von zentralen Servern (sog. “Repositories”) heruntergeladen. Dort können wiederum weitere (transitive) Abhängigkeiten hinterlegt sein; diese werden dann auch geladen. Alle Artefakte werden in einem lokalen Repository abgelegt, dieses funktioniert also als Cache. Für Unternehmen lohnt sich der Einsatz eines Proxy-Repositories im Unternehmensnetzwerk. Dieser Proxy hat seinen eigenen Cache und versucht Anfragen zunächst daraus zu bedienen. Fehlen hier Artefakte, werden diese über konfigurierbare zentrale Repositories heruntergeladen.&lt;/p&gt; &lt;p&gt;Maven vergibt für erstellte Artefakte automatisch Buildnummern, die sich niemals doppeln können. Grundsätzlich ist jeder Build zunächst als sog. “Snapshot” mit dem jeweiligen System-Benutzernamen markiert. Erst ein spezielles Plugin erzeugt auf Wunsche in komplettes Release. Zur Erzeugung eines solchen gehört dann auch der Upload auf ein angegebenes Repository. Auf öffentlichen zentralen Repositories sind idR keine Snapshots zu finden, dies garantiert die Stabilität der veröffentlichen Versionen. Wer dennoch gegen den “trunk/HEAD” bauen möchte, kann meist Snapshot-Versionen von den Servern der jeweiligen Projekte bekommen. Da Abhängigkeiten mit Versionsnummern definiert werden sollten (oder mit Versionsbereichen), erreicht Maven somit die so wichtige Reproduzierbarkeit von Builds.&lt;/p&gt; &lt;p&gt;Alle beschriebenen Abhängigkeiten eines&amp;nbsp; Artefakts werdem mit dem Project Object Model (POM) beschrieben. Dazu können auch Angaben über das verwendete SCM (mit Pfad zum Checkout) oder ein Ziel-Repository für Releases gehören. Fehlt der Quellcode kann Maven diesen automatisch aus dem gegebenen SCM herunterladen. Wird ein Release erzeugt, wird zunächst kontrolliert, ob im SCM noch Änderungen vorhanden sind. Falls es solche gibt, werden diese zunächst auch “ausgecheckt”. Anschließend wird der komplette Build durchgeführt und der Stand im SCM getagged. Das fertige Release wird dann ins lokale Repository und in das angegebene Ziel-Repository installiert.&lt;/p&gt; &lt;p&gt;Für .NET gibt es schon länger ein Reihe von Maven-Plugins, um .NET Compiler, Testrunner, Analysen, etc. zu unterstützen. Nach 2 Jahren im Apache Incubator konnte das Projekt aber nicht genügend Geschwindigkeit und Halt in der Community erzeugen. Deshalb ist der aktuelle (funktionierende) Stand nun unter neuem Namen nach Codeplex gewandert. Die Plugin-Sammlung heißt nun &lt;a href=&quot;http://www.codeplex.com/npanday&quot; target=&quot;_blank&quot;&gt;NPanday&lt;/a&gt;. Damit ist Maven sicherlich näher an .NET gerückt, fraglich ist aber ob der Ansatz einer Java-Runtime beibehalten werden kann. Derzeit scheinen die Pläne vorzusehen, sich noch stärker mit MSBuild im Rücken zu verbinden und langfristig die Java-Abhängigkeit zu verlieren. Auch veröffentlichen derzeit keine der großen Open Source Projekte in der .NET Welt ihre Artefakte auf zentralen Repositories. Für mehr Sichtbarkeit von Maven und die Aufnahme von mehr Geschwindigkeit müssten sicherlich Projekte wie &lt;a href=&quot;http://www.nhforge.org&quot; target=&quot;_blank&quot;&gt;NHibernate&lt;/a&gt;, &lt;a href=&quot;http://www.castleproject.org/container/index.html&quot; target=&quot;_blank&quot;&gt;Castle Windsor&lt;/a&gt;, &lt;a href=&quot;http://www.springframework.net/&quot; target=&quot;_blank&quot;&gt;Spring.NET&lt;/a&gt;, &lt;a href=&quot;http://www.nunit.org&quot; target=&quot;_blank&quot;&gt;NUnit&lt;/a&gt;, &lt;a href=&quot;http://www.codeplex.com/xunit&quot; target=&quot;_blank&quot;&gt;xUnit&lt;/a&gt;, … sich beteiligen und ein Deployment auf einem zentralen Server pflegen. Dazu müsste man sicherlich “unten” anfangen und die Basis (Unittesting-Frameworks, Castle Dynamic Proxy) zuerst deployen, damit alle darauf aufsetzenden Projekte ihre Abhängigkeiten korrekt definieren können.&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:e646a2b4-308d-4d9e-b580-026db2a0021a&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/alt.net&quot; rel=&quot;tag&quot;&gt;alt.net&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/altnetde&quot; rel=&quot;tag&quot;&gt;altnetde&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/dotnet&quot; rel=&quot;tag&quot;&gt;dotnet&lt;/a&gt;&lt;/div&gt;  </description><link>http://sjancke.blogspot.com/2008/12/altnet-cologne-4-buildmanagement.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-4229523130537894795</guid><pubDate>Thu, 11 Dec 2008 23:08:00 +0000</pubDate><atom:updated>2009-01-22T18:36:01.671+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">alt.net</category><category domain="http://www.blogger.com/atom/ns#">altnetde</category><category domain="http://www.blogger.com/atom/ns#">dotnet</category><category domain="http://www.blogger.com/atom/ns#">tdd</category><title>BDD dein MVC</title><description>&lt;p&gt;Vor ca. zwei Wochen habe ich mit dem ASP.NET MVC Framework im Rahmen eines verteilten Architektur-Prototypen begonnen. Ich war ich natürlich gespannt, ob sich mit dem MVC Framework auch nach BDD entwickeln lässt. Dies ist schließlich das Versprechen des MVC-Teams: Testbarkeit. &lt;/p&gt; &lt;p&gt;Ich kann sagen, dass nicht zu viel versprochen worden ist. Die Arbeit mit dem MVC Framework und die Erstellung einer Web-UI damit lässt sich problemlos mit Behavior Driven Development durchführen. Nachdem &lt;a href=&quot;http://www.der-albert.com&quot; target=&quot;_blank&quot;&gt;Albert&lt;/a&gt; schon einige seiner &lt;a href=&quot;http://www.der-albert.com/archive/2008/12/06/extension-methods-fuer-asp-net-mvc-unit-tests.aspx&quot; target=&quot;_blank&quot;&gt;Erweiterungen vorgestellt hat&lt;/a&gt;, möchte ich mich dem anschließen. Davon abgesehen ist dies ein guter Zeitpunkt, einmal Top-Down einen Controller mittels BDD zu entwickeln und damit BDD an einem konkreten Beispiel zu demonstrieren.&lt;/p&gt; &lt;h5&gt;Eingesetzte Frameworks&lt;/h5&gt; &lt;p&gt;Zunächst einmal ist es wohl fast Pflicht das Projekt &lt;a href=&quot;http://www.codeplex.com/MVCContrib&quot; target=&quot;_blank&quot;&gt;MvcContrib&lt;/a&gt; herunterzuladen, da es viele “fehlende” Erweiterungen mitbringt. Fehlend ist dabei in Anführungszeichen, weil sich das MVC Framework durch sehr gute Erweiterbarkeit auszeichnet: Factories für Controller, Routen und auch die komplette Render-Engine lassen sich austauschen. MvcContrib bringt eine Reihe von fertigen Implementierungen für IoC-Container (&lt;a href=&quot;http://www.castleproject.org/container/index.html&quot; target=&quot;_blank&quot;&gt;Castle Windsor&lt;/a&gt;, &lt;a href=&quot;http://www.springframework.net/&quot; target=&quot;_blank&quot;&gt;Spring.NET&lt;/a&gt;, …) und auch Render-Engines (&lt;a href=&quot;http://www.castleproject.org/monorail/documentation/v1rc2/viewengines/brail/index.html&quot; target=&quot;_blank&quot;&gt;Brails&lt;/a&gt;, &lt;a href=&quot;http://code.google.com/p/nhaml/&quot; target=&quot;_blank&quot;&gt;NHaml&lt;/a&gt;, …) mit. Als Render-Engine setzte ich ASP.NET ein, Windsor ist mein IoC Container der Wahl.&lt;/p&gt; &lt;p&gt;Darüber hinaus kommt für Unit- und Integrationstests &lt;a href=&quot;http://www.codeplex.com/xunit&quot; target=&quot;_blank&quot;&gt;xUnit&lt;/a&gt; mit Björns &lt;a href=&quot;http://code.google.com/p/xunitbddextensions/&quot; target=&quot;_blank&quot;&gt;xUnit.BDDExtensions&lt;/a&gt; zum Einsatz.&lt;/p&gt; &lt;h5&gt;Entwicklung eines Controllers anhand einer Userstory&lt;/h5&gt; &lt;p&gt;Für diesen Artikel habe ich eine Userstory gekürzt: Wenn der Anwender die Webseite “Index” aufruft, soll ihm “alle” gespeicherten Produkte auf der View “Index” angezeigt werden.&lt;/p&gt; &lt;p&gt;Zunächst erstellen wir also eine Specification für diese Userstory. Hier empfiehlt es sich Björns Templates für den Resharper zu installieren. Eine Specification spiegelt immer genau einen Kontext einer Userstory wieder. Diese Specification erzeugt einen ShopController (zunächst ohne weiteren Kontext). Bisher existiert der ShopController nicht. Diesen legen wir dann an. Damit haben wir in unserer Specification vorerst alles arrangiert (der Arrange-Teil von AAA). Wir können die Specification nun ausführen. Nun fügen wir Verhalten hinzu (der Act-Teil von AAA): die Aktion “Index” wird aufgerufen. Diese aufgerufene Methode des System-Under-Test fügen wir nun in die Klasse ShopController ein. Nun kompiliert die Specification wieder und wir können diese wiederum ausführen. Nun ist es an der Zeit, Beobachtungen einzufügen (der Assert-Teil von AAA). Nach der Erstellung einer Beobachtung in der Specification führen wir diese aus (Resultat: Failure, Rot), danach implementieren wir soviel, bis die Specification wieder grün wird. Anschließend fügen wir inkrementell weitere Beobachtungen ein und erfüllen diese wie beschrieben.&lt;/p&gt; &lt;p&gt;Im optimalen Fall beschreibt eine Userstory immer genau einen Kontext, andernfalls müsste diese noch feiner zerlegt werden. Eine Specification entspricht wie bereits gesagt genau einem Kontext, der sich im Namen der Specification samt Beschreibung der Handlung widerspiegelt. Unüblich für C# und Ähnliche ist die Verwendung von Unterstrichen anstelle von &lt;a href=&quot;http://en.wikipedia.org/wiki/CamelCase&quot; target=&quot;_blank&quot;&gt;Camel Casing&lt;/a&gt;. Trotzdem sollte dieser Stil genutzt werden, da er die Lesbarkeit auch in den Testrunnern und Methoden-Übersichten deutlich erhöht.&lt;/p&gt; &lt;p&gt;Bei der Erstellung des Kontext werden auch alle Abhängigkeiten initialisiert. Dabei versteckt die Basisklasse für Specifications die Mechanik (Mocking Framework, …) zur Erzeugung von Abhängigkeiten. Speziell für das MVC Framework habe ich die Basisklasse “ControllerInstanceContextSpecification” angelegt, da diese die &lt;a href=&quot;http://www.codeplex.com/MVCContrib/Wiki/View.aspx?title=TestHelper&amp;amp;referringTitle=Documentation&quot; target=&quot;_blank&quot;&gt;Testhelper von MvcContrib&lt;/a&gt; versteckt, um einen Controller vollständig zu initialisieren.&lt;/p&gt; &lt;p&gt;Als Beobachtungen sind grundsätzlich Überprüfung des Ergebnisses oder Überprüfung von Methodenaufrufen und Exceptions denkbar. Für Ergebnisse werden diese nach der Handlung in einem privaten Feld der Specification gespeichert (hier: “result”). Für die Überprüfung von Methodenaufrufen und Exceptions ist ein Mocking Framework nötig, das den AAA-Stil unterstützt (zB Rhino.Mocks). Ältere Record-Reply Varianten funktionieren damit nicht. Zur erhöhten Lesbarkeit werden Assertions auf Werten und Methodenaufrufen hinter besser lesbaren Extension-Methods versteckt. Beobachtungen erfüllen somit auch die Forderung, pro “Test” nur eine Assertion auszuführen – andernfalls sind Fehlschläge in Tests schwerer zu lokalisieren.&lt;/p&gt; &lt;h5&gt;Der beschriebene Quelltext&lt;/h5&gt; &lt;p&gt;Hier nun die komplette Specification:&lt;/p&gt; &lt;div style=&quot;border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, &#39;Courier New&#39;, courier, monospace; background-color: #f4f4f4; max-height: 200px&quot;&gt; &lt;div style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   1:&lt;/span&gt; [Concern(&lt;span style=&quot;color: #0000ff&quot;&gt;typeof&lt;/span&gt; (ShopController))]&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;class&lt;/span&gt; when_a_shop_controller_handles_the_index_action :&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   3:&lt;/span&gt;     ControllerInstanceContextSpecification&amp;lt;ShopController&amp;gt;&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   4:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   5:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;private&lt;/span&gt; IDiscService discService;&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   6:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;private&lt;/span&gt; ActionResult result;&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   7:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   8:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;protected&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;override&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;void&lt;/span&gt; EstablishContext()&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   9:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  10:&lt;/span&gt;         discService = Dependency&amp;lt;IDiscService&amp;gt;();&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  11:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  12:&lt;/span&gt;         discService.WhenToldTo(x =&amp;gt; x.FindDiscsForSale())&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  13:&lt;/span&gt;             .Return(&lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; List&amp;lt;Disc&amp;gt;&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  14:&lt;/span&gt;                         {&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  15:&lt;/span&gt;                             &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; Disc(3698, &lt;span style=&quot;color: #006080&quot;&gt;&quot;U2 / All the best&quot;&lt;/span&gt;, &lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  16:&lt;/span&gt;                                      2003,&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  17:&lt;/span&gt;                                      &lt;span style=&quot;color: #006080&quot;&gt;&quot;classical&quot;&lt;/span&gt;),&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  18:&lt;/span&gt;                         });&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  19:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  20:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  21:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;protected&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;override&lt;/span&gt; ShopController CreateSut()&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  22:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  23:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff&quot;&gt;return&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; ShopController(discService);&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  24:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  25:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  26:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;protected&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;override&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;void&lt;/span&gt; Because()&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  27:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  28:&lt;/span&gt;         result = Sut.Index();&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  29:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  30:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  31:&lt;/span&gt;     [Observation]&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  32:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;void&lt;/span&gt; should_redirect_to_search_view()&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  33:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  34:&lt;/span&gt;         result.should_be_rendered_view(&lt;span style=&quot;color: #006080&quot;&gt;&quot;Index&quot;&lt;/span&gt;);&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  35:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  36:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  37:&lt;/span&gt;     [Observation]&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  38:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;void&lt;/span&gt; should_retrieve_discs_from_disc_service()&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  39:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  40:&lt;/span&gt;         discService.AssertWasCalled(x =&amp;gt; x.FindDiscsForSale());&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  41:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  42:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Die Implementierung des Controllers sieht dann wie folgt aus:&lt;/p&gt;&lt;br /&gt;&lt;div style=&quot;border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, &#39;Courier New&#39;, courier, monospace; background-color: #f4f4f4; max-height: 200px&quot;&gt;&lt;br /&gt;&lt;div style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   1:&lt;/span&gt; [HandleError]&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   2:&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;class&lt;/span&gt; ShopController : Controller&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   3:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   4:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;private&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;readonly&lt;/span&gt; IDiscService service;&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   6:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; ShopController(IDiscService service)&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   7:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   8:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff&quot;&gt;this&lt;/span&gt;.service = service;&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   9:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  10:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  11:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; ActionResult Index()&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  12:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  13:&lt;/span&gt;         /* ...&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  14:&lt;/span&gt;         */&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  15:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  16:&lt;/span&gt;         var model = &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; ShopViewModel();&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  17:&lt;/span&gt;         model.Discs = service.FindDiscsForSale();&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  18:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff&quot;&gt;return&lt;/span&gt; View(&lt;span style=&quot;color: #006080&quot;&gt;&quot;Index&quot;&lt;/span&gt;, model);&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  19:&lt;/span&gt;      }&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;  20:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Zu guter letzt ist noch die neue Basisklasse für Instance-Specifications nötig. Diese ist speziell für Controller des MVC Frameworks und versteckt die Mechanik der Testhelper von MvcContrib bei der Initialisierung eines Controllers.&lt;/p&gt;&lt;br /&gt;&lt;div style=&quot;border-right: gray 1px solid; padding-right: 4px; border-top: gray 1px solid; padding-left: 4px; font-size: 8pt; padding-bottom: 4px; margin: 20px 0px 10px; overflow: auto; border-left: gray 1px solid; width: 97.5%; cursor: text; line-height: 12pt; padding-top: 4px; border-bottom: gray 1px solid; font-family: consolas, &#39;Courier New&#39;, courier, monospace; background-color: #f4f4f4; max-height: 200px&quot;&gt;&lt;br /&gt;&lt;div style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   1:&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;public&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;abstract&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;class&lt;/span&gt; ControllerInstanceContextSpecification&amp;lt;T&amp;gt; : InstanceContextSpecification&amp;lt;T&amp;gt;&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   2:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;where&lt;/span&gt; T : Controller&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   3:&lt;/span&gt; {&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   4:&lt;/span&gt;     &lt;span style=&quot;color: #0000ff&quot;&gt;protected&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;override&lt;/span&gt; &lt;span style=&quot;color: #0000ff&quot;&gt;void&lt;/span&gt; InitializeSystemUnderTest()&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   5:&lt;/span&gt;     {&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   6:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff&quot;&gt;base&lt;/span&gt;.InitializeSystemUnderTest();&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   7:&lt;/span&gt;         &lt;span style=&quot;color: #0000ff&quot;&gt;new&lt;/span&gt; TestControllerBuilder().InitializeController(Sut);&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   8:&lt;/span&gt;     }&lt;/pre&gt;&lt;pre style=&quot;padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none&quot;&gt;&lt;span style=&quot;color: #606060&quot;&gt;   9:&lt;/span&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:26fc339d-f7d2-452a-b155-ae85d3937387&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/alt.net&quot; rel=&quot;tag&quot;&gt;alt.net&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/altnetde&quot; rel=&quot;tag&quot;&gt;altnetde&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/bdd&quot; rel=&quot;tag&quot;&gt;bdd&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/dotnet&quot; rel=&quot;tag&quot;&gt;dotnet&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/tdd&quot; rel=&quot;tag&quot;&gt;tdd&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/asp.net&quot; rel=&quot;tag&quot;&gt;asp.net&lt;/a&gt;&lt;/div&gt;  </description><link>http://sjancke.blogspot.com/2008/12/bdd-dein-mvc.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-1073715924928939079</guid><pubDate>Sun, 02 Nov 2008 17:33:00 +0000</pubDate><atom:updated>2008-11-02T18:33:35.736+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">alt.net</category><category domain="http://www.blogger.com/atom/ns#">netos2008</category><title>.NET Open Space 2008 rekapituliert</title><description>&lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;img title=&quot;PICT2600&quot; style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;244&quot; alt=&quot;PICT2600&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIHcD2jdVVocoySHCtRt3IyhDg2x2CawTDN0menWc8Gyfh3XgXbdwmxklzTSVvQ_uCGOXLX91kLf3tfrfJf9-KvhM3CBKUS4cKus3BrS2rO0OOFXtbh3hXDmgT6g8Cmwjx34FcHYwUhmgE/?imgmax=800&quot; width=&quot;184&quot; align=&quot;right&quot; border=&quot;0&quot;&gt;Mit ganz viel Verspätung kommt nun also meine Zusammenfassung des .NET Open Space 2008 in Leipzig. Zunächst ist zu sagen, dass Leipzig wirklich eine schöne Stadt ist. Dank eines ortskundigen Teilnehmers konnten wir am Freitag einige tolle Ecken von Leipzig besichtigen (Auerbachs Keller war natürlich ein Muss). Die Party am Freitag Abend war eine angenehme, lustige Runde zum Kennenlernen. &lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;&lt;img title=&quot;PICT2608&quot; style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;184&quot; alt=&quot;PICT2608&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbFIvlOHIy4EV7v4Rh1hrIyyJsp4Rw1byuEzFPt4u9g_U1ztKQiUVzmhGzJXJMx8nHGaIedbqgrp1I36AUEqSs7Ryaiw9mK2AJe_dzw4_AD6sLxw7ZsYFKWwuFCrqZFAlLKSvp0Cno1Q6f/?imgmax=800&quot; width=&quot;244&quot; align=&quot;left&quot; border=&quot;0&quot;&gt;Der &lt;strong&gt;Samstag&lt;/strong&gt; startete dann mit einer Erklärung des Open Space Konzeptes durch Stefan und der anschließenden Planung der Sessions. Der Versuch, demokratisch jedem Wunsch (und jeder Kollisions-Vermeidung) bei den Sessions beizukommen stellte sich im Laufe des Tages noch als Problem heraus – es dauerte einfach zu lange.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Die erste Session zum Thema “Testen, Test-First, Testbarkeit” interessierte anscheinend fast alle Teilnehmer. Dies führte schnell zur Wandlung in eine (sehr gute) Einstiegs-Veranstaltung und schließlich dann auf die Frage:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font color=&quot;#444444&quot;&gt;Wie verkaufe ich das ans Management?&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Dank Björn und Gabriel kam die Diskussion von TDD schnell zu BDD. &lt;/p&gt; &lt;p&gt;Die zweite Session des Tages (die ich besuchte) war ein großer Pool von xDDs: “DDD, BDD, FDD, MDD, MDA, MDSD”. Abgesehen von der Tatsache, dass die Session einfach zu viele Themen gruppierte, gab es zunächst eine Einführung in einige der genannten xDDs. Leider kam die Diskussion zu “xDD – Wieviel wovon?”, die Lars und ich uns gewünscht hätten, nicht zum Zuge. Dafür gab es schnell mal wieder die Frage&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font color=&quot;#444444&quot;&gt;Wie verkaufe ich das ans Management?&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;font color=&quot;#333333&quot;&gt;Überhaupt schien dies für manche ein zentraler Aspekt der Konferenz (oder ihrer Probleme) zu sein: Wie lassen sich aktuelle Entwicklungsmethoden, Ansätze, Philosophien verkaufen? Manch einer soll über TDD auch sagen, dass es einfach zur Professionalität eines jeden Entwicklers gehört, maschinell überprüfbare Tests zu schreiben… Ich hätte gedacht, dass die treibenden Kräfte hinter dieser Dauer-Frage sich schließlich doch zu einer separaten Session treffen, um dies ausführlich zu diskutieren – leider kam es dazu nicht. Somit blieb die Frage weiterhin immer offen im Raum herumschwirren.&lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;img title=&quot;PICT2606&quot; style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;184&quot; alt=&quot;PICT2606&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0H9dBdOYTBiquytqWAqJ8fwMC2aKryy8a04giqtSy-pMt8JGhcAGUpUHLt-xLvwAxLeoMZEbCQn8jhCFv16uTBt21mP28te7ugAEDbKj168PcuS7ao3fO-Nbjv5jIRiKbe-Zw_qWFAioa/?imgmax=800&quot; width=&quot;244&quot; align=&quot;left&quot; border=&quot;0&quot;&gt;Open Space wird auch die organisierte&amp;nbsp; Kaffeepause genannt. Und in den Pausen von dieser organisierten Pause ergaben sich dann einige sehr Interessante Diskussionen unter anderem mit Lars und Björn über Architektur aus der ALT.NET-Sicht und “Von Java lernen”. &lt;/p&gt; &lt;p&gt;In der letzten Session, die ich am Samstag besuchte, war das Thema “ORMs – &lt;a href=&quot;http://www.nhforge.org&quot; target=&quot;_blank&quot;&gt;NHibernate&lt;/a&gt; vs LLBLGen”. Es stellte sich schnell heraus, dass hier datenzentrische auf objektzentrische Entwickler trafen, und die wahl der Tools davon maßgeblich geprägt ist. Heftig diskutiert war auch die Frage nach der Einstiegsschwelle von NHibernate. Einige Ehrfahrungsberichte brachten dann doch nahe, dass die grunsätzliche Schwelle niedrig ist – komplizierte Szenarien aber einfach von ihrer Natur her kompliziert sind.&lt;/p&gt; &lt;p&gt;Der erste Tag zeigte, dass die Organisation der Konferenz super, ja (fast) perfekt war. Das Konzept funktionierte wunderbar. Zu meiner Überraschung war das mehrheitliche Interesse doch im Themenbereich ALT.NET angesiedelt (neben den Bereichen Mobile und Softskills).&lt;/p&gt; &lt;p&gt;Am Abend setzten sich die Diskussionen in kleineren Runden auf der Party fort.&lt;/p&gt; &lt;p&gt;&lt;img title=&quot;PICT2622&quot; style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;184&quot; alt=&quot;PICT2622&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpUN_4T9E9z_0LaEO6POlz69cYv_YEYrIGUVxDC-E2yufpgbK9gqfivQMm4R7LvsPpKX1AFVzSUI5sQoPm7lczW3GSp7BkrFk8RBttSS82gtMP9csaxHjvrvCi0abGk1rj4kbjjoCk73Y6/?imgmax=800&quot; width=&quot;244&quot; align=&quot;right&quot; border=&quot;0&quot;&gt;Der &lt;strong&gt;Sonntag&lt;/strong&gt; stand zunächst ganz im Zeichen einer schnelleren Session-Aufteilung (Continuous Improvement !) und einer Live-Coding Session zur Demonstration von BDD und Pairprogramming. Diese wurde von Björn und Gabriel durchgeführt. Für mich zeigte sich wieder einmal, dass BDD unschlagbar gut zu vermitteln ist - im Gegensatz zu reinem, alten TDD. Auch die Art der Präsentation (Pairprogramming), wie sie bereits von JP Boodhoo in Bonn demonstriert wurde, scheint einfach gut zu funktionieren.&lt;/p&gt; &lt;p&gt;&lt;img title=&quot;PICT2629&quot; style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;244&quot; alt=&quot;PICT2629&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigCpGv0hnlQqqQFpAwHlZc_OOosvq41uIp5f-evwT2MYgKONzQYelVbITXF3woMKHOoIe1YkWlhUlXNO0POVyQXn5KkWoiVGy1lie_84rtIPsmxwa8j92aTK4VGB7qGE_QM4rwZc7lcuP0/?imgmax=800&quot; width=&quot;184&quot; align=&quot;left&quot; border=&quot;0&quot;&gt; Später kam es dann zur ersehnten Session zum Thema “ALT.NET Architektur – Von Java Lernen”. Diskutiert wurden zunächst ein typischen Szenario einer verteilten Anwendung. Das Szenario waren drei typische Services für Warenkorb, Kundenmanagement und Bestellungsbearbeitung. Anschließend stellte ein Teilnehmer seine .NET Architektur vor und ich habe mit Lars die gängigen Konzepte im Java Enterprise Bereich und auf&amp;nbsp; Java Application Servern vorgestellt. Offenkundig war die starke Tendenz, Skalierbarkeit in der Performanz durch Asynchronität und Messaging zu realisieren. &lt;/p&gt; &lt;p&gt;Als Ergebnis der Diskussion würde ich sehen, dass wir im ALT.NET Umfeld gerade erst noch am Anfang der Diskussion stehen. Eigentlich bauen alle irgendwie Enterprise Architekturen in .NET, nur scheint kaum jemand darüber zu sprechen (und die MS Guidelines sind von 2005…), gerade über komplexere Themen wie Skalierbarkeit, Sicherheit, … Wir können und müssen wohl noch einiges vom Java Enterprise Bereich lernen. Mehr dazu demnächst…&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p align=&quot;center&quot;&gt;&lt;img title=&quot;PICT2633&quot; style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;244&quot; alt=&quot;PICT2633&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgbBcPF-UT2cUHcK2Oig6ggF8__HcbcLXoMcd53yWnsYWHGM27Mm2Nkbj7gtq_eadEPrvjPam_PQuUUhTkfQNnNhAtU7heZqmzAV9KmhGZY1SyMamRoK2DkNxyhDCvpVDgUtK2mhyJCJ7B8/?imgmax=800&quot; width=&quot;184&quot; border=&quot;0&quot;&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:f1ce4355-69f2-4f1b-a3c2-1a49414ee4f4&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/netos2008&quot; rel=&quot;tag&quot;&gt;netos2008&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/alt.net&quot; rel=&quot;tag&quot;&gt;alt.net&lt;/a&gt;&lt;/div&gt;  </description><link>http://sjancke.blogspot.com/2008/11/net-open-space-2008-rekapituliert.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIHcD2jdVVocoySHCtRt3IyhDg2x2CawTDN0menWc8Gyfh3XgXbdwmxklzTSVvQ_uCGOXLX91kLf3tfrfJf9-KvhM3CBKUS4cKus3BrS2rO0OOFXtbh3hXDmgT6g8Cmwjx34FcHYwUhmgE/s72-c?imgmax=800" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-8437164986584877572</guid><pubDate>Thu, 16 Oct 2008 17:30:00 +0000</pubDate><atom:updated>2008-10-16T19:30:41.336+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">alt.net</category><category domain="http://www.blogger.com/atom/ns#">netos2008</category><title>.NET Open Space 2008, Twitter</title><description>&lt;p&gt;Morgen geht’s los zum .NET Open Space 2008 in Leipzig. Wer mir folgen möchte, kann dies nun auch auf Twitter tun:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;a href=&quot;http://www.twitter.com/sjancke&quot; target=&quot;_blank&quot;&gt;http://www.twitter.com/sjancke&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;font color=&quot;#333333&quot;&gt;Ich bemühe mich das ganze dort (und hier) zu dokumentieren – wir werden sehen ob’s klappt.&lt;/font&gt;&lt;/p&gt;  </description><link>http://sjancke.blogspot.com/2008/10/net-open-space-2008-twitter.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-4680597892534625273</guid><pubDate>Mon, 06 Oct 2008 20:00:00 +0000</pubDate><atom:updated>2008-10-07T11:45:22.245+02:00</atom:updated><title>DDD – Vortrag in Köln (UPDATE)</title><description>&lt;p&gt;&lt;/p&gt; &lt;p&gt;Hallo,&lt;/p&gt; &lt;p&gt;kurzfristig hat sich der Ort der Veranstaltung geändert. Die DNUG trifft sich morgen (07. Oktober 2008), 19h nun hier:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Grünfeld an der Brüsseler Straße 47.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Siehe dazu auch diese von Albert erstellte &lt;a href=&quot;http://is.gd/3C2H &quot; target=&quot;_blank&quot;&gt;Karte&lt;/a&gt;. &lt;/p&gt;  </description><link>http://sjancke.blogspot.com/2008/10/ddd-vortrag-in-kln-update.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-6434747034440876364</guid><pubDate>Mon, 15 Sep 2008 21:29:00 +0000</pubDate><atom:updated>2008-09-15T23:31:57.468+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ddd</category><category domain="http://www.blogger.com/atom/ns#">domain driven design</category><title>DDD – Vortrag bei DNUG Köln, 07-10-2008</title><description>&lt;p&gt;&lt;/p&gt; &lt;p&gt;Wie &lt;a href=&quot;http://www.der-albert.com/archive/2008/09/11/software-architektur-wochen-in-bonn-und-koumlln.aspx&quot; target=&quot;_blank&quot;&gt;Albert schon angekündigt&lt;/a&gt; hat, gebe ich am 07. Oktober 2008 einen Vortrag zum Thema &lt;a href=&quot;http://www.domaindrivendesign.org&quot; target=&quot;_blank&quot;&gt;Domain Driven Design&lt;/a&gt; in der &lt;a href=&quot;http://www.dnug-koeln.de/&quot; target=&quot;_blank&quot;&gt;DNUG Köln&lt;/a&gt;. &lt;/p&gt; &lt;p&gt;Allgemein ist die Konstruktion von Modellen ein effektives Mittel, um die Komplexität eines Problems zu beherrschen. Domain Driven Design setzt als Basis unserer Entwicklungsprozesse die Fokussierung auf die Domäne und ihre Modelle, uneingeschränkt durch technische Komplexität, die heutige Projekte meist überlädt. Das wichtigste Werkzeug ist dabei die &lt;a href=&quot;http://sjancke.blogspot.com/2008/07/ddd-allgegenwrtige-universelle-sprache.html&quot; target=&quot;_blank&quot;&gt;allgegenwärtige Sprache&lt;/a&gt; als Modell der Domäne und der Kontext, in dem sich das Modell einer Domäne befindet. &lt;/p&gt; &lt;p&gt;Der Vortrag gibt eine Einführung in das Thema und einen Überblick über fortgeschrittenere Techniken:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Voraussetzungen &lt;/li&gt; &lt;li&gt;Allgegenwärtige Sprache&lt;/li&gt; &lt;li&gt;Grundlegende Bausteine als Basis der Sprache und Orientierungshilfe&lt;/li&gt; &lt;li&gt;Modelle reichhaltiger gestalten&lt;/li&gt; &lt;li&gt;Modelle durch ihren Kontext trennen und integrieren&lt;/li&gt; &lt;li&gt;DDD in der Praxis: gängige Probleme und häufige Fragen&lt;/li&gt;&lt;/ul&gt; &lt;p&gt; &lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:85a71ec9-9454-4149-af57-03d758bf7986&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/ddd&quot; rel=&quot;tag&quot;&gt;ddd&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/domain+driven+design&quot; rel=&quot;tag&quot;&gt;domain driven design&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;  </description><link>http://sjancke.blogspot.com/2008/09/ddd-vortrag-bei-dnug-kln-07-10-2008.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-3487751622815990477</guid><pubDate>Tue, 02 Sep 2008 16:58:00 +0000</pubDate><atom:updated>2008-09-02T18:58:58.316+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">aosd</category><title>Aspektorientierung – der natürliche nächste Schritt</title><description>&lt;p&gt;&lt;/p&gt; &lt;p&gt;Angefangen hat Aspektorientierug mit Gregor Kiczales und seinem damaligen Forschuntsteam bei Xerox PARC. Seine Arbeit an “Metaobject Protocols” führte zur Erkenntnis, dass vor allem die Modularisierung von sog. “cross-cutting concerns” die größte Verbesserung brachte. Bei Xerox entstand dann AspectJ (welches heute ein Projekt im Eclipse-Bereich ist). AspectJ ist derzeit wohl die am meisten verbreitete AO-Sprache und vielleicht die einzige die wirklich in Produktion eingesetzt wird. Daneben existieren eine vielzahl von AO-Ansätzen durch Container wie das Spring-Framework oder Enterprise Java Beans (EJB), die eine weite Verbreitung gefunden haben und einer großen Zahl von Entwicklern einen einfachen Zugang zu AO-Technologie bieten.&amp;nbsp; Um zu verstehen, warum der Schritt zu Aspektorientierung natürlich und logisch ist, müssen wir zunächst verstehen, was treibende Kraft in der Weiterentwicklung der verschiedenen Paradigmen ist.&lt;/p&gt; &lt;p&gt;1974 war es Edsger W. Dijkstra, der in seinem Artikel “&lt;a href=&quot;http://www.cs.utexas.edu/users/EWD/transcriptions/EWD04xx/EWD447.html&quot; target=&quot;_blank&quot;&gt;On the role of scientific thought&lt;/a&gt;” den Begriff “separation of concerns” prägte:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;Let me try to explain to you, what to my taste is characteristic for all intelligent thinking. It is, that one is willing to study in depth an aspect of one&#39;s subject matter in isolation for the sake of its own consistency, all the time knowing that one is occupying oneself only with one of the aspects.&lt;/p&gt; &lt;p&gt;&lt;font color=&quot;#444444&quot;&gt;[..] But nothing is gained --on the contrary!-- by tackling these various aspects simultaneously. It is what I sometimes have called &quot;the separation of concerns&quot;, which, even if not perfectly possible, is yet the only available technique for effective ordering of one&#39;s thoughts, that I know of. This is what I mean by &quot;focussing one&#39;s attention upon some aspect&quot;: it does not mean ignoring the other aspects, it is just doing justice to the fact that from this aspect&#39;s point of view, the other is irrelevant. &lt;/font&gt;&lt;/p&gt; &lt;p&gt;&lt;font color=&quot;#444444&quot;&gt;(30th August 1974, Prof. Edsger W. Dijkstra)&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Dijkstra argumentierte, das wissenschaftliches Denken in der Entwicklung von Programmen fehlte, jedoch nötig sei um gute, fehlerfreie Programme zu konstruieren. Spätestens seit der erneuten Definition durch Chris Reade in seinem Buch “Elements of Functional Programming” gilt die Trennung der Anliegen als nötig, um die Komplexität eines Systems in den Griff zu bekommen. Die “Separation of concerns” kann als Geisteshaltung hinter dem Ziel der Modularisierung betrachtet werden. Damit ist aber noch nicht geklärt, was genau ein “concern” denn genau ist. Man könnte einen concern als jede Anforderung und jedes Anliegen an eine Software definieren, und dies scheint die anerkannte Definition zu sein. Dabei kann ein concern so generell wie “Interaktion mit einer Datenbank” sein, aber eben auch eine spezielle Berechnung detailliert vorgeben.&lt;/p&gt; &lt;p&gt;Vor dem Problemen der nötigen Modularisierung stehen wir aber nicht alleine. Andere Branchen haben es auf ihre eigene Art gelöst. Architekten scheinen separate Pläne für Wasserversorgung, Stromleitungen, Abflüsse, Lichtinstallationen und natürlich die Konstruktion an sich anzufertigen. Darüber hinaus ist die Innenarchitektur ein&amp;nbsp; ganz eigenständiger Beruf.&lt;/p&gt; &lt;p&gt;Modularisierung ist auf der einen Seite zwingend notwendig, um die Komplexität heutiger Anforderungen in Teile zu zerlegen und so zu reduzieren, damit ist jedoch unklar, wie weit wir die Modularisierung treiben müssen. Die Professorin &lt;a href=&quot;http://www.people.hbs.edu/cbaldwin/&quot; target=&quot;_blank&quot;&gt;Carliss Y. Baldwin&lt;/a&gt; von der Universität Harvard hat die Modularisierung von einem ökonomischen Blickpunkt aus untersucht und kam zu dem Schluss, dass Modularisierung eine treibende ökonomische Kraft ist, die ganze Märkte (zB den PC-Markt seit Einführung des modularisierten IBM-kompatiblen PCs) umkrempeln kann. Darüber hinaus hat sie auch die Modularisierung mittels Aspekten und den Optionswert von Aspekten &lt;a href=&quot;http://www.people.hbs.edu/cbaldwin/DR2/BaldwinClarkCES.pdf&quot; target=&quot;_blank&quot;&gt;untersucht&lt;/a&gt; und war &lt;a href=&quot;http://www.aosd.net/2006/archive/BaldwinAOSD06-keynote.ppt&quot; target=&quot;_blank&quot;&gt;Keynote-Speakerin&lt;/a&gt; bei der Konferenz AOSD 06. Interessant finde ich an dieser Stelle, dass auch Kent Beck bei seinem Plädoyer für möglichst späte Entscheidungen im eXtreme Programming mit Optionswerten argumentiert hat. &lt;/p&gt; &lt;p&gt;Alle Paradigmen, die bisher zu Felde geführt wurden, von der Strukturierten Programmierung über Prozedurale, Funktionale bis hin zur Objektorientierten Programmierung hatten ein Ziel: bessere Modularisierung. Dabei hat jedes Paradigma seine eigenen Konzepte, ein Modul abzubilden (…, Funktionen, Objekte) kreiert. Dabei wurde jedoch eine Gruppe von Anliegen stets ausgeschlossen, weil sie bei der Dekomposition in Module dieser Paradigmen über Module hinweg verstreut waren und und somit faktisch unsichtbar wurden.&amp;nbsp; Die genannten Paradigmen sind nicht im Stande, diese Gruppe von Anliegen selbst zu modularisieren. Der Grund dafür ist die einfache Tatsache, dass es immer zu einer Zahl von Anliegen einige Anliegen gibt, die andere kreuzen (darauf komme ich noch zurück).&lt;/p&gt; &lt;p&gt;Ich denke es ist klar, dass ich auf cross-cutting concerns hinaus will. Zu oft ist aber versucht worden AO zu verkaufen und dabei die “Neuen” mit einer Reihe von Fachbegriffen zu überladen. Da es sich bei der Aspektorientierung um einen völligen Paradigma-Wechsel handelt (der dennoch rückwärts kompatibel ist), halte ich es für eine gute Idee, vorerst auf genau diese Fachwörter (&quot;buzzwords” ?) zu verzichten. Ich denke dieser Ansatz wird auch durch die Aussage von Gregor Kiczales gestützt, dass die Geisteshaltung von Aspektorientierung weitaus wichtiger ist, als die derzeitigen technischen Umsetzungen und ihre spezielle Ausprägung der Fachbegriffe. Würde man diese nutzen wollen, so müsste zunächst ihre allgemeine Semantik erklärt werden. Dies wird fast nie getan und erscheint für eine Einführung auch zu fortgeschritten.&lt;/p&gt; &lt;p&gt;Im Jahre 2004 stellte Ted Neward, bei einer Podiumsdiskussion zum Thema AOP auf der Konferenz “The Server Side Symposium”, eine Aufgabe: Aspektorientierung zu erklären, ohne die gängigen “buzzwords” zu verwenden. Der Projektleiter des AspectJ-Projektes, &lt;a href=&quot;http://www.aspectprogrammer.org/blogs/adrian/archives.html&quot; target=&quot;_blank&quot;&gt;Adrian Colyer&lt;/a&gt; (heute auch für SpringSource tätig) antwortete mit seinem Artikel “&lt;a href=&quot;http://www.aspectprogrammer.org/blogs/adrian/2004/05/the_ted_neward.html&quot; target=&quot;_blank&quot;&gt;The Ted Neward Challenge (AOP without the buzzwords)&lt;/a&gt;”. Seine Argumentation basiert auf der Annahme, dass eine echte Trennung der Anliegen nur erreicht werden kann, wenn das Verhältnis von Konzepten zu Implementierungen genau 1:1 ist, also ein Konzept an genau einer Stelle in der Software Implementiert ist. &lt;/p&gt; &lt;p&gt;Nehmen wir uns ein einfaches Problem (welches auch von &lt;a href=&quot;http://www.cs.ubc.ca/~gregor/papers/kiczales-icse05-aopmr.pdf&quot; target=&quot;_blank&quot;&gt;Gregor Kiczales untersucht wurde&lt;/a&gt;): Eine Zeichentafel (Canvas) und eine Vielzahl verschiedener geometrischer Objekte (Shapes). Die verschiedenen Shapes (Dreieck, Viereck, Kreis, Oktaeder, …) verwalten ihre Eigenschaften und ihr Zeichenverhalten selbst. Wir modellieren sie als Objekte. Ebenso den Canvas. Ein weiteres Anliegen ist auch die Benachrichtigung des Canvas, wenn ein Shape sich verändert. Im Allgemeinen würde man dieses Anliegen durch eine Subject-Observer Beziehung zwischen Canvas und den verschiedenen Shape-Objekten implementieren. Bei allen Änderungen benachrichtigen die verschiedenen Shape-Objekte den Canvas. Das Anliegen der Benachrichtigung ist damit aber nicht mehr eigenständig modularisiert, denn alle verschiedenen Objekte (oder Klassen von Objekten) implementieren die Benachrichtigung auf ihre eigene Art. Wir haben also ein Verhältnis Konzept : Implementierung von 1 : n. Umgekehrt haben wir in einem Objekt nun mehr als ein Konzept implementiert und haben hier ein Verhältnis Konzept : Implementierung von n : 1. Die Krux liegt darin, dass wir schon bei einem sehr einfachen Beispiel ein Anliegen nicht mehr richtig Modularisieren konnten, weil es ein übergreifendes Anliegen ist. Skaliert man das Beispiel auf ein durchschnittlich großes System, ist die ganze Problematik daran vorstellbar.&lt;/p&gt; &lt;p&gt;Nun ließe sich erwidern, dass vielleicht eine andere Art der Dekomposition das Problem gelöst hätte. Dies ist in der Forschung untersucht worden und derzeitiger Stand ist anscheinend, dass es nicht möglich ist. Das Problem wird “Tyranny of the dominant decomposition” genannt. Dies möchte ich anhand eines Beispieles illustrieren: Es soll eine Zeit gegeben haben, in der wir statt MP3s jede Menge CDs im Regal stehen hatten. Wir wollen aus den CDs schnell einige zu einem speziellen Genre suchen. Dazu könnten wir sie nach Genre sortieren. Allerdings würden wir auch gerne schnell CDs nach einem Namen suchen. Vielleicht wäre es also besser, die CDs nach Namen zu sortieren. Dann könnten wir aber nicht mehr schnell nach Genre ähnliche CDs suchen. Die Lösung scheint greifbar: wir sortieren nach Genre und jedes Genre wiederum nach Namen. Damit gehen wir den Kompromiss ein, dass wir nicht sehr schnell nach Namen suchen können, aber wir können sehr gut nach Genre suchen, selbst wenn wir zunächst eine spezielle CD gesucht haben. Das Anliegen “Genre” ist also hier die dominante Dekomposition über dem Anliegen “Namen” (verkürzt gesagt). Kommt nun aber noch das Anliegen hinzu, CDs zu einem Jahr zu finden, haben wir ein Problem, egal welche Dekomposition wir als dominant wählen. Es gibt also nur einen Ausweg: wir müssten sowohl die Suche nach Genre, als auch die Suche nach Namen und auch die Suche nach Jahren eigenständig Modularisieren. Dies scheint mit den Mitteln Plazierung der CDs im Regal nicht möglich, wir brauchen also einen Paradigma-Wechsel.&lt;/p&gt; &lt;p&gt;Das Beispiel der CD-Sortierung zeigt nicht nur die Existenz von übergreifenden Anliegen aus der Problemdomäne heraus. Das Beispiel zeigt vor allem im Gegensatz zum Zeichenbrett, dass übergreifende Anliegen “mehrdimensional” sind und die Zahl der Dimensionen “unbegrenzt” sein kann. Diesem Umstand hat auch IBM mit der Forschung im HyperJ-Projekt Rechnung getragen.&lt;/p&gt; &lt;p&gt;Für Viele ist dennoch Aspektorientierung derzeit vor allem eines: Aspektorientierte Programmierung (AOP), mit einem starken Hang eine Sache Namens “Logging” besonders schön zu lösen. Dabei ist der eigentliche Witz am “Hello world”-Beispiel der AOP die Tatsache, dass dort Tracing modularisiert wird. Innerhalb von Experimenten beobachtet wurde, das in vielen Fällen richtiges Logging – die Präsentation von Debug und Context-Informationen – eigentlich kein cross-cutting concern ist, weil für jeden Context die Anforderungen völlig unterschiedlich sind. Eine Ausnahme bildet vielleicht die einheitliche Protokollierung von Fehlern im System. Darüber hinaus scheint für Viele die Formel cross-cutting = nicht-funktional zu gelten. Das auch diese Reduktion der Aspektorientierung zu kurz greift, zeigt die Tatsache, dass erfahrene AO-Experten in der Regel den wahren Wert von AO bei funktionalen, zur Domäne gehörigen cross-cutting concerns sehen. Nicht zuletzt, weil nicht-funktionale, Infrastruktur-Anliegen heute von Containern (EJB, Spring, …) hinreichend gut modularisiert wurden. Gleichzeitig scheint mir hierher die Popularität der (falschen) Formel cross-cutting = nicht-funtional zu kommen. Eben weil die obigen Beispiele mit dem Zeichenbrett oder der CD-Sortierung keinerlei nicht-funktionale Anliegen enthält, mag ich diese besonders. Sie zeigen zum einen, dass bereits sehr simple Domänen cross-cutting concerns enthalten. Zum anderen ist aber auch sichtbar, dass diese meist aus der Problemdomäne entstammen und (gefühlt) die “kleine” Zahl der nicht-funktionalen Infrastruktur Anliegen übersteigt.&lt;/p&gt; &lt;p&gt;Heute, ca. 10 Jahre nach der “Erfindung” der AO ist die Aspektorientierte Programmierung weitgehend stabil und wird produktiv eingesetzt (zumindest im Falle von AspectJ). Forschung findet natürlich auch noch hier statt, scheint sich aber derzeit vor allem auf die Auswirkungen von AO im Bereich des Software Engineerings zu konzentrieren: Requirements Engineering, Refactoring, Patterns, Productlines, Tooling und nicht zuletzt “Aspect Mining”. Diese Bereich bieten trotz akuter Forschung trotzdem bereits nutzbare Ergebnisse, die auch Anwendung zu scheinen finden. So gibt es einige nützliche Ergebnisse, bei der Anwendung von AspectJ zur Implementierung von Objektorientierten Patterns in einer Pattern-Library. Die Erweiterung von Use-Cases hin zu sog. “Use-Case slices” und die damit einhergehende 1:1 Implementierung der Kern-Usecases durch Objekte und der Varianten/Extension Points und anderen Usecases durch Aspekte ist sogar als &lt;a href=&quot;http://www.amazon.de/Aspect-Oriented-Software-Development-Addison-Wesley-Technology/dp/0321268881/&quot; target=&quot;_blank&quot;&gt;Buch&lt;/a&gt; verfügbar. Hier können auch einfache Angriffspunkte zur Feature-Konfiguration im Sinne von Productlines gesetzt werden. &lt;/p&gt; &lt;p&gt;Für “Joe Developer” (Zitat aus dem se-radio.net) scheinen aber viele dieser Techniken/Prozesse/Tools und Ergebnisse im Zusammenhang mit AO bisher unsichtbar gewesen zu sein. Um so mehr ist es an der Zeit, diese Dinge genau zu Beleuchten und statt AspectJ-Tracing-Tutorials lieber “Best practices” und mögliche Einsatzgebiete zu benennen. Den Syntax einer Sprache oder die Details einer Technologie lassen sich schließlich gut aus Büchern und Dokumentation entnehmen. Die Einsatzmöglichkeiten und gute Vorgehensweisen einer Technologie entstammen aber der Erfahrung und dem Umgang damit. Sie können eigentlich nur von den bereits Erfahrenen vermittelt werden, oder aber durch viele Experimente (und Fehlschläge) selbst erlernt werden. Dabei bevorzuge ich eindeutig den ersten Weg und versuche von den Experten zu lernen.&lt;/p&gt; &lt;p&gt;Im Interview von Gregor Kiczales durch Markus Völter (auf se-radio.net) spekulierten schließlich beide darüber, dass zur Annahme des OO-Paradigmas 20 Jahre nötig waren, die Annahme von AO aber bereits nach 10 Jahren sehr weit fortgeschritten ist und die Zukunft positiv aussieht. Nicht zuletzt kommen wohl die meisten heute schon damit in Kontakt, wenn sie Middleware-Plattformen wie EJB-Container oder das Spring-Framework einsetzten. &lt;/p&gt; &lt;p&gt;Zum Schluss möchte ich noch darauf zu sprechen kommen, dass ich bisher nur für Aspektorientierung plädiert habe, nicht aber für den Einsatz einer speziellen AOP-Technologie. Auch habe ich weder nur für AO-Sprachen noch gegen Container-AOP (Spring.AOP, Method interception, …) plädiert. Solche Entscheidungen sind schließlich nicht allgemein entscheidbar, da sie immer von den speziellen Anforderungen, Budgets, etc.. abhängen. Auch die Frage, wie fein Aspekte granuliert werden sollen steht im Raum und beeinflusst insbesondere den Einsatz von “Method interception”, Spring.AOP, AspectJ oder auch eine Kombination dieser. Der Grad der technischen Umsetzung und Einsatz von AO-Technologie ist nicht zuletzt auch durch die “Adoption strategy” gesteuert. Hierzu gibt es wiederum allgemeine Empfehlungen, auf die ich aber ein anderes Mal eingehen möchte und werde.&lt;/p&gt; &lt;p&gt;Nachtrag: Ich habe gestern gesehen, dass &lt;a href=&quot;http://www.lieser-online.de&quot; target=&quot;_blank&quot;&gt;Stefan Lieser&lt;/a&gt; die Thematik “Tyranny of the dominant decomposition” an einem anderen, aber ebenso schönen Beispiel erläutert hat: Ein Dokument mit Elementen (Text, Absätze, …) und dazu orthogonal die Frage der Formatierung.&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:0ad8e6b2-29fb-4f13-bec1-74feca5a945a&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/aosd&quot; rel=&quot;tag&quot;&gt;aosd&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/aop&quot; rel=&quot;tag&quot;&gt;aop&lt;/a&gt;&lt;/div&gt;  </description><link>http://sjancke.blogspot.com/2008/09/aspektorientierung-der-natrliche-nchste.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-554985649621885682</guid><pubDate>Sun, 31 Aug 2008 16:51:00 +0000</pubDate><atom:updated>2008-09-02T10:49:40.605+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ddd</category><category domain="http://www.blogger.com/atom/ns#">domain driven design</category><title>Was ist Domain Driven Design?</title><description>&lt;ul&gt; &lt;li&gt;&lt;strong&gt;&lt;strong&gt; &lt;h6&gt;&lt;strong&gt;Bisher in dieser Serie:&lt;/strong&gt; &lt;/h6&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/li&gt; &lt;li&gt; &lt;h6&gt;&lt;a href=&quot;http://sjancke.blogspot.com/2008/07/ddd-eine-einfhrung.html&quot; target=&quot;_blank&quot;&gt;DDD – Eine Einführung&lt;/a&gt;, &lt;/h6&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;http://sjancke.blogspot.com/2008/07/ddd-allgegenwrtige-universelle-sprache.html&quot; target=&quot;_blank&quot;&gt;&lt;/a&gt;&lt;a href=&quot;http://sjancke.blogspot.com/2008/07/ddd-allgegenwrtige-universelle-sprache.html&quot; target=&quot;_blank&quot;&gt; &lt;/a&gt;&lt;h6&gt;&lt;a href=&quot;http://sjancke.blogspot.com/2008/07/ddd-allgegenwrtige-universelle-sprache.html&quot; target=&quot;_blank&quot;&gt;DDD – Allgegenwärtige / Universelle Sprache&lt;/a&gt;&lt;/h6&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;In meinem Artikel “&lt;a href=&quot;http://sjancke.blogspot.com/2008/07/ddd-eine-einfhrung.html&quot;&gt;DDD – Eine Einführung&lt;/a&gt;” hatte ich versucht einen Überblick über &lt;a href=&quot;http://www.domaindrivendesign.org/&quot; target=&quot;_blank&quot;&gt;Domain Driven Design&lt;/a&gt; und seine Auswirkungen zu geben. Leider fehlte dabei eine genaue Definition. Dies ist allerdings nicht einfach und ich bezweifle, ob es derzeit eine komplette und exakte Definition von DDD gibt. Die Beschreibungen auf Wikipedia scheinen mir unvollständig, da sie zu sehr auf den Aspekt des Objekt-Design abzielen. Auch im Buch selbst wird eher schwammig in das Thema eingeführt: Man bekommt schnell ein Gefühl für DDD und, mit Blick auf das Inhaltsverzeichnis, auch für den Umfang. Trotzdem fehlt eine präzise, umfassende Definition. Daher ist dieser Artikel sicherlich zunächst nur ein Versuch – ich maße mir keine Vollständigkeit an.&lt;/p&gt; &lt;p&gt;Der Grund dafür liegt, meiner Meinung nach, in der Tatsache begründet, dass DDD eigentlich vor allem eines ist: ein philosophischer Ansatz, wie Problemdomänen in Software implementiert werden sollten:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Das Modell, und damit die Domäne, sind im Herzen unserer Software&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Und &quot;drumherum&quot; bildet DDD damit eine Entwurfsmuster-Sprache, die uns ermöglicht darüber zu kommunizieren. Dies würde ich als eine Definition von Domain Driven Design und dessen Kern bezeichnen wollen (siehe auch &lt;a href=&quot;http://laribee.com/blog/2007/05/08/domain-model-less-pattern-more-lifestyle/&quot;&gt;David Laribee&#39;s Artikel &lt;/a&gt;dazu).&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Worin liegt dies begründet und welche Auswirkungen hat dieser Ansatz für uns? Gehen wir also zurück zum Anfang. Zunächst dreht sich bei der Erstellung von Software alles um Modelle und Abstraktionen. Haben wir eine gegebene Domäne, so bauen wir zu einer Teilmenge daraus ein Modell, eine Abstraktion der Domäne. Die gesamte Domäne (wie eigentlich alles auf der Welt) ist natürlich zu groß, um sie vollständig zu modellieren. Wenn wir Software entwickeln, bauen wir also primär ein Modell einer Domäne.&lt;/p&gt; &lt;p&gt;Derzeit besteht unsere bester Weg zu Modularisierung und Abstraktion in der Nutzung von Objekt Orientierung. Damit liegt die Idee nahe, unser Modelle durch “nakte” Objekte zu implementieren - wie wir es in der Uni gelernt haben bevor wir über Datenbanken, Transaktionen und Infrastruktur nachdachten. Idealer weise gibt es zwischen Quelltext und Modell keine Unterschiede, also keine Übersetzungen. Im Artikel “&lt;a href=&quot;http://sjancke.blogspot.com/2008/07/ddd-allgegenwrtige-universelle-sprache.html&quot;&gt;DDD – Allgegenwärtige / Universelle Sprache&lt;/a&gt;” bin ich bereits darauf eingegangen, warum Eric Evans Übersetzungen als kritisch ansieht. Unser Modell ist also von der Domäne gesteuert.&lt;/p&gt; &lt;p&gt;Wenn wir nun ein Modell der Domäne erstellen, ergibt sich direkt die Frage: Wer kennt die Domäne? Die Architekten? Oder Software Analysten? Oder Entwickler? Wohl kaum. Erstere denken wohl eher an Entwicklung im großen Rahmen, letztere im sehr kleinen und Software-Analysten können wohl analysieren, aber kennen wohl nicht jede Problem-Domäne. Diejenigen, die eine Domäne am besten kennen sind aber direkt vor unseren Nasen: Der Kunde und seine Experten. Diese Idee sehen wir auch in anderen Bereichen, zB in den Agilen Prozessen. Im eXtreme Programming heißt das ganze “Customer On Site”. Da das Modell also keine verborgene Magie innerhalb der Software ist, sondern eine – für alle sichtbare – Abstraktion, ergibt sich die Grundlage des Domain Driven Design:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Das Modell, und damit die Domäne, sind im Herzen unserer Software&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Dies hat weitreichende Konsequenzen auf alle Bereiche, wie Anforderungen an die Architektur, Auswirkungen auf Objekt-Design, das Team, seine Prozesse, etc. Weil wir zum Beispiel dieses Modell kommunizieren müssen, sowohl intern als auch extern, liegt die Idee nahe, eine gemeinsame Sprache in allen Beriechen zu nutzen: angefangen bei der Kommunikation, über Dokumentation, Diagrammen bis hin zum Quelltext. Ideal ist es also, wenn sich die Sprache und damit das Modell im Quelltext manifestiert. Dann könnte man nur durch das Lesen des Quelltextes im Domänen-Modul eine Menge über die Domäne selbst lernen.&lt;/p&gt; &lt;p&gt;Zusammenfassend kann man also sagen, dass Domain Driven Design ein Ansatz zur Software-Entwicklung ist, der das Modell einer Problemdomäne ins Zentrum stellt. Kritik und Erweiterungen sind willkommen!&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Nachtrag: Definitions-Absatz erweitert um die Idee der Pattern-Language.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:98e0b777-68b2-4f67-8a05-d7b193bbcdf2&quot; style=&quot;margin: 0px; padding: 0px; display: inline; float: none;&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/domain+driven+design&quot; rel=&quot;tag&quot;&gt;domain driven design&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/ddd&quot; rel=&quot;tag&quot;&gt;ddd&lt;/a&gt;&lt;/div&gt;</description><link>http://sjancke.blogspot.com/2008/08/was-ist-domain-driven-design.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-1410342626380200756</guid><pubDate>Sun, 31 Aug 2008 16:41:00 +0000</pubDate><atom:updated>2008-08-31T18:41:40.108+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ddd</category><category domain="http://www.blogger.com/atom/ns#">domain driven design</category><category domain="http://www.blogger.com/atom/ns#">domainmodel</category><category domain="http://www.blogger.com/atom/ns#">dotnet</category><category domain="http://www.blogger.com/atom/ns#">patterns</category><title>Komplexität in Geschäftslogik</title><description>&lt;h4&gt;&lt;/h4&gt; &lt;h5&gt;Ein Vergleich der Patterns Table Module (DataSets,..), Transaction Scripts und Domain Model&lt;/h5&gt; &lt;p&gt;Abseits meiner Beiträge zum Thema &lt;a href=&quot;http://www.domaindrivendesign.org&quot; target=&quot;_blank&quot;&gt;Domain Driven Design&lt;/a&gt; möchte ich hier die drei Ansätze zur Handhabung von Komplexität in Geschäftslogik aus Martin Fowler’s Buch “&lt;a href=&quot;http://www.amazon.com/Enterprise-Application-Architecture-Addison-Wesley-Signature/dp/0321127420&quot; target=&quot;_blank&quot;&gt;Patterns of Enterprise Application Architecture&lt;/a&gt;” vergleichen. Alle drei stellen Wege dar, eine Domäne zu modellieren, wenn auch die beiden ersten Ansätze stark zu prozeduraler Programmierung tendieren:&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href=&quot;http://martinfowler.com/eaaCatalog/tableModule.html&quot; target=&quot;_blank&quot;&gt;Table Module Pattern&lt;/a&gt; (auch bekannt als DataSets in .NET)  &lt;li&gt;&lt;a href=&quot;http://martinfowler.com/eaaCatalog/transactionScript.html&quot; target=&quot;_blank&quot;&gt;Transaction Scripts&lt;/a&gt;  &lt;li&gt;&lt;a href=&quot;http://martinfowler.com/eaaCatalog/domainModel.html&quot; target=&quot;_blank&quot;&gt;Domain Model Pattern&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Fowler hat zum Vergleich eine ähnliche Grafik wie die folgende verwendet.&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;http://lh3.ggpht.com/sebastian.jancke/SLrJv9z1CyI/AAAAAAAAAEU/gcM2ZrcQg5c/s1600-h/ComplexityComparison10.png&quot;&gt;&lt;img title=&quot;Complexity-Comparison&quot; height=&quot;231&quot; alt=&quot;Complexity-Comparison&quot; src=&quot;http://lh6.ggpht.com/sebastian.jancke/SLrJwQxGK0I/AAAAAAAAAEY/WMEbwoyumM8/ComplexityComparison_thumb8.png?imgmax=800&quot; width=&quot;340&quot; align=&quot;left&quot; border=&quot;0&quot;&gt;&lt;/a&gt; In der Grafik ist Komplexität gegenüber Aufwand gestellt. Die rote Linie steht für das Table Module Pattern, die blaue Linie steht für Transaction Scripts und die grüne Linie steht für das Domain Model Pattern. Die Idee der Grafik ist es zu zeigen, wie die drei Ansätze mit erhöhter Komplexität skalieren. Dabei kommt es nicht so sehr auf den exakten Verlauf an. Wichtiger ist es zu sehen, dass die Grafik recht gut dem gefühlten “Aufwand” entspricht, bei der Arbeit mit den Ansätzen: der Aufwand bei Transactions Scripts und Table Module (in .NET also DataSets) steigt rasant und macht zunehmende Komplexität kaum noch handhabbar. Aber auch das Domain Model Pattern lässt sich nicht unendlich lange nutzen, ohne ans eine Grenzen zu stoßen. Trotzdem liegt diese Grenze bedeutend höher, was das Pattern so attraktiv für komplexe Domänen macht. Zu große Komplexität kann durch Zerteilen der Domäne in verschiedene Modelle begegnet werden. Diese müssen dann aber genau abgegrenzt und integriert werden müssen – andernfalls wird man weniger Nutzen davon haben. Die passenden Stichwörter wären hier Bounded Context, Context Map und Core Domain [/End buzzword dropping]. &lt;/p&gt; &lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/esfema/&quot;&gt;&lt;img title=&quot;Image is subject to create commons license. Created By: http://www.flickr.com/photos/esfema/&quot; style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;149&quot; alt=&quot;Image is subject to create commons license. Created By: http://www.flickr.com/photos/esfema/&quot; src=&quot;http://lh4.ggpht.com/sebastian.jancke/SLrJwi87k_I/AAAAAAAAAEc/p5jIoeKE0HI/499451486_ddea829654Byesfema4.jpg?imgmax=800&quot; width=&quot;244&quot; align=&quot;left&quot; border=&quot;0&quot;&gt;&lt;/a&gt; Die Große Frage am Vergleich der 3 Ansätze ist natürlich: Wo liegen die Grenzen auf der Achse der Komplexität? Dazu müssten wir aber zunächst einmal Komplexität messen – dies können wir aber kaum. Pragmatisch gesehen muss hier die Erfahrung des Teams herhalten. Praktisch gesehen lohnt sich ein Domain Model sicherlich nicht für eine reine CRUD-Anwendung mit nur sehr simpler Validierung. Trotzdem greift wohl auch diese Einordnung zu kurz. Niemand kann schließlich genau vorhersagen, wie sich das Geschäft des Kunden weiterentwickelt oder ob aus einer kleinen Anwendung nicht plötzlich eine große wird – dafür scheinen zu viele “Prototypen” bisher immer noch am Leben. Es besteht somit die Gefahr eine Entscheidung zu früh zu treffen, obwohl man die Notwendigkeit für das Domain Model Pattern erst später begründen können wird. Es besteht aber auch die Gefahr, sich mit der Wahl von Transaction Scripts oder Table Modul die Möglichkeit zu verbauen, jemals zu einem reichhaltigen Domänenmodell zu gelangen. Denn laut Fowler ist genau dieser Übergang extrem aufwending und teuer – obwohl die Alternative (kein Redesign) keine wirkliche Alternative ist. Interessant wäre wohl zu experimentieren, ob ein Redesign vom Domain Model Pattern hin zu Transaction Scripts gut funktioniert. Mein Tipp wäre, dass sich dies wohl leichter realisieren lässt, als der Weg anders herum; schließlich sehen wir heute viele Prozedurale Implementierungen mit einem anemischen Domänenmodell. &lt;/p&gt; &lt;p&gt;Klar ist, dass das Table Module Pattern gerade wegen seiner breiten Werkzeug-Unterstützung im .NET Bereich eine sehr geringe Hürde für den Einstieg hat. Table Module und Transactions Scripts zerlegen die Domäne in ein prozedurales Modell und bestechen durch ihre Einfachheit - für einfache Kontexte! Leider ist dieser Umstand bisher wenig bis gar nicht kommuniziert worden. Offensichtlich ist aber die Idee des simplen Drag&amp;amp;Drop / RAD / … für die meisten gescheitert. Beim Table Module Pattern gibt es in der Regel ein Objekt, dass die Logik und Kommunikation für eine Datenbank-Tabelle übernimmt. Transaction Scripts manifestieren sich in der Regel in einem “dicken” &lt;a href=&quot;http://martinfowler.com/eaaCatalog/serviceLayer.html&quot; target=&quot;_blank&quot;&gt;Application / Service Layer&lt;/a&gt; (Fowler). Für jede Transaktion haben wir dann eine Service-Operation. Hiermit sollte dann auch klar sein, warum beide Ansätze Probleme mit duplizierter Logik, Copy&amp;amp;Paste-Smells und vor allem Seperation of Concerns haben. Beim Einsatz eines Domain Models ist die Service Schicht hingegen sehr dünn. Sie koordiniert nur verschiedene Aktionen auf dem Domänenmodell. Vor allem aber eignet sich die Service Schicht zur Beschreibung der Session- und Transaction-Scopes zur Datenbank-Verbindung (mehr dazu später in der DDD Serie).&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;http://www.flickr.com/photos/ppdigital/&quot;&gt;&lt;img title=&quot;Image is subject to create commons license. Created By: http://www.flickr.com/photos/ppdigital/&quot; style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;184&quot; alt=&quot;Image is subject to create commons license. Created By: http://www.flickr.com/photos/ppdigital/&quot; src=&quot;http://lh4.ggpht.com/sebastian.jancke/SLrJw68ShoI/AAAAAAAAAEg/-Hja4RDMgzY/2054206709_fcc589776f_bByppdigital7.jpg?imgmax=800&quot; width=&quot;244&quot; align=&quot;right&quot; border=&quot;0&quot;&gt;&lt;/a&gt;Transaction Scripts und Table Module haben sicherlich geringere Anforderungen an die Erfahrung und das Abstraktionsvermögen eines Entwicklers. Domänenmodelle bieten dafür weitaus mehr Modularisierung und können so auch zu mehr Wiederverwendung führen. Je komplexer ein Modell wird, umso mehr scheint der Vorteil gegeben über Transaction Scripts und Table Module zu wiegen. Sicheres Einsatzgebiet sind somit auf jeden Fall jene Domänen, bei denen von Anfang an klar ist, dass die Komplexität jenseits von einfacherer Validierung (zB isolierte Validierung pro Feld) und CRUD liegt.&lt;/p&gt; &lt;p&gt;Am Schluss möchte ich noch zu Bedenken geben, dass vollständige Modularisierung mit OOP nicht möglich ist (siehe “Tyranny of the dominant decomposition”). Egal nach welchen Kriterien die Dekomposition der Anwendung von statten geht – es wird immer orthogonale, übergreifende Belange geben. Nach derzeitigem Stand der Forschung erreichen wir damit noch bessere Modularisierung nur durch den Einsatz von Aspekt-Orientierung. Meines Wissens ist aber weiterhin unklar, ob wir damit den “heiligen Gral” der Modularisierung erreichen. Vielleicht ist es am Ende auch egal und nur eine Frage des nötigen Pragmatismus.&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:60dd6ddc-1beb-4f9e-a5f9-07215b8b28ca&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/dotnet&quot; rel=&quot;tag&quot;&gt;dotnet&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/domainmodel&quot; rel=&quot;tag&quot;&gt;domainmodel&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/domain+driven+design&quot; rel=&quot;tag&quot;&gt;domain driven design&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/ddd&quot; rel=&quot;tag&quot;&gt;ddd&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/patterns&quot; rel=&quot;tag&quot;&gt;patterns&lt;/a&gt;&lt;/div&gt;  </description><link>http://sjancke.blogspot.com/2008/08/komplexitt-in-geschftslogik.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/sebastian.jancke/SLrJwQxGK0I/AAAAAAAAAEY/WMEbwoyumM8/s72-c/ComplexityComparison_thumb8.png?imgmax=800" height="72" width="72"/><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-6978037426532583316</guid><pubDate>Tue, 05 Aug 2008 23:05:00 +0000</pubDate><atom:updated>2008-08-06T01:11:47.861+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">alt.net</category><category domain="http://www.blogger.com/atom/ns#">altnetde</category><title>ALT.NET Bier Köln #1</title><description>&lt;p align=&quot;center&quot;&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Nachdem &lt;a href=&quot;http://www.lieser-online.de&quot; target=&quot;_blank&quot;&gt;Stefan Lieser&lt;/a&gt; in Blog und Maillingliste bereits grob &lt;a href=&quot;http://www.lieser-online.de/&quot; target=&quot;_blank&quot;&gt;berichtet hat&lt;/a&gt;, folgen hier nun noch die visuelle “Nachverfolgung” des ersten ALT.NET Treffens in Deutschland überhaupt.&lt;/p&gt; &lt;p align=&quot;center&quot;&gt;&lt;img title=&quot;Stefan, Sergey&quot; style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;184&quot; alt=&quot;Stefan, Sergey&quot; src=&quot;http://lh6.ggpht.com/sebastian.jancke/SJjc0wYej6I/AAAAAAAAAEQ/TXjPrsUVVMU/PICT2267%5B11%5D.jpg?imgmax=800&quot; width=&quot;244&quot; border=&quot;0&quot;&gt;&lt;img title=&quot;Sebastian, Bj&amp;ouml;rn, Stefan&quot; style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;184&quot; alt=&quot;Sebastian, Bj&amp;ouml;rn, Stefan&quot; src=&quot;http://lh6.ggpht.com/sebastian.jancke/SJjc1PgJHiI/AAAAAAAAAEM/Wm6M0MGiXp0/PICT2268%5B4%5D.jpg?imgmax=800&quot; width=&quot;244&quot; border=&quot;0&quot;&gt;&lt;/p&gt; &lt;p&gt;Stattgefunden hat das ganze in der Teba in Köln, wo auch die Treffen der DNUG Köln ihre Heimat haben. Themen waren unter anderem:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Mitarbeiter Motivation / Coaching in ALT.Net  &lt;li&gt;Messaging statt RPC, Publish Subscriber  &lt;li&gt;PostSharp erfüllt Obliviousness nicht &lt;li&gt;Parallelität&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Speziell zum Thema PostSharp und AOP-Obliviousness möchte ich noch den folgenden Link zum entsprechenden Paper nachreichen: &lt;a href=&quot;http://www.riacs.edu/research/technical_reports/TR_pdf/TR_01.12.pdf&quot; target=&quot;_blank&quot;&gt;Robert Filman, Daniel Friedman: “AOP is Quantification &amp;amp; Obliviousness”&lt;/a&gt;.&lt;/p&gt; &lt;p align=&quot;center&quot;&gt;&amp;nbsp;&lt;/p&gt; &lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:95a0891b-3ffb-485d-b513-428063ef16a2&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/ALT.NET&quot; rel=&quot;tag&quot;&gt;ALT.NET&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/altnetde&quot; rel=&quot;tag&quot;&gt;altnetde&lt;/a&gt;&lt;/div&gt;  </description><link>http://sjancke.blogspot.com/2008/08/altnet-bier-kln-1.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/sebastian.jancke/SJjc0wYej6I/AAAAAAAAAEQ/TXjPrsUVVMU/s72-c/PICT2267%5B11%5D.jpg?imgmax=800" height="72" width="72"/><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-524504795120975618</guid><pubDate>Tue, 05 Aug 2008 22:55:00 +0000</pubDate><atom:updated>2008-08-06T00:55:02.820+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">alt.net</category><category domain="http://www.blogger.com/atom/ns#">altnetde</category><category domain="http://www.blogger.com/atom/ns#">netos2008</category><title>.NET Open Space 2008</title><description>&lt;p&gt;&lt;a title=&quot;.NET Open Space vom 18.10. bis 19.10.2008 in Leipzig&quot; href=&quot;http://netopenspace.de/&quot;&gt;&lt;img alt=&quot;.NET Open Space vom 18.10. bis 19.10.2008 in Leipzig&quot; src=&quot;http://netopenspace.de/GetFile.aspx?File=Logos/nos-logo-1.png&quot;&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Nun ist es also raus: am 18. und 19. Oktober 2008 findet die .NET Open Space in Leipzig statt. Dabei bildet ALT.NET eines der drei Themenfelder und verspricht spannende Sessions. Ort der Veransaltung ist der &lt;a href=&quot;http://www.mediencampus-villa-ida.de/&quot;&gt;Mediencampus Villa Ida&lt;/a&gt;. Ich werde auf jeden Fall teilnehmen und habe mich bereits registiert. Vielleicht kommt ja auch eine Session zu DDD oder AOSD zustande – ich würde mich drauf freuen ;-)&lt;/p&gt;&lt;a title=&quot;.NET Open Space vom 18.10. bis 19.10.2008 in Leipzig&quot; href=&quot;http://netopenspace.de/&quot;&gt; &lt;/a&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:1470748e-1898-4207-a0eb-b3b4b80df40c&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/ALT.NET&quot; rel=&quot;tag&quot;&gt;ALT.NET&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/altnetde&quot; rel=&quot;tag&quot;&gt;altnetde&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/netos2008&quot; rel=&quot;tag&quot;&gt;netos2008&lt;/a&gt;&lt;/div&gt;  </description><link>http://sjancke.blogspot.com/2008/08/net-open-space-2008.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-5063586787383777099</guid><pubDate>Fri, 11 Jul 2008 18:49:00 +0000</pubDate><atom:updated>2008-07-11T21:09:49.653+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ddd</category><category domain="http://www.blogger.com/atom/ns#">domain driven design</category><category domain="http://www.blogger.com/atom/ns#">domainmodel</category><category domain="http://www.blogger.com/atom/ns#">dotnet</category><title>DDD – Allgegenwärtige / Universelle Sprache</title><description>&lt;p&gt;&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;h6&gt;Bisher in dieser Serie: &lt;a href=&quot;http://sjancke.blogspot.com/2008/07/ddd-eine-einfhrung.html&quot; target=&quot;_blank&quot;&gt;DDD – Eine Einführung&lt;/a&gt;&lt;/h6&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Die zentrale Technik im &lt;a href=&quot;http://www.domaindrivendesign.org&quot; target=&quot;_blank&quot;&gt;Domain Driven Design&lt;/a&gt; ist die “Allgegenwärtige / Universelle Sprache”, engl. ubiquitous language. Um zu erklären, wobei es darum geht, möchte ich zunächst weg von der technischen Sprache. Wir alle kennen das Phänomen, das manche Filme und Bücher in der originalen Sprache einfach aussagekräftiger und präziser sind. Übersetzungen gehen oft soweit, das Film- und Buch-Titel einfach die Aussage des originalen Titels kaum noch widerspiegeln. Übersetzungen erzeugen schlicht kleine Fehler und Abweichungen, die in der Summe (bei schlechten Übersetzungen) einfach nicht mehr die selbe Aussage treffen.&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;http://flickr.com/photos/nofrills/&quot; target=&quot;_blank&quot;&gt;&lt;img title=&quot;Image is subject to creative commons license. Created by: http://flickr.com/photos/nofrills/&quot; style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;184&quot; alt=&quot;Image is subject to creative commons license. Created by: http://flickr.com/photos/nofrills/&quot; src=&quot;http://lh6.ggpht.com/sebastian.jancke/SHevSBhGNdI/AAAAAAAAAD4/OHzghIom5fE/10895361_a831db15b2_o%5B4%5D.jpg?imgmax=800&quot; width=&quot;244&quot; align=&quot;right&quot; border=&quot;0&quot;&gt;&lt;/a&gt; Übertragen wir diese Film-Metapher auf die Software Entwicklung. In manchen starren Prozessen gibt es Entwickler, Architekten und Analysten. Letztere kommunizieren direkt mit dem Kunden, übersetzten die Anforderungen des Kunden in die Sprache der Architekten und Entwickler. Meist haben Entwickler und Architekten kaum noch die selbe Sicht und Sprache auf die Domäne wie der Kunde. Wie wir bereits gesehen haben, sind solche Übersetzungen nicht trivial und fehlerfrei. Im Extremfall kommunizieren die Team-Mitglieder in einer anderen Sprache und damit mit einem anderen Modell, als im Quelltext des Systems abgebildet ist. Sicherlich kennt fast jeder solche Projekte und Situationen. &lt;/p&gt; &lt;p&gt;Evans schlägt hier einen Ansatz vor, der zunächst manchem radikal erscheinen mag. Aber wie bei allen neuen Techniken ist ein wenig Dogmatik der Verbreitung sicherlich dienlich (siehe zum Beispiel TDD). Evans schlägt eine vereinheitlichte Sprache zwischen Kunden und Entwicklern vor. Diese allgegenwärtige, universelle Sprache bildet das Modell der Domäne ab. Diese Sprache manifestiert sich in der Kommunikation zwischen Team und Kunden, in Dokumenten und natürlich auch im Quelltext. Sie ist das Kernstück, das Rückgrat des Modells und muss unbedingt von allen Mitgliedern des Team kommuniziert werden.&lt;/p&gt; &lt;p&gt;Interessant zu diskutieren wäre hierbei das gebräuchliche Vorgehen, Quelltext in englischer Sprache zu halten während wir fast alle auf Deutsch kommunizieren. Denn dies ist bei deutschsprachigen Kunden schließlich auch eine Übersetzung. Auf der anderen Seite gehört es zum “guten Ton”, Quelltext auf Englisch zu schreiben – wohl auch weil die deutsche Sprache teilweise einfach mehr Wörter zum Ausdruck braucht.&lt;/p&gt; &lt;p&gt;&lt;a href=&quot;http://flickr.com/photos/cleverclaire1983/&quot; target=&quot;_blank&quot;&gt;&lt;img title=&quot;Image is subject to creative commons license. Created by: http://flickr.com/photos/cleverclaire1983/&quot; style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;184&quot; alt=&quot;Image is subject to creative commons license. Created by: http://flickr.com/photos/cleverclaire1983/&quot; src=&quot;http://lh3.ggpht.com/sebastian.jancke/SHevSS6WICI/AAAAAAAAAEA/Fwq3lVyB37U/539891798_014392fb54_b%5B5%5D.jpg?imgmax=800&quot; width=&quot;244&quot; align=&quot;left&quot; border=&quot;0&quot;&gt;&lt;/a&gt; Die Wahl der Dokumentation ist unbedingt dem Kontext anzupassen, denn die allgegenwärtige Sprache wird sich über einige Zeit weiterentwickeln und ständig Verändern, bis sie sich in ihrem Kern stabilisiert hat. Für manche Projekte machen hier sicher starre UML-Diagramme und Anforderungsdokumente Sinn, wenn das Projekt nicht mit dauernden Änderungen in der Domäne umgehen muss. Für Domänen mit häufigen, ständigen Änderungen empfehlen sich dann wohl eher temporäre Diagramme (Skizzen). Evans gibt hierbei zu bedenken, das gerade Diagramme eher nur Ausschnitte des Modells reflektieren sollten. Gerade UML-Diagramme tendieren dazu, sich extrem zu vermehren oder aber allumfassend zu werden. Solche Diagramme sind sicherlich kaum zur Kommunikation geeignet, weil es viel zu lange dauert sie zu lesen und zu ändern. Gerade in der Anfangsphase der Modellierung ist das Modell in der Regel noch nicht Stabil genug. Hier sind Skizzen und Ausschnitte unter Umständen viel schneller von Hand zu erstellen als jedes andere Diagramm. Zu bedenken ist auch, dass je mehr komplexe Dokumentation des Modells es gibt, desto mehr Artefakte müssen auch synchron mit der Entwicklung der Sprache gehalten werden. Aus der eigenen Erfahrung kann ich berichten, dass in manchen Projekten einfache digitale Mindmaps ausreichen, um Änderungen an der Sprache (und damit auch an der Domäne) zu dokumentieren. Dies hat unter Umständen aber den Nachteil, dass alle Dokumente fast nur inkrementelle Ausschnitte sind. Auf der anderen Seite sind solche Mindmaps schnell geschrieben, strukturiert und auch schnell verstanden. &lt;/p&gt; &lt;p&gt;Egal welcher Ansatz gewählt wurde: Die Sprache und damit auch das Modell der Domäne manifestiert sich vor allem in der Kommunikation zwischen Team und Kunde und vor allem auch innerhalb des Teams. Dies bedeutet automatisch, dass jedes Konzept in der Sprache seine Entsprechung im Quelltext finden muss. Alle Änderungen in der Sprache sind somit auch eine Änderung am Modell. Somit muss dann auch der Quelltext die Änderungen mittragen. Andersherum kann es auch Konzepte geben, die bisher nur implizit vorhanden – und vielleicht bisher kaum verstanden - sind. Dies manifestiert sich vielleicht erst in der Entwicklung des Systems. Solche impliziten Konzepte müssen dann explizit gemacht werden und auch Eingang in die Sprache finden. Erst dann sind sie schließlich mit den Experten in der Domäne diskutierbar.&lt;/p&gt; &lt;p&gt;Unsere allgegenwärtige, universelle Sprache ist während der Modellierung natürlich Änderungen unterworfen - auch wenn wir Big-Design-Up-Front arbeiten. Dann gibt es diese Änderungen hoffentlich nur während der Modellierungs-Phase (was ich aus meiner bisherigen Erfahrung eher selten glaube). Dies kann dazu führen, dass dass Modell der Domäne nicht mehr mit den neuen Anforderungen skaliert. Dann ist es Zeit, Teile des Modells zu entfernen und neu zu beginnen. Dies erreicht man im Prinzip nur durch Experimenten mit dem Modell und Diskussion mit den Experten der Domäne. Beispiele für solche Vorgänge sind in den Büchern von Eric Evans und Jimmy Nilsson in vielen Beispielen zu finden.&lt;/p&gt; &lt;p&gt;Einen Vergleich, den ich sehr interessant finde, gibt es zwischen der allgegenwärtigen Sprache des DDD und der System-Metapher des eXtreme Programming. Die &lt;a href=&quot;http://www.xprogramming.com/xpmag/whatisxp.htm#metaphor&quot;&gt;Metapher&lt;/a&gt; wurde in den ursprünglichen XP-Büchern kaum behandelt (nur auf wenigen Seiten) und ist daher vielleicht eine der kaum praktizierten Methoden (jedenfalls hört&amp;nbsp; und liest man eher selten davon). Man kann die allgegenwärtige Sprache im Domain Driven Design als ein Schlüssel zur Erstellung einer solchen System-Metapher auffassen. &lt;/p&gt; &lt;h5&gt;Abschließend ein Ausblick: &lt;/h5&gt; &lt;p&gt;In den folgenden Teilen der Serie stelle ich den von Evans eingeführten Sprach-Elemente vor, um aus der Kommunikation mit Experten der Domäne dann ein Modell zu strukturieren. Weitere Teile werden Techniken enthalten um Konzepte im Quelltext expliziter zu machen, das Modell reichhaltiger zu gestalten, seine Anstrengungen in der Modellierung zu fokussieren und ein Modell gegen unerwünschte Einflüsse zu schützen sowie mit anderen Modellen zu integrieren.&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;Zum Schluss: ein gutes Beispiel für schwierige Übersetzungen ist schon der Titel dieses Beitrags: “ubiquitous langauge” lässt sich übersetzten, verliert dann aber schnell an Bedeutung – jedenfalls in meinem sprachlichem Empfinden.&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:b324e08d-f0e7-482c-bcac-1df5fb225d89&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/ddd&quot; rel=&quot;tag&quot;&gt;ddd&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/domain+driven+design&quot; rel=&quot;tag&quot;&gt;domain driven design&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/domainmodel&quot; rel=&quot;tag&quot;&gt;domainmodel&lt;/a&gt;&lt;/div&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;h5&gt;DDD Serie:&lt;/h5&gt; &lt;ul&gt; &lt;li&gt;&lt;a href=&quot;http://sjancke.blogspot.com/2008/07/ddd-eine-einfhrung.html&quot; target=&quot;_blank&quot;&gt;DDD – Eine Einführung&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;  </description><link>http://sjancke.blogspot.com/2008/07/ddd-allgegenwrtige-universelle-sprache.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/sebastian.jancke/SHevSBhGNdI/AAAAAAAAAD4/OHzghIom5fE/s72-c/10895361_a831db15b2_o%5B4%5D.jpg?imgmax=800" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-8618194908313152017</guid><pubDate>Fri, 11 Jul 2008 18:18:00 +0000</pubDate><atom:updated>2008-07-15T16:38:28.869+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">ddd</category><category domain="http://www.blogger.com/atom/ns#">domain driven design</category><category domain="http://www.blogger.com/atom/ns#">domainmodel</category><category domain="http://www.blogger.com/atom/ns#">dotnet</category><title>DDD – Eine Einführung</title><description>&lt;p&gt;Dies ist der Beginn einer Serie zum Thema Domain Driven Design (DDD). Ich werde versuchen, die Serie mit weiteren Beiträgen zu füllen, während ich an einem Vortrag zum Thema arbeite. &lt;/p&gt; &lt;p&gt;Domain Driven Design ist der Titel eines &lt;a href=&quot;http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215&quot; target=&quot;_blank&quot;&gt;Buches von Eric Evans&lt;/a&gt;. Das Buch selbst ist nicht mehr “ganz neu” – trotzdem gab es (gerade auch in den Java und ALT.NET Gemeinschaften) einigen “Hype” darum. Dabei gibt es eigentlich nicht genau das DDD. Zunächst ist DDD eine Kombination aus “Model Driven Design” (nicht zu verwechseln mit MDA – Model Driven Architecture) und Prozessen rund um Kunden-Kommunikation, Integration und Modularisierung verschiedener Domänen, etc..&lt;/p&gt; &lt;p&gt;Nun stellt sich natürlich die Frage, wann DDD eingesetzt werden sollte. Zunächst ist die Ansatz der allgegenwärtigen Sprache sicherlich universell nutzbar. Um den vollen Nutzen zu erfahren ist aber sicherlich die Kopplung mit Model Driven Design empfehlenswert. Ausgangspunkt ist das &lt;a href=&quot;http://martinfowler.com/eaaCatalog/domainModel.html&quot; target=&quot;_blank&quot;&gt;Domain Model Pattern&lt;/a&gt; von Martin Fowler. Hierbei sollen die kompletten Fähigkeiten unserer OOP-Sprachen genutzt werden, um die Komplexität der Domäne in ein reichhaltiges Objektmodell zu übersetzten. &lt;/p&gt; &lt;p&gt;Damit dürfte klar sein, dass Model Driven Design, also OO-Modelle der Domäne, sich vor allem in OLTP-Szenarios einsetzten lassen. Derzeit ist Objekt-Orientierung einer der stärksten Ansätze, die wir kennen, um hohe Modularisierung und Reduzierung der Komplexität zu erreichen. &lt;/p&gt; &lt;p&gt;Dies bedeutet aber auch, dass OLAP-Szenarios ungeeignet für den Einsatz eines reichhaltigen Objektmodells sind – denn hierbei geht es primär um die Analyse von Daten und weniger um komplexe Prozesse und Regeln innerhalb von Transaktionen. Die Frage nach Ad-hoc Reporting wurde auf der DDD-Mailingliste schon mehrfach gestellt und auch beantwortet – mittlerweile gibt es dazu auch einen &lt;a href=&quot;http://www.domaindrivendesign.org/discussion/archive/reporting_from_database.html&quot; target=&quot;_blank&quot;&gt;Artikel und eine Diskussions-Zusammenfassung&lt;/a&gt; auf der &lt;a href=&quot;http://www.domaindrivendesign.org/&quot; target=&quot;_blank&quot;&gt;Webseite zu DDD&lt;/a&gt;. Ich möchte hier nicht direkt im Detail darauf eingehen - dies werde ich zu einem späteren Zeitpunkt noch tun. Zusammenfassend möchte ich aber sagen, das solche Objektmodelle und damit verbundene Datenbank-Schemata eigentlich nicht zum performanten Ad-hoc Reporting geeignet sind. Alternativen wären flache, spezielle Datenbank-Sichten oder eine Art Data-Warehouse-Lösung.&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;Ziel des Model Driven Design ist also die Erstellung eines reichhaltigen Objektmodells, das wir mit völliger Freiheit unter Ausnutzung aller Sprach-Features erstellen. Zu starke Kopplung an die Infrastruktur (etwa Basisklassen mit Transaktions- und Datenbank-Logik) sind hier hinderlich. Deshalb ist der Begriff “Persistence Ignorance” eng mit der Erstellung solcher Objektmodelle verbunden. Objekte ohne Einschränkung durch Infrastruktur oder Runtime-Container (wie zB EJB 2.0 - Java , CSLA - dotnet) werden auch POCOs genannt – Plain Old CLR Objects. Ich würde sogar noch ein Stück weiter gehen und von Infrastruktur-Ignoranz sprechen, da Persistenz nur ein Aspekt der Infrastruktur ist.&lt;/p&gt; &lt;p&gt;Natürlich bedeutet dies auch, dass wir gewisse Anforderungen an die Architektur solcher Systeme haben, auf der anderen Seite aber auch eine Menge gewinnen. Zunächst möchte ich auf die Gewinne eingehen. Solche Objektmodelle eigenen sich perfekt um Komplexität zu verstecken und Änderung zu handhaben. Die Arbeit mit solchen Modellen führt zu ausdrucksstarken Kombinationen aus bereits bestehenden ausdrucksstarken Teilen. Damit gewinnen wir als Lesbarkeit und auch Wartbarkeit. Objektmodelle ohne Abhängigkeit von der Infrastruktur bedeuten natürlich auch einfache Testbarkeit. Somit ist es möglich, die gesamte komplexe Logik in Objektmodelle mit automatisierten Tests ständig zu überprüfen. Unsere Architektur wird hier also testbar und wir werden nicht gehindert Tests zu entwickeln oder gar Test-first (TDD) zu arbeiten. Solche Objektmodelle erleichtern die Arbeit mit automatisierten Tests geradezu.&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;Es gibt aber auch einige Anforderungen an unsere Architekturen, um solche reichhaltigen Objektmodelle im Sinne von DDD zu entwickeln. Diese sind nicht unbedingt negativ (haben sogar positiven Einfluss auf das gesamte System), sind teilweise aber fast Voraussetzung. Zunächst einmal lassen sich Infrastruktur-Ignorante Objektmodelle im Prinzip nur entwickeln, wenn wir das Dependency Inversion Principle anwenden. Dies führt sofort zur Notwendigkeit eines Dependency-Injection-Containers zur Konfiguration der Abhängigkeiten. Natürlich ließe sich das DIP auch anders realisieren, pragmatisch gesehen nehmen uns solche Container (&lt;a href=&quot;http://www.castleproject.org/&quot; target=&quot;_blank&quot;&gt;Castle Windsor&lt;/a&gt;, &lt;a href=&quot;http://www.springframework.net/&quot; target=&quot;_blank&quot;&gt;Spring.NET&lt;/a&gt;, &lt;a href=&quot;http://structuremap.sourceforge.net/Default.htm&quot; target=&quot;_blank&quot;&gt;StructureMap&lt;/a&gt;, &lt;a href=&quot;http://ninject.org/&quot; target=&quot;_blank&quot;&gt;Ninject&lt;/a&gt;) aber sehr viel Arbeit ab. Der Einsatz eines solchen IoC/DI-Containers hat darüber hinaus einen positiven Effekt auf die gesamte Anwendung: lose Kopplung ist schließlich eine Eigenschaft, die man sich generell (neben hoher Kohäsion) für seine Module wünscht.&lt;/p&gt; &lt;p&gt;Soll unser Objektmodell persistiert werden, brauchen wir auch einen starken, flexiblen O/R-Mapper. In letzter Zeit gab es viel Rumoren um das Entity Framework – um es kurz zu machen: derzeit sieht sowohl das EF-Team als auch die ALT.NET Community das EF nicht als eine Option an, wenn man DDD nutzt. Derzeit stärkstes Framework auf dem Markt ist damit &lt;a href=&quot;http://www.hibernate.org/343.html&quot; target=&quot;_blank&quot;&gt;NHibernate&lt;/a&gt;, eine ehemalige Portierung des Java-Frameworks Hibernate. NHibernate ist komplett in das dotnet-Ökosystem integriert und weit verbreitet.&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;Die Entwicklung reichhaltiger Objektmodelle erfordert zudem generell eine Leistungsfähige Entwickler-Struktur, denn ohne gute, OOP-erfahrene Entwickler ist es schwierig ein reichhaltiges Objektmodell zu erstellen. Viele Entwickler sehen sich zwar als OOP-erfahren, doch ist es noch ein großer Unterschied eine OOP-Sprache wie C# einzusetzen oder aber gute, leistungsfähige Objektmodelle zu entwickeln. Dies merkt eigentlich jeder, der bisher noch nie mit aller Kraft versucht hat, ein Modell noch reichhaltiger zu machen. Die ersten Versuche scheitern wohl in der Regel (und sind es auch bei mir). Das eingestehen und sehen der Fehler ist hier der Schlüssel um sich weiterzuentwickeln. Viele open-source Projekte nutzen reichhaltige Objektmodelle und sind optimal zum Lernen.&lt;/p&gt; &lt;p&gt;Zum Schluss noch einige Worte zum Aufwand. Ein Objektmodell zur Repräsentation der Domäne zu erstellen ist harte Arbeit und aufwendig – dem gegenüber steht aber die Leichtigkeit mit der später Komplexität gehandhabt werden kann (wenn das Modell gut genug ist). Als Alternativen gäbe es noch die Arbeit mit &lt;a href=&quot;http://martinfowler.com/eaaCatalog/transactionScript.html&quot; target=&quot;_blank&quot;&gt;Transaction Scripts&lt;/a&gt; (Fowler) oder dem &lt;a href=&quot;http://martinfowler.com/eaaCatalog/tableModule.html&quot; target=&quot;_blank&quot;&gt;Table Module Pattern&lt;/a&gt; (Fowler). Letzteres erfreut sich gerade bei .NET-Entwicklern großer Beliebtheit wegen der guten IDE-Unterstützung in Visual Studio, dort bekannt als DataSets. Für einen genauen Vergleich möchte ich auf Martin Fowler’s Buch “&lt;a href=&quot;http://www.amazon.com/Enterprise-Application-Architecture-Addison-Wesley-Signature/dp/0321127420&quot; target=&quot;_blank&quot;&gt;Patterns of Enterprise Application Architecture&lt;/a&gt;” verweisen. Es sei aber gesagt, dass gerade das Table Module Pattern wahrscheinlich am wenigsten mit steigender Komplexität der Domäne skaliert, gefolgt von &lt;a href=&quot;http://martinfowler.com/eaaCatalog/transactionScript.html&quot; target=&quot;_blank&quot;&gt;Transaction Scripts&lt;/a&gt;. Beide haben vor allem das Problem von Copy&amp;amp;Paste-Smells und Dopplung von Logik. Nach derzeitigem Stand ist ein objekt-orientieres Modell das einzige, das wirklich besser mit wachsender Komplexität skaliert. Problematisch ist allerdings, dass man Komplexität schlecht messen kann und keiner genau weiß, wo die Schwellwerte liegen. Letzten Endes ist hier die Erfahrung und Experimente / Prototypen gefragt.&lt;/p&gt; &lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:2f390633-7c9b-46a9-a94d-2685f047d348&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/dotnet&quot; rel=&quot;tag&quot;&gt;dotnet&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/domain+driven+design&quot; rel=&quot;tag&quot;&gt;domain driven design&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/ddd&quot; rel=&quot;tag&quot;&gt;ddd&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/domainmodel&quot; rel=&quot;tag&quot;&gt;domainmodel&lt;/a&gt;&lt;/div&gt;  </description><link>http://sjancke.blogspot.com/2008/07/ddd-eine-einfhrung.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>5</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-9010552761938617104</guid><pubDate>Tue, 08 Jul 2008 16:33:00 +0000</pubDate><atom:updated>2008-07-11T01:09:58.350+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">domainmodel</category><category domain="http://www.blogger.com/atom/ns#">dotnet</category><category domain="http://www.blogger.com/atom/ns#">maintainability</category><category domain="http://www.blogger.com/atom/ns#">readability</category><title>Objekt-Modellierung: Nomen? Verben? Beides? Keins?</title><description>&lt;p&gt;Die allermeisten lernen wohl OOP – bis heute – in seiner einfachsten Form zunächst als “Finding the nouns”. Die Nomen finden – und dann daraus Objekte machen. Fehlen noch Aktionen, um daraus Methoden für ein Objekt zu erstellen – wie gut das es ja noch Verben gibt. &lt;/p&gt; &lt;p&gt;Vielen Entwicklern dürfte klar sein, dass diese Schema &lt;a href=&quot;http://blogs.concedere.net:8080/blog/discipline/software+engineering/?permalink=Design-Is-Inevitable-Programming-is-Not-Art.html&quot; target=&quot;_blank&quot;&gt;zu simpel ist&lt;/a&gt; und höchstens für die ersten OOP-Beispiele ausreicht. Fortgeschrittenere “Richtlinien” und Möglichkeiten zur Strukturierung bieten unter anderem der DDD-Prozess, und das Entity-Controller-Boundary Modell. &lt;/p&gt; &lt;p&gt;Trotzdem habe ich schon zu oft Entwickler gesehen, die krampfhaft versuchen, ein Objekt nach Nomen zu benennen, obwohl ein Verb viel aussagekräftiger wäre. Das Resultat sind die allerseits beliebten Konstrukte:&lt;/p&gt;&lt;pre class=&quot;csharpcode&quot;&gt;AnotherCarFinder.FindCar(myCarId);&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Neben der Dopplung – die sich sehr holprig liest – ist das ganze auch kaum aussagekräftig. Deshalb wäre mein Ratschlag: Weg vom OO-Denken in Nomen, hin zu mehr Flexibilität und Kreativität. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;Das obige Beispiel sieht so sicherlich viel lesbarer aus:&lt;/p&gt;&lt;pre class=&quot;csharpcode&quot;&gt;FindAnotherCar.By(myCarId)&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Dies ist sicherlich noch nicht das non-plus-ultra und auch nicht das Ende der Möglichkeiten. Deshalb möchte ich alle Leser auffordern, mir ihre Beispiele und Ideen doch vielleicht zukommen zu lassen. Mich interessiert brennend, welche Techniken andere (unter anderem) nutzen, um die Lesbarkeit zu erhöhen.&lt;/p&gt;&lt;br /&gt;&lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:f9f3d711-dc12-42df-a30e-82058ac944e2&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/domainmodel&quot; rel=&quot;tag&quot;&gt;domainmodel&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/readability&quot; rel=&quot;tag&quot;&gt;readability&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/maintainability&quot; rel=&quot;tag&quot;&gt;maintainability&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/dotnet&quot; rel=&quot;tag&quot;&gt;dotnet&lt;/a&gt;&lt;/div&gt;</description><link>http://sjancke.blogspot.com/2008/07/objekt-modellierung-nomen-verben-beides.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-1060124602724755345</guid><pubDate>Wed, 02 Jul 2008 21:44:00 +0000</pubDate><atom:updated>2008-07-04T00:57:34.351+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">dotnet</category><category domain="http://www.blogger.com/atom/ns#">nhibernate</category><category domain="http://www.blogger.com/atom/ns#">orm</category><title>“ORMs für .NET im Vergleich” – Eine kleine Kritik</title><description>&lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;p&gt;Nach Monaten ohne (öffentliche) Reaktionen und einer Diskussionen auf der ALT.NET.DE Mailing-Liste will ich versuchen, meine Kritik am Artikel &lt;a href=&quot;http://www.dotnetpro.de/Grafix/OnlineArticles/ormapper.pdf&quot; target=&quot;_blank&quot;&gt;“Objektrelationale Mapper für .NET im Vergleich”&lt;/a&gt; zu formulieren. Der Artikel wurde von Holger Schwichtenberg geschrieben und in dem Magazin &lt;a href=&quot;http://www.dotnetpro.de/Grafix/OnlineArticles/ormapper.pdf&quot; target=&quot;_blank&quot;&gt;dotnetpro (Ausgabe 4/2008)&lt;/a&gt; publiziert. &lt;/p&gt; &lt;p&gt;Da dieser Artikel sicherlich auch von Einsteigenden gelesen wird, oder von Menschen ohne Erfahrung speziell mit NHibernate, finde ich es wichtig, dass keine Halb-Wahrheiten stehen bleiben. Dieser Eintrag soll ein Versuch sein, mit einigen Fehlern und Missverständnisse im besagten Artikel aufzuräumen. Die Aufstellung ist sicherlich nicht komplett und ich maße mir auch keinerlei Wertung über den Artikel oder das Magazin oder den Autor an. &lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;(Abschnitt: Henne oder Ei) Beim Forward Mapping machen NHibernate und das ADO.NET Entity Framework bislang nicht mit; sie können eine Datenbank nicht auf Basis von Geschäftsobjekten generieren.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;font color=&quot;#333333&quot;&gt;Ich zitiere dazu (frei) aus der NHibernate Dokumentation, &lt;a href=&quot;http://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/session-configuration.html#configuration-optional&quot; target=&quot;_blank&quot;&gt;Abschnitt 3.5 “Optional configuration properties”&lt;/a&gt;: Die Eigenschaft “hibernate.hbm2ddl.auto” bestimmt, ob das DDL Schema automatisch bei Erzeugung der ISessionFactory exportiert werden soll. Mögliche Werte sind unter anderem “create” und “drop”. Mit “create-drop” wird das Datenbank-Schema zunächst erzeugt und beim Schließen der ISessionFactory dann gelöscht. Ich kann jedem nur empfehlen, diese Optionen auszuprobieren. Bisher habe ich sie auf Entwicklungs-Datenbanken erfolgreich nutzen können, um meine Produktivität in diesem Bereich zu steigern. Gleichzeitig halte ich eine Kopie der bisher ausgelieferten Datenbank vor. Mit Werkzeugen wie “Quest Comparison Suite” oder “RedGate SqlCompare” kann ich dann zum Ende einer Iteration die Änderungen automatisiert in ein Script übertragen lassen.&lt;/font&gt;&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;(Abschnitt: Geschäftsobjektklassen) Die Fachwelt spricht dann von Persistance Ignorance oder von Plain Old CLR Objects (POCOs). In diese Kategorie fällt NHibernate. NDO kann POCOs als Unterobjekte eines zu persistierenden Objekts verwenden.&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;font color=&quot;#333333&quot;&gt;Hierbei geht wohl die eigentliche Bedeutung des Wortes “POCO” verloren. Frei nach Fowler ist ein POCO ein “Plain Old CLR Object”. Also ein Objekt, das sonst keine Abhängigkeiten und Einschränkungen hat. Vererbung ist vielleicht die stärkste Form der Abhängigkeit. Durch Vererbung von einer zentralen Basisklasse meines Persistenz-Frameworks gehe ich somit eine sehr starke Abhängigkeit ein. Das Objekt ist somit kein POCO mehr. Die Begriffe POJO und POCO implizieren damit im Bezug auf Persistenz auch direkt einen Teil des Begriffes “Persistence Ignorance”. NDO ist somit nicht PI-fähig und die Geschäftsobjekte in diesem Zusammenhang sind keine POCOs.&lt;/font&gt;&lt;/p&gt; &lt;blockquote&gt;&lt;/blockquote&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font color=&quot;#333333&quot;&gt;(Abschnitt: Mapping und Treiber) Nicht alle Werkzeuge verwenden im Untergrund ADO.NET. VOA und NHibernate arbeiten mit JDBC (Java Database Connectivity), da es sich um Portierungen aus der Java-Welt handelt.&lt;/font&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Dazu möchte ich wieder die NHibernate Dokumentation frei zitieren, im speziellen den &lt;a href=&quot;http://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/architecture.html&quot; target=&quot;_blank&quot;&gt;Abschnitt 2 “Architecture”&lt;/a&gt;: NHibernate kann grundsätzlich auf zwei Arten eingesetzt werden: Entweder die Anwendung stellt NHibernate die entsprechenden ADO.NET Verbindungen zur Verfügung, oder aber NHibernate schirmt die Anwendung von der gesamten Datenbank-Kommunikation ab. Wie man in diesem Fall an der entsprechenden Grafik (&quot;full cream&quot; architecture) sehen kann, liegt auch dann ADO.NET (neben OLE DB und ODBC) zu Grunde. Noch deutlicher ist die Beschreibung des Interfaces ISession: “… kapselt eine ADO.NET Verbindung”.&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;p&gt;Abschließend möchte ich noch einige Worte zum Fazit des Autors verlieren. Herr Schwichtenberg legt in seinem Vergleich anscheinend sehr viel Wert auf die Unterstützung mittels grafischer Werkzeuge. Ich kann diese Wahl der Kriterien nicht teilen und auch nicht unterstützen. Für Einsteigende mögen grafische Werkzeuge am Anfang sehr eingängig und leicht zu erlernen sein. Ich bezweifle allerdings, dass die “Dekoration” der Geschäftsobjekte mit Attributen schwieriger ist. Dies ist zwar kein “best practice” – da wir die Persistence Ignorate verlieren – ist aber für den Einstieg akzeptabel. &lt;/p&gt; &lt;p&gt;Schwerer wiegt für mich aber noch das Argument der Skalierbarkeit solcher grafischer Werkzeuge. Dazu reicht meist schon der Versuch, eine “mittelgroße” Anwendung (vielleicht 2-3 Mannmonate Aufwand?) in solch einem grafischen Werkzeug darzustellen. Hierbei scheitert derzeit vor allem der Entity Framework Designer – es werden schlicht alle Objekte auf der gesamten “Leinwand” dargestellt (&lt;a href=&quot;http://odetocode.com/Blogs/scott/archive/2008/05/19/12107.aspx&quot; target=&quot;_blank&quot;&gt;Scott Allen - Visual Designers Don’t Scale&lt;/a&gt;). Auch mit Zoom-Funktion, Gruppierungen und Ausschnitte bleibt immer die Tatsache, das visuelle Werkzeuge in der Regel (bisher) einfach schlecht mit der Größe des Domänen-Modells skalieren. &lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:ee79f6a9-8638-4c13-9e3c-36d2cb84bafc&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;Technorati Tags: &lt;a href=&quot;http://technorati.com/tags/orm&quot; rel=&quot;tag&quot;&gt;orm&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/nhibernate&quot; rel=&quot;tag&quot;&gt;nhibernate&lt;/a&gt;&lt;/div&gt;</description><link>http://sjancke.blogspot.com/2008/07/orms-fr-net-im-vergleich-einige.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-5323166189824705145</guid><pubDate>Wed, 02 Jul 2008 21:44:00 +0000</pubDate><atom:updated>2008-07-04T00:56:45.191+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">dotnet</category><title>Auf zu neuen Ufern</title><description>&lt;p&gt;Anlässlich der Diskussion auf der deutschen ALT.NET Mailing-Liste zum Thema: “Deutschsprachige Inhalte rund um ALT.NET” und der Tatsache, dass ich mich aus meiner Blog-Lethargie befreien möchte:&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Ab jetzt ist hier alles in Deutsch geschrieben (naja fast alles) ;-)&lt;/strong&gt;&lt;/p&gt;</description><link>http://sjancke.blogspot.com/2008/07/auf-zu-neuen-ufern.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-7791543037289037067</guid><pubDate>Thu, 31 Jan 2008 12:46:00 +0000</pubDate><atom:updated>2008-07-02T22:36:52.936+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">dotnet</category><category domain="http://www.blogger.com/atom/ns#">nant</category><category domain="http://www.blogger.com/atom/ns#">nunit</category><category domain="http://www.blogger.com/atom/ns#">tdd</category><category domain="http://www.blogger.com/atom/ns#">visualstudio</category><title>Improving Agility in Visual Studio</title><description>&lt;p&gt;What Visual Studio (2005) Professional lacks out of the box, is a good support for unit testing and build scripting. Actually, VS2005 Pro does not provide any support for it. So in case you don&#39;t want to buy the Team Edition (for testing support), looking for a free alternative, the following might be a solution.&lt;/p&gt; &lt;p&gt;TDD (with NUnit) is definitely at the heart of my day-to-day development process. But I was in a snit to call NUnit-GUI-Runner from the custom tools menu. Further, I needed a possibility to automate my release processes (compile, test, commit, tag, zip, name with version). On the java side of our dev world, I was used to Ant. And happily, there is a .NET alternative to crude MSBuild: NAnt. &lt;/p&gt; &lt;p&gt;Without going into the details of NAnt, one can say: NAnt is XML-based, easy to use, has a bunch of tasks and plugins for all sort of things (vcs&#39;s, io, vs-solution stuff, compression, ...) and can be easily extended with your own tasks/plugins. What&#39;s really cool about NAnt is the fact that it&#39;s Ant for .NET - I don&#39;t need to relearn anything and can reuse my knowledge of Ant (which is the standard build scripting system in the Java/eclipse world).&lt;/p&gt; &lt;p&gt;Using these visual studio addins:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a href=&quot;http://www.netlogics.ch/devcenter/display/NLC/NAntAddin&quot; target=&quot;_blank&quot;&gt;NAntAddin&lt;/a&gt;&lt;/li&gt; &lt;li&gt;&lt;a href=&quot;http://www.netlogics.ch/devcenter/display/NLC/NUnitAddin&quot; target=&quot;_blank&quot;&gt;NUnitAddin&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;saved my day-to-day dev life. &lt;/p&gt; &lt;table cellspacing=&quot;0&quot; cellpadding=&quot;2&quot; width=&quot;400&quot; border=&quot;0&quot;&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign=&quot;top&quot; width=&quot;398&quot;&gt;&lt;a href=&quot;http://www.netlogics.ch/devcenter/display/NLC/NAntAddin&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;646&quot; alt=&quot;NAnt-Snapshot&quot; src=&quot;http://lh4.google.com/sebastian.jancke/R6HDE0o3jvI/AAAAAAAAACo/bDfOdYvtV2U/NAnt-Snapshot%5B11%5D&quot; width=&quot;325&quot; align=&quot;left&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign=&quot;top&quot; width=&quot;398&quot;&gt;&lt;font size=&quot;1&quot;&gt;Courtesy of &lt;font size=&quot;1&quot;&gt;Eric Harth and Olivier Chekroun&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;&amp;nbsp;&lt;/p&gt; &lt;table cellspacing=&quot;0&quot; cellpadding=&quot;2&quot; width=&quot;400&quot; border=&quot;0&quot;&gt; &lt;tbody&gt; &lt;tr&gt; &lt;td valign=&quot;top&quot; width=&quot;400&quot;&gt;&lt;a href=&quot;http://www.netlogics.ch/devcenter/display/NLC/NUnitAddin&quot; target=&quot;_blank&quot;&gt;&lt;img style=&quot;border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px&quot; height=&quot;640&quot; alt=&quot;NUnitAddinSourceForge&quot; src=&quot;http://lh6.google.com/sebastian.jancke/R6HDGUo3jxI/AAAAAAAAACs/7gwW3NnWL6A/NUnitAddinSourceForge%5B17%5D&quot; width=&quot;434&quot; border=&quot;0&quot;&gt;&lt;/a&gt; &lt;/td&gt;&lt;/tr&gt; &lt;tr&gt; &lt;td valign=&quot;top&quot; width=&quot;400&quot;&gt;&lt;font size=&quot;1&quot;&gt;Courtesy of &lt;font size=&quot;1&quot;&gt;Eric Harth and Olivier Chekroun&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt; &lt;p&gt;Running NAnt scripts is fairly easy. Running NUnit tests directly within the IDE (without buying TestDriven.NET) made my day. Both addins are written for Visual Studio 2005 (I don&#39;t know about compatibility with 2008). They are easy to install and use.&lt;/p&gt; &lt;p&gt;Both addins accelerated my development process a lot, because I don&#39;t need to leave the IDE any more for testing and my release process is now automated&lt;/p&gt; &lt;p&gt;Perhaps, one day someone ports these for VS 2008 (if they incompatible). Both are open source, so this task should be pretty easy.&lt;/p&gt; &lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:dba2aff4-7f41-4832-a7b8-252cf04f15f1&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;Technorati-Tags: &lt;a href=&quot;http://technorati.com/tags/dotnet&quot; rel=&quot;tag&quot;&gt;dotnet&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/nant&quot; rel=&quot;tag&quot;&gt;nant&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/nunit&quot; rel=&quot;tag&quot;&gt;nunit&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/tdd&quot; rel=&quot;tag&quot;&gt;tdd&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/visualstudio&quot; rel=&quot;tag&quot;&gt;visualstudio&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/plugin&quot; rel=&quot;tag&quot;&gt;plugin&lt;/a&gt;&lt;/div&gt;</description><link>http://sjancke.blogspot.com/2008/01/improving-agility-in-visual-studio.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-7879486104630178962</guid><pubDate>Wed, 12 Dec 2007 09:45:00 +0000</pubDate><atom:updated>2007-12-12T10:53:16.536+01:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">process</category><title>Presenter First - MVP put into an agile process</title><description>&lt;p&gt;Last time, I have tried to &lt;a href=&quot;http://pragmatic-code.blogspot.com/2007/12/presenter-first-decoupling-presentation.html&quot; target=&quot;_blank&quot;&gt;show&lt;/a&gt;, how do decouple the presentation layer. Today the topic or point of view is slightly different. The Model-View-Presenter patterns can be integrated as default construction of your presentation layer into your development process. Atomic Object has build a complete agile process around the MVP pattern, called &quot;Presenter First&quot;. This process includes Test-Driven-Development (TDD), Story-Driven-Development and the MVP pattern. &lt;/p&gt; &lt;p&gt;The Model-View-Presenter pattern can be used to build domain logic and presenters based on the user stories, without a single line of UI code (or a single click). The views are all mocked out using a mocking framework (JMock, EasyMock, NMock, RhinoMock, ...). All domain logic and presentation logic is tested in isolation, the presenter comes &lt;strong&gt;first &lt;/strong&gt;(well, before the view).&lt;/p&gt; &lt;p&gt;So I would see this process broken down into the following steps:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Write a unit test, covering your user story in the domain layer&lt;/li&gt; &lt;li&gt;Fulfill with domain code, until green&lt;/li&gt; &lt;li&gt;Write a unit test for your presenter&lt;/li&gt; &lt;li&gt;Fulfill with presenter code, until green&lt;/li&gt; &lt;li&gt;Write an integrative unit test from the presenter down to the domain (at least you should)&lt;/li&gt; &lt;li&gt;Now it&#39;s time to build some UI&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;My conclusion is, that the Model-View-Presenter pattern really decouples any UI concerns from the actual user stories and their presenter/domain implementation.&lt;/p&gt; &lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:2ff5d2a1-220c-4734-9368-443aafcd672c&quot; style=&quot;padding-right: 0px; display: inline; padding-left: 0px; padding-bottom: 0px; margin: 0px; padding-top: 0px&quot;&gt;Technorati-Tags: &lt;a href=&quot;http://technorati.com/tags/process&quot; rel=&quot;tag&quot;&gt;process&lt;/a&gt;&lt;/div&gt; &lt;p&gt;Reference Material: &lt;a href=&quot;http://atomicobject.com/pages/Presenter+First&quot; target=&quot;_blank&quot;&gt;Atomic Object - Presenter First&lt;/a&gt;&lt;/p&gt;</description><link>http://sjancke.blogspot.com/2007/12/presenter-first-mvp-put-into-agile.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3738779467711724977.post-8692832267052336992</guid><pubDate>Fri, 07 Dec 2007 00:55:00 +0000</pubDate><atom:updated>2008-07-02T22:37:39.941+02:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">domainmodel</category><category domain="http://www.blogger.com/atom/ns#">patterns</category><category domain="http://www.blogger.com/atom/ns#">presentationlayer</category><title>Decoupling presentation logic with MVP</title><description>&lt;h4&gt;Motivation&lt;/h4&gt; &lt;p&gt;Lot&#39;s as been written on decoupling presentation logic since the ages of Smalltalk and the MVC-Framework. But still today, even in medium sized projects (far beyond the stage of prototype), developers - and that&#39;s me also - tend to put far too much code into the UI layer. Simultaneous, details on validation and security constrains applied to the UI have mostly left out.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;What&#39;s the problem?&lt;br /&gt;&lt;/strong&gt;The problems do not show up immediately, but after some time and growth. Most know, that putting domain logic into the UI layer is one of the worst habits. But few identify presentation logic in the UI-Implementation as a source of high coupling and low cohesion.&lt;/p&gt; &lt;p&gt;This is in conflict with one of the most basic rules of object oriented design principles: &lt;strong&gt;Subsystems should be highly cohesive and have low coupling&lt;/strong&gt;. Some guys out there have a pretty short answer: &quot;Using partial classes [in C#] decouples UI controls and logic&quot;. They fail to recognize, that partial classes in C# split a class across several files - but it does not bring in low coupling, as it is still one class.&lt;/p&gt; &lt;p&gt;Looking at the widespread known patterns discussed by the GoF, one can notice that there are couple of patterns with &quot;Split Object&quot; behavior: Decorator, Compositor, Proxy, Strategy, ...&lt;/p&gt; &lt;p&gt;What we need is a similar &quot;Split Object&quot; solution for decoupling of UI implementation and presentation logic concerns.&lt;/p&gt; &lt;h5&gt;&lt;/h5&gt; &lt;p&gt;&lt;strong&gt;A possible solution&lt;br /&gt;&lt;/strong&gt;Since the ages of Smalltalk, we (should) know MVC - Model View Controller. It is a simple and working pattern for presentation logic decoupling. So why switching minds and using another one? What MVC fails, is to enable isolated unit testing. The guys of Atomic Objects noticed that [&lt;a href=&quot;http://atomicobject.com/files/PresenterFirstAgile2006.pdf&quot; target=&quot;_blank&quot;&gt;Atomic Objects Agile2006&lt;/a&gt;] and introduced the MVP - Model View Presenter pattern. Fowler has gone even further and split this pattern into two: Supervising Controller [&lt;a href=&quot;http://martinfowler.com/eaaDev/SupervisingPresenter.html&quot; target=&quot;_blank&quot;&gt;Fowler EAA, SC&lt;/a&gt;] and Passive View [&lt;a href=&quot;http://martinfowler.com/eaaDev/PassiveScreen.html&quot; target=&quot;_blank&quot;&gt;Fowler EAA, PV&lt;/a&gt;].&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Passive View&lt;br /&gt;&lt;/strong&gt;Passive View reduces the UI (read: the views) to its absolute minimum. The difference to Model-View-Controller is that the view does not care about changes in the model. The presenter is in charge of updating the view with any changes in the model. Events on the view are subscribed by the presenter, views do not change the model.&lt;/p&gt; &lt;p&gt;As a direct result, all view logic lives in the presenter (sometimes also called controller, as this can be considered a MVC variant). The view and the model do not know of each other and have no direct reference. &lt;/p&gt; &lt;p&gt;Implementing it results in chatty interfaces between presenter and view, as all shown fields are transferred through properties on the view interface. I see it as an disadvantage, especially on complex objects. Supervising Controller can help, but it depends (as always) on your context.&lt;/p&gt; &lt;p&gt;A nice side effect is the following: Passive View makes it possible to implement views, that are totally unaware of your domain model. Splitting these layers into different subsystems (to be language and platform neutral) makes it physically nearly impossible to put business concerns into the views. &lt;/p&gt; &lt;p&gt;&lt;strong&gt;Supervising Controller&lt;br /&gt;&lt;/strong&gt;Passive View is a nice solution, as it fits our needs and decouples the presentation logic. Still it has some drawbacks. Data binding is the most important. Current view technologies have advanced support for (object) data binding. Using it can make your life a lot easier, writing less mapping code transferring values from and to the views.&lt;/p&gt; &lt;p&gt;Supervising Controller stands in. Presentation logic and command execution on view-events is still task of the presenter. Simple data mapping is done declaratively by the frameworks data binding. This solution lacks the ability to split view and presenter/model physically. Still it has the advantage of less code by using data binding.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Handling modal state&lt;br /&gt;&lt;/strong&gt;Presenters lack a concrete coupling to the view implementation. Unanswered is the task of showing model dialogs (Message Boxes) and asking the user for information (File selection, ...). Directly using message boxes in the presenter is generally a bad idea. It prevents us from isolated testing and worse: from testing at all.&lt;/p&gt; &lt;p&gt;A better approach is using the most valuable weapon in computer science - abstraction. We create a thin interface:&lt;/p&gt;&lt;pre&gt;public interface IHumbleMessageBoxService&lt;br /&gt;{&lt;br /&gt;bool AskYesNoQuestion(string title, string message);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Our view subsystem implements this interface, for example with a standard message box. This service is injected into the presenter (follow up: Dependency Inversion), communication is only going through this interface. The presenter is unaware of the message box details, model dialogs, etc.&lt;br /&gt;&lt;p&gt;Using this approach now enables us to use unit testing again on our presenters. Generally everything should be decoupled by dependency inversion - it makes your testing life easy and your design more flexibly and explicit.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Validation&lt;br /&gt;&lt;/strong&gt;I consider validation as an integral part of the business logic. Complex validation rules regarding more than simple per-field checks are near to impossible to implement correctly in the UI (without high efforts). Those validation rules can be easily implemented in the domain model. Using current technology for declarative validation checks (Spring.Validation (Java, .NET) and MS Validation Block) make this task easy. Executing those checks should be initiated from the presenter, pushing the results (read: all at once) to the UI. &lt;/p&gt;&lt;p&gt;The habit of using the default &quot;ErrorProvider&quot; of .NET&#39;s Windows.Forms is a bad idea, because it locks the user to the current field, triggering errors. Complex validation rules require the presentation of all errors at once, thus triggering of the complete validation in the presenter is key. You may start to think, how popular &quot;complex&quot; rules are. The most &quot;complex&quot; rule one may think of is two date fields as input for a date range.&lt;/p&gt;&lt;p&gt;Further, there are several types of validation rules in a system. Some are part of your business requirements, but some are introduced by a certain persistence architecture(files, databases, ...). Not aggregating all types of rules in the domain layer results in wide spreading of validation concerns. Mediating validation and their results to the views is naturally placed in the presenter. No one (?) wants his UI layer to talk directly to services and operations of the domain layer.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Security&lt;br /&gt;&lt;/strong&gt;Securing operations on the domain layer is easily achieved with declarative and imperative security. Microsoft Security Block (Part of Enterprise library) is capable of both, using Aspects for this task can be easily implemented with Spring.Aop in Java and .NET. Currently this is the way, security is build into famous frameworks like JBoss Seam. &lt;/p&gt;&lt;p&gt;While it is acceptable for users of web applications to read &quot;Operation not allowed&quot;, it is definitely &lt;strong&gt;not &lt;/strong&gt;for rich desktop applications. I expect the same to happen in the field of AJAX enabled web applications. The question is: how can we prevent the user right in the UI layer from trying to execute certain operations?&lt;/p&gt;&lt;p&gt;In our domain model, we should have all operations available. Using declarative security is key here, because it clearly states security constrains at well defined,&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Generically, we need to access these security attributes through reflection. For those in the .NET world and using Microsoft&#39;s IPrincipal:&lt;br /&gt;&lt;/p&gt;&lt;pre class=&quot;code&quot;&gt;bool roleMemberFlag = Thread.CurrentPrincipal.IsInRole(&quot;CanApproveClaims&quot;);&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;this is an easy task. It enables us to access security information for certain fields and operations via reflection. The presenter enables and disables the involved controls. Try doing that directly in your &quot;code behind&quot; of Dialogs, wihtout messing up all of your code.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Better design with higher effort?&lt;br /&gt;&lt;/strong&gt;Using the MVP pattern (and using patterns in general) rises the question of effort and results. In our case, testing presentation logic with unit testing the presenters in isolation is simpler and easier than any complex blackbox testing at the UI front. &lt;/p&gt;&lt;p&gt;Further, we gain more flexibility, code reuse and a design that meets object oriented principles. On the effort side, extracting an interface is of actually no cost, using today&#39;s refactoring support available. &lt;/p&gt;&lt;br /&gt;&lt;div class=&quot;wlWriterSmartContent&quot; id=&quot;scid:0767317B-992E-4b12-91E0-4F059A8CECA8:eba2b39c-1168-477b-8d07-8ea2fac4f0d6&quot; style=&quot;margin: 0px; padding: 0px; display: inline; float: none;&quot;&gt;Technorati-Tags: &lt;a href=&quot;http://technorati.com/tags/patterns&quot; rel=&quot;tag&quot;&gt;patterns&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/domainlayer&quot; rel=&quot;tag&quot;&gt;domainlayer&lt;/a&gt;,&lt;a href=&quot;http://technorati.com/tags/presentationlayer&quot; rel=&quot;tag&quot;&gt;presentationlayer&lt;/a&gt;&lt;/div&gt;</description><link>http://sjancke.blogspot.com/2007/12/presenter-first-decoupling-presentation.html</link><author>noreply@blogger.com (Sebastian Jancke)</author><thr:total>1</thr:total></item></channel></rss>