Overview

In my previous post, “Using server simulation for UI development” I discussed the motivation for developing an application that simulates server behavior as an aid for the main UI development. This is mostly relevant in cases where the main UI needs to interface the back end services through a layer that hides the details of a more complex database, hardware, business logic or any other types of services. But “using a simulator” (as nobel as this purpose may be…) is not a goal on it’s own. It’s only means to an end. What we want is an architecture that supports a development process where UI developers can work without interfering with the server development and vice verse. A “friendly” development process where the mutual dependency is cut to the minimum. Where the teams are so decoupled from each other that they may actually work from afar while keeping the need for mutual synchronization to the minimum, but at the same time still allowing for simple integration. We want to allow for an easy process, but at the same time, we do not want to have an expensive overhead.

So, lets start to bring this topic down to earth, lets talk architecture and code. Since I am mainly focused on WPF, my examples will revolve around WPF desktop application that consume server services. While the code may be specific to the .Net framework, the principles may be applied to various other environments.

The scenario

Ok, let’s assume I am starting to work for a new customer that requested an application “face lift” – to build a new WPF “face” to replace their old application. The business logic remains the same, the server remains the same, we just need a face lift. (This, by the way, is exactly how most of my work these days start). I will not bother you with the first steps, usually involving a process between one of my graphic designer partners and a contact serving as “product manager” on the customer side (IMHO, a fascinating topic on its own, BTW). Eventually I am handed a word document describing functionality and Photoshop documents describing the various screens in details. My next step is to sit down with the technical team and define the “contract”. I do not mean a legal contract, but an “object oriented interface” contract. The definition of how the application and the server will talk with each other. This usually involves 2 things:

  1. The interface between the client and the server.
  2. The Data model.

The solution structure

In code, this means that the client and the server are going to share a single project, a class library, that will contain both the interface and the data model:

Contract project structure

The contract is contained in a single class library project that is called “Contract”. This is the only DLL that will be shared by both the desktop application and the server. The contract is divided into 3 folders. The interface folder contains the single interface named IContract. This interface holds a list of all the actions that the client may perform on the server and vice verse. As far as the client is concerned, if there is an instance of an object that implements all the methods in IContract succefully, then all is well.

The methods in the interface usually involve some data flowing back and forth between the client and server. Both client and server should be familiar with these objects. So we strive to keep them as simple as possible. They should only serve as data structures. Each should be a container of properties, nothing more. They should be easily serializable so that they may be translated into a stream of bits and transferred through communication channels. These classes are the data entities and together they are known as the Model. The Model folder contains these data entities. Each Method in the contract may take several of these entities as parameters, and return other entities as results.

Sometimes however, there are methods that may need to return several results at once. For example a method that performs a sale. It connects a “Person” entity with a “Product” that was purchased, and may return both the person , the product, and the credit card confirmation code. Such methods may also return a success code or a description if the action failed. To allow a C# method to return more than one entity, we provide “Wrappers“. These objects are similar to data entities in implementation. They are also structures that serve only as containers of properties. They also need to be serializeable, but they are not really a part of the business logic “language”. They are not “stored” in the database, the real server may not be familiar with them and they only serve as means to package data together to serve for the client. That’s what the “Wrappers” folder contains.

The other projects

Once we have defined the contract DLL we need to define a few more projects. So here is what the initial skeleton will look like:

Solution Structure

MainApp is the WPF application I am writing. This is the new fancy UI. It will include a reference to the Contract class library and will talk to the server through it. Server is a class library that the server team develops as an abstraction layer. It will also include a reference to the Contract and will at least include a class also called Server which implements the IContract interface. To comply with the “Friendly development process” guidelines, the UI developers focus on the MainApp project. The server developers focus on the Server project development. Nobody touches code that does not belong to him, and the only time they actually need to synchronize what they are doing is when they modify the Contract package. MainApp, at some point during startup, will create an instance of Server.cs and use it as an implementor of the contract interface. The server class wraps all the services that the server may provide the client. It hides connectivity details, and all other stuff that UI developers should not be aware of and only exposes information that the application needs to present through methods and events.

The goal of this post is to talk about architecture that supports comfortable and efficient development process that also includes a server simulator. Well, this is where the SimApp project comes into play. SimApp provides a SimApi.cs class. This class is an alternative IContract implementation. But this class does not talk with any real web services, databases or hardware. Instead, it launches an additional WPF window that manages the way SimApi works. It implements the same API but the results are controlled by UI. we will dive into more details later, but lets just say that the user may run scripts, edit data entities, and generally simulate real server scenarios. In the world of friendly development process, the SimApp is owned by the UI team (which is lucky since its mostly a WPF application so server developers are not expected to be fluent in that code). But the behavior of the simulator may serve as guidelines to server developers because the statement is as follows: As long as the real server behaves just like the Simulator, we are certain that the application will behave in a similar way. This minimizes the number of surprises during integration, and everybody is on the same page. Everybody is happy.

When MainApp launches it needs to decide which instance to create and use as an IContract. The decision may be controlled by a configuration file, or by any other logic. If it comes to the conclusion that this is “real” environment, it generates an instance of Server.cs. Otherwise it generates an instance of SimApi, which launches the UI application and starts to act as a real server while communicating with the simulation UI to get the results of the actions that the MainApp is triggering. Once the instance is created, the application runs exactly the same in both cases – simulation and real server. In fact, except that initial step during startup, the application should be completely unaware that its not running against a real server. It’s important that the rest of the code does not have any “if” that checks this condition and run differently. This way, integration to the real server has a good chance of being completely transparent.

So this is the ideal. This is the process we aim for, and as long as we keep the SimApi up to date with contract modifications, the entire process will run smoothly. Of course, there is a cost. Maintenance of the simulator has its overhead, but if we manage to keep it small enough, it is well worth its price. From experience, teams that agreed to pay the initial price were rewarded later. As the application development progresses, the overhead of maintaining a simulation does not grow, (in fact, as the teams get used to it, the overhead even shrinks a little). But when you do not work in such a method, knowledge flow problems grow exponentially and at some point the overhead around developing, testing and integrating a new feature becomes so big that they inflate the development cost substantially, not to mention the effects of frustration on your development teams.

Summary

We have discussed the way that the product architecture may serve to support a more friendly and fluent Client – Server development process. We’ve seen a solution architecture that is comprised of a small package called “the contract” which encapsulates the minimum that both the client and the server need to know. The contract comprises of an interface containing all the methods that the client and server may call on each other, the data model that describes information on the business model and the wrappers that are simply packages that wrap data together to serve as method results. We have talked about how the client and server each uses the contract and on how to incorporate a simulator application that imitates the server both as means to test the UI development but also as ways to communicate between the team on the expected behavior of the simulator.

In the next posts, I’ll demonstrate the MainApp structure, and show exactly how it allows to easily work with an instance of the simulator during UI development and instances of the real server during Server development and production. I will also demonstrate how the SimApi is written and how it communicates with the simulator application.