<?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>Agile at Work &#187; Domain Driven Design</title>
	<atom:link href="http://www.agileatwork.com/tag/domain-driven-design/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.agileatwork.com</link>
	<description>by Michael Valenty</description>
	<lastBuildDate>Sat, 10 Sep 2011 14:35:33 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>A Class Isn&#8217;t Always a Noun</title>
		<link>http://www.agileatwork.com/a-class-isnt-always-a-noun/</link>
		<comments>http://www.agileatwork.com/a-class-isnt-always-a-noun/#comments</comments>
		<pubDate>Fri, 04 Dec 2009 20:45:46 +0000</pubDate>
		<dc:creator>Michael Valenty</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Chain of Responsibility]]></category>
		<category><![CDATA[Domain Driven Design]]></category>

		<guid isPermaLink="false">http://www.agileatwork.com/?p=230</guid>
		<description><![CDATA[There is a convention programmers go by that says object names should be nouns and methods names should start with a verb. That’s crap and I’ll tell you why. First off, it’s an old rule kind of like Hungarian notation. Okay that was low. To be fair, I would probably recommend this rule to a [...]]]></description>
			<content:encoded><![CDATA[<p>There is a convention programmers go by that says object names should be nouns and methods names should start with a verb. That’s crap and I’ll tell you why. First off, it’s an old rule kind of like Hungarian notation. Okay that was low. To be fair, I would probably recommend this rule to a college student.</p>
<p>However, if you’re doing this as your full-time job and you’re neck deep in a complex business domain, then you are seriously selling yourself short. When working in a team environment you’ve got to use every means possible to communicate what you were thinking and what hard-earned knowledge you gained along the way. Some poor sucker is going to open your project at some point and your code should be screaming important concepts right from the class list.</p>
<p><img title="yext" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="595" alt="yext" src="http://www.agileatwork.com/wp-content/uploads/2009/12/yext1.png" width="277" border="0" /> </p>
<p>I don’t expect you to understand how the app works, but you should at least get a feel right away for the things that are important. Knowing it’s a console app, you could find the entry point and quickly navigate to the meat and potatoes of the application.</p>
<pre class="prettyprint"><code>public class SyncListingJob : MarshalByRefObject, IJob
{
    private IServiceProvider locator;
    private YextListing listing;

    public SyncListingJob(IServiceProvider locator)
    {
        this.locator = locator;
    }

    public void Init(YextListing listing)
    {
        this.listing = listing;
    }

    [UnitOfWork]
    public void Execute()
    {
        GuardAgainstNotInitialized();
        SyncListing();
    }

    private void SyncListing()
    {
        new LocatorChain&lt;Yextlisting&gt;(locator)
            .AddNew&lt;RevertDiscontinuedListing&gt;()
            .AddNew&lt;RefreshLinkedBusiness&gt;()
            .AddNew&lt;CreateLinkToExistingBusiness&gt;()
            .AddNew&lt;CreateNewBusinessAndLink&gt;()
            .Process(listing);
    }

    private void GuardAgainstNotInitialized()
    {
        if (listing == null) throw new Exception("Job not initialized!");
    }
}</code></pre>
<p><em><font size="2">* The <font face="Courier New">LocatorChain&lt;T&gt;</font> is an implementation of the chain of responsibility pattern.</font></em></p>
<p>I do everything I can to push out all the noise and bring the behavior to the surface.&#160; Sometimes the right way to name a class is after a feature or behavior. I want my code to read like a DSL and making everything a noun just doesn’t cut it. The drivers for me are context and readability.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.agileatwork.com/a-class-isnt-always-a-noun/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Domain Driven Design in the Small</title>
		<link>http://www.agileatwork.com/domain-driven-design-in-the-small/</link>
		<comments>http://www.agileatwork.com/domain-driven-design-in-the-small/#comments</comments>
		<pubDate>Sun, 09 Aug 2009 05:20:41 +0000</pubDate>
		<dc:creator>Michael Valenty</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Decorator Pattern]]></category>
		<category><![CDATA[Domain Driven Design]]></category>
		<category><![CDATA[Refactoring]]></category>

		<guid isPermaLink="false">http://www.agileatwork.com/?p=180</guid>
		<description><![CDATA[A few months ago we built a Magento extension to send orders to a product supplier via soap for payment and fulfillment along with affiliate tracking. As part of the process, a contact record was created in the affiliate&#8217;s CRM account.
&#160; 
Recently, the stake holders came up with a twist that went something like this: [...]]]></description>
			<content:encoded><![CDATA[<p>A few months ago we built a <a href="http://www.magentocommerce.com/">Magento</a> extension to send orders to a product supplier via soap for payment and fulfillment along with affiliate tracking. As part of the process, a contact record was created in the affiliate&#8217;s CRM account.</p>
<p>&#160;<img title="SubmitYourIdea" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="240" alt="SubmitYourIdea" src="http://www.agileatwork.com/wp-content/uploads/2009/08/SubmitYourIdea1.jpg" width="240" border="0" /> </p>
<p>Recently, the stake holders came up with a twist that went something like this: If the order contains a gift card, add the contact to a specific folder in the CRM application. No big deal, we had a nicely abstracted <font face="Courier New" size="2">OrderGateway</font> interface and I was already envisioning a quick addition to the existing decorator chain.</p>
<pre class="csharpcode"><span class="kwrd">class</span> OrderWithGiftCardGateway <span class="kwrd">extends</span> OrderGatewayDecorator
{
    ...

    <span class="kwrd">public function</span> createOrder(CreateOrderRequest $order)
    {
        <span class="kwrd">if</span> ($this-&gt;containsGiftCard($order))
        {
            $this-&gt;addContactToFolder($order);
        }

        <span class="kwrd">return parent</span>::createOrder($order);
    }
}</pre>
<p>I had a few minutiae questions like what happens with duplicates, etc. It took me nearly an hour to track down the right person and get real answers. During the conversation, a subtle comment was made that I almost missed.</p>
<p><em>Stake holder</em>: We should check with the product supplier to make sure the gift card sku I made up isn’t for a real product.</p>
<p><em>Me</em>: Say what?</p>
<p><em>Stake holder</em>: The gift card is not fulfilled by the product supplier, it’s fulfilled by the affiliate.</p>
<p><em>Me</em>: %$@!&amp;, I’m glad we had this conversation.</p>
<p>We talked about what it meant for the the affiliate to fulfill the product and basically the folder stuff was okay, but I recommended we remove the fake sku from the order before sending it through.</p>
<pre class="csharpcode"><span class="kwrd">public function</span> createOrder(CreateOrderRequest $order)
{
    <span class="kwrd">if</span> ($this-&gt;containsGiftCard($order))
    {
        $this-&gt;addContactToFolder($order);
        $this-&gt;removeGiftCardFromOrder($order);
    }

    <span class="kwrd">return parent</span>::createOrder($order);
}</pre>
<p>I didn’t have a buddy to pair with so I just grabbed Keith for a minute at the end of the day to walk through things. I recapped the stake holder discussion and we looked through the code. He pointed out I was missing the concept of fulfillment and that was hard earned knowledge that would be lost!</p>
<pre class="csharpcode"><span class="kwrd">public function</span> createOrder(CreateOrderRequest $order)
{
    <span class="kwrd">if</span> ($this-&gt;containsGiftCard($order))
    {
        $this-&gt;sendToAffiliateForFulfillment($order);
        $this-&gt;removeGiftCardFromOrder($order);
    }

    <span class="kwrd">return parent</span>::createOrder($order);
}</pre>
<blockquote>
<p>That was huge. – Paris Hilton</p>
</blockquote>
<p><object width="560" height="340"><param name="movie" value="http://www.youtube.com/v/3nGAk_mo6Rw&amp;hl=en&amp;fs=1&amp;"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/3nGAk_mo6Rw&amp;hl=en&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="560" height="340"></embed></object></p>
<p>Why was that huge? Because it changed the conversation. Right away we thought of important requirements like this should be in a transaction with the order and the template email the affiliate gets should include the customer’s address, etc.</p>
<p>It tells an important story for the next guy looking at the code and it changes the role of the programmer from code monkey to business partner. Maybe you think I’m crazy, but this stuff matters to me.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.agileatwork.com/domain-driven-design-in-the-small/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>This Could Have Been a Stored Procedure</title>
		<link>http://www.agileatwork.com/this-could-have-been-a-stored-procedure/</link>
		<comments>http://www.agileatwork.com/this-could-have-been-a-stored-procedure/#comments</comments>
		<pubDate>Fri, 12 Jun 2009 05:44:27 +0000</pubDate>
		<dc:creator>Michael Valenty</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Domain Driven Design]]></category>
		<category><![CDATA[Specification Pattern]]></category>

		<guid isPermaLink="false">http://www.agileatwork.com/this-application-could-have-been-a-stored-procedure/</guid>
		<description><![CDATA[ I read Domain Driven Design about a year and a half ago and when I got to the part about the specification pattern, I thought it was really cool and I couldn’t wait to try it out. Maybe the pattern gods were listening or maybe I was unknowingly using the secret. Either way, it [...]]]></description>
			<content:encoded><![CDATA[<p><img title="domain-driven-design-book-cover" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; margin: 0px 0px 0px 10px; border-right-width: 0px" height="196" alt="domain-driven-design-book-cover" src="http://www.agileatwork.com/wp-content/uploads/2009/06/domaindrivendesignbookcover.jpg" width="150" align="right" border="0" /> I read <a href="http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215">Domain Driven Design</a> about a year and a half ago and when I got to the part about the specification pattern, I thought it was really cool and I couldn’t wait to try it out. Maybe the pattern gods were listening or maybe I was unknowingly using <a href="http://www.thesecret.tv/">the secret</a>. Either way, it was pretty much the next morning that I went to work and had the perfect project dropped in my lap.</p>
<p>Our phone system routes live phone calls to doctor’s offices and the project was to bill the doctor if the call met the following criteria:</p>
<p>1) Caller is a new patient (pressed “1” instead of “2” in response to a voice prompt)</p>
<p>2) A live call was connected for more than 20 seconds or message longer than 10 seconds was recorded.</p>
<p>3) The doctor has not already been billed for this caller.</p>
<p>4) The call is not from a known list of test numbers.</p>
<p>The application subscribes to an event stream of new call records and runs them through this composite specification to determine if the call is billable.</p>
<pre class="prettyprint">
<code>public bool IsBillable(CallRecord call)
{
    ISpecification&lt;CallRecord&gt; billableCallSpecification = new NewPatient()
        .And(new MinLengthLiveCall(liveCallSeconds).Or(new MinLengthMessage(messageSeconds))
        .And(new RepeatCall(referralFinder).Not())
        .And(new TestCall(testNumbers).Not()));

    return billableCallSpecification.IsSatisfiedBy(call);
}</code>
</pre>
<p>I have to admit that I was already an hour into Query Analyzer blasting through another monster stored procedure when I caught myself. Not just the criteria logic either, I mean bypassing all the event stream hooha and basically just writing the whole enchilada as one gnarly stored procedure that would run as a job. That was a close one!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.agileatwork.com/this-could-have-been-a-stored-procedure/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Unit of Work with Unity and ASP.NET MVC</title>
		<link>http://www.agileatwork.com/unit-of-work-with-unity-and-aspnet-mvc/</link>
		<comments>http://www.agileatwork.com/unit-of-work-with-unity-and-aspnet-mvc/#comments</comments>
		<pubDate>Sun, 10 May 2009 07:58:14 +0000</pubDate>
		<dc:creator>Michael Valenty</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[AOP]]></category>
		<category><![CDATA[ASP.NET MVC]]></category>
		<category><![CDATA[Domain Driven Design]]></category>
		<category><![CDATA[NHibernate]]></category>
		<category><![CDATA[Unity]]></category>

		<guid isPermaLink="false">http://blog.agileatwork.com/?p=9</guid>
		<description><![CDATA[I was recently asked how I get the context of&#160; “this” in the UoW relating to the current page request.
 
Before I get into the guts, I would like to provide a little context. My application has 20+ databases scattered across 4 machines.

IRepository&#60;Customer&#62; customerRepository; // customer database on server 1
IRepository&#60;Package&#62;  packageRepository; // customer database [...]]]></description>
			<content:encoded><![CDATA[<p>I was recently asked how I get the context of&#160; “this” in the UoW relating to the current page request.</p>
<p><a href="http://blog.agileatwork.com/wp-content/uploads/2009/05/howididit.jpg"><img title="howididit" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="179" alt="howididit" src="http://blog.agileatwork.com/wp-content/uploads/2009/05/howididit-thumb.jpg" width="240" border="0" /></a> </p>
<p>Before I get into the guts, I would like to provide a little context. My application has 20+ databases scattered across 4 machines.</p>
<p><!-- code formatted by http://manoli.net/csharpformat/ --></p>
<pre class="csharpcode">IRepository&lt;Customer&gt; customerRepository; <span class="rem">// customer database on server 1</span>
IRepository&lt;Package&gt;  packageRepository; <span class="rem">// customer database on server 1</span>
IRepository&lt;Contact&gt;  contactRepository; <span class="rem">// contact database on server 2</span></pre>
<div>So, I might ask for a Customer object and a Package object and I want to get the same ISession for both and if I ask for the same Customer twice, I want to get the one from the 1st level cache (I’m using NHibernate). If I ask for a Contact object, I will get a different ISession. All opened sessions are managed by my UoW. So, when the page request is complete, I call UoW.Commit and all sessions are committed.</div>
<p>The “magic” if you will, happens in the global.asax. I was nosing around in Rhino.Commons for inspiration and adapted a technique I saw there. This is how it looks:</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> GlobalApplication : HttpApplication
{
    <span class="kwrd">private</span> <span class="kwrd">static</span> IUnityContainer container;

    <span class="kwrd">public</span> GlobalApplication()
    {
        BeginRequest += <span class="kwrd">new</span> EventHandler(GlobalApplication_BeginRequest);
        EndRequest += <span class="kwrd">new</span> EventHandler(GlobalApplication_EndRequest);
    }

    <span class="kwrd">protected</span> <span class="kwrd">void</span> Application_Start(<span class="kwrd">object</span> sender, EventArgs e)
    {
        RegisterRoutes(RouteTable.Routes);

        container = <span class="kwrd">new</span> UnityContainer();
        container.AddNewExtension&lt;PolicyInjectorContainerExtension&gt;();
        container.AddNewExtension&lt;HttpRequestLifetimeCoreContainerExtension&gt;();
        container.AddNewExtension&lt;WebMvcContainerExtension&gt;();

        ControllerBuilder.Current.SetControllerFactory(<span class="kwrd">new</span> UnityControllerFactory(container));
    }

    <span class="kwrd">void</span> GlobalApplication_BeginRequest(<span class="kwrd">object</span> sender, EventArgs e)
    {
        var unitOfWork = container.Resolve&lt;IUnitOfWork&gt;();
        unitOfWork.Start();
    }

    <span class="kwrd">void</span> GlobalApplication_EndRequest(<span class="kwrd">object</span> sender, EventArgs e)
    {
        var unitOfWork = container.Resolve&lt;IUnitOfWork&gt;();
        unitOfWork.Commit();
    }
}</pre>
<p>I register the UoW with an HttpRequestLifetimeManager so I get a new instance for each request.</p>
<pre class="csharpcode">Container.RegisterType&lt;IUnitOfWork&lt;ISession&gt;,
	NHibernateUnitOfWork&gt;(<span class="kwrd">new</span> HttpRequestLifetimeManager());</pre>
<div>My NHibernateRepository gets injected with the UoW for the current HttpRequest and when the request is complete, the global.asax commits the whole thing.</div>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> NHibernateRepository&lt;T&gt; : IRepository&lt;T&gt;
{
    <span class="kwrd">protected</span> ISession session;

    <span class="kwrd">public</span> NHibernateRepository(IUnitOfWork&lt;ISession&gt; unitOfWork)
    {
        session = unitOfWork.GetContextFor&lt;T&gt;();
    }

    ...

    <span class="kwrd">public</span> <span class="kwrd">virtual</span> <span class="kwrd">void</span> Save(T obj)
    {
        session.Save(obj);
    }
}</pre>
<p>Now, this is all the context of an ASP.NET MVC Controller, but I have a similar issue for other (non-web) services. In that context I am using AOP and decorating a particular method with [UnitOfWork], which looks like:</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> UnitOfWorkCallHander : ICallHandler
{
    <span class="kwrd">private</span> IUnitOfWork&lt;ISession&gt; unitOfWork;

    <span class="kwrd">public</span> UnitOfWorkCallHander(IUnitOfWork&lt;ISession&gt; unitOfWork)
    {
        <span class="kwrd">this</span>.unitOfWork = unitOfWork;
    }

    <span class="kwrd">public</span> <span class="kwrd">int</span> Order { get; set; }

    <span class="kwrd">public</span> IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        unitOfWork.Start();

        <span class="kwrd">try</span>
        {
            <span class="kwrd">return</span> getNext()(input, getNext);
        }
        <span class="kwrd">finally</span>
        {
            unitOfWork.Commit();
        }
    }
}</pre>
<p>In that context I use a PerThreadLifetimeManager for the NHibernateUnitOfWork, and code ends up looking like:</p>
<pre class="csharpcode">[UnitOfWork]
<span class="kwrd">public</span> <span class="kwrd">void</span> Process(Job job)
{
    ...
}</pre>
<p>You know, there is really no reason why you couldn’t do the same thing in the MVC context. You could basically ditch the global.asax event hooha and just annotate the Controller task:</p>
<pre class="csharpcode">[UnitOfWork]
<span class="kwrd">public</span> ActionResult ControllerTaskThatRequiresUoW()
{
    ...
}</pre>
<p>It’s more explicit than using the global.asax technique and it would allow you to specify different UoW behavior on each controller task:</p>
<pre class="csharpcode">[UnitOfWork(IsolationLevel.ReadCommitted]
<span class="kwrd">public</span> ActionResult SomeTaskThatShouldNotReadUncommitedData()
{
}

[UnitOfWork(IsolationLevel.ReadUncommitted)]
<span class="kwrd">public</span> ActionResult AnotherTaskWithDifferentRequirements()
{
}</pre>
<p>I’d like to try this out next time I get back into ASP.NET MVC, the global.asax event technique felt a little too magical and I don’t think Uncle Bob would approve.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.agileatwork.com/unit-of-work-with-unity-and-aspnet-mvc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>An Order Processing Pipeline in ASP.NET MVC</title>
		<link>http://www.agileatwork.com/an-order-processing-pipeline-in-aspnet-mvc/</link>
		<comments>http://www.agileatwork.com/an-order-processing-pipeline-in-aspnet-mvc/#comments</comments>
		<pubDate>Sun, 03 May 2009 07:57:28 +0000</pubDate>
		<dc:creator>Michael Valenty</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[ASP.NET MVC]]></category>
		<category><![CDATA[Domain Driven Design]]></category>
		<category><![CDATA[Fluent Interface]]></category>

		<guid isPermaLink="false">http://blog.agileatwork.com/?p=8</guid>
		<description><![CDATA[Lately, I can’t seem to shake the pipeline pattern. It keeps popping up in all my applications. It’s like when I think about buying a new car and then I start seeing them everywhere on road and think – have there always been that many out there?
So, here it is in action. Below is a [...]]]></description>
			<content:encoded><![CDATA[<p>Lately, I can’t seem to shake the pipeline pattern. It keeps popping up in all my applications. It’s like when I think about buying a new car and then I start seeing them everywhere on road and think – have there always been that many out there?</p>
<p>So, here it is in action. Below is a controller from an ASP.NET MVC application. The method accepts an order in the form of xml for provisioning products in our system.</p>
<pre class="prettyprint">
<code>public ActionResult EnqueueOrders(string orderXml)
{
    var context = new OrderContext(orderXml);

    var pipeline = new FilterPipeline&lt;OrderContext&gt;()
        .Add(new RewriteLegacyUsernameFeature(productFinder))
        .Add(new ValidateOrderXml())
        .Add(new ValidateReferenceCode(customerFinder))
        .Add(new IgnoreOnException(new ValidateRemoteAccountUsernames(packageRepository)))
        .Add(new IgnoreOnException(new ValidateRemoteAccountUniqueEmail(packageRepository)))
        .Add(new EnqueueOrders(customerFacade)).When(new OrderHasNoErrors())
        .Execute(context);

    var xml = BuildResponseFromOrderContext(context);

    return new XmlResult(xml);
}</code>
</pre>
<p>Most of it is just validation logic, but there are a few meatier pieces. Take a look a the first filter – RewriteLegacyUsernameFeature. If you’ve ever published an API that accepts xml, then you’ve probably wanted to change your schema 5 minutes later. The pipeline is great way to deal with transforming legacy xml on the way in.</p>
<p>Next is the implementation of the FilterPipeline which is essentially a chain of responsibility with a few convenience features.</p>
<pre class="prettyprint">
<code>public class FilterPipeline&lt;T&gt; : IFilter&lt;T&gt;
{
    private IFilterLink&lt;T&gt; head;

    public void Execute(T input)
    {
        head.Execute(input);
    }

    public IFilterConfiguration&lt;T&gt; Add(IFilterLink&lt;T&gt; link)
    {
        var specificationLink = new SpecificationFilterLink&lt;T&gt;(link);

        AppendToChain(specificationLink);

        return specificationLink;
    }

    public IFilterConfiguration&lt;T&gt; Add(IFilter&lt;T&gt; filter)
    {
        return Add(new FilterLinkAdapter&lt;T&gt;(filter));
    }

    public void AppendToChain(IFilterLink&lt;T&gt; link)
    {
        if (head == null)
        {
            head = link;
            return;
        }

        var successor = head;

        while (successor.Successor != null)
        {
            successor = successor.Successor;
        }

        successor.Successor = link;
    }
}</code>
</pre>
<p>You might be scratching your head and wondering what this business is with both IFilter&lt;T&gt; and IFilterLink&lt;T&gt;. IFilter&lt;T&gt; is just a simpler version of IFilterLink&lt;T&gt; that doesn’t require the implementer to deal with calling the next link in the chain. The subject will always pass through, no short-circuiting, hence the pipeline.</p>
<p>My favorite part  is the SpecificationFilterLink&lt;T&gt; which is a decorator that uses a Specification to decide if the filter should be invoked. So you can do little readable snippets like:</p>
<pre class="prettyprint">
<code>pipeline.Add(new EnqueueOrders(customerFacade)).When(new OrderHasNoErrors());</code>
</pre>
<p>Maybe this post will get it out of my system and I can move on to other solutions. It’s just so handy…</p>
]]></content:encoded>
			<wfw:commentRss>http://www.agileatwork.com/an-order-processing-pipeline-in-aspnet-mvc/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

