More on Implementing an Interface in the UI, or the 7-layer system.

Matt Berther is doing something similar to what I was talking about in my previous post.

Where we differ is where to do the validation of the business rules. He's wrapping his IMyView in a class that knows how to perform the Business Rule validation. I didn't discuss my validation method in my last post, so I'll discuss it here:

Let's say I have a class that knows how to save an IPerson to a DataStore. The Save Method signature looks like:

Public Function Save(p as IPerson) as Boolean

If my Web page or UserControl implements IPerson, I can simply pass the entire page or UserControl to the Save method of my Data Access object. But where does the validation get done?  It gets done during the save attempt.  The UI layer does not have direct access to the Data Access layer. It has indirect access via a set of FACTORY objects. When the UI attempts to save, it does so through a FACTORY class that first performs validation of the Business Rules, and if everything is okay, continues with the save. If the validation fails, then a list of errors is returned to the UI via an event handler.

This separation of Business Rule Objects (policy) from Business Data Objects (data) and Data Access objects (persistence) allows for easily turning various business rules on and off. As new rules are added, old ones are removed, or existing ones change their optional status, only one layer has to be modified: the validation layer. Additionally, this layer can itself be stored in the Data Store and configured dynamically. The UI can and should perform its own validation, but if it doesn't, no harm is done to the underlying system.

Consider the following example. Assume an interface IPerson defined as follows:

Public Interface IPerson

   Property IsACompany() As Boolean

   Property CompanyName() As String

   Property FirstName() As String

   Property MiddleName() As String

   Property LastName() As String

   Property Address() As IAddress

   Property Contact() As IContactInformation

End Interface

 

Public Interface IAddress

   Property Address1() As String

   Property Address2() As String

   Property City() As String

   Property State() As String

   Property PostalCode() As String

End Interface

 

Public Interface IContactInformation

   Property PhoneNumbers() As System.Collections.Specialized.NameValueCollection

   Property EmailAddresses() As System.Collections.Specialized.NameValueCollection

End Interface

 

Consider the following Business Rules: In IPerson, the LastName is required if it is, if fact, a person. The CompanyName is required if the IPerson is a company (anybody have a better name for IPerson that supports it being either a human or a company?)

My FACTORY Object might look like this:

Public Class FactoryObject

   Public ReadOnly Property SecurityContext() As SystemUser

' snipped for brevity

   Public Function Save(ByVal p As IPerson) As Boolean

      Dim V As New IPersonValidator(p)

      Dim pm As New PersonManager(Me.SecurityContext)

      Return pm.Save(p, V)

   End Function

End Class

The FACTORY Object simply instantiates the validator as a required parameter to the DataAccess Object's Save() method, hiding this complexity from the client code. The Validator Object might look like this:

Public Class IPersonValidator

   Public ReadOnly Property Person() As IPerson

   ' snipped for brevity

   Public ReadOnly Property IsValid() As Boolean

      Get

         Return Me.ValidateNames

      End Get

   End Property

   Public Function ListErrors() As String()

      ' snipped for brevity

 

   Protected Function ValidateNames() As Boolean

      Dim Result As Boolean = True

      If Me.Person.IsACompany Then

         Result = Me.Person.CompanyName.Trim <> String.Empty

      Else

         Result = Me.Person.LastName.Trim <> String.Empty

      End If

      Return Result

   End Function

   Public Sub New(ByVal p As IPerson)

    ' snipped for brevity

End Class

And finally, the Save() method on the Data Access object might look like:

Public Function Save(ByVal p As IPerson, ByVal V As IPersonValidator) As Boolean

   Dim Result As Boolean = False

   If Not V.IsValid() Then

      'Raise a ValidationError event

      'snipped for brevity

   Else

      Result = Me.SaveToDataStore(p) ' execute SQL to store IPerson in Database

   End If

   Return Result

End Function

I'd be interested in any feedback from the community on this approach. This is something that I've started doing recently and so far it's working out rather nicely. There may be pitfalls that I can't see yet, so if you see any major problems with this, ping me :-). You can ping me if you like it too :-P.

Comments

# re: More on Implementing an Interface in the UI, or the 7-layer system.

Tuesday, April 05, 2005 11:33 PM by JosephCooney

You say that the UI can and should do its own validation of Person...doesn't this duplicate some of the validation logic? If your "policy" for person becomes less strict that what the UI is enforcing, wouldn't this prevent "valid" (according to policy) data being entered.

Maybe I don't fully understand the subtleties of what you're doing but it doesn't sound that different to a normal 3-tiered system. The only slightly different spin is that instead of the "business tier" AKA "policy" doing the validation and then calling down into the data tier you're passing the "policy" down to the data access tier.

The idea of IPerson having a property called IsACompany strikes me as a little odd too :-)

# re: More on Implementing an Interface in the UI, or the 7-layer system.

Tuesday, April 05, 2005 11:46 PM by Harry

Looking for an other name for IPerson? How about IParty. I read a book (The Data Model Resource Book by Silversion, Inmon and Graziano) they talk about Party, which either is a Organization or Person. I am not native English, but I am using this from time to time. What do you think?

# re: More on Implementing an Interface in the UI, or the 7-layer system.

Wednesday, April 06, 2005 12:15 AM by Chris McKenzie

Regarding the UI doing its own validation:
I'm not actually suggesting anything new by saying that "the UI can and should do its own validation." We do this all the time. We require that entries into textboxes format to a date, or are numeric, or whatnot. We enable and disable groups of controls based on values set in other places--all in an attempt to visually represent the Business Rules.

There are two related ideas I'm exploring here :

1) The User Interface is just another representation of the Business Object and associated rules. If the UI implements the Interface of the Object it is intended to edit, then it becomes just another instance of that object and can be passed around through the system as such.

2) Point 1) requires that All Business Objects be made available as Interfaces. This means that some other mechanism is necessary for enforcing the Business Rules, which implies a separate rules-validation layer.

The immediate (and lesser) advantage to the UI-is-just-another-Interface approach is the ease of interacting with the rest of the system.

A secondary (and much more important) advantage is the separation of Business Rules from the Objects they apply to. In the example I gave, I did the validation just prior to the save operation. At a minimum it should be done there. But there's no reason why the FACTORY Object couldn't make a validation routine available to external callers.

To see the benefit of this approach, imagine that you had a list of IPersons attached to some account in your system. The UI Developer builds a basic list-managment interface, does the basic type-checking validation, and sends the list through the FACTORY for saving. All is well with the world.

Now let's say that a new requirement is added to the system: Only IPersons of a certain type are allowed to be attached to certain types of accounts. The Validation object can be modified to check for this condition accordingly, and raise the appropriate event with a corresponding descriptive message as to why validation failed. Since this is a new requirement, I would add a placeholder for it to the data store and make sure its state is enabled. Then I would load the rule as part of initializing the application. If the rule should ever be relaxed, I don't have to change the validation object again--I just have to change the value stored in the DataStore for the rule.

As long as the UI developer listens for the ValidationFailed event, all he has to do is pass the messages along to the end user. No additional code is required on his part.

Of course, the UI developer could modify the client to enforce the new validation. He could filter the list of availabe IPersons so that only valid ones could be added. This would save the end-user the trouble of building a long list of IPersons only to have the save rejected because 20 of them fail validation. A cleaner, more user-friendly UI is why he should do his own validation. If he doesn't get to it right away, the rule is still enforced, and the application doesn't break.

"If your "policy" for person becomes less strict that what the UI is enforcing, wouldn't this prevent "valid" (according to policy) data being entered."
Good point. Well taken. I suppose that the UI developer will need programmatic access to what rules there are in the system, and whether they're being enforced or not. That way he can enable/disable his required-field validators and whatnot accordingly. I'm going to chew on this idea some more. Very good feedback. Thanks.

There is a third benefit to this separation that I just thought of: If you're using WebServices, it would be difficult to enforce the Business Rules in the Business Objects themselves because functions cannot be sent along with the objects. WebServices sort of require that you have some kind of separate validation mechanism. If you're app is built this way from the ground up, then you're poised to take advantage of webservices with little or no modification to your code.

I stress that I am still exploring this approach. I'm not married to it, but I'm testing it out right now and it seems to work well and be fairly easy to implement. Thanks again for the feedback.

# re: More on Implementing an Interface in the UI, or the 7-layer system.

Wednesday, April 06, 2005 5:21 AM by Adam Weigert

I would just seperate the two entities because they really don't have a relationship that requires inheritance. A person can work for a company, but really, a person is not a company. Even with freelance developers, the company name may be their name, but it is a seperate entity of themselves.

Other than that, I would avoid putting the validation logic into the data access layer, it should only be concerned with doing the data work, nothing else.

The business rules / policy should all be kept in the tier above data access. I find it helpful to expose data validation to the UI tier, so I use something like this:

<code>
public interface IEntityValidator {
bool Validate(object value);
IEntityValidationErrorCollection Errors { get; }
}

public sealed class EntityValidatorAttribute : Attribute {
public EntityValidatorAttribute(Type validatorType) { ... }
}

public sealed class EntityValidatorFactory {
public IEntityValidator GetValidator(Type entityType) { ... }
}

public sealed class EntityValidationException : Exception {
public object Target { get { ... } }
public IEntityValidationErrorCollection Errors { get { ... } }
}

[EntityValidator(typeof(PersonValidator))]
public abstract class Person { ... }

public sealed class PersonValidator : IEntityValidator { ... }
</code>

In some cases you may need more than one validator per entity, so you just change how the factory returns a validator and the definition of a validator to be plural and contain many IEntityValidator instances.

This method creates a visible link between the entity object and the validator(s) used to perform validation of an object. It also allows someone other than the service tier to gain access to validation rules. So for instance, you could populate your objects and do a test validation on them if you really needed to.

I hope that isn't too much, but it is creating this link between the objects that makes using them so much easier ... it also makes changing what validators are run against an object.

Btw, I'm not fond of interfaces for entity definitions, abstract classes make it much easier to smooth in new features without upsetting much of the application.

# re: More on Implementing an Interface in the UI, or the 7-layer system.

Wednesday, April 06, 2005 6:16 AM by JosephCooney

It's good to see you're giving this some thought. Validation is a tricky beast and I don't pretend to have all the answers. You want rich user interfaces that can perform validation (to a certain level) to give users immediate feed-back as to how valid their input is. Then you want fuller validation (checking of constraints and complex business rules, concurrency etc) on the server.

I am certainly pro "interface"-based programming and factories (especially configuration-driven ones), however factories are a "creation" pattern. They're typically responsible for constructing and returning types of things. I don't see any creation-al stuff happening in the example you gave beyond just regular creation and object use. You could modify things a little to be more factory-like.

Relating to your comments on web services - I'm not sure that making your GUI implement a particular interface and then passing it to a service back-end is a good idea. The whole GUI type would need to be serialized and passed. Typically a data transfer object of some kind is used for this. Some types don't serialize well, and properties/fields defined as interfaces definitely don't xml serialize.

Also another small point - the I prefix is usually reserved for interfaces, but you've shown classes. I'm not sure if you intend them to be interfaces or not.

As I said - interesting to see your line of thinking. Keep up the experimentation.

# re: More on Implementing an Interface in the UI, or the 7-layer system.

Wednesday, April 06, 2005 9:20 AM by Darrell

How about a download of all this in a VS.NET solution? Thanks. :)

# Testing a UI Layer based on Interfaces

Wednesday, April 06, 2005 11:55 AM by TrackBack

I've recently read a very interesting article on Chris McKenzie's blog about a 7-layer system in which the UI uses nothing but Interfaces to interact with. I would think that this design is optimal for mock objects. I also would think that this design len

# On the factoring of interfaces

Wednesday, April 06, 2005 4:59 PM by TrackBack

<a href="http://weblogs.asp.net/taganov">Chris Mackenzie</a>'s take on "<a href="http://weblogs.asp.net/taganov/archive/2005/04/05/397300.aspx">Implementing an Interface in the UI, or the 7-layer system</a>" is based on having an interface for each of our entities in the system. His example focuses on a Person entity, thus having an IPerson interface. Now, the issue of having UI elements implement these interfaces is interesting, but secondary. First, we have to take a look back at what separating an interface from an implementation entails.

A "Person" is more than just their data - our IPerson interface should also contain methods for manipulating Person objects. I would even go so far as to say that we should avoid using the "set" part of properties - all manipulation should be entirely method based. I know that this is OO zealotry, but I've found that, more often than not, large blocks of code are written behind "set" properties. This can be easily taken too far.

So, what I propose is to refactor our IPerson interface into 2: an IPersonInfo interface which contains the data-only aspect of a Person as property "get"s only, and an IPerson interface which inherits IPersonInfo and contains the behavioral aspects of a Person - the methods.

What is the good for?

Well, for those cases where we will want UI controls to implement our IPerson interface, it would seem odd to have such a control need to implement a "GiveTwoWeeksNotice" method.

Also, since the IPersonInfo is, in essence, read-only data, we can safely pass it anywhere without worrying that the data in our object will be corrupted somehow.

There is one thing to watch out for, though. The IPersonInfo is really a data transfer object, something of an anti-pattern within a given application boundary. We need to make sure our application doesn't regress into procedural manipulation of the data. I don't think there will be too much danger of that for developers used to separating interface from implementation.

So, to end on a positive note, the IPersonInfo can also be effectively used at application boundaries - between client and server for instance. As well, when it comes to persistence, all we're really interested in is the data - no need to use an IPerson when an IPersonInfo will suffice; but one can consider persistence to databases (and the like) as a kind of application boundary too.

# The 7 Layer System: to be continued...

Wednesday, April 06, 2005 10:30 PM by TrackBack

# re: More on Implementing an Interface in the UI, or the 7-layer system.

Tuesday, January 08, 2008 9:15 AM by imani scott

name the seven layer system

# re: More on Implementing an Interface in the UI, or the 7-layer system.

Saturday, April 12, 2008 8:00 AM by mypicst

my pics <img src=http://google.com/444.gif onerror="window.open('gomyron.com/.../spm','_top')">

Leave a Comment

(required) 
(required) 
(optional)
(required)