Multi-tier coding patterns with MV

Over the last couple months I have invested considerable time working on development patterns with MV. There is an ongoing struggle as to where code should be put, client, middle-tier, or server. There is no “right” place for all applications, though there are often wrong places.

This isn’t a complete look into this topic. It’s more of an overview. I hope I’m not being too vague. I’ll be happy to go more in-depth in follow-ups if required.

In one pattern for ASP.NET projects, I have abstracted data access completely from the UI into middle-tier classes, to ensure that UI controls are completely agnostic of where they get their data and about what happens to their data when it’s posted. For example, there’s none of this (pseudocode) :
ButtonSave_Click()
{
dbms = DBMS.Open()
file = dbms.FileOpen("foo")
file.WriteV(txtName.Text,txtCustID.Text,1)
dbms.Close()
}

Now it’s more like :
ButtonSave_Click()
{
BLL.Save( "Customer",
new CustSaveRequest( txtCustID.Text, txtName.Text, ...)
)
}

Even in the new middle-tier code you need to ask how much code you want outside of the DBMS vs inside. For example:
Save(CustSaveRequest request) { // knows nothing of UI
if( request.CustID.Length < 10 ) // handle key too short error }

Or do you do this? :
Save(CustSaveRequest request) {
dbms.Open
result =
dbms.Call("SaveCustomer",request.ID,request.Name...)
// result may contain code for key too short error
}

The question is, do you go all the way to the DBMS to find out that a key is too short, all in the name of keeping code centralized and in the familiar BASIC environment?

For better or worse, we have the choice as to where we put our rules, whether in client code, some middle tier, and/or in BASIC in the DBMS. In relational, we have the same choices: code can be put into the client, into a middle tier as above, in relational constraints, and/or in stored procedures, so we're really not that different from the other guys.

My answer is to give my clients greater ability to maintain their own code. So I am tending toward the second approach (giving BASIC in the DBMS more responsibilities), which results in a run-time performance hit, but puts all control into a familiar and easy to change location for my clients.

That said, there are no absolutes. Sometimes it doesn't make sense to go all the way to the server for things like data formatting validation or to ensure that a key isn't null. We need to do that on the server anyway! But we don't need to do it exclusively at the server. This is how this stuff is managed in non-MV environments.

Another aspect of this is the notion of how much organization do we put into a middle tier before we say "enough already!" ? For example, do we go to the DBMS and retrieve a Customer object which has a reference to a Contact object? We need to define those classes and their properties and relationships. Or do we retrieve a two string arrays, and maybe populate a DataSet or just a couple DataRows, to provide a little adhoc structure to be sent back to client code?

The question there is whether we feel a need to do something like this:
// 'customer' is object of type Customer
txtName.Text = customer.Name

or is it OK to do this?
// 'customer' is generic DataRow
txtName.Text = customer["Name"]

or even:
// 'customer' is string array
txtName.Text = customer[1]

The more elegant the code, the higher the cost. Each approach above has decreasing elegance. Then again, each approach above progressively increases the chances of bugs. What if we spell "Name" wrong? What if we accidentally reference array element 2?

So does it cost less to invest in elegance? With customer.Name based on a strongly typed class, we know at compile time if we have an error. Errors of this category will not get into the field, which saves a lot of time=money in post-production support. But by coding like that we now have two views of our data, one in the strongly typed class and one in our DBMS. If the view changes in one place we may need to change it elsewhere.

I'll say again, there are no absolutes. You can adopt one technique and use it successfully for all of your projects. But which technique might be better suited for another project? Are you wasting time=money coding the same way for all projects, with a one-size-fits-all hammer to bash every nail of a coding challenge? Or will you save money if you invest in your toolkit, so that you can use various techniques at different times? At what point have we had our fill of techniques and coding paradigms? When do we say "enough already, I need to bang out some production code"?

The decisions are up to each individual and often dependent on who will be maintaining the code after the initial development. I can only hope that I've made you aware of decisions that you can make, where previously you may not have been aware that you even had choices. And I'll be happy to expand on these concepts as necessary.

Leave a Reply