Sequencing
Along with Data Validation and Versioning, probably the most vexing
problem confronting the Assessment package is how to handle conditional
navigation through an Assessment guided by user input. Simple branching
has already been accomplished in the "complex survey" package via hinge
points defined by responses to single items. But what if
branching/skipping needs to depend on combinations of user responses to
multiple items? And how does this relate to management of data
validation steps? If branching/skipping depends not merely on what
combination of "correct" or "in range" data the user submits, but also
on combinations of "incorrect" or "out of range" data, how the heck do
we do this?
One basic conceptual question is whether Data Validation is a
distinct process from Navigation Control or not. Initially we thought
it was and that there should be a datamodel and set of procedures for
checking user input, the output of which would pipe to a separate
navigation datamodel and set of procedures for determining the user's
next action. This separation is made (along with quite a few other
distinctions/complexities) in the IMS "simple sequencing" model
diagrammed below). But to jump the gun a bit, we think that actually it
makes sense to combine these two processes into a common
"post-submission user input processing" step we'll refer to here as
Sequencing. (Note: we reviewed several alternatives in the archived
prior discussions here.
So here is our current approach. We note that there are two scopes
over which Sequencing needs to
be handled:
- intra-item: checks pertaining to user responses to a single item
- inter-item : checks pertaining to user responses to more than
one item; checks among multiple items will be built up pairwise
So how might we implement this in our datamodel? Consider the
"sequencing" subsystem of the Assessment package:
Specific Entities
- Item-checks (as_item_checks) define 1..n ordered
evaluations of a user's response to a single Item. These can occur
either via client-side Javascript when the user moves focus from the
Item, or server-side once the entire html form comes back. They are
associated (related) to as_items.
The goal is to have a flexible, expressive grammar for these
checks to support arbitrary types of checks, which will be input
validation ("Is the user's number within bounds?"; "Is that a
properly formatted phone number?"). One notion on check_sql. Instead of
using comparators we store the whole SQL command that makes up this
check with a predefined variable "value" that contains the response of
the user to the item the item_check is related to. If we want to make
sure the value is between 0 and 1 we store "0 < :value < 1" with
the check. Once an item is submitted, the system looks up the related
checks for this item and replaces in each of them ":value" with the
actual response.
Item Checks thus will have these attributes:
- item_check_id
- cr:name - identifier
- cr:description - Explanation what this check does
- check_location - client-side or server-side
- javascript_function - name of function that gets called when
focus moves
- user_message - optional text to return to user if check is
true
- check_sql - The sql that contains the check
- Inter-Item-checks (as_inter_item_checks) are
similar to Item-Checks but operate over multiple Items. They are server
sided checks that are associated with as_sections defining if a section
should be displayed or with as_items, defining if an item should be
displayed.
The goal is to have a way of telling if a section (or an item within a
section) shall be displayed or not depending on the section-checks.
This way you could say that you only display this section if the
response to item(1234) "Color of your eye" was "blue" and the response
to item(4231) "Color of your hair" was "red". Sadly we can't use such
an easy way of checking the ":value" as we do with item_checks, as we
do not know which item this refers to. Instead we store the item_id
like this ":item_1234". This way the check_sql would look like
":item_1234 == 'blue' AND :item_4231 == 'red'". Additionally other
variables might be defined by the API at a later
stage, e.g. ":percent_score", which would be replaced by the
current percentage value (a.k.a. score) that subject had in the test so
far (taken from the as_session_table). It might be interesting to pass
these variables along in the API,
this remains to be seen when actually implementing the system.
The Inter Item Checks also allow post section navigation (in contrast
to the pre section / item navigation mentioned above). If post_check_p
is true, the check will be done *after* the user has hit the submit
button. Depending on the result of the check (if it is true) the user
will be taken to the section given by section_id or to the item given
by item_id, depending whether this assessment is section based
(questions are displayed in sections) or item based (each item will be
displayed on a separate page). If there are multiple post checks for a
given section/item the order will be defined by the relationship (which
means this relationship has to have a sort_order attribute).
- inter_item_check_id
- cr:name - identifier
- cr:description - Explanation what this check does
- user_message - optional text to return to user
- check_sql - The sql that contains the check
- post_check_p - Is this a check that should be executed after
the user hit the submit button while answering the item / section.
- section_id - Section to call if we are in a section mode (all
items will be displayed in sections) and it is a post_check.
- item_id - Item to call if we are in "per item" mode (all
items will be displayed on a separate page) and it is a post_check.
- Potential extension: item_list - list of item_ids that are
used in the check_sql to speed up the check.