Skip to content

Refactoring points calculation code #888

Open

Description

@skulonen

(From #880, delayed feedback)

There are several different places that find the final submission (best/last/marked as final) for one or many students. We should try to find a unified way of doing this, or at least reduce the number of different implementations. Especially now that the "delayed feedback" and "mark as final" updates have made the logic of finding the final submission much more complicated.

Here are the alternative implementations:

annotate_submitter_points

def annotate_submitter_points(

  • considers delayed feedback
  • considers grading mode
  • considers mark as final
  • works with multiple users at a time
  • works with multiple exercises at a time
  • not cached

UserExerciseSummary

class UserExerciseSummary(object):

  • does not consider delayed feedback (caller is required to filter points)
  • considers grading mode
  • considers mark as final
  • works with one user at a time
  • works with one exercise at a time
  • not cached

CachedPoints

class CachedPoints(ContentMixin, CachedAbstract):

  • considers delayed feedback
  • considers grading mode
  • considers mark as final
  • works with one user at a time
  • works with multiple exercises at a time
  • cached

filter_best_submissions

def filter_best_submissions(

  • considers delayed feedback
  • considers grading mode
  • considers mark as final
  • works with multiple users at a time
  • works with multiple exercises at a time
  • not cached

Activity

  1. added
    area: e-examImportant for electronic exams
    type: refactoringRefactoring of code without changing features
    area: exercisesRelated to exercises. Use other labels to focus issue to UI/backend
    effort: daysEstimated to take less than one week, from the creation of a new branch to the merging
    requester: teamThe issue is raised by a person inside the A+ developer team
    area: points/gradeIncludes points and grader per user and for all
    on Oct 19, 2021
  2. lainets commented on Jun 14, 2023

    @lainets
    Contributor

    CachedPoints is used for these things (mostly the first one):

    1. get user's points/submissions/best submission for a specific exercise (API and otherwise)
    2. get user's points/submissions/best submission for all modules and exercises in a course instance (in API and instance views)
    3. get user's points/submissions/best submission for some set of exercises speified by query params (in API)
    4. get user's points for whole course instance

    UserExerciseSummary is used for these things (mostly the first one):

    1. get user's best submission for an exercise (or a set of exercises using a loop)
    2. get all user's submissions for an exercise
    3. get user's points for an exercise (or a set of exercises using a loop)

    annotate_submitter_points just annotates the total points for an exercise (i.e. finds the best submission) and is used for the following:

    1. submitter list view
    2. all results page
    3. CourseAggregateDataViewSet

    filter_best_submissions is only used once in CourseSubmissionDataViewSet.

    Based on these, I propose that we store each exercise's data separately in the cache instead of having a single dump of the whole instance. The instance would also be cached but it would only contain the ids of the exercises instead of the actual data. If one needs both the exercises of an instance, they can just fetch twice: first to get the instance and then to get the exercises. Doing two fetches seems to be a normal thing for storing collections in memcached and should only have a trivial effect on performance.

    This method would make UserExerciseSummary trivial to consolidate in to the cache and works well with how CachedPoints is used currently. Whether CourseSubmissionDataViewSet could be implemented using the cache instead of filter_best_submissions requires a bit more thinking but at the very least we should be able to make a single best_submissions function that can be used by both the cache and CourseSubmissionDataViewSet. annotate_submitter_points would be harder to replace as it works in SQL but I'd take a look at implementing the three use cases using the cache instead. It might even make all results page faster and simpler.

    Also, we wouldn't need to invalidate everything after every small change. E.g. a submission would only invalidate the one exercise and the instance instead of all exercises and the instance.

  3. markkuriekkinen commented on Jun 20, 2023

    @markkuriekkinen
    Contributor

    @lainets Sounds good! To elaborate, does the course instance points cache item include any user-specific data or just the exercise ids? Does one exercise points cache item include one user's points in one exercise?

    Querying the exercise points cache is easy with the exercise id and the user id, right?

  4. self-assigned this
    on Jun 20, 2023
  5. moved this to In Progress in A+ sprints on Jun 20, 2023
  6. added this to the Summer 2023 milestone on Jun 20, 2023
  7. lainets commented on Jun 20, 2023

    @lainets
    Contributor

    @lainets Sounds good! To elaborate, does the course instance points cache item include any user-specific data or just the exercise ids? Does one exercise points cache item include one user's points in one exercise?

    The current code calculates some overall stats for the user that are stored at the instance level. Only caching the exercises would make the resulting architecture simpler but we'll have to test if calculating the aforementioned stats on demand is too slow.

    Querying the exercise points cache is easy with the exercise id and the user id, right?

    Yes

  8. markkuriekkinen commented on Jun 20, 2023

    @markkuriekkinen
    Contributor

    The current code calculates some overall stats for the user that are stored at the instance level. Only caching the exercises would make the resulting architecture simpler but we'll have to test if calculating the aforementioned stats on demand is too slow.

    That's OK. I didn't first realize that there are course-level user stats stored in the cache. I am not against having user-specific course-level points cache. Your suggestion sounds good (both the original suggestion and the later).

    Indeed, it is best to test the performance in practice to find the fastest solution.

  9. removed this from the v1.20 - Summer 2023 milestone on Oct 19, 2023
  10. moved this from In Progress to Todo in A+ sprints on Oct 19, 2023
  11. markkuriekkinen commented on Oct 19, 2023

    @markkuriekkinen
    Contributor

    #1231 fixed some parts of this issue. See the pull request description.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: e-examImportant for electronic examsarea: exercisesRelated to exercises. Use other labels to focus issue to UI/backendarea: points/gradeIncludes points and grader per user and for alleffort: daysEstimated to take less than one week, from the creation of a new branch to the mergingexperience: expertrequired knowledge estimaterequester: teamThe issue is raised by a person inside the A+ developer teamtype: refactoringRefactoring of code without changing features

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions