Don asks about mixing data and code

3 minutes read

Don asks what I think about mixing code and data "at storage" inside a database. I simply call that a "data service". I'll give you the long answer:

The "layers and tiers" story that we presented at our tour is very simple. Everything you can talk to has layers: a public interface, an internal implementation and services and resource access hidden inside the internal implementation. It starts as simple as this:

public class MyService : IMyService
{
    // from IMyService 
    public int MyMethod(SomeData data) 
    { 
        return InternalMyMethod(); 
    }

    protected int InternalMyMethod(SomeData data)
    {
         MyBackend backend = new MyBackend();
         // do something with data
         backend.SomeMethod(data);
         return 0;

    }
}

I can add any number of variations of similar interfaces to that class without having to rewrite my internal implementation allowing for flexible binding of public interfaces to my implementation. Whenever I go outside the class I am using an external service or resource that I am often rather tightly bound to. I can go through a factory, but in the end I need to call a method or create a certain message. This basic principle remains true as you look at code from higher and higher up:

public class MyWebService : WebService
{
    [WebMethod]
    public int MyWebMethod(SomeData data) 
    { 
        return InternalMyWebMethod(data); 
    }
   
    [WebMethod]
    public int MyLiberalWebMethod(XmlElement any) 
    { 
        // try to map XML to SomeData here
        return InternalMyWebMethod(data); 
    }

    protected int InternalMyWebMethod(SomeData data)
    {
         // the "service access" layer is the proxy-portion of MyService().
         MyService backend = new MyService();
         // do something with data
         backend.MyMethod(data);
         return 0;

    }
}

Now we have a web service that uses the above class as its backend service. (When you leave the triplet of layers you are hitting a tier boundary, by the way). MyWebService, implementing an endpoint appropriate for "far" scenarios, as a whole is the public interface for our internal implementation MyService.

[Note: "Far" is not only strictly geographical, but also related to platform, trust, organization and other hurdles]

public class MyRPCService : ServicedComponent
{
    public int MyRPCMethod(SomeData data) 
    { 
        return InternalMyRPCMethod(data); 
    }
    
    protected int InternalMyRPCMethod(SomeData data)
    {
         MyService backend = new MyService();
         // do something with data
         backend.MyMethod(data);
         return 0;
    }
}

If can have any number of public interfaces for my internal implementation. Now I also have an RPC service with appropriate infrastructure for "near" scenarios (ServicedComponent) for the same internal implementation. Any service that deals with data can serve as an external service or resource manager for any other service. Layers are a recursive thing.

Any service provides appropriate functionality for its context. A web service front deals with all matters that have to do with mapping data from and to XML representations of data within the limits of its contract and leaves all other work to a backend service that serves as internal implementation. Another web service, possibly using the same backend is again scoped in functionality by its contract. A web form application deals with rendering data into HTML and handling interactive events and, again, leaves the actual work to its backend. There is very few appropriate code that might be useful in multiple contexts.

Now back to Don's question:

Sure it's appropriate to have data and code mixed in the database. The public interface implementation tools for a database are called "stored procedure" and "view". The internal implementation tools are called "table", "index" and "view". The service and resource access interface is called SQL. A database is just another layered service. When I have a proper public interface to submit my data to or initiate operations on and if the internal implementation is appropriately hidden from me, it doesn't matter how the database is implemented. The database gods can throw indexes and tables around as they wish and they can make it look for me as if nothing ever changed -- if it is an OODBMS that's just fine, too. The OODB "objects" in the database just can't "leave the database" and can't implement functionality that is not immediately appropriate for the context they're in. Storing instances of a class that has methods knowing how to render its data onto spinning cube using Direct3D isn't appropriate; storing an instance of a class that has methods that implement functions to transition between two consecutive consistent states are appropriate. Any use of these methods outside the database is inappropriate again.

Of course, what one wants to do in the bigger picture is to have a proper data service on the client side, whose internal implementation deals with client caching and techniques to eliminate/limit locking as appropriate the the character of data. With that, a "data service" consists of two sub-services. One service lives in the database, one service lives on the client and they have a tier boundary between them. Still, from the outside, the "data service" is a black box with a single public interface (the client's) that serves as an  implementation tool for the services and resource access for layers higher up.

Updated:

Leave a Comment