| Intro | Part I | Part II | Part III | Part IV | Part V (4.1) | Part VI (6.0) | Summary |
Broadvision chooses to maintain this session 'state' information on the server. When you connect to a Broadvision site, it allocates a unique session 'ID' and uses it in every generated link and form so that with each incoming request, it can work out which of its currently active users is making the request. Naturally, an application built using Broadvision will need to maintain its own state information: an example from our travel site is the set of destination / price range / date range choices that you make as you wander around the site.
Broadvision provides a very simple interface for application data: an associative array of strings called the application data dictionary. In C++ terms, this is effectively map<string,string> but wrapped up in a session ID based lookup mechanism (i.e., map< SessionID, map<string,string> >). The base Broadvision class, Dyn_Object, provides 'store_app_data' and 'find_app_data' methods to access the application dictionary (thus hiding the session ID lookup - the object already knows about session IDs).
The first part of the application we tackled was the foreign currency section of the site. We needed to store the user's choices of currency and amounts for the conversion process. We tried to fit in with Broadvision's application dictionary by mapping our array of currencies, rates and amounts down to strings and then converting them back when we needed them. It worked but it was painfully ugly and very inefficient. I looked in vain for a more generic way to deal with state data - Broadvision had none.
After a bit of thought about the way Broadvision worked, I realised that I could solve the problem with static member data - the Broadvision CGI application ran continuously in the background so static data would have a suitable lifetime. So I wrote a small template class called 'SessionStore<T>' to store data of type 'T'. Since I could now store arbitrarily complex data structures on a per session basis, I decided to allow only a single object of each type to be stored for any one session and to have it accessed through a writable reference, i.e., the one and only copy of each state object for a session lived in its own 'SessionStore' container. We didn't bother rewriting the currency handler - after all, it worked and we were somewhat pressed for time - but we used the new 'SessionStore' for our search context objects and our customised shopping basket. It's a trivial template class and it seems an obvious omission from the Broadvision framework. Another design blind spot.
Naturally, I don't like this. If I'd wanted that architecture, I'd be programming in C. I like C++ because it can provide a better match to the problem domain by encapsulation. Part of our application generates emails from the web site to back office staff containing certain details of the user's profile (name, address etc). As part of our OO design, we wanted to pass a UserProfile object into the EmailRequest object so that it could interrogate the profile to fill out fields in the email message. Broadvision doesn't have a UserProfile object, instead it provides the equivalent of get_user_profile_field / set_user_profile_field as API calls. UserProfile became the first of many classes that we created to wrap up parts of the API so we could pass suitable objects around within our application. Like many such wrapping classes it is rather crude and was tedious to write:
class UserProfile
{
public:
UserProfile() { }
RWCString name() const
{ return get_user_profile_field("NAME"); }
UserProfile& name(RWCString n)
{ set_user_profile_field("NAME",n); return *this; }
// about a dozen similar methods
};
Now, I don't think of myself as an OO purist, nor do I think I'm an unreasonable man, but given a framework for an application where concepts such as
'visitor', 'profile', 'shopping basket' are absolutely key, doesn't it seem somewhat disappointing that equivalent classes are not provided within
the framework?
Using such a UML based CASE tool on a Broadvision project helps you separate the meat of the design from the continual workarounds that arise from struggling with the application framework. One of the first tasks was to create diagrammatic (and, hence, Java) representations of the main Broadvision classes on which to build the application-specific classes. It's been a much more pleasant way to work, being able to concentrate on the design and get that right. I'd like to think that the rigours of working within a strict OO design framework have made me a better designer overall and I'm off on a QA Training course for OOA/D using UML shortly so I'll probably write up specific pieces both on the course and the 'Together' tool in due course.