Facades, Repositories, and Model-View-Whatever

This week, in a couple different contexts, I saw the debate emerge as to whether or not an application’s UI can be developed prior to the data end-points it requires being available or finished. While obviously the completed end-to-end application cannot be finished, I see no reason why any UI, following any MV* pattern, cannot be completed independent of it’s data dependencies. By completion I mean rendering, input validation, and error handling related to all CRUD operations; as well as all concomitant unit tests. I also think this can be done even without any initial agreement on the end-points’ contracts, and whether the data is simple or complex. And I think it can be done easily with modern design patterns, and that the majority of people would agree with me and find it obvious. All that is required is an agreed upon specification or acceptance criteria that both the front-end and mid-tier developers adhere to.

Anyone doing UI development following a MV* (model-view-“whatever”) pattern can define a view-model that represents the data the UI tier receives from the mid-tier for rendering, or the data the UI submits to the mid-tier. This view-model can be a facade of any models defined in the mid-tier and need not map exactly to any one mid-tier model. For that matter, so long as the acceptance criteria is well-defined, we need not know how the mid-tier developer is going to define his models. Let’s call our view-model MyViewModel. MyViewModel will contain an identifier property that is also a facade, and let’s say we define it to be of type MyViewModelId. This allows it to be any primitive, composite or custom type.

Following from that, the UI developer can define an interface something like the following:

interface IDataRepository
{
    MyViewModelId Create(MyViewModel data);
    MyViewModel Read(MyViewModelId id);
    void Update(MyViewModel data);
    void Delete(MyViewModelId id);
}

At this point it should be obvious where this is going, but let’s continue for the sake of completeness. The UI developer would then define a class, say MyDevelopmentRepository, that implements the IDataRepository interface. The developer could stub these interface members, or even have them interact with a basic data store (even as simple as the file system). This class can be instantiated in the controllers (or handlers, or whatever) with the appropriate method being called such that he can build the UI as if he is calling the actual end-point(s). He can then define further repository classes that implement the IDataRepository interface, that represent different test and error cases, and he can swap these repository classes in place of the MyDevelopmentRepository in code to develop for different cases and provide his unit tests.

Then, when the end-point(s) are finally finished and we’re ready to do integration, the UI developer defines one final repository class–say MyMidtierRepository–that implements IDataRepository, and additionally has private members that maps the view-model to the end-point models (and vice versa), as well as serializing and deserializing the identifier. The CRUD operators would then internally call their corresponding end-points and map the view-model to the end-point model(s). This new repository is then swapped in, and we’re done (well, we should do integration testing). In addition to allowing the developer build the UI prior to the end-points(s) being completed, and allowing unit test to be built, this approach also insulates the UI code from any changes to how the data is retrieved. If at some point the data comes from a different source, we simply swap in a new repository.

And that’s it. I think it’s that simple. Perhaps I’m missing something, and I put this out there for anyone to point out to me what that may be. Else I really do see no reason why a UI can’t be developed independent of the end-point(s).

Advertisements