zaterdag 31 mei 2008

Building an Allors application

As explained in my previous post I am going to build an application to demonstrate what Allors is and how to use it.  I will hopefully have to time to build the same application later on using NHibernate to show both frameworks differences. 

The application I'll be building will take care of the invoicing for a contractor.  It is built using the YAGNI principle (this basically states if you think you need to add complexity to your domain model, you should defer it until the moment you actually need it.  Probably you ain't gonna need it).  Lets discuss the domain shall we.  The most important class obviously is the Contract signed between a Customer and a contractors's Company.  Both the customer and the company are subclasses of the corporation class, which gives them some common attributes (Name, Address and Account).  On the Contract you can register your hours you worked for them and eventually generate an Invoice for a specific period.

All relations and classes are shown in the following model:

Version1 
I deliberately kept everything as simple as possible so I can make future improvements to demonstrate what this means in terms of database upgrades, refactorings possibilities, etc....  If you want to follow everything that is explained here below, you can download the complete solution here or built everything yourself of course :-)

Building the domain (Allors)

To start building an Allors domain you first need to download the binaries and the Allors Repository.  You can either checkout the sources from the subversion (https://www.allors.com/svn/platform) or you can download the Quick Start file I've put together. The zip contains two directories & a command file

  • lib: Directory containing the Allors binaries and the Allors Repository, you should extract these in your solution folder.
  • Allors: Directory for the Allors Domain Files, you should extract these in your domain project folder.
  • AllorsRepository.cmd: file that will startup the AllorsRepository Tool for you domain, this should be extracted in your solution folder.

Step 1: Setting up the solution hierarchy

The solution structure I have applied consists of 4 projects.

  • Diagrams: containing the diagrams of my domain.  This project will contain only generated code with getters/setter that reflect your domain.  You can then use this generate your class diagrams.
  • Domain: the heart and soul of our accounting application, you should refer to the Allors.Framework.dll here.
  • Population: Helper classes to build your domain objects and setup an initial population for unit/integration testing.
  • Unittests: proving our design and domain is correct and well thought.

image 

Step 2: Creating the Allorized domain

The Allors folder from the zip file needs to be copied into your domain folder.  This folder will contain the meta information (allors.repository) about your domain classes, which is built up using the AllorsRepository-Application (included in the zip file).  if you modify the command file that was included in the zip file so that the parameter passed in to start up the "Allors.Repository.Application.exe" refers to the allors.repository in your domain folder, this file will now fire up the AllorsRepository-Application for your domain.  You should see the following (if you are building from scratch, otherwise your domain will be completely filled in).

image

This screen has three main parts. 

  • The top left has a tree containing all your types and relations in your domain
  • The top right is the property window of the selected treeNode
  • The bottom gives information about errors in your domain

All actions are available by rightclicking the treeNode and then select the action in the context menu or change the node's corresponding properties.  If you need to know how things are getting done, you can checkout the getting started page of the Allors website.  On the bottom you can see that the repository already has one error.  It has no name, so you need to select the domain node and fill in the name in the properties window.

Step 3: Namespaces & Types

Our solution will have two namespaces to start with.  You can see here how you can add namespaces in the repository.  The types we are building are shown in the diagram above, you can easily add them yourself in the allors repository.  It is written out here how you can achieve that.  All objects belong to the Accounting namespace, only the DatePeriod type is more generic and is placed into its own General namespaces

Step 4: Attributes & Relations

We now have domain containing single classes without any attributes or relationships between them.  You cannot call this a domain of course so the logical next step to give our objects data and connect them through the use of relations.  As always you can checkout here how everything can be done.  The above diagram gives you all the information you need to create all the relations.

Step 5: Adding Domain Logic

The Allors domain has been built (you can download the zip file here).  The next step is to generate (right click the domain and select generate) our allors classes, these will be our base classes for our domain objects.  You don't have to remember to inherit any classes or interfaces because we generate a partial class for you as well.  Include these files (located inside the Allors/output/folder by default, but this can be tweaked of course) in your domain project and you can start using them.  Every object you instantiate now is done inside a Session, the creation is performed through the Session as you can see in the next code block:

1 public static Account Create(AllorsSession session,
2 string bank,
3 string number)
4 {
5 Check.Argument(number, "number").IsNotNullAndNotEmptyAndNotWhiteSpace();
6 Check.Argument(bank, "bank").IsNotNullAndNotEmptyAndNotWhiteSpace();
7
8 var account = session.Create<Account>();
9 account.Bank = bank;
10 account.Number = number;
11
12 return account;
13 }


Adding the actual business logic is done simply by adding the methods into your class (as you normally would)



1 public TimeRegistration RegisterWorkingTime(DateTime date, Double hours)
2 {
3 return TimeRegistration.Create(AllorsSession, date, this, hours);
4 }
5
6 public Invoice BuildInvoice(DatePeriod period,
7 String reference,
8 DateTime invoiceDate,
9 IInvoiceCalculator invoiceCalculator)
10 {
11 VerifyThatInvoiceReferenceIsUnique(reference);
12
13 var timeRegistrations = new TimeRegistrationFinder(AllorsSession)
14 .GetNotInvoicedTimeRegistrationsFor(this,period);
15 if (timeRegistrations.Length == 0)
16 {
17 throw new ArgumentException("Invoice must contain TimeRegistrations");
18 }
19
20 var invoice = Invoice.Create(AllorsSession, reference, invoiceDate);
21 AddInvoice(invoice);
22
23 foreach (var timeRegistration in timeRegistrations)
24 {
25 invoice.InvoiceTimeRegistration(timeRegistration, invoiceCalculator);
26 }
27
28 return invoice;
29 }


Step 6: Unit Testing



Since all objects are Session aware we need to have a Session in our UnitTests.  For performance reasons we will not use a real database, but rather work completely in memory.  The following code creates an in-memory session for our domain:





var population = new Allors.Adapters.Memory.AllorsConnectedMemoryPopulation(new AccountingDomainConfiguration());
population.Init();
_session
= population.CreateSession();




The final step is to make our domain persistent.



For this I created a new project (IntegrationTests).  You do not need to supply mapping files because Allors will make and initialize the database scheme for you based on the meta information you supplied.  This is achieved by simply pointing our Session to the correct strategy, here we will use the SQL Server Express Edition.  For unittesting we created the population in code (and for memory), you could as well set everything in the config file:




  • First of all you need to declare the allors section in the config


  • You need to configure your populations(or multiple of them)


  • Finally you need to create the population from based on the name in the config



1 <configSections>
2 <section name="allors" type="Allors.AllorsConfigurationSection, Allors.Framework"/>
3 </configSections>
4
5 <allors>
6 <populations>
7 <add name="AccountingPopulation"
8 type="Allors.Adapters.SqlClient.AllorsSqlClientPopulation, Allors.Adapters.SqlClient"
9 domainConfiguration="AllorsDomains.AccountingDomainConfiguration, Pdbc.Accounting.Domain"
10 connectionStringName="accounting">
11 </add>
12 </populations>
13 </allors>
14
15 <connectionStrings>
16 <add name="accounting" connectionString="Data Source=Pdbc-Laptop\SqlExpress;Initial Catalog=accounting;Integrated Security=True"/>
17 </connectionStrings>



Then in code we can retrieve the population and instantiate the session.  The Init method by the way drops the database and recreates it which makes sure that our integration tests always have the latest version of the database scheme available.

1 var population = AllorsConfiguration.GetPopulation("AccountingPopulation");
2 population.Init();
3 _session = population.CreateSession();



Check the complete sample along with the unittests for a complete overview.  As you notice, the major difference with traditional POCO domain objects is that we need to inherit from an Allors Class.  This Class encapsulates the access to a strategy object which contains all your class attributes and object relations.  This way we can keep all objects managed by Allors which has a lot of benefits, but that is for a next post.  Let me know what you think about it and have a spin with the sample.

Check you later. 

Submit this story to DotNetKicks

Building an Allors application

As explained in my previous post I am going to build an application to demonstrate how to use Allors.  I will hopefully have to time to build the same application later one using NHibernate to show both frameworks differences. 

The application I'll be building will take care of the invoicing for a contractor.  It is built using the YAGNI principle (this basically states if you think you need to add complexity to your domain model, you should defer it until the moment you actually need it.  Probably you ain't gonna need it).  Lets discuss the domain shall we.  The most important class obviously is the Contract signed between a Customer and a contractors's Company.  Both the customer and the company are subclasses of the corporation class, which gives them some common attributes (Name, Address and Account).  On the Contract you can register your hours you worked for them and eventually generate an Invoice for a specific period.

All relations and classes are shown in the following model:

Version1 
I deliberately kept everything as simple as possible so I can make future improvements to demonstrate what this means in terms of database upgrades, refactorings possibilities, etc....  If you want to follow everything that is explained here below, you can download the complete solution here or built everything yourself of course :-)

Building the domain (Allors)

To start building an Allors domain you first need to download the binaries and the Allors Repository.  You can either checkout the sources from the subversion (https://www.allors.com/svn/platform) or you can download the Quick Start file I've put together. The zip contains two directories & a command file

  • lib: Directory containing the Allors binaries and the Allors Repository, you should extract these in your solution folder.
  • Allors: Directory for the Allors Domain Files, you should extract these in your domain project folder.
  • AllorsRepository.cmd: file that will startup the AllorsRepository Tool for you domain, this should be extracted in your solution folder.

Step 1: Setting up the solution hierarchy

The solution structure I have applied consists of 4 projects.

  • Diagrams: containing the diagrams of my domain.  This project will contain only generated code with getters/setter that reflect your domain.  You can then use this generate your class diagrams.
  • Domain: the heart and soul of our accounting application, you should refer to the Allors.Framework.dll here.
  • Population: Helper classes to build your domain objects and setup an initial population for unit/integration testing.
  • Unittests: proving our design and domain is correct and well thought.

image 

Step 2: Creating the Allorized domain

The Allors folder from the zip file needs to be copied into your domain folder.  This folder will contain the meta information (allors.repository) about your domain classes, which is built up using the AllorsRepository-Application (included in the zip file).  if you modify the command file that was included in the zip file so that the parameter passed in to start up the "Allors.Repository.Application.exe" refers to the allors.repository in your domain folder, this file will now fire up the AllorsRepository-Application for your domain.  You should see the following (if you are building from scratch, otherwise your domain will be completely filled in).

image

This screen has three main parts. 

  • The top left has a tree containing all your types and relations in your domain
  • The top right is the property window of the selected treeNode
  • The bottom gives information about errors in your domain

All actions are available by rightclicking the treeNode and then select the action in the context menu or change the node's corresponding properties.  If you need to know how things are getting done, you can checkout the getting started page of the Allors website.  On the bottom you can see that the repository already has one error.  It has no name, so you need to select the domain node and fill in the name in the properties window.

Step 3: Namespaces & Types

Our solution will have two namespaces to start with.  You can see here how you can add namespaces in the repository.  The types we are building are shown in the diagram above, you can easily add them yourself in the allors repository.  It is written out here how you can achieve that.  All objects belong to the Accounting namespace, only the DatePeriod type is more generic and is placed into its own General namespaces

Step 4: Attributes & Relations

We now have domain containing single classes without any attributes or relationships between them.  You cannot call this a domain of course so the logical next step to give our objects data and connect them through the use of relations.  As always you can checkout here how everything can be done.  The above diagram gives you all the information you need to create all the relations.

Step 5: Adding Domain Logic

The Allors domain has been built (you can download the zip file here).  The next step is to generate (right click the domain and select generate) our allors classes, these will be our base classes for our domain objects.  You don't have to remember to inherit any classes or interfaces because we generate a partial class for you as well.  Include these files (located inside the Allors/output/folder by default, but this can be tweaked of course) in your domain project and you can start using them.  Every object you instantiate now is done inside a Session, the creation is performed through the Session as you can see in the next code block:

public static Account Create(AllorsSession session,
string bank,
string number)
{
Check.Argument(number,
"number").IsNotNullAndNotEmptyAndNotWhiteSpace();
Check.Argument(bank,
"bank").IsNotNullAndNotEmptyAndNotWhiteSpace();

var account
= session.Create<Account>();
account.Bank
= bank;
account.Number
= number;

return account;
}


Adding the actual business logic is done simply by adding the methods into your class (as you normally would)



public TimeRegistration RegisterWorkingTime(DateTime date, Double hours)
{
return TimeRegistration.Create(AllorsSession, date, this, hours);
}

public Invoice BuildInvoice(DatePeriod period,
String reference,
DateTime invoiceDate,
IInvoiceCalculator invoiceCalculator)
{
VerifyThatInvoiceReferenceIsUnique(reference);

var timeRegistrations
= new TimeRegistrationFinder(AllorsSession)
.GetNotInvoicedTimeRegistrationsFor(
this,period);
if (timeRegistrations.Length == 0)
{
throw new ArgumentException("Invoice must contain TimeRegistrations");
}

var invoice
= Invoice.Create(AllorsSession, reference, invoiceDate);
AddInvoice(invoice);

foreach (var timeRegistration in timeRegistrations)
{
invoice.InvoiceTimeRegistration(timeRegistration, invoiceCalculator);
}

return invoice;
}


Check the complete sample along with the unittests for a complete overview.  As you notice, the major difference with traditional POCO domain objects is that inheritance from an Allors Class.  This Class encapsulates the access to a strategy object which contains all your class attributes.  This way we can keep all objects managed by Allors which has a lot of benefits, but that is for a next post.



Let me know what you think!



 







Submit this story to DotNetKicks

Submit this story to DotNetKicks

dinsdag 27 mei 2008

It's Peter Time

Today (actually yesterday) Peter Eysermans started his blog.  Peter is one of my colleagues and a really funny guy, he is an authority (or will be :-)) on Web Development.  So if you want to follow his quest for world web domination then check out his blog or subscribe to it).  I for one am looking forward to his next post : The pussy way of development'!

Submit this story to DotNetKicks

vrijdag 23 mei 2008

Resharper 4.0 Stable release

I am using Resharper since version 2.0 and VS2003.  In those days there were major problems with the memory consumption of the tool, resulting in a slow IDE and multiple crashes.  Just when I was going to remove it from my system, I made the shift to VS2005 and Resharper 2.5 (and 3.0).  It couldn't have come at a better time because I never doubted the guys from Jetbrains ever again.

A while ago I installed one of the 4.0 EAP Releases (4.0.775.22).  Some of my solutions not even the big ones took ages to start up and occasionally my studio froze!  I quickly reverted to my old version no harm done.  But a couple of days ago a Stable version was released and I decided to give it another try.  My problem solution now still take a little longer to load, but I didn't suffer any freezes anymore.  The support for the .NET 3.5 framework makes the loading time a necessary evil, besides you need this version if you really want to develop in VS2008 (and not be annoyed by non-compilation warnings from Resharper about the new language stuff)

You can buy a license for the currently released 3.5 and are allowed to upgrade to 4.0 once this version becomes available.  So what is stopping ya?

By the way, thanks to Ilya Ryzhenkov for providing a list of nice plug-ins for Resharper, these have proven to be quite helpful.

Submit this story to DotNetKicks

woensdag 30 april 2008

NHibernate here we come !

Currently we are starting up a project to rewrite the security service.  The previous version was build using data sets (argh it even gives me the creeps just writing this word), relying heavily on the database.  For every change (big or small) on the user profile the entire thing was deleted out of the database and the new version was inserted.  It even came this far that with large profiles, the timeout of the web service was hit and the application refused to work altogether.  Lessons learned from this debacle, we decided to build a clean domain model and use a UnitOfWork to decide what needs to be saved into the database.  We added features like lazy loading and caching as well to avoid database payloads.  Then we decided, based on the patterns already examined, we would need an ORM.  We looked at some possibilities (Allors, NHibernate, ...) , did some spikes and decided that when building a Persistence Ignorant domain model, Nhibernate was the best choice.

We presented our findings and spike results along with our proposed solution to the enterprise architects.  It was turned down for no apparent reason.  Their solution was to align with the rest of the organization and go for a data-driven approach (they even mentioned data sets) and thus avoid complex domains that need mapping through a tool.  In case of caching, we were told to write it in stored procedures (because that is why they are there for :-)).  "Why on earth did we even have a complex domain model" was the last question of the meeting.  This coming from a team  that believes that writing unit tests is more time consuming than it is beneficial.  Wait until they have to maintain one of these data-driven applications :-). 

We lost the battle, but we didn't surrender.  We already assembled some followers:

  • The DBA team loved the caching and the reduced database hits.
  • Other development teams were experiencing the same problems so were asking for similar solutions. 

Long story short, the decision to use it or not was postponed until a meeting were both us and the A-Team would present our cases.  The meeting was last Monday and given this blog posts title our arguments have won it.

Thank God because we already started on the ground work of our own ORM and it would take a lot of work to build the features we are now getting for free!  We've worked about two weeks on it and I think we could cover about 75% percent of our basic CRUD operations.  We didn't yet added support for collections the UnitOfWork, but we already had ideas about how to do it (build a custom persistent collection for it).  Our implementation depended heavily on the dynamic proxy of castle project and was inspired by the NHibernate source code.  Writing it ourselves made me think about this scene from the matrix were Morpheus asked Neo to take the blue pill and stay ignorant (about persistence issues) or take the red pill and see what really going on.  We were forced to take the red pill or doom the project before it even began.  It was fun to experiment with it, but when your problem domain is security, that should be the focus of your development all time you spent on infrastructure code is time wasted!

Anyway we are going to test NHibernate in our project, then it will be evaluated and eventually rolled out to the rest of the development teams. Lets start reading about it!

See ya next time.

Submit this story to DotNetKicks

maandag 28 april 2008

Accounting (part 1)

As explained in my previous post I am going to demonstrate the potential of Allors by building a sample application.

I'll be building an invoice application which has the following domain model:

Version1

Submit this story to DotNetKicks

Blog changed

Okay, this was my 'test' blog.

Please continue reading at my new blog or register at my feedburner

Submit this story to DotNetKicks

maandag 21 april 2008

Blog test....

Please ignore this post, just testing some of my live writer stuff...

Quoting: Can be done like this.

   1: public class MyClass 


   2: {


   3:     /// Constructor of My Class


   4:     public MyClass() 


   5:     {


   6:     }


   7:  


   8:     /// Action Method


   9:     public void Action() 


  10:     {


  11:     }


  12: }


Submit this story to DotNetKicks

zaterdag 19 april 2008

Think you are a serious developer? Think Resharper...

I am using Resharper

since version 2.0 and VS2003.  Back then I had major problems with my studio crashing because of the memory consumption the application took.

It improved a lot when moving to version 2.5 (and 3.0) and studio 2005. 

Currenlty I am evaluating the 4.0 EAP version (actually 4.0.775.22) Jetbrains is releasing by their nightly build.  Currently I haven't found any major issues with it.  So to the nice people of Jetbrains, keep up the good work.

By the way, thanks to Ilya Ryzhenkov for providing a list of nice plug-ins for resharper.

EDIT: Apparantly one of my solutions failed to load now.  So I shifted back to the 3.1 version of resharper. 

Tags van Technorati: ,

Submit this story to DotNetKicks

vrijdag 18 april 2008

TFS 2005 upgrade to TFS 2008

We are experiencing problems upon upgrading our TFS to the new 2008 version.  All is going magically well, but when we are converting our Scrum template from conchango, we hit the problem.  We already reported it on their portal and currently they are working on a solution for it.

Anyway, since only the portal does not work I am willing to take that loss (we didn't use it anyway :-)).  Next checks are that our customized Work Items and Reports are correctly converted to 2008.  I don't see lots of issues coming our way since all other templates converted perfectly.

When we originally updated our work items I did it manually.  Exporting the the WIT, changing the XML and then importing it again.  Now apparantly it is all incorporating in the team foundation server power tools.  Making life a little bit easier.

 

Tags van Technorati: ,,

Submit this story to DotNetKicks

'Trac' - ing Allors

We have just created a trac website for allors.  Both the platform and the applications have a seperate website to track its progress.

By doing this we have as well released the code to the community.  The platform is nearly 1.0 ready, thus this means we can begin shifting the focus the applications section.

Currently I'am integrating simple workflow features in the Core Domain.  Although some of my collegues do not believe in workflow (sometimes including me).  I think, when used carefully, it can simplify your overall project structure.

Tags van Technorati: ,,

Submit this story to DotNetKicks

donderdag 17 april 2008

How to seperate Domain and infrastructure logic?

Tags van Technorati: ,,

Today I struggled with the fact that some infrastructure code drippled into my domain while building the ORM features ourselves.

The problem was that I had to load a bunch of objects as a Tree Collection.  So the easy solution was to add an extra Id field to the class to store the parent/child object Id and after all where loaded, iterate an link to the correct solution.  Now I polluted my domain with some infrastructure fields (I had to add some more...).

Because we are already using the Windsor container as our dependency container and the dynamix Proxy Interceptors for lazy loading on the project, I thought about using the mixin functionality they offer.  I created an extra data object in the infrastructure layer and then wanted to 'mix' them.  Bummer, dynamic proxy 2 does not support this functionality (although ayende claims he added support for about a year ago)!

So I went for the second solution, much simpler in my opinion.  Instead of creating an seperate data structure to hold the extra data, I decorated my domain object.  My mapper object now creates the decorated objects (which are internal).  After I loaded all my objects into memory, the repository uses the extra data to build up the tree and voila we're done.  My domain remains mean, lean and clean, but I have the extra information at my disposal.

Till next time...

Submit this story to DotNetKicks

dinsdag 15 april 2008

Our Service Architecture: Why oh why....

On my current job we (me and Jan) are currently building an security service.  It will be a WCF Service who's primary use will be for authenticating users on the intranet.  Another service is currently under development to manage the permissions of these users.

We are having huge fights with the architecture team (indeed we still have an architecture team) about how we should build the services. Me and Jan are firm believers of domain centric applications while architecture thinks it should be data driven.  It shows that they do not need to maintain and give support for it.

Anyway we have won the fight and have already built the domain (in a TDD driven manner of course).  Yesterday I started with the infrastructure layer which is primary targetting a DB2 database. 

A second battle we had with the A-Team was about the use of an ORM to take care of the persistence, the features for caching, unit of work and lazy loading were a nice extra. Since I told you I was already started with writing this code myself you know we lost this time (at least we put up a fight to improve things....). 

During the last two days I find out why ORM are so popular.  It takes so much out or your hands that you take otherwise for granted.  Have you ever tried writing a unit of work yourself?  Not the most fun job if you know it has absolutely nothing to do with the core of the application we are writing. 

Anyway hopefully in one of the upcoming months someone sees the light and gives us a boost in our productivity.

Tags van Technorati: ,,,

Submit this story to DotNetKicks

donderdag 10 april 2008

Open Source

Together with Koen and Martien we are building on a framework (called Allors) that enables domain driven development. 

With Allors you build a meta domain with a repository tool, where you describe your objects.  At runtime you have access to the meta information, this means you can ask it for information about your domain. 

The following posts will be a tutorial on how to use Allors for your projects and what are the benefits!

Submit this story to DotNetKicks

dinsdag 8 april 2008

Getting started (about me...)

Here goes.....

As this is my first blog ever, I'd like to start with introducing myself.  My name is Patrick De Boeck and I live with my girlfriend in Merksem, a small city next to the center of the earth, Antwerp.  I am the proud father of a two year old little girl, Amber.

Professionally I am developing software since the year 2000 (that's right just after that millennium fuss thing).  I started out as Java developer by doing consultancy work across Europe (Antwerp, London, Luxembourg and Frankfurt).  In 2003 I had to opportunity to become lead developer/architect of a major software insurance project in Eindhoven.  I had to switch to the .NET world for it though, but so far I haven't regretted that.

In 2004 I decided to make a leap in the dark and become a freelance software developer.  My company is called PDBC - Systems and is specialized in .net consultancy.  I also participated in Allors.  In future blog post I will elaborate on this. 

Domain Driven Development will be the major theme of this blog.  I strongly believe that any development team should focus on their problem domain instead on infrastructural and persistence problems.  There are tools (see Allors) to take care of that for you.

That's enough about me now, but I promise the following blog posts will be more interesting.

Submit this story to DotNetKicks