Monday, December 29, 2008
Ayende - Open Closed Principle
Read this 10 page epic blog post:
http://ayende.com/Blog/archive/2008/12/30/discussion-oo-101-solutions-and-the-open-close-principle-at.aspx
Monday, December 22, 2008
Unity - OMG... it just works!
The other dev's and I have come up with a nice MVP/Presenter First framework with a repository pattern for the DAL and are currently using service with DTO's in the middle. All good so far.
Then I learnt we were using EF... ahhh ok...
Well, luckily the guys here have enough experience with it and have manged to put together a nice usable repository implementation using EF that is agnostic enough that any non EF should be able to come along and use it.. happy days.
Next step for me was to introduce IoC and AOP to the stack. These are somewhat new concepts here so I wasn't to sure how they would go down. I have a wrapper Container that I use to abstract away all the container specific gunk and jargon that you can get with some containers. As we were very much in the EF/PnP/EntLib park here I thought I had better at least look into Unity to see if it is a viable option.
My last dealing with M$ IoC was ObjectBuilder in CAB... what a f&?king pig.
Needless to say I was not expecting anything special. I was however pleasantly surprised. Unity is supper usable and slotted in perfectly to my abstracted container adapter. If you are in a M$ centric software house I HIGHLY recommend trying out Unity. Far to many M$ devs don't use IoC, often because there is a 3rd party framework that is not from M$ that is now required... the amount of time i have been told i can not use OSS on a project... grrr...well now there is no excuse. To see how painless it is checkout PnP guru David Hayden screencast and posts. Actually if you use any on the EntLib or PnP stuff you should be subscribed to DH blog; he is the ninja in this field and pragmatic enough to use (and have extensive knowledge of) other 3rd party frameworks such as the wonderful Castle stack.
Next step is to investigate the PnP AOP implementation namely the Policy Injection Application Block... will keep y'all posted
DDD : Value Types
*A follow on from : http://rhysc.blogspot.com/2008/09/when-to-use-enums-vs-objects.html
This is a brief demo of mapping constructing and using Value type in the domain. To stick with the cliches we will use orders and order status. To give some structure we will lay out some ground business rules
- When an order is created it is of the status In Process
- it is then Approved
- then Shipped
- Cancelled backordered need to be in the mix too
Ok, not the most robust order system, but that's not the point.
Lets first look at how the domain logic could be handled with using an Enum.... bring on the switch statement!!!!
Ok so let see if we can edit an order when the status is an enum:
public class Order{
//...
public bool CanEdit()
{
switch(this.OrderStatus)
case: OrderStatus.InProcess
return true;
case: OrderStatus.Approved
return false;
case: OrderStatus.Shipped
return false;
//etc etc
}
//...
}
Ok that is not exactly scalable... the more statuses we get the more case statements we have to add. If we add a status we also have to find every place that there is a switch statement using this enum and add the new status is not a case. think about his for a second... really think about it, how many enum do you have that have functionality tied to them. Right.
No lets look at the same code but we are using "real" objects; Exit the switch and enter the strategy pattern:
public class Order
{//...
public bool CanEdit()
{
return this.OrderStatus.CanEditOrder();
}//...
}
Now obviously there need to be some know-how on this non-enum enum. let have a look at how I have done this is the past.
/// <summary>
/// Sales Order Status Enumeration
/// </summary>
public abstract class SalesOrderStatus
{
#region Statuses
/// <summary>
/// InProcess
/// </summary>
public static SalesOrderStatus InProcess = new InProcessSalesOrderStatus();
/// <summary>s
/// Approved
/// </summary>
public static SalesOrderStatus Approved = new ApprovedSalesOrderStatus();
/// <summary>
/// Backordered
/// </summary>
public static SalesOrderStatus Backordered = new BackorderedSalesOrderStatus();
/// <summary>
/// Rejected
/// </summary>
public static SalesOrderStatus Rejected = new RejectedSalesOrderStatus();
/// <summary>
/// Shipped
/// </summary>
public static SalesOrderStatus Shipped = new ShippedSalesOrderStatus();
/// <summary>
/// Cancelled
/// </summary>
public static SalesOrderStatus Cancelled = new CancelledSalesOrderStatus();
#endregion
#region Protected members
/// <summary>
/// The status description
/// </summary>
protected string description;
#endregion
#region Properties
/// <summary>
/// Gets the description of the order status
/// </summary>
/// <value>The description.</value>
protected virtual string Description
{
get { return description; }
}
#endregion
#region Public Methods
/// <summary>
/// Determines whether this instance allows the diting of it parent order.
/// </summary>
/// <returns>
/// <c>true</c> if this instances parent order can be edited; otherwise, <c>false</c>.
/// </returns>
public abstract bool CanEditOrder();
#endregion
#region Child Statuses
private class InProcessSalesOrderStatus : SalesOrderStatus
{
public InProcessSalesOrderStatus()
{
description = "In Process";
}
public override bool CanEditOrder()
{
return true;
}
}
private class ApprovedSalesOrderStatus : SalesOrderStatus
{
public ApprovedSalesOrderStatus()
{
description = "Approved";
}
public override bool CanEditOrder()
{
return false;
}
}
private class BackorderedSalesOrderStatus : SalesOrderStatus
{
public BackorderedSalesOrderStatus()
{
description = "Back ordered";
}
public override bool CanEditOrder()
{
return true;
}
}
private class RejectedSalesOrderStatus : SalesOrderStatus
{
public RejectedSalesOrderStatus()
{
description = "Rejected";
}
public override bool CanEditOrder()
{
return false;
}
}
private class ShippedSalesOrderStatus : SalesOrderStatus
{
public ShippedSalesOrderStatus()
{
description = "Shipped";
}
public override bool CanEditOrder()
{
return false;
}
}
private class CancelledSalesOrderStatus : SalesOrderStatus
{
public CancelledSalesOrderStatus()
{
description = "Cancelled";
}
public override bool CanEditOrder()
{
return false;
}
}
#endregion
}
Note this is especially good for Value object in a DDD sense and can be easily mapped to the database. More benefits include that I do not have to hit the DB to get a status. As they are value object and have no need for an ID (in the the domain), we only map the id in the mapping files. The POCO object know nothing of ids. I can also create lists for drop down binding too if required... with no need to retrieve from the DB.
I have had some people raise the point "but what if we need a change in the DB for a new status?". Well that sounds like new logic to me and should mean reworking the logic and then a recompile anyway, however now we are being very clear with how we handle each enum as the object now possesses its own logic.
If you are using NHibernate the mapping would look like this:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="Sample.SalesOrderStatus,Sample" table="Sales.SalesOrderStatus" abstract="true">
<id column="SalesOrderStatusID" type="Int32" unsaved-value="0">
<generator class="native"/>
</id>
<discriminator column="SalesOrderStatusID" />
<property column="Description" type="String" name="Description" not-null="true" length="50" />
<subclass discriminator-value="1" extends="Sample.SalesOrderStatus,Sample" name="Sample.SalesOrderStatus+InProcessSalesOrderStatus,Sample"/>
<subclass discriminator-value="2" extends="Sample.SalesOrderStatus,Sample" name="Sample.SalesOrderStatus+ApprovedSalesOrderStatus,Sample"/>
<subclass discriminator-value="3" extends="Sample.SalesOrderStatus,Sample" name="Sample.SalesOrderStatus+BackorderedSalesOrderStatus,Sample"/>
<subclass discriminator-value="4" extends="Sample.SalesOrderStatus,Sample" name="Sample.SalesOrderStatus+RejectedSalesOrderStatus,Sample"/>
<subclass discriminator-value="5" extends="Sample.SalesOrderStatus,Sample" name="Sample.SalesOrderStatus+ShippedSalesOrderStatus,Sample"/>
<subclass discriminator-value="6" extends="Sample.SalesOrderStatus,Sample" name="Sample.SalesOrderStatus+CancelledSalesOrderStatus,Sample"/>
</class>
</hibernate-mapping>
The above SalesOrderStatus abstract class can now have static method on it to do thing you may normally hit the DB for eg to get Lists of Statuses, however now you are confined to the realms of the domain. This makes life easier IMO as there is less external dependencies. I have found I use enums very rarely in the domain and usually only have them in the UI for Display object or in DTOs across the wire (eg error codes; as an enum fails back to its underlying universal int type).
Try it out, see if you like it and let me know how it goes.
Sunday, December 14, 2008
T4 GAX & GAT: Revisited
I have dabbled with T4, GAX and most specifically the GAT before and never really got any traction. Its a great idea but it is very intricate. Nothing by itself is overly complicated but there are lots of little things that can quickly put you off.
I am trying to set up default MVP solutions for myself. I have a default architecture that I have used for several commercial application and would like a quick way to replicate it. Typically I follow a Presenter First pattern and interact with a service layer for the model. The service layer may be a proxy for a distributed app or it may be a thin tier for interaction with the model, it doesn't really matter. The fact is I have very similar classes, very similar tests, and very similar structure on many of these app's. This is a perfect time to look to generate these frameworks. One of the big things I want out of this exercise is to get my default build configurations and build scripts predefined. This is a fiddley aspect that I hate doing, but always do it because of the time it saves in the long run.
So attempt one will be a WinForms MVP solution with out a domain project. I will use MSTest, RhinoMocks and MSBuild on 3.5 version of the framework. Not sure what IoC I will use yet.
As this is something i want to reuse where ever I work I don't want to make NH a default aspect. i may include an NH model project in later.
So far the whole process has not been overly pleasant. I have had files (as in dozens of them) just get deleted on an attempt to register a project, projects trying to compile template that are marked as content (ie not for compilation), packages that just decide they are no longer packages... so I decided to set up a vm to contain the madness.. unfortunately I only have vista 64 install on me and VPC can only host 32 bit OSs... oh well the PnP (Pain 'n Phailures?) impedance continues.
Wish me luck...
Wednesday, December 10, 2008
DDD Confusion
http://the-software-simpleton.blogspot.com/2008/12/twat-of-ddd-increasing-complexity-in.html
My points:
- DDD is not needed in every situation.
- DDD is used when there is a significant amount of business logic. If you are writing crud screens DDD is probably not the best option.
- DDD is hugely beneficial in an Enterprise Solution. This is because there is business logic in business applications.
- DDD is not hard, if done right. Start simple and add complexity AS REQUIRED.
- DDD scales. I have a base framework that I use for DDD solutions which let me get up and running with in a few minutes. I still have to write the domain objects, but if these are simple objects this takes a trivial amount of time, but still leaves me open to scaling to a large solution if and when it is necessary.
Of the last 5 web applications I have done DDD was involved in only 1 of them. The other 4 took less than a week to complete.
Here is something a little more concrete: I would use my NH based DDD stack for anything I thought would take more than 2 weeks of dev time to complete.
Like anything the more you do it the more you learn, you pick up good ideas and recognise bad ones. The problem with DDD is you cant just read the book and know it you have to go thru the pain of doing whole projects to get that knowledge.
Thursday, December 4, 2008
Asp.Net
Things I have forgotten about asp.net and web dev:
ASP.Net thinks safari is old skool and not capable. this is annoying when you cant change the servers .browser files (http://www.big-o.org/?p=20)... meaning some of the web controls don't work to well.
CSS can be a pain in the ass. In fact I hate UI altogether. Relying on customers to give you pictures and content is painful too
Linq 2 XML is a god sent for customers that don't want to pay for a database but still want some dynamic features.. my XML and file system interrogation based web control library is growing fast ;)
In saying that, building web sites in general is fast. Unfortunately it is all the tedious things that take time. Seriously I can get a site up in under a day but its the finicky crap is the thing that will annoy me...font changes, image alignment, cross browser qwirks.. arrrgh!!!
One site I always for get about is http://www.html-kit.com/favicon/ its great for creating your favicon.
So If any one need a Ma and Pa web site, holla. I don't promise anything uber wicked but can give a quick turn around.... plus my girlfriends hand bags don't pay for themselves... pffft ;)