M-V-VM Building an ERP-system – part 2 of N – the model implementation

Skrevet - Wednesday, May 26th, 2010 kl. 23:15 | Kategori - * Coding, English posts

As discussed in part 1, we need to implement the model somehow. The solution-source code shows the refactored result. There are 3 major implementation details that I will touch here:

Validation
I chose a solution here that is a bit more basic than I like in a production system, but still very capable – and easy to expand into a separate class when needs expand. I quickly added a generic base-class to handle all the ‘plumbing’-code (DRY applied harshly here). Below is the result for validation:

public abstract class AggregateRoot<TAggregate> : IAggregateRoot
{

protected static IListt<ValidationRulet<TAggregate>> _validationRules = new Listt<ValidationRulet<TAggregate>>();

public virtual bool IsValid(out string[] errors)
{
errors = _validationRules.Where(rule => rule.IsBroken(this as TAggregate)).Select(rule => rule.BrokenMessage).ToArray();
return !errors.Any();

}

}

Basically, I use a ValidationRule class to encapsulate validation – these rules can be very simple, or very complex and are applied sequentially. This means that I can get a list of all the things that are wrong (very usefull in UI for complex types). I hate (and I really do!) long if-statements thrown together with loads of unreadable conditions. For very complex rules, I would use a composite rule that would break all the scenarios into manageable chunks. To keep things simple, I didn’t add an IValidationRule<TAggregate> interface which I normally would to handle the composite rules. I favour encapsulated validation ie. the objects are capable of validating themselves. It’s mostly a matter of religion – but I like to have things encapsulated.

Equality and Identity
Equality and Identity may be the same thing – and then again might not be. We have two basic scenarios in our simple application – objects can either be an aggregate root (thus having an Id) or they can be a ‘simple type’ with little concept of identity. For aggregates, I’ve used the Id to determine whether we are talking about the same order. I cannot rely on two instances of any given order to be sharing the same memory allocation (ie. reference equality) – so, I’ll have a fall-back plan. I use the Id to do this. This leaves a problem with transient orders (ie. orders that have not been assigned an Id yet). I’ll not address this here (if I had used GUIDs this would not have been a problem), but just accept that if equality is important – users are only allowed to new one order up at the time…

For ‘simple types’ – here the order lines – I don’t really care if they are equal, but to facilitate later performance-runs, I will use the state to determine if these are equal – also, this enforces the idea that order lines are expandable and are replaced rather than copied – so, all state is used to determine if they are equal.

Collections
I didn’t discuss a major design decision in part 1 – why did I use an IEnumerable instead of an IList in the IOrder interface? Because I don’t want developers using all of the IList interface without my say-so. I might decide that all orderlines added will trigger some side-effect – or if the order is billed, you can no longer add order lines etc. Now, this can be easily added later by adjusting the AddOrderLine method. If I had OrderLines.Add(..) scattered all over my code-base, this would be very hard. Also the problem around .Remove() (see Part 1 for an explanation), could introduce nasty side-effects if developers are not consistent in how they treat the collection. Basically, I’m telling my colleagues – “This is what you can do – everything else is out of the question.” Internally I use an IList for convinience. I don’t expect an order’s orderlines to be so large that it will matter performance-wise – so, an IList is chosen here.

Part 3 will focus on the first ViewModels.

About the series:
The solutions introduced here are not entry-level material. You should understand generics and basic patterns to fully utilize the material presented. The solution represents about 3 years of experience working with one ERP-solution. Some of the choices taken are heavily influenced from the large-scale solution and may seem overkill for the simple examples here, but the idea is to show the end-result of my experience and hopefully you as the reader will at least see a new way of doing things. The solution is built in .Net 4.0 with heavy use of WPF’s capabilities. Here you can find the source-code for the series. You are free to use this code for any purpose, but it is presented as-is with no guarantees. Enjoy!

Feed | Trackback |

2 Comments
  1. Goblincave » M-V-VM Building an ERP-system – part 1 of N – the model design said,

    June 6, 2010 at 22:20

    [...] part 2, I’ll discuss the implementations of the above interfaces and the reasoning behind [...]

  2. Goblincave » M-V-VM Building an ERP-system – part 3 of N – the first ViewModels said,

    June 6, 2010 at 22:23

    [...] part 2 – we now have a model to work from – and it is time to create the first [...]

Post a Comment