Solution Architecture For The Masses. Step 2: Design Your Entities & Business Components

 Alik Levin   After I have structured my solution in Visual Studio I decided to first design my Business Entities and Business Components that will act upon the Entities. I like the idea of focusing on domain first – something that Domain Driven Design is all about.

Quick Resource Box

Chapter 4: Designing Your Architecture guides to “Use stories from multiple perspectives to help expose the key scenarios for your system” and in the Domain Driven Design presentation there is a good guidance how to use the stories to model the language used by business analysis [domain experts]:

  • Nouns == Classes
  • Verbs == Methods, Services, etc

Looks like old plain OOP, eh?

I have two user stories [scenarios]:

    1. User transfers money from one account to another.
    2. User searches for transactions he performed.

Identifying Aggregates and Repositories

How To: Domain Driven Design guides how to use Entity Framework to implement Domain Driven Design. I will stick with something simpler than that. It also shows how to derive Aggregates [Nouns/Classes/Entities] and Repositories [Verbs/Methods/Services].

For my scenarios I’ll stick with these Entities:

  • AccountInfo
  • TransactionInfo

and these repositories [I could call it xxxRepository but I love xxxServices better ;)]:

  • AccountServices
  • TransactionServices

Defining Entities

I am a big fan implementing entities based on custom objects [vs. DataSets, XML, or other options]. How To: Design Business Entities offers fantastic comparison between different options. The following only makes me more comfortable to stick with custom objects [performance is my favorite, of course]:

“…Consider using custom objects:

  • If you must implement complex business rules.
  • If you are using the ADO.NET Entity Framework or ADO.NET LINQ.
  • If you are working with large volumes of data.
  • If you want to maximize performance when passing data across AppDomain, process, and physical boundaries. Custom objects can be serialized using a binary format, which is much faster than XML formats…”

Expand Entity folder in Visual Studio. Expand Entities project. Add a class and name it AccountInfo. It’s behaviorless class. Its behavior [methods or services] will be defined in separate project in Business Services folder as AccountServices class with static methods. This separation fosters service oriented design regardless of actual final physical deployment. Same story with Transaction. This is how the guide explains it:

“…Domain Value Objects are lightweight objects that represent domain entities, but do not contain business rules. These objects are sometimes referred to Data Transfer Objects (DTO), which is a design pattern used to package multiple data structures into a single structure for transfer across AppDomain, process, and physical boundaries. With a domain value object, the main goal is to define business entities that represent entities in the business domain while maintaining the relationship between those entities…”

I mark entity classes with DataContract and DataMember attributes as I expect I might be using it for my services too that would be implemented as WCF services. AccountInfo entity should look similar to the following.

namespace Entities {     [DataContract]     public class AccountInfo     {         private string m_id = string.Empty;         private string m_ownerId = string.Empty;         private string m_currency = string.Empty;         private double m_balance = double.NaN; [DataMember]         public string Id         {             get { return m_id; }             set { m_id = value; }         }         [DataMember]         public string OwnerId         {             get { return m_ownerId; }             set { m_ownerId = value; }         }         [DataMember]         public string Currency         {             get { return m_currency; }             set { m_currency = value; }         }         [DataMember]         public double Balance         {             get { return m_balance; }             set { m_balance = value; }         }     } }

The TransactionInfo class looks similar to the following(consider adding [DataContract] and [DataMember] if you are planning to use it in WCF. Consider adding it anyway, if you do not use it in WCF in the end – it won’t hurt anybody anyway):

    public class TransactionInfo     {         private string m_transactionId = string.Empty;         private string m_transactionAccount = string.Empty;         private string m_transactoinAction = string.Empty;         private double m_transactionAmount = double.NaN;         private DateTime m_transactionDateTime = DateTime.MaxValue;

        public DateTime TransactionDateTime         {             get { return m_transactionDateTime; }             set { m_transactionDateTime = value; }         }

        public string TransactionId         {             get { return m_transactionId; }             set { m_transactionId = value; }         }

        public string TransactionAccount         {             get { return m_transactionAccount; }             set { m_transactionAccount = value; }         }

        public string TransactoinAction         {             get { return m_transactoinAction; }             set { m_transactoinAction = value; }         }

        public double TransactionAmount         {             get { return m_transactionAmount; }             set { m_transactionAmount = value; }         }     }

Defining Business Services

Expand Business Services folder in Visual Studio. Expand BusinessServices project. Add two classes AccountServices and TransactionServices. Also, add reference to Entities project. Basically, these classes define behavior for the entities.  I’ll start with AccountServices. I will be using it with my first user story which goes along the line “User transfers money from one account to another”. To transfer from one account to another I’d first present the list of accounts – that’s where it’ll be useful.

public class AccountServices {     public static List<AccountInfo> GetCurrentUserAccounts()     {         List<AccountInfo> result = null;         //MOCKING UP THE RETURN RESULT         //IT WILL BE IMPLMENTED FURTHER VIA DAL         result = new List<AccountInfo>         {             new AccountInfo("ac1","ownr1", "USD", 1001),             new AccountInfo("ac2","ownr2", "USD", 1002),             new AccountInfo("ac3","ownr3", "USD", 1003),             new AccountInfo("ac4","ownr4", "USD", 1004),             new AccountInfo("ac5","ownr5", "USD", 1005),             new AccountInfo("ac6","ownr6", "USD", 1006),         };         return result;     } }

Test Your Implementation Using Unit Test

I am ready to test my simple design and implementation. I will do it using adding a unit test to my solution. To do so right click on GetCurrentUserAccounts method and then “Create Unit Tests…”. Name the new project BusinessServicesTests in ‘Output project:” field. Click OK. Optionally drag the project under Business Services folder. Implement simple Unit test under GetCurrentUserAccountsTest. The result should look as follows:

image

Now lets run the Unit Test to verify the implementation. To do so choose Test in the menu->Windows->Test View. You should see Test View window and the Unit Test you have just created in it. Right click on it and choose “Run Selection”. The outcome should be present in “Test Results” window below:

image

Seems like it works. I can go off and implement the rest of the services this way so I could use it in my Web UI which is the next step.

Related Books