Friday, September 15, 2006

Business Objects and Value Objects

Encapsulation of data and behavior is one of the cornerstones of object-oriented programming. This basically means that a business object contains both the data and methods that manipulate the data. In the example below, a CreditCard object contains public method Authorize and public property AuthorizationCode. It's important for the object to establish a proper public interface. Authorization code value is returned by the payment processor; we wouldn't want clients to accidentally modify it. Therefore, I exposed a read-only property rather than a field.

public CreditCard
{
...
private string _AuthorizationCode;
public string AuthorizationCode
{
get { return _Authorizationcode; }
}

public bool Authorize(double amount) {...}
...
}


Object-oriented approach is great - within a single application tier. When designing a distributed application, we need to take other factors into consideration. Suppose, my application needs to display customer credit card data on a web page. Should I pass the CreditCard object to the web tier? Sure, it is possible, but the web tier only needs credit card data, not the behavior. Frankly, I wouldn't want web tier code to accidentally call Authorize() method. So, for the sake of security, we should somehow limit the objects. Performance is another concern, especially when passing objects between physical tiers. Regardless of which remote technology we use - web services, .NET Remoting, or COM+ - large objects with lots of methods and properties may not be ideal for this.

A simple and elegant solution is to combine essential business object data into a "value object". Individual data elements of the value object are exposed to business object's clients via public properties. Revised CreditCard class below demonstrates this approach. Note how overload of the constructor allows us to easily create a business object from a value object. We can extract value object just as easily and send it to another application tier.

public CreditCard
{
...
private CreditCardInfo _CCInfo;
public CreditCardInfo CCInfo
{
get { return _CCInfo; }
}

public CreditCard(CreditCardInfo info)
{
_CCInfo = info;
}

public string AuthorizationCode
{
get { return _CCInfo.Authorizationcode; }
}

public bool Authorize(double amount) {...}
...
}


public CreditCardInfo
{
...
public string CardNumber;
public DateTime ExpDate;
public string Authorizationcode;
public DateTime? LastTransactionDate;
...
}

Saturday, September 02, 2006

How Many Layers Is Enough?

A colleague recently asked my advise about the design of a web application he was working on. He showed me the draft: an elaborate architecture involving web application calling web service, which in turn invoked application server over .NET Remoting. The problem? This was an intranet application, with maximum number of concurrent users below 50. Had he implemented this original design, he would end up with an extremely scalable system which will never get a chance to realize its potential. On the other hand, the flip side of scalability - poor performance - will be obvious to any user.

So, how many layers is enough for an enterprise application? I am talking about physical layers, of course. With logical layers, approach is well-known: you would typically have data abstraction tier, business objects tier, and workflow tier. In addition, web application itself should be designed using Model-View-Presenter pattern .

With physical layers, it's far less straightforward. When we have all logical tiers running inside single application domain, we achieve best possible performance, because all calls are in-process. Once we place business and data tiers in a dedicated application server, we lose performance to out-of-process calls even if the application server is running on the same physical server. It really doesn't matter what specific remote calling mechanism we use: Web services, .NET Remoting, or Enterprise Services (COM+) - performance will suffer. When we move application server to a separate hardware, performance gets even worse because of network latency.

So why not run everything in-process? Well, many web application do just that - every web server in a farm has all logical tiers of the application. The downside is that web servers have to process both web application logic and business logic. This limits the number of HTTP requests each server could process and thus dramatically reduces system scalability. There are other drawbacks, too. Servers have to be really beefed up to handle the load, so hardware cost is high. Also, this deployment layout is inherently insecure: web servers are usually placed in a DMZ outside company firewall. Think of all the connection strings, encryption keys and other sensitive data that hacker could obtain by breaking into a web server.

By placing business and data tiers on separate physical layer (application server farm) we are trading performance to scalability. Web servers no longer have to process business logic, so they can handle much more page requests (and don't require high-end CPUs and tons of memory). Application servers can utilize connection pooling, object pooling and data caching in order to effectively support the web layer. Better yet, if we move from a homogenous app servers to more specialized "application services", we can improve performance even more by fine-tuning server configuration.

Coming back to the question I used as a title, there really isn't a universal rule. Number of physical layers can be different depending on scalability, performance, security, and other requirements of a particular application.