Defining a Contract Is Hard

Friday, November 18, 2005

We often talk about interfaces defining contracts.

interface UserValidator

{

    bool ValidateUser(string username, string password);

}

The above interface seems simple. We can go to any object implementing the interface and invoke the ValidateUser method. Pass in a username and password, and the object will tell us if the user is valid.

Still, there is plenty left unspoken. Take the abstract base class MembershipProvider in ASP.NET. MembershipProvider includes an abstract ValidateUser method, just like the one in the interface defined above. Here are the remarks for the method:

Takes, as input, a user name and a password and verifies that the values match those in the data source. ValidateUser returns true for a successful user name and password match; otherwise, false.
For successful validations, ValidateUser updates the LastLoginDate for the specified user.

Now we know a little more about our “contract”. If we implement ValidateUser we should update the LastLoginDate during a successful validation. If software were really a science, I think we’d have some language construct to announce and enforce the LastLoginDate update.

There’s more though – if you look at the two available implementations of MembershipProvider in ASP.NET (SqlMembershipProvider and ActiveDirectoryMembershipProvider), they have another side-effect in common. Both classes increment performance counters and raise health monitoring events when users authenticate and fail to authenticate.

To the client who needs a method to validate a user, these events and perfcounters are inconsequential side effects. The events don't change the state of my object, or the provider. However, if I was a sysadmin who monitors failed authentication events, but can’t get the events to work when I plug in a custom build membership provider, I’d consider something broken.

A contract is a simple concept, but the devil still waits in the details.


Comments
Keyvan Nayyeri Friday, November 18, 2005
The second parameter in your interface would be "string password", I think. Isn't it?
scott Friday, November 18, 2005
Oops, thanks Keyvan. See how hard this is? :).
Steve Campbell Friday, November 18, 2005
Lets assume that you are correct that the additional actions performed are part of the interface (some people might say they are implementation-specific).

From a test-driven perspective, I would want to mock out a class that updates the last login date, and other classes that update performance counters. I can use the mocks to write tests that assert that the relevant methods are called by a particular implementation.

Should I have multiple implementations, I can verify that they all meet the definition of my interface by generalizing the test to work against that interface.

In practical terms, my interface might more end up looking like this:<pre>
bool ValidateUser(string username, string password, ILoginAudit audit, IPerformance perf);
</pre>
That is much more expressive of what I expect the function to do, and my tests would fill in the gaps of the specific requirements.
Jeff Atwood Friday, November 18, 2005
> if you look at the two available implementations [..] they have another side-effect in common. Both classes increment performance counters and raise health monitoring events when users authenticate and fail to authenticate.

Perhaps this should be base class inheritance instead of contract-- the inherited base method would do all these "common" things.
scott Friday, November 18, 2005
Steve:

You make a great point. Microsoft doesn't provide us with unit tests for provider implementations - that would be a great idea though.

Jeff:

I was thinking of inheritance, or an interception pattern. The only problem is - the interceptor has to decide what to do based soley on the return value of a method call (which in this case is probably enough information to go on).
Comments are now closed.
by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!