<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://www.aspnetzone.de/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Search results matching tags 'Refactoring' and 'Entwicklung'</title><link>http://www.aspnetzone.de/search/SearchResults.aspx?o=DateDescending&amp;tag=Refactoring,Entwicklung&amp;orTags=0</link><description>Search results matching tags 'Refactoring' and 'Entwicklung'</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61120.2)</generator><item><title>Event Based Components</title><link>http://www.aspnetzone.de/blogs/juergengutsch/archive/2010/08/18/event-based-components.aspx</link><pubDate>Wed, 18 Aug 2010 20:22:00 GMT</pubDate><guid isPermaLink="false">ce930855-ae9b-4fa4-8077-06a76071cc6a:218522</guid><dc:creator>Jürgen Gutsch</dc:creator><description>&lt;P&gt;In den vergangen Monaten habe ich einiges theoretisches über Event Based Components (kurz EBCs) gelesen. Das meiste von Ralf Westphal, in &lt;A href="http://ralfw.blogspot.com/search/label/Event-based%20Components"&gt;seinem Blog&lt;/A&gt; oder aus seiner Feder in der &lt;A href="http://www.dotnetpro.de/"&gt;dotnetpro&lt;/A&gt;. Auch Golo Roden schrieb in seinem Blog &lt;A href="http://www.des-eisbaeren-blog.de/?tag=/event-based+components"&gt;über das Thema&lt;/A&gt;. &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Verwirrung&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Angespornt durch die Beiträge habe ich in den letzten Wochen selber versucht EBCs zu schreiben und zu entwickeln und bin zuerst gescheitert. Sobald ich die ersten Komponenten geschrieben und “zusammengesteckt” hatte, verlor ich relativ schnell den Überblick über die Komponenten und deren Verbindungen. &lt;/P&gt;
&lt;P&gt;Woran lag das?&lt;/P&gt;
&lt;P&gt;Golo wies mich auf die fehlerhafte Benennung der Events in Ralf Westphals Beispielen hin, die entgegen dem .NET Framework mit dem Präfix “On” begannen.&lt;/P&gt;
&lt;P&gt;Ich habe also von vorne begonnen und die Events wie im .NET-Framework üblich benannt. &lt;/P&gt;
&lt;P&gt;Beispiel:&lt;/P&gt;
&lt;P&gt;public event Action&amp;lt;Customer&amp;gt; &lt;STRONG&gt;EntitySaving&lt;/STRONG&gt; (wird vor dem Speichern ausgelöst) &lt;BR&gt;public event Action&amp;lt;Customer&amp;gt; &lt;STRONG&gt;EntitySaved&lt;/STRONG&gt; (wird nach den Speichern ausgelöst)&lt;/P&gt;
&lt;P&gt;Und siehe da: die Verwirrung war beseitigt :-)&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Vorteile&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Die Vorteile der EBCs sind klar und wurden in den oben genannten Beiträgen auch oft genug angesprochen. Die zwei größten Vorteile sind – aus meiner Sicht – zum einen die isolierte Testbarkeit der Komponenten und die flexible Möglichkeit die Komponenten zusammenzuführen.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Refactoring&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;In den letzten Wochen habe ich also meinen angehenden Lizenz-Manager, einem großen Refactoring unterzogen und auf EBCs umgebaut. Ich habe allerdings vorerst&amp;nbsp;meine Service-Klassen nicht komplett auseinandergerissen. Also nicht fürs Speichern, Löschen und Lesen separate Komponenten gebaut (das wäre dann der nächste schritt), sondern es bei jeweils einer Komponente mit standardmäßig drei Input- und drei Output-Pins belassen. Ich habe lediglich die generische Validierung komplett entkoppelt und dafür eine weitere Komponente angelegt, die vor jedem Speichern “eingesteckt” werden kann.&lt;/P&gt;
&lt;P&gt;Die vorhandenen Unit-Tests musste ich leicht anpassen. Die Tests für die Servies, die hauptsächlich die Validierung getestet haben&amp;nbsp;konnte ich entfernen und in die Test für die Validator-Komponente aufnehmen. Die Tests sind alle kleiner geworden, da Abhängigkeiten gar nicht mehr berücksichtigt werden müssen, wenn sie nicht zusammengesteckt worden sind. Beispiel: Die Service-Methode zum Speichern, muss keine Validierung mehr testen. Und die Tests der Validierung ist unabhängig vom Speichervorgang.&lt;/P&gt;
&lt;P&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt; &lt;br /&gt;&lt;br /&gt;[TestFixture] &lt;br /&gt;[Category(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"GO.LicenceManager.Services.ModelValidator"&lt;/span&gt;)] &lt;br /&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;class&lt;/span&gt; Wenn_ein_Kunde_validiert_wird &lt;br /&gt;{ &lt;br /&gt;    [Test] &lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;void&lt;/span&gt; darf_der_Vorname_nicht_fehlen() &lt;br /&gt;    { &lt;br /&gt;        Customer customer &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; Customer &lt;br /&gt;                                { &lt;br /&gt;                                    [….] &lt;br /&gt;                                }; &lt;br /&gt;&lt;br /&gt;        IModelValidator&amp;lt;Customer&amp;gt; modelValidator &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; ModelValidator&amp;lt;Customer&amp;gt;(); &lt;br /&gt;        Assert.Throws&amp;lt;PropertyNotSetException&amp;lt;Customer&amp;gt;&amp;gt;( &lt;br /&gt;            () =&amp;gt; modelValidator.Validate(customer), &lt;br /&gt;            &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"'Name' must not be null or empty"&lt;/span&gt;); &lt;br /&gt;    } &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;class&lt;/span&gt; ModelValidator&amp;lt;T&amp;gt; : IModelValidator&amp;lt;T&amp;gt; where T : IEntity &lt;br /&gt;{ &lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;void&lt;/span&gt; Validate(T model) &lt;br /&gt;    { &lt;br /&gt;        Type type &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;typeof&lt;/span&gt;(T);  &lt;br /&gt;        IEnumerable&amp;lt;PropertyInfo&amp;gt; propertyInfos &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; type &lt;br /&gt;                .GetProperties(BindingFlags.Public &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;|&lt;/span&gt; BindingFlags.Instance);  &lt;br /&gt;        [….] &lt;br /&gt;    } &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;class&lt;/span&gt; CustomerService : ICustomerService &lt;br /&gt;{ &lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;private&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;readonly&lt;/span&gt; ICustomerRepository _customerRepository;  &lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; CustomerService(ICustomerRepository customerRepository) &lt;br /&gt;    { &lt;br /&gt;        _customerRepository &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; customerRepository; &lt;br /&gt;    }  &lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;void&lt;/span&gt; Save(Customer customer) &lt;br /&gt;    { &lt;br /&gt;       OnEntitySaving(customer);  &lt;br /&gt;       &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;if&lt;/span&gt;(customer.Id==Guid.Empty) &lt;br /&gt;       { &lt;br /&gt;           customer.Id &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; Guid.NewGuid(); &lt;br /&gt;       }  &lt;br /&gt;        _customerRepository.Save(customer); &lt;br /&gt;    }  &lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;event&lt;/span&gt; Action&amp;lt;Customer&amp;gt; EntitySaving; &lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;void&lt;/span&gt; OnEntitySaving(Customer entity) &lt;br /&gt;    { &lt;br /&gt;        var entitySaving &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; EntitySaving; &lt;br /&gt;        &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;if&lt;/span&gt; (entitySaving !&lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;null&lt;/span&gt;) &lt;br /&gt;        { &lt;br /&gt;            entitySaving(entity); &lt;br /&gt;        } &lt;br /&gt;    } &lt;br /&gt;&lt;br /&gt;    [….] &lt;br /&gt;}&lt;/span&gt;&lt;/code&gt; &lt;/P&gt;
&lt;P&gt;Zusammenstecken:&lt;/P&gt;
&lt;P&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;Customer customer &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; Customer &lt;br /&gt;                                    { &lt;br /&gt;                                        [….] &lt;br /&gt;                                    };  &lt;br /&gt;IModelValidator&amp;lt;Customer&amp;gt; validator &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; ModelValidator&amp;lt;Customer&amp;gt;(); &lt;br /&gt;ICustomerService customerService &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; CustomerService(customerRepository); &lt;br /&gt;customerService.EntitySaving += validator.Validate; &lt;span style="color: Green;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;// &amp;lt;== zusammenstecken &lt;/span&gt;&lt;br /&gt;customerService.Save(customer);&lt;/span&gt;&lt;/code&gt;&lt;/P&gt;
&lt;P&gt;Die Tests hätten wir damit vereinfacht, die Komponenten müssen sich nicht mehr kennen und sind komplett entkoppelt. Die Komponenten müssen aber irgendwie und irgendwo zusammengeführt werden, um zu funktionieren. &lt;/P&gt;
&lt;P&gt;Die Komponenten müssen “zusammensteckt” werden. &lt;/P&gt;
&lt;P&gt;Dabei ist entweder Handarbeit und eine gute Dokumentation gefordert, oder man versucht das zu automatisieren. Ralf Westphal hat dafür einen &lt;A href="http://ebcbinder.codeplex.com/"&gt;EBC-Binder&lt;/A&gt; geschrieben, der allerdings nur funktioniert, wenn gewisse Konventionen eingehalten werden: Unter anderem müssen die Events eben mit dem Präfix “On” beginnen…&lt;/P&gt;
&lt;P&gt;Ich werde hierfür wahrscheinlich eine Art Binding-Datei anlegen die im XML-Format nicht nur das Binding selber regelt, sondern dieses&amp;nbsp;auch dokumentiert. Mal sehen, was sich so machen lässt :-)&lt;/P&gt;
&lt;P&gt;Vorerst werde ich im Lizenz-Manager allerdings noch die Repositories und die verschiedenen Views implementieren müssen. Bis zur &lt;A href="http://www.seesharpparty.de/"&gt;See# Party&lt;/A&gt; werde ich wohl aber nicht mehr dazu kommen…&lt;/P&gt;
&lt;DIV style="TEXT-ALIGN:left;PADDING-BOTTOM:4px;MARGIN:0px;PADDING-LEFT:4px;PADDING-RIGHT:4px;PADDING-TOP:4px;" class=wlWriterHeaderFooter&gt;&lt;A href="http://dotnet-kicks.de/kick/?url=http://www.aspnetzone.de/blogs/juergengutsch/archive/2010/08/18/event-based-components.aspx"&gt;&lt;IMG border=0 alt="DotNetKicks-DE Image" src="http://dotnet-kicks.de/Services/Images/KickItImageGenerator.ashx?url=http://www.aspnetzone.de/blogs/juergengutsch/archive/2010/08/18/event-based-components.aspx&amp;amp;bgcolor=3169AD&amp;amp;fgcolor=FFFFFF&amp;amp;border=000000&amp;amp;cbgcolor=D4E1ED&amp;amp;cfgcolor=000000"&gt;&lt;/A&gt;&lt;/DIV&gt;</description></item></channel></rss>