The Kickoff Meeting
A typical application kick-off meeting at the Center for Teaching and Learning includes a big-picture discussion on desired functionality and features. A recurring wishlist item is the desire to foster collaboration among students within the online space.
This collaborative learning wish is most frequently expressed by describing Google Docs functionality. The collaborative features of Google Docs, Sheets and Slides is the gold standard, offering not just synchronous editing but presence, comments and task assignments. These time-intensive implementations often feel intimidating to our small project teams.
Learning a Lesson
DESIGN Online is an interactive curriculum builder that guides education students to construct effective and engaging nutrition-related learning experiences. The application models the DESIGN Procedure, the brainchild of Professor Isobel Contento with the support of her colleague Associate Research Professor Pam Koch.
At the kickoff meeting, Profs. Contento and Koch both felt strongly that collaborative elements were non-negotiable application features. They have long assigned students to work together on lesson plans. They understood and valued the benefits of cooperative work. Our implementation plan included this feature as a high priority.
A DESIGN Online lesson plan is composed of a set of models. The primary model captures the basics, like the title and authors. Submodels capture more complex structured data such as the student’s theory model and planning matrix.
An initial implementation approach was to allow synchronous editing, and then detect and reconcile changes at save time. The complexity of the object model made this a daunting task. Data loss was a definite possibility with this approach. We could not tolerate lost or overwritten student work.
I decided instead to go with a read-only lock approach. A lesson plan author acquires the write lock when they access the lesson plan’s editable views. A co-author can then interact with the lesson plan in read-only mode.
The lock object records the current editor and the last access time.
class LessonPlanLock(models.Model):
editor = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL,
related_name='editor')
plan = models.OneToOneField(
LessonPlan, on_delete=models.CASCADE,
related_name='lock')
modified_at = models.DateTimeField(auto_now=True, null=True)
The access time is updated on every GET or POST request generated by the current editor. This approach does break the idempotency of the GET request. I’m comfortable with this noncompliance as only the “metadata” lock object is modified and does not cause side-effects. The base LessonPlan instance and its submodel instances are unchanged.
The current editor keeps the lock while active. A co-author can acquire the lock after 20 minutes of inactivity or if the current editor explicitly releases the lock. An editor sees an error message if they’ve lost the lock through inactivity when an update is attempted.
Missed a Spot
This system has worked well for the past year. But, a student team found a corner case in their work this fall. Here’s the scenario.
Student A edits the lesson plan, then walks away from their computer, leaving the lesson plan open.
Student B views the lesson plan an hour later. This student acquires the edit lock as Student A has been inactive for more than 20 minutes.
Student A returns to their open lesson plan in the morning. They have an older writable version on their screen. The student acquires the edit lock as Student B has been inactive for more than 20 minutes. The student merrily makes changes, and on save, overwrites Student B’s work.
Arg!
Timeout & Versioning
Luckily, I integrated django-reversion on the LessonPlan model and its related models. I was easily able to rollback the changes Student A made and recover Student B’s work.
The first and quickly implemented fix was to log out a user after 20-minutes inactivity. I used the django-session-security library to achieve this approach. However, 20 minutes is relatively short for an auto-logout. And, I get really annoyed when I’m summarily logged out of applications.
A better solution, I thought, could be found with django-reversion. As a LessonPlan instance changes, django-reversion stashes a serialized copy and a version number.
I updated the code to send the most recent version number down to the client. When the client tries to save a LessonPlan instance, the server verifies the version number is current, otherwise the update is rejected.
The editor receives a friendly message notifying them of the issue, prompting them to make a copy and asking them to refresh their browser to get the latest plan version. Problem solved.
For more on how we built DESIGN Online, see my previous blog post Interacting with Nutrition Theory.
Printed from: https://compiled.ctl.columbia.edu/articles/shared-editing/