For a while now I've been in "lurker" mode in all of the .NET community
blogs. One of the interesting transitions that's been going on is the demo code
for...well...just about everything including LINQ (whether it's the ADO.NET
Entity Framework, LINQ-to-SQL, etc) or even ASP.NET MVC which includes using
LINQ. Specifically, the removal of application "layers." Don't get me wrong, I
think logically there's great patterns of cohesion to support the whole ability
necessary for things like ASP.NET MVC's indirection. However sometimes, looking
at this code (not to mention writing it) gives me a sense of going backwards
into monolithic-type architecture. So I've been pondering from an
architecture/design perspective how to implement all of this cool stuff but at
the same time keep my mind at ease. So in playing around with Northwind (my
favorite example database of all time :) )
- Data Access Layer - Simply generate an ADO.NET Entity Framework Model
(.edmx)
- Business Interface - This layer contains our use-cases where the UI
leverages its services via messages, data structures, whatever makes sense.
- Common Library - Since I don't like the idea of ADO.NET EF objects as my
DTOs, I'd rather roll my own
POJO (C#)
objects (or even use DataTable or derivative of it).
//Common
Library Assembly DTO Class
namespace
Northwind.Common {
public class
CustomerEntity {
public string
Address { get; set;
}
public string
City { get; set;
}
public string
CompanyName { get; set;
}
public string
ContactName { get; set;
}
public string
ContactTitle { get; set;
}
public string
Country { get; set;
}
public string
CustomerID { get; set;
}
public string
Fax { get; set;
}
public string
Phone { get; set;
}
public
string PostalCode { get;
set; }
public string
Region { get; set;
}
}
}
//Business Interface (or Facade) Assembly
namespace
Northwind.BusinessInterface {
static public
class
CustomerInterface {
static public
List<Northwind.Common.CustomerEntity>
GetAll() {
using (var
nwEntities = new NorthwindAPI.NorthwindEntities())
{
var results = from
custs in nwEntities.Customers
select
new Northwind.Common.CustomerEntity()
{
Address = custs.Address,
City = custs.City,
CompanyName = custs.CompanyName,
ContactName = custs.ContactName,
ContactTitle = custs.ContactTitle,
Country = custs.Country,
CustomerID = custs.CustomerID,
Fax = custs.Fax,
Phone = custs.Phone,
PostalCode = custs.PostalCode,
Region = custs.Region
};
Debug.WriteLine(((ObjectQuery)results).ToTraceString());
return results.ToList();
}
}
}
}
//Client
Console App
namespace
TestClient {
class Program
{
static void
Main(string[] args) {
List<Northwind.Common.CustomerEntity>
custs = Northwind.BusinessInterface.CustomerInterface.GetAll();
custs.ForEach(c => Console.WriteLine(c.CustomerID));
}
}
}
This is nothing new as far as architecture ideas go - many designers are
running into the same philosophical conflict, but what is interesting is the
other questions it raises. When you've had tried-and-true methodologies for many
years, it's difficult to simply jump ship and feel good about compiling LINQ
queries into your code versus writing stored procs, or using ORM entities
throughout your application versus creating more vanilla DTOs. For
something intended as only a Web application, how much do I care about tier
separation versus logic-layers? We're assuming the application will end up only
being a Web application. If it turns into a system that then needs to become
published into a service, do you then refactor at that point, or do you plan
ahead by separating layers as I'm inclined to do? What is the maintenance
impact? How can we assume that our database is already designed and fleshed-out
enough to the point where it is OK to use an ORM against it? Does this mean we
design our database first? Generally it makes more sense to come up with our
use-cases first, which is more of the BusinessInterface layer (and UI to some
extent) before we identify what our system entity/attribute and data storage
look like. If we start with use-cases (or tests for our TDD enthusiasts), will
the database ever change during the development cycle? If so, will having to
refactor my model and the corresponding ORM-generated classes have a significant
impact on my team during development?
It is interesting stuff to think about. I'll keep lurking and see what others
come up with too. Drop me a line if you have any interesting opinions on the
subject. :)