<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>PHP hates me - Der PHP Blog &#187; Softwaretechnik</title>
	<atom:link href="http://www.phphatesme.com/archives/category/softwaretechnik/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.phphatesme.com</link>
	<description>PhpHatesMe, but that&#039;s ok!</description>
	<lastBuildDate>Sat, 11 Feb 2012 10:13:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Don’t reinvent the squared wheel &#8211; Die Elbphilharmonie</title>
		<link>http://www.phphatesme.com/blog/softwaretechnik/dont-reinvent-the-squared-wheel-die-elbphilharmonie/</link>
		<comments>http://www.phphatesme.com/blog/softwaretechnik/dont-reinvent-the-squared-wheel-die-elbphilharmonie/#comments</comments>
		<pubDate>Wed, 25 Jan 2012 06:00:59 +0000</pubDate>
		<dc:creator>Nils Langner</dc:creator>
				<category><![CDATA[Softwaretechnik]]></category>

		<guid isPermaLink="false">http://www.phphatesme.com/?p=11919</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p>Der Spruch „Don’t reinvent the squared wheel”  ist wahrscheinlich einer der meistzitierten in der Softwareindustrie. Jedem ist klar, dass man Probleme, die bereits von jemand anderem gelöst sind, nicht neu lösen muss. Meist ist es ein Irrglaube, dass die Anforderungen, die in einem Projekt gestellt wurden, besonders sind. Bricht man zu implementierenden Features nur klein genug runter, so findet man immer Bausteine, die es so bereits gibt. Projekte besitzen meist in ihrem ganzen Alleinstellungsmerkmale, aber nicht in jedem einzelnen Feature.</p>
<p>Was passieren kann, wenn man etwas ganz besonderes, noch nie zuvor dagewesenes, versucht zu bauen, haben die Hamburger 2007 und folgende Jahre gelernt. Architektur muss nicht unbedingt in der Softwareentwicklung schief gehen, auch in der ursprünglichen Disziplin, der Architektur von Gebäuden, kann dies geschehen.</p>
<p>April 2007 begann der Bau der Hamburger Elbphilharmonie.  Ein Meisterwerk der Baukunst war geplant und das Gebäude sollte neben drei Konzertsälen und Backstagebereichen auch ein Hotel, Gastronomiebereiche, 47 Eigentumswohnungen, eine öffentlich zugängliche Plaza auf 37 Metern Höhe und ein Parkhaus mit 500 Stellplätzen enthalten. Die Optik sollte an nichts erinnern, was bereits auf der Welt zu finden ist.</p>
<p>Vielen Entwicklern wird diese Situation sehr bekannt vorkommen. Nichts was es auf dem Markt gibt, deckt den Bedarf ab und so macht man alles selbst. Die Schätzung die man am Anfang eines solchen Mammutprojektes abgibt, sollte aber trotzdem möglichst genau sein. Gute Schätzungen beruhen auf Erfahrungswerten. Wenn diese nicht vorhanden sind, wird auch das Zieldatum nicht  eingehalten werden können. Was passiert also mit einem Projekt wie der Elbphilharmonie? Zur ersten Verzögerung kam es 2010, die zweite wurde im Jahre 2011 angekündigt. Mittlerweile sind die Kosten von ursprünglich 77 Millionen auf 476 Millionen gestiegen und ein Ende ist nicht in Sicht.</p>
<p>Was man aus diesem Vergleich mitnehmen kann ist einfach. Wenn eine Architektur aufgesetzt wird, sollte man das bekannte Territorium so selten wie möglich verlassen, denn dort wo man sich nicht auskennt, verläuft man sich mit Leichtigkeit. Der Einsatz von bereits existierenden Frameworks und Bibliotheken ist in den meisten Fällen der Eigenentwicklung vorzuziehen.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phphatesme.com/blog/softwaretechnik/dont-reinvent-the-squared-wheel-die-elbphilharmonie/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Continuous Integration &#8211; Teil 2</title>
		<link>http://www.phphatesme.com/blog/softwaretechnik/continuous-integration-teil-2/</link>
		<comments>http://www.phphatesme.com/blog/softwaretechnik/continuous-integration-teil-2/#comments</comments>
		<pubDate>Tue, 10 Jan 2012 06:00:41 +0000</pubDate>
		<dc:creator>Nils Langner</dc:creator>
				<category><![CDATA[Projektmanagement]]></category>
		<category><![CDATA[Softwaretechnik]]></category>

		<guid isPermaLink="false">http://www.phphatesme.com/?p=11788</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p>Vor ein paar Tagen habe ich ja angefangen ein wenig über <a href="http://www.phphatesme.com/blog/softwaretechnik/continuous-integration/">Continuous Integration</a> zu reden und war dabei stehen geblieben, bei dem, was ich glaube, die meisten unter CI verstehen: dem Einsatz eines CI-Servers. Jetzt hab ich gleich mal Anschiss von Tobi S. bekommen, dass man nicht das Falsche vor dem Richtigen erklärt. War mir aber egal, der Artikel war ja eh schon draußen. Ich bin halt ein Rebell und mich hält nichts auf.</p>
<p>Falsch ist das ja alles nicht, was ich erklärt habe, es ist ein wichtiger Bestandteil des Konzepts, dass man nach jedem Commit, also möglichst oft und automatisch durchtestet und sein System baut. Wichtig dabei st aber auch, dass man möglichst oft comittet. In den meisten Fällen ist es ja so, dass man erst seine Änderungen in den Trunk eincheckt, wenn das Feature fertig ist und vollständig implementiert ist. CI geht da einen anderen Weg, nicht wenn das vollständige Feature fertig ist, sondern wenn etwas funktionsfähig fertig ist, wird comittet.</p>
<p>Die Idee dahinter ist, dass man viel einfacher kleine Inkremente in das Gesamtsystem mergen kann, als das große Ganze am Ende. Konflikte mit anderen Änderungen (von den lieben Kollegen) findet man so zeitnah und kann auch von dem Code, den die anderen produzieren profitieren. Ob das System in der Art für einen funktioniert, hängt auch immer davon ab, wie sehr man bereit ist Testabdeckung für seinen Code und seine Funktionalitäten hochzuschrauben. Denn wenn die Abdeckung hoch ist, so weiß man jeder Zeit, ob der Code, den man gerade produziert hat etwas am bereits bestehenden System ändert. Wenn nicht, kann es auch nicht schaden, den Code mit in die Versionskontrolle zu packen.</p>
<p>Continuous Integration ist ein sehr großes Thema, auch wenn es eigentlich nur auf zwei Grundsätzen beruht. Ich werde versuchen in der nächsten Zeit noch mal etwas über einzelne Implementationen zu schreiben, dann will ich auf Feature-Toggles eingehen und etwas für Continuous Deployment verfassen. Wenn euch etwas fehlt, dann schreibt es in den Kommentaren. Ich kümmere mich dann darum.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phphatesme.com/blog/softwaretechnik/continuous-integration-teil-2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Continuous Integration</title>
		<link>http://www.phphatesme.com/blog/softwaretechnik/continuous-integration/</link>
		<comments>http://www.phphatesme.com/blog/softwaretechnik/continuous-integration/#comments</comments>
		<pubDate>Thu, 05 Jan 2012 06:00:13 +0000</pubDate>
		<dc:creator>Nils Langner</dc:creator>
				<category><![CDATA[Softwaretechnik]]></category>
		<category><![CDATA[Tools & Helferlein]]></category>

		<guid isPermaLink="false">http://www.phphatesme.com/?p=11780</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p>Wer hat ihn nicht mitbekommen, den Streit um Hudson und die Entstehung von Jenkins. Continuous Integration Server waren eine Zeit lang in aller Munde. Auf PHP-Konferenzen gab immer wieder Vorträge über die Server. Und das auch alles zu Recht. Ich liebe unseren Bamboo!</p>
<p>Aber für all diejenigen, für die Continuous Integration noch ein Buch mit sieben Siegeln ist, hier noch mal die Schnelleinführung von dem, was die meisten glauben. was CI ist. Im nächsten Artikel schreibe ich dann, warum das nicht ganz richtig ist.</p>
<p>Wenn man einen CI-Server einsetzt, dann übernimmt der hauptsächlich eine Aufgabe. Er testet die Applikation. Grob zusammengefasst prüft er in wiederkehrenden Intervallen ein Source-Code-Repository (z.B. SVN), ob Änderungen am Code vorgenommen wurden. Falls es Änderungen gab, so wirft er die vorher definierte Test-Suite an und gibt einem das Ergebnis aus. Je nach Konfiguration bekommen die Teammitglieder dann eine Mail. falls etwas kaputt ist. In den meisten Fällen handelt es sich bei der Test-Suite um Unit Tests. Es ist aber auch problemlos möglich Tools wie Selenium, Code-Sniffer, PHPMD oder ähnliches einzuhängen. Alles was über die Kommandozeile funktioniert, funktioniert auch im CI-Server.</p>
<p>Vorteil von einem solchen Server ist somit, dass kaputter Code nicht lange unentdeckt bleibt, da es jemanden gibt, der sicher nicht vergisst die Tests auszuführen, so wie es einem Entwickler vielleicht passieren könnte. Schön ist es auch, dass es keine Zeit frisst. Niemand sitzt vorm Rechner und lässt die Tests laufen, das macht alles der dumme und günstige Server im Hintergrund.</p>
<p>Das war jetzt also die Quick-and-dirty-Version von dem, was die meisten Leute unter Continuous Intergration verstehen, dem Einsatz eines Continuous Integration Servers. Wie gesagt, im nächsten Artikel ergänzen wir das.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phphatesme.com/blog/softwaretechnik/continuous-integration/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>&#8220;Kunden, die diesen Artikel gekauft haben, kauften auch&#8221; in der Softwareentwicklung</title>
		<link>http://www.phphatesme.com/blog/softwaretechnik/kunden-die-diesen-artikel-gekauft-haben-kauften-auch-in-der-softwareentwicklung/</link>
		<comments>http://www.phphatesme.com/blog/softwaretechnik/kunden-die-diesen-artikel-gekauft-haben-kauften-auch-in-der-softwareentwicklung/#comments</comments>
		<pubDate>Fri, 25 Nov 2011 06:00:04 +0000</pubDate>
		<dc:creator>Nils Langner</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Projektwerkstatt]]></category>
		<category><![CDATA[Qualitätssicherung]]></category>
		<category><![CDATA[Softwaretechnik]]></category>

		<guid isPermaLink="false">http://www.phphatesme.com/?p=11303</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p>Zeit für Ideen. Leider nicht meine, sondern von einem anderen Held. Darüber erfahren hab ich über Sebastian Bergmann. Genug verwirrt? Aber eigentlich sollte die Idee im Mittelpunkt stellen, ich wollte nur mal schnell sagen, dass ich damit kaum was zu tun habe.</p>
<p>Wenn man Sebastian Bergmann hört, dann ist ja schon klar, dass es sich um ein QA- oder QM-Thema handelt und genau das ist es auch. im Prinzip geht es dabei nur um einen Commit-Hook. Ja ich weiß, da gibt es viele, aber was haltet ihr von der Idee, dass er einen darauf hinweist, wenn man vergessen hat eine Datei zu comitten oder sogar sie unzupassen? Hääh? Wie soll denn das gehen? Im Prinzip muss man nur folgende Aussage in den Raum stellen: &#8220;<strong>Wenn sie in der Vergangenheit Datei A comitted haben, dann haben sie auch immer Datei B angefasst.</strong>&#8221;</p>
<p>Finde den Ansatz genial. Er ist simpel und trotzdem scheint es effizient zu sein. So viel ich weiß, hat Sebastian dies sogar mal in PHP implementiert. Leider fehlen mir dazu die Links. Hatte mir nur die Idee gemerkt weil ich sie toll fand.</p>
<p>Ich würde ja gerne mehr darüber erzählen, aber die Idee ist ja schon in dem einen Satz wunderbar erklärt, deswegen wird es heute mal ein wenig kürzer und wir denken uns alle, wie toll es wäre, wenn wir das mal austesten dürften.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phphatesme.com/blog/softwaretechnik/kunden-die-diesen-artikel-gekauft-haben-kauften-auch-in-der-softwareentwicklung/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Forrest-Gump-Syndrom</title>
		<link>http://www.phphatesme.com/blog/softwaretechnik/forrest-gump-syndrom/</link>
		<comments>http://www.phphatesme.com/blog/softwaretechnik/forrest-gump-syndrom/#comments</comments>
		<pubDate>Fri, 11 Nov 2011 06:00:41 +0000</pubDate>
		<dc:creator>Nils Langner</dc:creator>
				<category><![CDATA[Projektmanagement]]></category>
		<category><![CDATA[Softwaretechnik]]></category>

		<guid isPermaLink="false">http://www.phphatesme.com/?p=10976</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p>Ich wollte schon immer mal einen Smell benennen und vielleicht klappt es ja heute. Zumindest bin ich guter Dinge und wer gerne um mehrere Ecken denkt, der wird den Transfer, den ich später vornehmen werde lieben. Oder hassen. Oder es ist ihm egal. Habe ich eine Option vergessen? Ich glaube nicht.</p>
<p>Aber fangen wir einfach mal an. Als Qualitätsmanager, der sich gerne um Softwarequalität kümmert komme ich nicht dran vorbei auch mal älteren Code anzuschauen, um rauszufinden, wo die Entwicklungsteams schwächen aufzeigen und um Muster in den auftretenden Fehler oder Schwächen zu finden. Jetzt stand ich letzte Woche mal wieder vor einem Stück Code, dass schon in die Jahre gekommen, aber dennoch wichtig für das Gesamtsystem ist.</p>
<p>Was stank (engl. Smell) an dem Stück Code? Zuerst einmal hatte man das Gefühl, dass es nicht stimmig war. Es gab Methoden, die sich um das eine gekümmert haben und andere, die eigentlich zu einer ganz anderen Aufgabe gehörten. Ihre Schnittmenge war recht gering. Alles im allen war es so, dass man mit einem sauberen Stück Software begonnen hat und dann immer wieder unter Zeitdruck dem existierenden Code neue Funktionalitäten aufgedrückt hat, die vielleicht gar nicht dort hinzugehört haben, aber irgendwie doch dort gepasst haben. Oder am ehesten gepasst haben. Und für eine kleine Erweiterung hat man nicht den Elan die ganze Architektur umzubauen, so dass es dann vielleicht sauberer gewesen wäre.</p>
<p>In den meisten Fällen, wenn man einen Softwareentwickler mal auf solchen gewachsenen Code anspricht, kommt das Argument der fehlenden Zeit. Alles muss schnell gehen und am besten gestern fertig sein. Kennen wir alle und so entsteht auch Softwareerosion. Das System fällt in sich zusammen. Es wird immer schwerer &#8230; das habt ihr schon tausendmal gehört. Je mehr Hacks und Workarounds eingebaut sind, desto schmutziger ist der nächste Workaround und man muss immer schneller arbeiten, um pünktlich an sein Ziel zu kommen.</p>
<p>Ein bekannter Smell. Ein Freund von mir hat mir mal den Satz gesagt &#8220;<strong>Wenn du dich im Wald verlaufen hast, dann solltest du nicht einfach losrennen, sondern kurz anhalten, um dich zu orientieren</strong>&#8220;. Und genau das sollte man auch bei der Softwareentwicklung machen. Wenn man merkt, dass der Weg, den man gerade beschreitet nicht aus dem Wald hinaus führt, dann sollte man stoppen. Kurz Luft holen, die Lage evaluieren und dann erst weitermachen. Es hilft niemanden wenn man einfach drauf losrennt und den echten Weg soweit verlässt, dass man nicht mehr zurückfindet.</p>
<p>Wenn ihr also eines aus dem Artikel mitnehmen solltet, dann ist es die Metapher, die wie ich finde wunderbar passt.</p>
<p>So jetzt der Transfer zum Titel und dem Smell-Namen. Ihr kennt alle einen der bekanntesten Sätze aus Forrest Gump: &#8220;Run Forrest Run&#8221;. Naaa macht&#8217;s klick? Ich glaube schon. Ok, vielleicht klappt es nicht mit dem offiziellen Namen für einen Smell, aber sicherlich hilft es euch an ihn zu denken.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phphatesme.com/blog/softwaretechnik/forrest-gump-syndrom/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Teile und Herrsche! – CQRS, Teil 2</title>
		<link>http://www.phphatesme.com/blog/softwaretechnik/teile-und-herrsche-%e2%80%93-cqrs-teil-2/</link>
		<comments>http://www.phphatesme.com/blog/softwaretechnik/teile-und-herrsche-%e2%80%93-cqrs-teil-2/#comments</comments>
		<pubDate>Mon, 07 Nov 2011 06:00:51 +0000</pubDate>
		<dc:creator>Nino Martincevic</dc:creator>
				<category><![CDATA[Softwaretechnik]]></category>

		<guid isPermaLink="false">http://www.phphatesme.com/?p=10910</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<h2>Vorbedingungen</h2>
<p>Es sei angemerkt, dass man mit den Vorteilen der SOLID Prinzipien <sup>[1]</sup> vertraut sein sollte, um den ganzen Sinn von CQRS zu verstehen. Es entstanden im <a href="http://phoop.blogspot.com/2011/10/teile-und-herrsche-cqrs-pt-1.html">letzten Artikel</a> viele Diskussionen über grundsätzliche Aspekte wie SRP oder OCL, weil diese Prinzipien nicht angewandt oder verstanden werden. Ebenso sollte man schon mal etwas über den Sinn von Layering und Modularität von Software gehört haben.</p>
<h2>Zusammenfassung CQRS</h2>
<p>Um noch mal die entscheidenden Punkte, die für einen Einsatz von CQRS sprechen, zu erläutern, hier eine kurze Zusammenfassung:</p>
<p>In CQRS geht es um eine weitere Auftrennung von Verantwortlichkeiten bzw. Belangen in einer Software, über Methoden und Klassen bis hin zu den Schichten der Applikation selbst.</p>
<p>In einer Businessanwendung geht es vor allem darum, dass Anweisungen zuverlässig und korrekt verarbeitet werden. Das Ergebnis sollte ein jederzeit gültiger und erwarteter Zustand sein, der alle Regeln der Geschäftslogik einhält. Dabei spielen Faktoren wie u.a. Transaktionssicherheit, Konsistenz oder Nebenläufigkeit eine Rolle.</p>
<p>Commands spiegeln, wie gesagt, den tatsächlichen Umfang und Wert der Software wider.<br />
Was sie machen, ist der Funktionsumfang, also die Erfüllung gestellter Aufgaben.<br />
Und wie gut sie es machen, die Qualität.</p>
<p><strong>Die Summe aller Commands spiegelt den gesamten Funktionsumfang und die Fähigkeiten einer Domain wider.</strong></p>
<p>Beim Anzeigen, Reporten und Überprüfen der Änderungen wiederum entstehen ganz anderen Anforderungen an die Software, z.B. Performance oder Skalierbarkeit.</p>
<p>Abfragen müssen nicht zwangsläufig aktuell oder konsistent sein. Dies ist übrigens auch aus der inzwischen verbreiteten NoSQL-Technologien bekannt: Eventual Consistency <sup>[2]</sup>.</p>
<p>Da jede Art von Abfrage den Zustand zur Zeit der Abfrage selbst widerspiegelt aber nicht unbedingt den augenblicklichen Stand, liefert sie sehr oft sowieso nur „veraltete“ Daten.</p>
<p>Ein fehlerhaftes Reporting lässt sich immer wieder neu aufbauen.<br />
Aber ein inkonsistenter Zustand der Domain und der Daten nur sehr schwer.</p>
<p>Umgekehrt kann man sagen, dass die meisten Anwendungen wenige Befehle verarbeiten müssen, diese aber mit höchster Präzision. Hingegen müssen sie aber ein Vielfaches an Querys abarbeiten und deren Ergebnisse schnell ausliefern.</p>
<p>Allein diese kurzen Erläuterungen zeigen schon, dass es einerseits komplett verschiedene Anforderungen an die Software gibt es aber auch komplett unterschiedliche Implementierungen geben sollte. Denn für so unterschiedliche Belange wird es kaum ein System geben, dass in der Lage ist, beide Belange optimal darzustellen.</p>
<h2>CQRS in der Praxis: Implementierung mit DomainEventing</h2>
<p>Es gibt viele Möglichkeiten, CQRS zu implementieren. Einen davon möchte ich hier vorstellen: Domain Eventing mit Commands und Events.</p>
<p>Wenn man den Wert von CQRS erkannt hat und mit der Umsetzung beginnt, ist der nächste, fast zwangsläufig logische, Schritt die Einführung einer Messagingarchitektur auf Domainebene.</p>
<p>Es geht darum, dass das komplette Verhalten einer Domain über Commands gesteuert wird.Dabei entstehen Zustandsänderungen, wie Erzeugung von neuen Objekten oder beliebige andere Änderungen des Zustands.</p>
<p>In der Praxis sieht das beispielsweise so aus:</p>
<p><a style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;" href="http://4.bp.blogspot.com/-8w-O0kJYJ8s/TrPoTQ6NRgI/AAAAAAAAAqQ/gVAXnXACo5Y/s1600/DomainEventing.PNG"><img src="http://4.bp.blogspot.com/-8w-O0kJYJ8s/TrPoTQ6NRgI/AAAAAAAAAqQ/gVAXnXACo5Y/s640/DomainEventing.PNG" alt="" width="640" height="292" border="0" /></a></p>
<p>Wem die Begriffe Repository und Aggregate nicht bekannt sind: das sind Bausteine, die in Domain Driven Design <sup>[3]</sup> verwendet werden. Eine Repository ist im Prinzip ein DAO und eine Aggregat nichts anderes als ein einzelnes Objekt oder ein Objektgraph.</p>
<p><strong>Das Wichtigste dabei ist: eine Repository stellt genau <span style="text-decoration: underline;">ein</span> Aggregat zur Verfügung, das in der Lage ist, einen Command <span style="text-decoration: underline;">vollständig </span>abzuarbeiten.</strong></p>
<p>Die einzelnen Bausteine sind:<br />
<strong>Command</strong><br />
Ein Command ist ein Befehl, der eine Statusänderung durchführen soll. Er ist immer im Imperativ benannt: CreateCustomer, AddContactPerson, LockCustomer. Technisch ist ein Command ein simples DTO, dass nur die Daten bereithält, die zur Ausführung des Befehls gebraucht werden. Ein Command wird an einen CommandBus (der mit mindestens einer Repository ausgestattet wird) geschickt, dieser sucht den entsprechenden Handler und übergibt diesem das Command. Werden diese Commands auch mitgeloggt erhält man damit eine komplette Historie aller Vorgänge und Zustandsänderungen einer Domain.</p>
<p><strong>CommandHandler</strong></p>
<p>Führt das entsprechende Kommando aus, in dem er über die Repository ein Aggregat holt und den Befehl an dieses delegiert, oder (über eine Factory) ein Aggregat erstellt und es über Repository/Unit of Work persistiert.<br />
<strong>Event</strong><br />
Events sind Messages, die eine Zustandsänderung beschreiben.<br />
Es sind geschehene Ereignisse, die aus der Ausführung von Commands resultieren und deshalb immer in der Vergangenheitsform benannt (CustomerLocked, MoneyTransferred) und nicht mehr änderbar (!) sind. Sie werden zuerst im EventBus registriert (i.d.R. aus einem Service heraus) und an der Stelle erzeugt, an der das Command als abgearbeitet bezeichnet werden kann. Events werden an den EventBus geschickt (raise).<br />
<strong>EventHandler</strong><br />
Wenn die Sicherstellung der Konsistenz eines Aggregates exakt bestimmt werden kann, wird an dieser Stelle dafür gesorgt, dass alle bisher gesammelten Events im EventBus veröffentlicht werden (publish). Dies kann im Aggregat selbst, in unserem Fall jedoch oft erst in der Repository sichergestellt werden (nach erfolgreichem save()). Der EventBus sucht alle Events, die die Interfaces der registrierten Events implementieren und führt diese aus. So können mehrere EventHandler nach einem bestimmt Event die weitere Arbeit übernehmen.<br />
<strong>CommandBus, EventBus</strong><br />
Das können vollwertige Messaging Lösungen (z.B. ActiveMQ)<sup>[4]</sup> sein, wenn es um verteilte Anwendungen oder asynchrone Prozesse geht. In der Regel sind es aber simple Container, die nur für eine Transaktion (Thread) aufgebaut werden und Commands und Events abhandeln und verwalten.</p>
<p>Wichtig dabei sind folgende Dinge:</p>
<ul>
<li>Ein Command wird immer vollständig oder gar nicht abgearbeitet.</li>
<li>Ein Command darf genau <strong>einmal</strong> abgearbeitet werden.</li>
<li>Für jedes Command gibt es exakt EINEN CommandHandler.</li>
<li>Commands und Events müssen serialisierbar sein.</li>
<li>Für einen Event kann es mehrere EventHandler geben.</li>
</ul>
<h2>Vorteile DomainEventing</h2>
<p>Dieser Mechanismus hat gleich mehrere Vorteile:</p>
<p>Commands und CommandHandlern geben präzise die Intention des Befehls wider. CommandHandler sind quasi als Microservices anzusehen, durch den Fokus auf die Erledigung genau einer Aufgabe sind sie zudem besonders gut testbar.</p>
<p>Die Testbarkeit wird dadurch erhöht, dass man Testfälle so definieren kann:</p>
<ol>
<li>Ausgangssituation (given)</li>
<li>Befehl, der ausgeführt werden soll (when)</li>
<li>Erwartetes Resultat bzw. eingetretenes Ereignis (then)</li>
</ol>
<p>Man braucht also nicht mehr auf Werte zu testen, um zu sehen, ob eine Zustandsänderung erfolgt ist (wovon sowieso stark abzuraten ist, da es sehr anfällig ist und dem Prinzip der Kapselung widerspricht), sondern braucht nur zu schauen, ob ein Event erzeugt wurde.</p>
<p>Beispiel „Kunden sperren“:</p>
<pre><code>public function testLockCustomerRaisesEvent ()
{
  EventBus::<em>clearAll</em>();
  EventBus::<em>register</em>('CustomerLocked');
  $cmd = <strong>new </strong>LockCustomer(array(‘customerId’ =&gt; 1);
  $cmdBus = <strong>new </strong>CommandBus($this-&gt;customerRepository);
  $cmdBus-&gt;dispatch($cmd);
  $event = EventBus::<em>getLastPublished</em>();
  $this-&gt;assertType('CustomerLocked', $event);
}
</code></pre>
<p>Die Hauptaufgabe der Eventhandler ist es, weitere Prozesse innerhalb eines Threads anzustoßen. Damit sie in der Domain Sinn machen, dürfen sie z.B. nur <strong>innerhalb des Threads</strong> weitere Commands erzeugen. Dies sollte man aber so weit wie möglich vermeiden.</p>
<p>Alle außerhalb liegenden (z.b. asynchrone oder auf anderen Systemen operierende) werden wie gehabt über bestehende Messaginglösungen abgearbeitet.</p>
<p>Eine der häufigsten Aufgaben von EventHandlern ist die Denormalisierung der Aggregate in die entsprechenden Datenhaltungen für die Lesevorgänge zu erledigen.</p>
<h2>Nachteile DomainEventing</h2>
<p>Hm, gute Frage. Am ehesten noch die erhöhte Anzahl von Interfaces und Klassen.</p>
<p>Das ist aber nicht wirklich ein Nachteil. Denn viele kleine Klassen haben im Gegensatz zu wenigen aber zu großen Klassen sowieso Vorteile.</p>
<h2>Fazit aus der Praxis</h2>
<p>Bei einer aktuellen Anwendung, mit der ich mich als Teil eines Teams gerade beschäftige, handelt es sich um ein großes und komplexes System, dass aus knapp 1.000.000 Codezeilen, ca. 220 Datenbanktabellen und etwa 250 GB Daten besteht.</p>
<p>Wie es viele von uns (leider) kennen, gibt es kaum oder nur wenige Tests. Und wenn, dann meist nur Integrationstests. Also eine typische Legacy-Anwendung (mit Legacy meine ich hier nicht Fremdsysteme, sondern nicht getestete Software – was das gleiche ist.)</p>
<p>Dabei zeigte sich sehr schnell, dass es nur eine relativ kleine Anzahl von Commands und Events im Verhältnis zur Größe des Sourcecodes gibt.<br />
Und es zeigte sich ebenso, wie man schrittweise Legacy Code umbauen kann, in dem man die Anforderungen schrittweise in Commands umsetzte und diese erst mal nur über Wrapper bestehende Services benutzen und später dann ausgetauscht werden.</p>
<p>Aber durch die oben erwähnte ideale Testbarkeit konnte man das sogar bei einem bisher kaum mit Tests versehenem System relativ einfach tun.</p>
<p>Es wurde bei so einem System schnell klar, dass dies das eigentliche Killerfeature von DomainEventing ist.</p>
<p>[1] <a href="http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29">http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29</a></p>
<p>[2] <a href="http://www.allthingsdistributed.com/2008/12/eventually_consistent.html">http://www.allthingsdistributed.com/2008/12/eventually_consistent.html</a></p>
<p>[3] <a href="http://de.wikipedia.org/wiki/Domain-Driven_Design">http://de.wikipedia.org/wiki/Domain-Driven_Design</a></p>
<p>[4] <a href="http://it-republik.de/php/artikel/Ein-Ueberblick-zu-Message-Queues-fuer-PHP-2262.html">http://it-republik.de/php/artikel/Ein-Ueberblick-zu-Message-Queues-fuer-PHP-2262.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phphatesme.com/blog/softwaretechnik/teile-und-herrsche-%e2%80%93-cqrs-teil-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Teile und Herrsche! &#8211; CQRS, Teil 1</title>
		<link>http://www.phphatesme.com/blog/softwaretechnik/teile-und-herrsche-cqrs-teil-1/</link>
		<comments>http://www.phphatesme.com/blog/softwaretechnik/teile-und-herrsche-cqrs-teil-1/#comments</comments>
		<pubDate>Fri, 28 Oct 2011 05:00:23 +0000</pubDate>
		<dc:creator>Nino Martincevic</dc:creator>
				<category><![CDATA[Softwaretechnik]]></category>

		<guid isPermaLink="false">http://www.phphatesme.com/?p=10762</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[<p><em>Letzte Woche habe ich eine E-Mail von <a href="http://phoop.blogspot.com">Nino</a> bekommen, ob ich Interesse hätte an einem fortgeschrittenen Artikel und da wäre ich ja doof, wenn ich &#8220;Nein&#8221; sagen würde. Nino hatte auch gleich etwas parat zum Thema &#8220;Command Query Responsibility Segregation&#8221;. Da ich davon noch nie was gehört hatte und er bereits etwas darüber geschrieben hat, haben wir uns schnell geeinigt, dass wir <a href="http://phoop.blogspot.com/2011/10/teile-und-herrsche-cqrs-pt-1.html">diesen Artike</a>l doch auch gerne bei uns hätten. Hier ist das Resultat und der zweite Artikel zum Thema wird sicherlich auch nicht lange auf sich warten lassen.</em></p>
<p>Im Leben eines Entwicklers gibt es immer wieder „Aha“- oder sog. „Breakthrough“-Momente, in denen man entweder etwas entdeckt, dass die eigenen Fähigkeiten beträchtlich erweitert oder lange bestehende Probleme löst.</p>
<p><span style="font-family: Verdana,sans-serif;">Hier geht es um ein solches, (noch) kaum bekanntes und bisher selten angewendetes Prinzip für das Design von objektorientierter Software.  Meines Erachtens ist es sehr einfach  zu verstehen und auch sehr einfach anwendbar. Aber noch größer sind die Vorteile die es bietet.</span></p>
<p><span style="font-family: Verdana,sans-serif;">Aber erst mal die Auflösung des Akronyms:</span></p>
<p><span style="font-family: Verdana,sans-serif;"><em><strong>CQS </strong></em>= Command Query Separation  (nach Bertrand Meyer):</span></p>
<p><span style="font-family: Verdana,sans-serif;">“Separate command methods that change state from query methods that read state. But not both.”<br />
</span></p>
<p><span style="font-family: Verdana,sans-serif;">Das heißt, die Trennung von Methoden, die entweder Zustände ändern (Befehle verarbeiten) oder den Zustand eines Objekts lesen bzw. darüber berichten.</span></p>
<p><span style="font-family: Verdana,sans-serif;"><em><strong>CQRS </strong></em>= Command Query Responsibility Segregation </span></p>
<p><span style="font-family: Verdana,sans-serif;">Auf Deutsch: Auftrennung der Verantwortlichkeit nach Befehl und Abfrage. </span></p>
<p><span style="font-family: Verdana,sans-serif;">Ist doch das gleiche, oder?</span></p>
<p><span style="font-family: Verdana,sans-serif;">Nicht ganz, bei CQRS ist nicht die Rede von Methoden…</span></p>
<h2>SOLIDe Klassen und Methoden</h2>
<p><span style="font-family: Verdana,sans-serif;">Bevor ich in die Details gehe, möchte ich darauf hinweisen, dass dem Leser die SOLID Prinzipien <sup><span style="font-size: x-small;">[1]</span></sup> und auch Clean Code <sup><span style="font-size: x-small;">[2]</span></sup> ein Begriff sein sollten. Zusammengefasst geht es um elementare Prinzipien, mit Hilfe derer man qualitativ hochwertige, d.h. vor allem änderbare, wartbare und testbare Software schreibt.</span></p>
<p><span style="font-family: Verdana,sans-serif;">Schauen wir uns eine oft in dieser oder ähnlicher Form auftretende, „traditionelle“ Klasse eines Models an:</span></p>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">class Customer</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">{</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    private $name;</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    private $zipcode;</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    private $street;</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    private $city;</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    </span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    public function doThis() {</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">        // &#8230;some sophisticated domain logic</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">        return $yuk;</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    }</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    </span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    public function doThat() {</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">        // &#8230;some other sophisticated domain logic</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">        return $yak;</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    }</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    </span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    public function setCity($aCity) {</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">        $this-&gt;city = $aCity;</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    }</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    </span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    public function getCity() {</span></div>
<div style="background-color: #eeeeee;">
<p><span style="font-family: 'Courier New',Courier,monospace;">        return $this-&gt;city;</span></p>
</div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    }</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    </span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">    // &#8230; a bunch of other setters and getters</span></div>
<div style="background-color: #eeeeee;"><span style="font-family: 'Courier New',Courier,monospace;">}</span></div>
<p><span style="font-family: Verdana,sans-serif;">Selbst in diesem rudimentären Beispiel erkennt man beim genaueren Hinschauen mehrere Probleme und Verstöße gegen SOLID:</span></p>
<ol>
<li><span style="font-family: Verdana,sans-serif;">SRP: was ist die Verantwortlichkeit dieser Klasse?</span><span style="font-family: Verdana,sans-serif;">Sie tut mehrere Dinge (<em style="font-family: 'Courier New',Courier,monospace;">doThis</em>, <em style="font-family: 'Courier New',Courier,monospace;">doThat</em>),<br />
man kann einen ihrer Zustände direkt setzen (<em><span style="font-family: 'Courier New',Courier,monospace;">setBar</span></em>) und sie berichtet<br />
direkt über einen ihrer Zustände (<em><span style="font-family: 'Courier New',Courier,monospace;">getCity</span></em>)</span></li>
<li><span style="font-family: Verdana,sans-serif;">Information Hiding – sie exponiert ihren Zustand direkt.</span></li>
<li><span style="font-family: Verdana,sans-serif;">Die Befehlsmethoden doThis und doThat führen zwar eine Anweisung aus, geben aber zugleich auch etwas zurück.</span></li>
<li><span style="font-family: Verdana,sans-serif;"><em><span style="font-family: 'Courier New',Courier,monospace;">setCity </span></em>ist fast schon kriminell, denn<br />
letztendlich soll es eine Änderung (eines Teils) einer Adresse sein, es<br />
werden aber einzelne Attribute des Konzepts Adresse gesetzt. </span><span style="font-family: Verdana,sans-serif;">(Aber das ist Thema des kommenden Posts „Das ultimative Ende aller Getter und Setter“…)  </span></li>
</ol>
<p><span style="font-family: Verdana,sans-serif;">Sowohl SOLID als auch Clean Code propagieren das „Tell, don’t ask!“-Prinzip <sup><span style="font-size: x-small;">[3]</span></sup>:</span></p>
<p><span style="font-family: Verdana,sans-serif;">Sag einem Objekt was es tun soll und frage nicht erst, ob es das tun kann (wie elementar wichtig diese Regel ist, werde ich hoffentlich mal getrennt abhandeln). </span></p>
<p><span style="font-family: Verdana,sans-serif;">Und nach CQS sollte eine Methode, die einen Befehl darstellt, keine Informationen zurück liefern bzw. gar keine Rückgabe haben.</span></p>
<p><span style="font-family: Verdana,sans-serif;">Aber das grundlegendste Problem dieser ( und der meisten mir bekannten Klassen oder Modelle) ist die Verletzung von SRP.</span></p>
<p><span style="font-family: Verdana,sans-serif;">Denn die Verantwortlichkeit der obigen Klasse kann man minimal so formulieren als „Die Klasse Foo macht doThis und doThat, und man kann mit ihr bar setzen und lesen“.</span></p>
<p><span style="font-family: Verdana,sans-serif;">Eine einzige Verantwortlichkeit ist das nicht. Überprüft bitte eure bestehenden Modell-Klassen eines aktuellen Projektes. Wie viele davon machen zu viel und verstoßen gegen SRP?</span></p>
<p><span style="font-family: Verdana,sans-serif;">Ein weiteres Beispiel für einen möglichen Service:</span></p>
<div style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;">class BlogService</div>
<div style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;">{</div>
<div style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;">    public function setPost($post);</div>
<div style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;">    public function deletePost($postId);</div>
<div style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;">    public function getPost($postId);</div>
<div style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;">    public function getAllPosts();</div>
<div style="background-color: #eeeeee;"><span style="font-family: Verdana,sans-serif;">}</span></div>
<p><span style="font-family: Verdana,sans-serif;">Auch hier sehen wir keine klare Verantwortlichkeit. Vielmehr ein Sammelsurium aus mehreren Anweisungen und vieler Abfragen.</span></p>
<p><span style="font-family: Verdana,sans-serif;">Jetzt kommt CQRS ins Spiel.</span></p>
<p><span style="font-family: Verdana,sans-serif;">Im Prinzip geht es darum, die obigen Prinzipien und CQS auf einer höheren Ebene anzuwenden:</span></p>
<p><strong><span style="font-family: Verdana,sans-serif;">„Trenne zwei Endpunkte (oder Objekte) und gib dem einen die Aufgabe, Befehle zu verarbeiten und einem anderen, Abfragen durchzuführen.“</span></strong></p>
<p><span style="font-family: Verdana,sans-serif;"><br />
Das ist die Essenz  von CQRS.</span></p>
<p><span style="font-family: Verdana,sans-serif;">CQRS ist eine m.E. logische Weiterentwicklung von CQS, SOLID, Clean Code und Domain Modeling. </span></p>
<p><span style="font-family: Verdana,sans-serif;">Wenn obige Methodiken und Prinzipien eine Trennung von Anweisungen (commands) und Abfragen (queries) auf Methodenebene propagieren, macht CQRS dies auf Klassen- bzw. sogar Architekturebene.</span></p>
<h2>Verdopple deine Klassen</h2>
<p><span style="font-family: Verdana,sans-serif;">Was bedeutet die Anwendung von CQRS in der Praxis?</span></p>
<p><span style="font-family: Verdana,sans-serif;">Zu aller erst mal nur, dass man seine Klassen (Service- als auch Domain-Klassen) klar nach der jeweiligen Verantwortlichkeit trenne sollte. Also nichts anderes, als das wir aus jeder Klasse zwei machen, so dass sie entweder nur Befehle verarbeiten (also Zustände ändern)  oder Abfragen durchführen.</span></p>
<p><span style="font-family: Verdana,sans-serif;">Aus dem einen Service BlogService wird dann:</span></p>
<div style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;">class BlogService</div>
<div style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;">{</div>
<div style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;">    public function setPost($post);</div>
<div style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;">    public function deletePost($postId);</div>
<div style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;">}</div>
<div style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;">class BlogReadService</div>
<div style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;">{</div>
<div style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;">    public function getPost($postId);</div>
<div style="background-color: #eeeeee; font-family: 'Courier New',Courier,monospace;">    public function getAllPosts();</div>
<div style="background-color: #eeeeee;"><span style="font-family: Verdana,sans-serif;">}</span></div>
<p><span style="font-family: Verdana,sans-serif;">Jetzt hat jede von beiden zumindest eine fokussierte  Aufgabe: die eine führt alle möglichen Befehle im Zusammenhang mit Posts durch und die andere berichtet uns darüber.</span></p>
<p><span style="font-family: Verdana,sans-serif;">„Aber dann habe ich ja doppelt so viele Klassen wie vorher!“</span></p>
<p><span style="font-family: Verdana,sans-serif;"><br />
Ist das relevant? </span></p>
<p><span style="font-family: Verdana,sans-serif;">Entweder halten wir grundlegende, inzwischen allgemein akzeptierte, Prinzipien guter OOP ein oder behaupten es nur und mauscheln uns weiter durch. Wenn die Anzahl der Klassen das größte Problem ist, dann ist es wohl eher ein Luxusproblem.</span></p>
<p><span style="font-family: Verdana,sans-serif;">Und dabei werden nicht nur die bereits oben erwähnten Prinzipien befolgt, sondern auch noch viele Weitere, wie OCP oder ISP.</span></p>
<p><span style="font-family: Verdana,sans-serif;">[Ha, nun habe ich doch wieder Getter benutzt. Hier sind sie aber harmlos, da sie nur Zustände reporten, nicht aber Vermutungen anstellen, um darauf basierend etwas mit den abgefragten Zuständen zu tun]</span></p>
<h2>Was bringt das alles?</h2>
<p><span style="font-family: Verdana,sans-serif;">Selbst diese simpelste Form von CQRS bringt enorme Vorteile und beseitigt viele Nachteile einer “traditionellen” (meist dreischichtigen) Architektur.</span></p>
<p><span style="font-family: Verdana,sans-serif;">Simples CQRS ähnelt übrigens sehr dem MVC Pattern:</span></p>
<div class="separator" style="clear: both; text-align: center;"><a style="margin-left: 1em; margin-right: 1em;" href="http://4.bp.blogspot.com/-cQfaZiGNgF8/Tpgl7b8sRuI/AAAAAAAAAp4/TXYmtExrMyI/s1600/image001.png"><img src="http://4.bp.blogspot.com/-cQfaZiGNgF8/Tpgl7b8sRuI/AAAAAAAAAp4/TXYmtExrMyI/s320/image001.png" alt="" width="320" height="147" border="0" /></a></div>
<p><span style="font-family: Verdana,sans-serif;">Auch dabei wird eine Trennung von Befehlen (controller) zu Abfragen bzw. Ansichten der Daten (view) bereitgestellt.</span></p>
<p><span style="font-family: Verdana,sans-serif;">CQRS geht noch einen Schritt weiter und führt eine zusätzliche vertikale Trennung ein:</span></p>
<div class="separator" style="clear: both; text-align: center;"><a style="margin-left: 1em; margin-right: 1em;" href="http://4.bp.blogspot.com/-9lCJZG0eMAo/Tpgl_yFJ3aI/AAAAAAAAAqA/d0wJBBjVrDc/s1600/image004.jpg"><img src="http://4.bp.blogspot.com/-9lCJZG0eMAo/Tpgl_yFJ3aI/AAAAAAAAAqA/d0wJBBjVrDc/s320/image004.jpg" alt="" width="320" height="228" border="0" /></a></div>
<p><span style="font-family: Verdana,sans-serif;">Daneben gibt es noch etliche weitere Vorteile:</span></p>
<ul>
<li><span style="font-family: Verdana,sans-serif;">Transaktionen können wesentlich spezieller und isolierter ausgeführt werden</span></li>
<li><span style="font-family: Verdana,sans-serif;">Module, Klassen und Methoden sind wesentlich expliziter, da sie nur auf ganz spezielle Aufgaben fokussiert sind</span></li>
<li><span style="font-family: Verdana,sans-serif;">Die eigentliche Businesslogik wird nicht durch unnötige Abfragen aufgebläht</span></li>
<li><span style="font-family: Verdana,sans-serif;">Man kann sich mehr auf Konsistenz statt auf Skalierung konzentrieren</span></li>
</ul>
<p><span style="font-family: Verdana,sans-serif;">Oder noch spezieller</span></p>
<ul>
<li><span style="font-family: Verdana,sans-serif;">Lesevorgänge erfordern kein kompliziertes und langsames Umwandeln komplexer Objektgraphen zu DTOs</span></li>
<li><span style="font-family: Verdana,sans-serif;">Es können hoch performante Abfragen erzeugt und eigesetzt werden</span></li>
<li><span style="font-family: Verdana,sans-serif;">Skalierung kann bei Abfragen praktisch unbegrenzt erfolgen</span></li>
<li><span style="font-family: Verdana,sans-serif;">Es können spezialisierte Persistenzmethoden für die jeweilige Aufgabe eingesetzt werden (DB, Key-Value-Store, DocDB, 1NF, 3NF)</span></li>
</ul>
<h2>Fazit und Vorschau</h2>
<p><span style="font-family: Verdana,sans-serif;">Natürlich hat CQRS, wie alles, seine Grenzen, Ausnahmen und auch seinen Preis.</span></p>
<p><span style="font-family: Verdana,sans-serif;">Da es aber ein sehr rudimentäres, klares und auf bekannten Prinzipien  basierendes Konzept ist, sind diese fast zu vernachlässigen. </span></p>
<p><span style="font-family: Verdana,sans-serif;">Die Vorteile sind fast unglaublich. </span></p>
<p><span style="font-family: Verdana,sans-serif;">Ich setze es nun bereits länger ein und bis auf die nötige Umstellung auf eine andere Denkweise bei der Entwicklung von Softwareanwendungen, gab es kaum praktische Probleme. Es war auch völlig egal, ob man das Prinzip in kleinen oder sehr komplexen Projekten einsetzt. Bei steigender Komplexität sind die Vorteile auf Dauer noch evidenter.</span></p>
<p><span style="font-family: Verdana,sans-serif;">Ein weiteres Thema, das oft als „Konsequenz“ oder Erweiterung zu CQRS angesehen wird, ist Domain Eventing mit Commands und Events. Oder Event Sourcing, ein Ansatz zur ausschließlichen Speicherung von Zustandsänderungen von Objekten.</span></p>
<p><span style="font-family: Verdana,sans-serif;">Falls genügend Interesse zu diesen weiterführenden Themen oder zu CQRS vorliegt, kann ich gerne die entsprechenden Artikel veröffentlichen.</span></p>
<p><span style="font-family: Verdana,sans-serif; font-size: x-small;">[1] <a href="http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29">http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29</a></span><span style="font-size: x-small;"><br style="font-family: Verdana,sans-serif;" /></span></p>
<p><span style="font-family: Verdana,sans-serif; font-size: x-small;">[2] <a href="http://www.amazon.de/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882">http://www.amazon.de/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882</a></span><span style="font-size: x-small;"><br style="font-family: Verdana,sans-serif;" /></span></p>
<p><span style="font-family: Verdana,sans-serif; font-size: x-small;">[3] <a href="http://pragprog.com/articles/tell-dont-ask">http://pragprog.com/articles/tell-dont-ask</a></span></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phphatesme.com/blog/softwaretechnik/teile-und-herrsche-cqrs-teil-1/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
	</channel>
</rss>

