CSC/ECE 517 Spring 2025 - E2532. Reimplement Missing ResponseMap Subclasses
Team
Mentor
- Anish Toorpu
Members
- Dennis Christman <dchrist2@ncsu.edu>
- Eleanor Maye <edmaye@ncsu.edu>
- Ryan Gallagher <rtgalla2@ncsu.edu>
Problem Statement
The ResponseMap concept in Expertiza exists as a hierarchy of several different Rails models, that utilize Singe Table Inheritance to allow for the use of polymorphism across the different types of Assignments that different ResponseMaps may map to. It maps from two participants, the reviewer and the reviewee, and the relevant assignment to the response object that contains the actual responses to the questions.
While part of the ResponseMap hierarchy has been reimplemented in the the new Expertiza backend, most of it has not. Our team has been tasked with the reimplementation of several of these. Below is the full ResponseMap hierarchy. Class names in bold are ones we are tasked with reimplementing, those in italics are for future projects, and those in neither have already been reimplemented:
- ResponseMap
- SurveyResponseMap
- AssignmentSurveyResponseMap
- CourseSurveyResponseMap
- GlobalSurveyResponseMap
- ReviewResponseMap
- BookmarkRatingResponseMap
- FeedbackResponseMap
- MetareviewResponseMap
- QuizResponseMap
- SelfReviewResponseMap
- TeammateReviewResponseMap
- SurveyResponseMap
The current implementation lacks a clear hierarchical structure for models, encapsulation of business logic, flexibility due to hardcoded values, and comprehensive testing. This results in maintainability issues, scalability problems, and poor integration with existing components. Additionally, while the current implementation is functional, it is poorly documented, making it difficult for someone new to the project to understand what the purpose of each subclass is.
Design Goal
We have several goals for this project:
- Utilize the existing hierarchy and ensure proper inheritance between models.
- Ensure that all business logic and validations are in the proper model. This includes both making sure that code is not unnecessarily repeated in a class and its subclasses and making sure that a class does not contain logic based on its subclasses.
- Move hardcoded values to an environment variables file, and replace instance of that value in the repo with the new environment variable.
- Develop extensive test coverage for each new model.
- Document each new model with clear comments on its use and methods.
Implementation
Implementation Plan
Our plan will be to start at the top of the hierarchy and find code that is repeated in different places and consolidate to the highest point of the hierarchy where it makes sense, looking at associations, validations and methods. An example of this are the lines:
belongs_to :reviewee, class_name: 'Participant', foreign_key: 'reviewee_id' belongs_to :assignment, class_name: 'Assignment', foreign_key: 'reviewed_object_id'
which appear in several different models, including the ResponseMap class itself. We will also identify methods such as the email method that appear in different subclasses that share much of the implementation and refactor the shared parts into a shared method.
Reimplementing Subclasses
Many of the subclasses are fairly similar with only slight changes in the values returned. An example of one of these is the FeedbackResponseMap:
FeedbackResponseMap
The FeedbackResponseMap class is a subclass of ResponseMap and represents feedback provided in response to a review. It establishes a belongs_to association with a Response object, referenced as review, using reviewed_object_id as the foreign key. The assignment method returns the assignment associated with the original review by accessing it through the review's map. The questionnaire method retrieves a questionnaire record that matches the reviewed_object_id. Lastly, the get_title method returns a predefined constant, FEEDBACK_RESPONSE_MAP_TITLE, that denotes a title for feedback response maps.
It is not part of a sub-hierarchy so it inherits directly from ResponseMap and only has associations that are different from the parent ResponseMap model.
Removing Hardcoded Values
Each bottom level subclass contains a get_title method that returns a string representing the a formatted name of the class. We moved these all to one module that we could include in the parent class, then use the constants from in the subclass methods. We examined other approaches, but felt this would be more extendable if other classes needed to follow the same pattern:
module ResponseMapSubclassTitles ASSIGNMENT_SURVEY_RESPONSE_MAP_TITLE = 'Assignment Survey' BOOKMARK_RATING_RESPONSE_MAP_TITLE = 'Bookmark Review' COURSE_SURVEY_RESPONSE_MAP_TITLE = 'Course Survey' FEEDBACK_RESPONSE_MAP_TITLE = 'Feedback' GLOBAL_SURVEY_RESPONSE_MAP_TITLE = 'Global Survey' METAREVIEW_RESPONSE_MAP_TITLE = 'Metareview' QUIZ_RESPONSE_MAP_TITLE = 'Quiz' REVIEW_RESPONSE_MAP_TITLE = 'Review' TEAMMATE_REVIEW_RESPONSE_MAP_TITLE = 'Teammate Review' end
Files Added/Modified
- survey_response_map.rb
- assignment_survey_response_map.rb
- course_survey_response_map.rb
- global_survey_response_map.rb
- review_response_map.rb
- bookmark_rating_response_map.rb
- feedback_response_map.rb
- meta_review_response_map.rb
- quiz_response_map.rb
- self_review_response_map.rb
- teammate_review_response_map.rb
- concerns/response_map_subclass_titles.rb
Testing Plan
Foremost, for Unit Testing, we will write tests to ensure that all validations are functioning as anticipated for each model. Furthermore, we will verify that all belongs_to and has_many associations are configured properly and ensure that no dangling records remain after creating or destroying records involved. Moreover, various testing measures will ensure that business logic operates correctly in the model, paying special attention will be given to methods shared across multiple subclasses. Lastly, any refactored code that incorporates environmental variables will be thoroughly tested to ensure that correct values appear in place of hardcoded ones.
Example Tests
This RSpec test suite verifies the functionality of FeedbackResponseMap model by including tests for the three main methods. The assignment test ensures that the model correctly returns the assignment linked to the feedback through the associated review. The questionnaire test checks that it retrieves the appropriate questionnaire, specifically one of type AuthorFeedbackQuestionnaire, based on the reviewed_object_id. Lastly, the get_title test confirms that the method returns the expected title constant defined for feedback response maps.