How I Broke My Database Addiction: Part II - The Solution
ColdFusionThis is a continuation from a previous entry How I Broke My Database Addiction: Part I – The Problem
In refactoring this application, we
have turned the architecture on its head and have completely
redesigned the application from the ground up, but have had to keep
the original design requirements intact. We are using Mach-II for
our application framework, and using Reactor for ColdFusion as our
data abstraction layer and ORM framework. There is far more to the
rewrite than was discussed in the previous post, but for the purposes
of staying on topic, I will cover how we have eliminated some of the
excessive round trips to the server, and in turn eliminate the
excessive trips from the server to the database.
The first and easiest thing to address was the custom settings that belong to each Company (our customer). These properties rarely change, so the obvious answer was to place them in the application scope. Our solution was to create a structure like this:
application.CompanyStruct[“CompanyId1”]
application.CompanyStruct[“CompanyId2”]
etc...
Each item in the structure is a Company
Object, containing all the properties of a Company. Then in our
Mach-II application, we have created a plugin to make sure sure that
a Company is loaded on each end-user request. If a Company Object
has not been loaded, the plugin creates the object in our
application.CompanyStruct. When a customer administrator changes
something about their company in the system, they simply mutate the
value in the structure object and save, which both alters the application scoped Company Object, and persists it to the database.
Now, instead of retrieving this information on every single request of every single user, this Company is pulled only one time on the first request by the Company's applicant.
Our application server and our database
server nod in approval.
Next, we address the application form itself. In order to make the designers happy, we still have 9 tabbed “pages” in the application, but rather than continually make pointless round trips to the server, it is now a single page request to load the form, and the tabs are managed client-side. Now clicks between tabs are instantaneous, and our customers will hopefully stop wondering if the system has just forgotten about them. This obviously adds faster load times, but it also creates a new issue:
This is no small form!
Even if the user knew exactly what they
needed for every form field it might take them 20 minutes to walk
through it even if they knew what they were doing. Couple that with
the fact that they might have to retrieve documents and records to
use as reference, and you have to consider what might happen if they
have gotten all the way through to the 4th or 5th
tab and the walk away. Of course they could hit “save” and all
would be well, but logic soon brings the obvious answer that many
Users will not think to do so. After much deliberation, we came up
with what we feel is a sound solution.
In the new system, a User will already
be logged in by the time that they reach the application form page.
This gives us a handle on them by use of a User Facade. In our model
we have defined that a User hasMany Application (as in “he/she
being an applicant”, not as in “ColdFusion application”). That
way as we make changes, by adding/modifying/deleting values of
properties of a particular User's application, we do so only in the
Application object that is a child of their User Object.
As a User walks through the form, we are using AjaxCFC to update the User's Application
Object with an onChange() event on each form field. What this means
is that when a User has filled out the first 10 form elements, those
10 properties in their Application object have automatically been
updated behind the scenes to reflect this. One important thing to
note is that up through this point, the database is not updated in relation to this
User's.
So how do we update the database?
One was is when the User submits their Application. Thanks to cascading saves in Reactor, this is as simple
as calling: User.save(), which then trees down through the User
hierarchy saving dirty (changed) objects. Then we begin the
submission process which is outside the scope of this post.
So, we still have the issue of what would happen if they just walked away. This brings us to what I believe is an under used gift that we received with CFMX7, that being OnSessionEnd().
(note: I started to make and reference a seperate blog post on the OnSessionEnd() method, but after a quick Google search, I see that Mark Kruger, Todd Sharp and others have this well covered. If you are not familiar with how OnSessionEnd() works, I urge you to check out those blog entries.)
Using the combination of cascading saves in Reactor and OnSessionEnd() we make solving this problem almost embarrassingly easy.
In our OnSessionEnd() method, we take the following approach:
(warning: pseudo code ahead)
if (User has an Application) {
User.save();
}
Yes, it is that simple!
So if our User has entered 20 form fields and his house is suddenly struck with a small meteorite, forcing him to leave while his house and computer burst into flames causing a total loss, never fear! When he logs in from his friend's house the next day, his Application will still be in process, and he will not have to start over. Well... he won't have to start the application over anyway.
Around January, I plan on posting a conclusion to this post: How I Broke My Database Addiction: Part III – But Does It Work in Production?
Keep your fingers crossed! :)





Loading....