CSC/ECE 517 Spring 2022 - E2243. Refactor student teams functionality: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
(edited for clarity)
Line 1: Line 1:
This page contains information about Expertiza Issue E2243. Refactor student teams functionality which was a project in CSC517 Spring 2022.  
This page contains information about Expertiza Issue E2243. Refactor student teams functionality which was a project in CSC517 Spring 2022.  


Please see below for a description of the project.
Please see below for a description of the design of the project.


== Background ==
== Background ==
Users & Participants: Everyone who took the OODD class is a user in expertiza, and instructors can add users as participants in an assignment so that they can access it.
 
Almost everything within Assignments is done by participants, not users. That is, everything except teams_users. In the documentation, it can be noted that the team_users table references users instead of participants.
The Expertiza project is software to create reusable learning objects through peer review. It also supports team projects, and the submission of almost any document type, including URLs and wiki pages.
This anomaly causes problems with how student teams are rendered in the UI, and it doesn’t go well with the new functionality that were recently introduced.
 
Users & Participants: Everyone who took the OODD class is a user in expertiza, and instructors can add users as participants in an assignment so that they can access it to contribute, make changes and submit.
Almost all of the works within Assignments is done by participants, not users. That is, everything except teams_users. In the documentation, it can be noted that the team_users table references users instead of participants.
This anomaly causes problems with how student teams are rendered in the UI, and it doesn’t mix well with the new functionality that was recently introduced.


teams_users should be changed to teams_participants. the team_id, user_id mapping in this table should be changed to team_id, participant_id. All the references of user_id should be updated to use participant_id.
teams_users should be changed to teams_participants. the team_id, user_id mapping in this table should be changed to team_id, participant_id. All the references of user_id should be updated to use participant_id.
Line 12: Line 15:
== Schema Changes ==
== Schema Changes ==


In teams_users table add new column '''participant_id''' which is a foreign key from participants table and remove column '''user_id'''. Remove the '''user_id''' column '''only after data migration'''
In teams_users table, we can add a new column '''participant_id''' which is a foreign key from participants table and remove the column '''user_id'''. Remove the '''user_id''' column '''only after data migration'''


=== ER diagram for updated schema ===
=== ER diagram for updated schema ===
Line 20: Line 23:
=== Analysis ===
=== Analysis ===


Participants contains user_id attribute which is a foreign key from users table. teams_users contains user_id which is also a foreign key from users table. Although the user_id field corresponds to same attribute, we cannot use this attribute alone to find the respective participant id because user_id is not a primary key in the participants table. i.e. same user_id can be associated with multiple participants. This is because in expertiza, all the users are stored in users table but, for each assignment, for each user, an entry is added in participants table. So, each user will have an entry in participants tables for all the assignments.  
The Participants relation contains the user_id attribute which is a foreign key from users table. teams_users contains user_id which is also a foreign key from users table. Although the user_id field corresponds to same attribute, we cannot use this attribute alone to find the respective participant id because user_id is not a primary key in the participants table. i.e. same user_id can be associated with multiple participants. This is because in expertiza, all the users are stored in users table but, for each assignment, for each user, an entry is added in participants table. So, each user will have an entry in participants tables for all the assignments.  


Assignment contains participants list (Assignment has_many Participant). Since a user can have only one entry in the participants table for each assignment, (assignment_id, user_id) pair will have only one participant id associated with it.  
An Assignment contains a list of participants (An Assignment has many Participants). Since a user can have only one entry in the participants table for each assignment, (assignment_id, user_id) pair will have only one participant id associated with it.  


==== Finding Assignment ID By Team ID ====
==== Finding Assignment ID By Team ID ====


teams_users table contains team_id, user_id and duty_id. Each team is associated with an assignment. parent_id attribute in the teams table corresponds to assignment id. So, team_id in the teams_users table can be used to get the Team object from which we can fetch the assignment ID (parent_id).
The teams_users table contains team_id, user_id and duty_id. Each team is associated with an assignment. The parent_id attribute in the teams table corresponds to assignment id. So, team_id in the teams_users table can be used to get the Team object using which we can fetch the assignment ID (parent_id).


  # Code snippet to fetch assignment_id based on team_id
  # Code snippet to fetch assignment_id based on team_id
Line 33: Line 36:
==== Finding Participant ID By Assignment ID and User ID ====
==== Finding Participant ID By Assignment ID and User ID ====


Assignment object can be fetched using the assignment ID. Each assignment contains participants list. Participant object contains user_id attribute. Since, a user can have only one entry in participants table for an assignment, we can use user_id to find the user's participant_id from this list.
The Assignment object can be fetched using the assignment ID. Each assignment contains a list of participants. The Participant object contains a user_id attribute. Since, a user can have only one entry in the Participants table for an assignment, we can use user_id to find the user's participant_id from this list.


  # Code snippet to fetch participant_id based on assignment_id and user_id
  # Code snippet to fetch participant_id based on assignment_id and user_id
Line 40: Line 43:
=== Brute Force Data Migration ===
=== Brute Force Data Migration ===


The above mentioned code snippets can be used for each tuple in the teams_users table.
The above mentioned code snippets can be used for each tuple in the teams_users table.


  # Brute Force Code Snippet
  # Brute Force Code Snippet
Line 50: Line 53:


=== Efficient Data Migration ===
=== Efficient Data Migration ===
In the brute force approach, db calls are made multiple times inside the loop. Moving the db calls out of the loop will give us a more efficient solution.
In the brute force approach, database calls are made multiple times inside the loop. Moving the database calls out of the loop will give us a more efficient solution.


Steps:
Steps:
Line 61: Line 64:
# For all TeamUser objects, find the participant_id from the maps generated from the previous steps and update the participant_id attribute.
# For all TeamUser objects, find the participant_id from the maps generated from the previous steps and update the participant_id attribute.


In this approach,  we make a total of 3 db calls which is way better than the previous approach.
In this approach,  we make a total of 3 database calls which is considerably better than the previous brute-force approach.


== Code Changes ==
== Code Changes ==
user_id attribute is used in multiple places within the application. Since, the new schema changes does not include user_id attribute in teams_users table, all the references of user_id must be updated to use participant_id equivalent instead.
The user_id attribute is used in multiple places within the application. Since, the new schema changes do not include user_id attribute in teams_users table, all the references of user_id must be updated to use participant_id, which is its new equivalent instead.


=== Impacted Files ===
=== Impacted Files ===

Revision as of 13:59, 1 April 2022

This page contains information about Expertiza Issue E2243. Refactor student teams functionality which was a project in CSC517 Spring 2022.

Please see below for a description of the design of the project.

Background

The Expertiza project is software to create reusable learning objects through peer review. It also supports team projects, and the submission of almost any document type, including URLs and wiki pages.

Users & Participants: Everyone who took the OODD class is a user in expertiza, and instructors can add users as participants in an assignment so that they can access it to contribute, make changes and submit. Almost all of the works within Assignments is done by participants, not users. That is, everything except teams_users. In the documentation, it can be noted that the team_users table references users instead of participants. This anomaly causes problems with how student teams are rendered in the UI, and it doesn’t mix well with the new functionality that was recently introduced.

teams_users should be changed to teams_participants. the team_id, user_id mapping in this table should be changed to team_id, participant_id. All the references of user_id should be updated to use participant_id.

Schema Changes

In teams_users table, we can add a new column participant_id which is a foreign key from participants table and remove the column user_id. Remove the user_id column only after data migration

ER diagram for updated schema

Data Migration

Analysis

The Participants relation contains the user_id attribute which is a foreign key from users table. teams_users contains user_id which is also a foreign key from users table. Although the user_id field corresponds to same attribute, we cannot use this attribute alone to find the respective participant id because user_id is not a primary key in the participants table. i.e. same user_id can be associated with multiple participants. This is because in expertiza, all the users are stored in users table but, for each assignment, for each user, an entry is added in participants table. So, each user will have an entry in participants tables for all the assignments.

An Assignment contains a list of participants (An Assignment has many Participants). Since a user can have only one entry in the participants table for each assignment, (assignment_id, user_id) pair will have only one participant id associated with it.

Finding Assignment ID By Team ID

The teams_users table contains team_id, user_id and duty_id. Each team is associated with an assignment. The parent_id attribute in the teams table corresponds to assignment id. So, team_id in the teams_users table can be used to get the Team object using which we can fetch the assignment ID (parent_id).

# Code snippet to fetch assignment_id based on team_id
assignment_id = Team.find(team_id).select(:parent_id)

Finding Participant ID By Assignment ID and User ID

The Assignment object can be fetched using the assignment ID. Each assignment contains a list of participants. The Participant object contains a user_id attribute. Since, a user can have only one entry in the Participants table for an assignment, we can use user_id to find the user's participant_id from this list.

# Code snippet to fetch participant_id based on assignment_id and user_id
participant_id = Assignment.find(assignment_id).participants.find_by(:user_id user_id)

Brute Force Data Migration

The above mentioned code snippets can be used for each tuple in the teams_users table.

# Brute Force Code Snippet
TeamsUser.all.each do |teamsUser|
    assignment_id = Team.find(teamsUser.team_id).select(:parent_id)
    participant_id = Assignment.find(assignment_id).participants.find_by(:user_id teamsUser.user_id)
    teamsUser.update_attribute(:participant_id, participant_id)
end

Efficient Data Migration

In the brute force approach, database calls are made multiple times inside the loop. Moving the database calls out of the loop will give us a more efficient solution.

Steps:

  1. Load all the TeamUser objects.
  2. Load all the Team objects for all the team_ids in TeamUser object
  3. Create a map with team_id as key and assignment_id as value. The resultant map usage: map[team_id] = assignment_id
  4. Load all the Assignment objects for all the assignment_ids from the map in the previous step. Also eager fetch participants along with the assignments.
  5. Create a nested map with assignment_id and user_id as key and participant_id as value. The resultant map usage: map[assignment_id][user_id] = participant_id
  6. For all TeamUser objects, find the participant_id from the maps generated from the previous steps and update the participant_id attribute.

In this approach, we make a total of 3 database calls which is considerably better than the previous brute-force approach.

Code Changes

The user_id attribute is used in multiple places within the application. Since, the new schema changes do not include user_id attribute in teams_users table, all the references of user_id must be updated to use participant_id, which is its new equivalent instead.

Impacted Files

  1. teams_users_controller
  2. suggestion_controller
  3. assessment360_controller
  4. grades_controller
  5. join_team_requests_controller
  6. review_mapping_controller
  7. student_teams_controller

The respective test cases associated with these files must be fixed before fixing the code so that we can make sure that the proposed refactoring does not raise any new bugs.