Question

I am a big fan of NTiers for my development choices, of course it doesnt fit every scenario.

I am currently working on a new project and I am trying to have a play with the way I normally work, and trying to see if I can clean it up. As I have been a very bad boy and have been putting too much code in the presentation layer.

My normal business layer structure is this (basic view of it):

  • Business
    • Services
      • FooComponent
        • FooHelpers
        • FooWorkflows
      • BahComponent
        • BahHelpers
        • BahWorkflows
    • Utilities
      • Common
      • ExceptionHandlers
      • Importers
      • etc...

Now with the above I have great access to directly save a Foo object and a Bah object, via their respective helpers.

The XXXHelpers give me access to Save, Edit and Load the respective objects, but where do I put the logic to save objects with child objects.

For example:

We have the below objects (not very good objects I know)

  • Employee
  • EmployeeDetails
  • EmployeeMembership
  • EmployeeProfile

Currently I would build these all up in the presentation layer and then pass them to their Helpers, I feel this is wrong, I think the data should be passed to a single point above presentation in the business layer some place and sorted out there.

But I'm at a bit of a loss as to where I would put this logic and what to call the sector, would it go under Utilities as EmployeeManager or something like this?

What would you do? and I know this is all preference.

A more detailed layout

The workflows contain all the calls directly to the DataRepository for example:

public ObjectNameGetById(Guid id)
{
    return DataRepository.ObjectNameProvider.GetById(id);
}

And then the helpers provider access to the workflows:

public ObjectName GetById(Guid id)
{
    return loadWorkflow.GetById(id);
}

This is to cut down on duplicate code, as you can have one call in the workflow to getBySomeProperty and then several calls in the Helper which could do other operations and return the data in different ways, a bad example would be public GetByIdAsc and GetByIdDesc

By seperating the calls to the Data Model by using the DataRepository, it means that it would be possible to swap out the model for another instance (that was the thinking) but ProviderHelper has not been broken down so it is not interchangable, as it is hardcode to EF unfortunately. I dont intend to change the access technology, but in the future there might be something better or just something that all the cool kids are now using that I might want to implement instead.

projectName.Core

projectName.Business
    - Interfaces
        - IDeleteWorkflows.cs
        - ILoadWorkflows.cs
        - ISaveWorkflows.cs
        - IServiceHelper.cs
        - IServiceViewHelper.cs
    - Services
        - ObjectNameComponent
            - Helpers
                - ObjectNameHelper.cs
            - Workflows
                - DeleteObjectNameWorkflow.cs
                - LoadObjectNameWorkflow.cs
                - SaveObjectNameWorkflow.cs
    - Utilities
        - Common
            - SettingsManager.cs
            - JavascriptManager.cs
            - XmlHelper.cs
            - others...

        - ExceptionHandlers
            - ExceptionManager.cs
            - ExceptionManagerFactory.cs
            - ExceptionNotifier.cs


projectName.Data
    - Bases
        - ObjectNameProviderBase.cs
    - Helpers
        - ProviderHelper.cs
    - Interfaces
        - IProviderBase.cs
    - DataRepository.cs

projectName.Data.Model
    - Database.edmx

projectName.Entities (Entities that represent the DB tables are created by EF in .Data.Model, this is for others that I may need that are not related to the database)
    - Helpers
        - EnumHelper.cs

projectName.Presenation

(depends what the call of the application is)

projectName.web
projectName.mvc
projectName.admin

The test Projects

projectName.Business.Tests
projectName.Data.Test
Was it helpful?

Solution

+1 for an interesting question.

So, the problem you describe is pretty common - I'd take a different approach - first with the logical tiers and secondly with the utility and helper namespaces, which I'd try and factor out completely - I'll tell you why in a second.

But first, my preferred approach here is pretty common enterprise architecture which I'll try to highlight in brief, but there's much more depth out there. It does require some radical changes in thinking - using NHibernate or Entity framework to allow you to query your object model directly and let the ORM deal with things like mapping to and from the database and lazy loading relationships etc. Doing this will allow you to implement all of your business logic within a domain model.

First the tiers (or projects in your solution);

YourApplication.Domain

The domain model - the objects representing your problem space. These are plain old CLR objects with all of your key business logic. This is where your example objects would live, and their relationships would be represented as collections. There is nothing in this layer that deals with persistence etc, it's just objects.

YourApplication.Data

Repository classes - these are classes that deal with getting the aggregate root(s) of your domain model.

For instance, it's unlikely in your sample classes that you would want to look at EmployeeDetails without also looking at Employee (an assumption I know, but you get the gist - invoice lines is a better example, you generally will get to invoice lines via an invoice rather than loading them independently). As such, the repository classes, of which you have one class per aggregate root will be responsible for getting initial entities out of the database using the ORM in question, implementing any query strategies (like paging or sorting) and returning the aggregate root to the consumer. The repository would consume the current active data context (ISession in NHibernate) - how this session is created depends on what type of app you are building.

YourApplication.Workflow

  • Could also be called YourApplication.Services, but this can be confused with web services
  • This tier is all about interrelated, complex atomic operations - rather than have a bunch of things to be called in your presentation tier, and therefore increase coupling, you can wrap such operations into workflows or services.
  • It's possible you could do without this in many applications.

Other tiers then depend on your architecture and the application you're implementing.

YourApplication.YourChosenPresentationTier

If you're using web services to distribute your tiers, then you would create DTO contracts that represent just the data you are exposing between the domain and the consumers. You would define assemblers that would know how to move data in and out of these contracts from the domain (you would never send domain objects over the wire!)

In this situation, and you're also creating the client, you would consume the operation and data contracts defined above in your presentation tier, probably binding to the DTOs directly as each DTO should be view specific.

If you have no need to distribute your tiers, remembering the first rule of distributed architectures is don't distribute, then you would consume the workflow/services and repositories directly from within asp.net, mvc, wpf, winforms etc.

That just leaves where the data contexts are established. In a web application, each request is usually pretty self contained, so a request scoped context is best. That means that the context and connection is established at the start of the request and disposed at the end. It's trivial to get your chosen IoC/dependency injection framework to configure per-request components for you.

In a desktop app, WPF or winforms, you would have a context per form. This ensures that edits to domain entities in an edit dialog that update the model but don't make it to the database (eg: Cancel was selected) don't interfere with other contexts or worse end up being accidentally persisted.

Dependency injection

All of the above would be defined as interfaces first, with concrete implementations realised through an IoC and dependency injection framework (my preference is castle windsor). This allows you to isolate, mock and unit test individual tiers independently and in a large application, dependency injection is a life saver!

Those namespaces

Finally, the reason I'd lose the helpers namespace is, in the model above, you don't need them, but also, like utility namespaces they give lazy developers an excuse not to think about where a piece of code logically sits. MyApp.Helpers.* and MyApp.Utility.* just means that if I have some code, say an exception handler that maybe logically belongs within MyApp.Data.Repositories.Customers (maybe it's a customer ref is not unique exception), a lazy developer can just place it in MyApp.Utility.CustomerRefNotUniqueException without really having to think.

If you have common framework type code that you need to wrap up, add a MyApp.Framework project and relevant namespaces. If your're adding a new model binder, put it in MyApp.Framework.Mvc, if it's common logging functionality, put it in MyApp.Framework.Logging and so on. In most cases, there shouldn't be any need to introduce a utility or helpers namespace.

Wrap up

So that scratches the surface - hope it's of some help. This is how I'm developing software today, and I've intentionally tried to be brief - if I can elaborate on any specifics, let me know. The final thing to say on this opinionated piece is the above is for reasonably large scale development - if you're writing notepad version 2 or a corporate phone book, the above is probably total overkill!!!

Cheers Tony

OTHER TIPS

There is a nice diagram and a description on this page about the application layout, alhtough looks further down the article the application isnt split into physical layers (seperate project) - Entity Framework POCO Repository

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top