3

I am about to start prototyping a 'quiz'-like web application that tests test-scoring methodologies, and I have an interesting architectural question.

Each quiz given to a user needs to use a set methodology to score it (e.g. Formula Scoring, Number Right Scoring, Negative Marking, etc.). A quiz consists of a series of questions, asked one by one, whose score is calculated after each question answered. The user's quiz score, among other things, is used to select the next question of appropriate difficulty for the user's progress so far, from a pool of theoretically infinite questions.

Beyond the scoring methodologies used to calculate the score, the 'next question' aspect of the program will be quite complex; it is tightly coupled with the structure of the data (e.g. a user will have to answer a medium-difficulty question from X topic... and more criteria).

I would like to separate out the logic of the scoring methodologies and 'next question' aspect of the application in order to keep the web application simple. The library could accept a set of inputs (e.g. the set of questions answered by the user), and the methodology to be used, in order to calculate the running score as well as select the next question. If I make changes to the library code that affects score calculation, the database would have incorrect data. I could re-calculate all scores after affecting such a change, but that could cause confusion to users who already got their final scores (this is just speculation, I don't know how 'open' of a project this will be).

The problem is that the logic is, as far as I have mapped it out thus far, tightly coupled to the structure of the data (e.g. a question has a list of topics, which could be used to choose the next question). Not only that, but the results given by the library need to be stored by the database for in-progress, as well as completed quizzes.

I would also like to make the logic of the application open source for academic purposes, so separating it out into a dependency would make this quite a bit easier (I don't necessarily want to open source the web application).

How can I decouple this data from the logic of the components so that I can separate it out as a dependency?

If necessary, I can whiteboard out the overall structure and goals of the application and update my question to make the description of my problem more clear.

| improve this question | | | | |
2

If this problem were purely in memory, we would use OOP techniques. However, given that you are trying to persistent scoring results, and are likely to develop new scoring methods and next-question finders that will involve new code and restarting your server, a scheme that applies to your persistence layer seems indicated.

Fundamentally, you need to develop and capture some metadata to keep things straight in your database. One piece of this metadata is an abstraction for versioning of scoring methods. And another is for capturing dependencies that next-question methods have.

For example, I'd suggest an immutable versioning scheme, where you can refer to the scoring method by the pair: name and version number, and, whenever you introduce a new scoring method or a scoring method change, you either introduce a new name or use a larger version number. Thus, we have a stable abstraction for identifying a scoring method, for allowing us to refer multiple scoring methods at the same time.

Realizing that the output type of scoring method may vary (say, from single numeric score on some scale, to multiple scores on multiple scales), you might also develop a scheme for referring to that score type (scoring method output type).

You also need to develop an abstraction for identifying dependencies for the next-question finders. I'd suggest capturing the set of required scoring methods and set of scoring method output types for each next-question finder. (At present there doesn't appear to be a requirement for persisting this information in the database, this so there is a wide variety of available methods for capturing this, ranging from data stored in code to dependency injection for external manipulation.)

As it seems you don't want user's scores to change after the first reporting, you will need to positively persist only either the original score as reported to the user, or the original scoring method (so you can regenerate that score to show the user).

You can choose to generally cache scoring method results, but realize that using the immutable version scheme, you could toss this cache and regenerate as needed. If you did cache results, they would be of the pair: result and (reference to or identity of) scoring method for any given answer.

You will need a manager that can generate the score results required for a given next-question finder, if not caching, and if caching, can detect the absence of certain scoring method results, and generate & cache those before using the finder.

| improve this answer | | | | |
0

Your logic works on data, if it worked on nothing, it would be useless.

So your logic is going to be coupled to your data; but, that doesn't mean it has to be coupled to the exact format of your data.

For example, there are many different kinds of lists: Arrays of objects, Linked lists of numbers, etc. To keep list oriented processing from becoming too coupled with the implementation of a List, the Java language makes List an interface. The logic then works on the List interface, hiding the details of how the list is implemented from the logic.

So the logic (algorithm) works on a generalized List, with some specific implementation of the list being added to the mix later.

There are other techniques, a visitor pattern is a bit more abstract than the list example above, but it also permits more complicated data structures (like trees).

Note that in an Object-Oriented programming environment, the fundamental belief is that data and logic which are "local" to an idea are coupled together in the same class. Consider this carefully, because while approaches like the ones mentioned above are sometimes necessary, they should never be the first choice for adding logic to data in an object-oriented environment. The first choice in an object-oriented environment is to add a method to the object.

| improve this answer | | | | |
0

I think that could be usefull to implement your requirements with a static class factory and several "set methodology to score" class providers.

The factory will concern to select the right provider based on some choice cryterion, for example the complessity of quiz(low, medium, high, etc..), the providers will concern to carry out the expected calculations.

In order to do that, you need to design an interface with the minimum methods to calculate the scores, I think that it should need only two methods (ie calculateScore() and getScore(), or better a property Score), then you could implements how many providers of your methodology to calculate the score as you want, having as inputs eg. an array of answers to the quiz, and the right answer for each question of that given quiz.

Then, provider can process that data to do some calculation of the score and assign a data with the score (decimal or an array of int).

In your client code, you may statically get the right provider reference by calling the factory with the choice cryterion (enumeration type) and assign its interface, then call method calculateScore passing it array of customer answers and right answers and then get the score by interface property.

Finally, you could go forward by your "next question" method..

| improve this answer | | | | |
0

Your project is a data-monster and as such you have to think first in terms of database design. Yes, you will end up using a database.

  • Your app will be data-driven.
  • I think you should carefully model a database.
  • Take all the neccessary time in this step.
  • Convert as much logic into data so your code is as trivial as it can be.
  • Model a database topics, dificulties, criterias, questions, rules, decision tables, etc.
  • Even store formulas so your code can apply them. YOu should be able to change formulas in a table and your code should not break.
  • Your code should do as the data tells it to do.
  • Make a conceptual ER first and discuss it A LOT. Fine-tune it. Do brain storming. Plot it in a big format and have it revised by seasoned database designers.

Only after you have done that will you have a better idea of what memory structures you will be using, and start modeling your OO design.

Bottom-line:

Don't think of decoupling yet. Put as much intelligence and data in tables, decision tables, etc. So your code will do as your database tells it to do.

| improve this answer | | | | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.