CSC/ECE 517 Spring 2025 - E2533. Reimplement the Team hierarchy
Wiki page for E2533 - reimplementing the Team hierarchy
Introduction
The Team hierarchy consists of classes that manage student teams within Expertiza. These teams can reserve topics and submit assignments. The hierarchy includes four classes: Team (the superclass), CourseTeam, AssignmentTeam, and MentoredTeam. Since all functional teams belong to one of the three subclasses, direct instances of the Team superclass should never be created.
CourseTeams remain intact throughout a course, collaborating on all assignments. While some instructors opt not to use them, others find CourseTeams beneficial, especially in Team-Based Learning environments. These teams can be converted into AssignmentTeams (and vice versa) as needed.
AssignmentTeams are formed specifically for individual assignments. However, if an assignment is configured to automatically assign mentors, teams are instantiated as MentoredTeams—a subclass of AssignmentTeam with a designated mentor guiding the group.
Objective
This project seeks to modernize and streamline Expertiza’s Team hierarchy, transforming it into a leaner, more intuitive system by eliminating legacy inefficiencies. The current design suffers from code bloat, tangled dependencies, and duplicated logic, particularly in the Team and AssignmentTeam classes, which host numerous overlapping methods. By rearchitecting the hierarchy, we will enforce cleaner inheritance, remove redundant functions, and introduce a more flexible team membership model—shifting from Users to Participants for better alignment with the platform’s evolving structure. The overhaul will emphasize modularity, maintainability, and scalability, ensuring a robust foundation for future enhancements. Through principled object-oriented design, we will redefine relationships between CourseTeam, AssignmentTeam, and MentoredTeam, optimizing their interactions while preserving functionality. The end goal is a decluttered, high-performance team management system that supports seamless collaboration across courses and assignments.
Requirements
The project requires the implementation of a well-structured team hierarchy with clearly defined responsibilities.
- Base Team Class must be created to serve as the parent class, encapsulating core team functionality such as managing members (adding/removing), checking team size, and verifying if a team is empty.
- Specialized subclasses that must be implemented with distinct behaviors while inheriting shared logic:
- CourseTeam.rb - teams persisting throughout a course
- AssignmentTeam,rb - assignment-specific teams
- MentoredTeam.rb - mentor-included variant of AssignmentTeam
- Team membership rules must enforce valid user assignments, ensuring course participants are correctly mapped to CourseTeams and assignment participants to AssignmentTeams.
- Team operations must support copying teams between categories (e.g., converting a CourseTeam to an AssignmentTeam) while maintaining data integrity.
- Comprehensive RSpec tests must validate all team operations, including edge cases like exceeding team limits or handling empty teams.
- Code readability and documentation are critical—methods should be self-documenting with clear naming conventions, supplemented by detailed comments explaining complex logic. The implementation must prioritize modularity, maintainability, and adherence to object-oriented principles to ensure long-term scalability.
Existing Issues
The current Team hierarchy in Expertiza suffers from several structural and functional deficiencies that hinder maintainability and scalability. The system exhibits excessive code duplication, particularly between the Team superclass and its subclasses (AssignmentTeam, CourseTeam), with redundant methods bloating the codebase (e.g., AssignmentTeam contains many methods that overlap with Team's methods). Poor inheritance design forces subclasses to reimplement logic that should be inherited, violating DRY principles. Team membership is tightly coupled to the User model, requiring a disruptive migration to the newer Participant system. Additionally, ambiguous team-type relationships complicate operations like copying teams between course and assignment contexts. The lack of modular boundaries creates brittle dependencies, while insufficient test coverage for edge cases (e.g., team size limits, empty teams) risks regression errors. These issues collectively result in a fragile, hard-to-extend architecture that necessitates a thorough redesign.
While code duplication, inheritance issues, and the User-to-Participant transition were addressed in the previous implementation, foundational work like base class implementation, membership rules, comprehensive testing, and documentation remains to be completed.
Design
Controller diagram
The following diagram illustrates the interaction between the controller, helper, and models in the proposed Team hierarchy reimplementation. The controller acts as the main entry point for all team-related API calls, delegating logic to helpers and interacting with the appropriate Team subclass.

TeamsController.rb: Method / API calls
# | Method | Endpoint | Description |
---|---|---|---|
1 | index | GET /teams/:type | Return a list of teams of a specific type (CourseTeam / AssignmentTeam) |
2 | show | GET /teams/:id | Return details of a specific team |
3 | create | POST /teams | Create a new team |
4 | add_members | PATCH /teams/:id/add_member | Add a participant to a team |
5 | remove_member | DELETE /teams/:id/remove_member/:participant_id | Remove a participant from a team |
6 | copy_to_assignment | POST /teams/:id/copy_to_assignment/:assignment_id | Copy a course team to a new assignment team |
7 | check_size | GET /teams/:id/size | Return current size of the team |
8 | Empty | GET /teams/:id/empty | Returns true/false if the team has no members |
TeamsHelper.rb methods
1. Valid_member?(user, team_type) – It will check if a user is valid for a given team type (e.g., participant type matches).
2. team_full?(team) – It will cehck if the team has reached max size.
3. sanitize_team_params() – It will ensure only permitted params are accepted for team creation.
4. mentor_of?(user, team) – It will check if a user is the designated mentor (MentoredTeam only).
5. copy_team_structure() – It will be used for copying team members and metadata.
Patterns
Template Method Pattern
This project will use the Template Method Pattern, which allows subclasses to override certain stages without changing the general structure. It defines the foundation of fundamental team-related processes in a base class. This pattern is especially useful for creating a uniform but adaptable team hierarchy architecture, where each team type adheres to the same overall process but implements its own unique logic.
Where Will It Be Used?
Base Class: Team
Generic methods like `add_member`, `remove_member`, `copy_to`, and `empty?` will be defined by the `Team` class. These methods will use placeholder or hook methods, such as `validate_participant_type` or `handle_special_roles`, which will be implemented by subclasses, while adhering to a standard structure.
Subclasses: CourseTeam, AssignmentTeam, and MentoredTeam
These subclasses will define unique validations and behaviors by overriding the hook methods:
- `CourseTeam` will validate participants in the course.
- `AssignmentTeam` will define assignment-specific logic.
- `MentoredTeam` will take precedence over the member addition rationale to handle mentor responsibilities.
Reason for Using Template Method:
- Promotes code reuse by including shared functionality in the main `Team` class.
- Enforces a consistent framework for all team operations.
- Allows customizable behavior in subclasses without duplicating code.
- Simplifies future enhancements by offering a scalable and maintainable solution (e.g., when introducing new team types).
SOLID Principles
Open/Closed Principle (OCP)
The Open/Closed Principle states that software entities should be open for extension but closed for modification. This principle will be a core part of the Team hierarchy reimplementation.
The Team base class in this project will be created so that when more team kinds are added, it doesn't need to be changed. Instead, by constructing subclasses like CourseTeam, AssignmentTeam, and MentoredTeam, developers will be able to expand the current structure.
Without changing the shared logic specified in the Team base class, each subclass will extend or override particular methods (such as add_member, validate_participant_type, or copy_to). With this design, the basic class will continue to be dependable and robust while providing room for expansion and personalisation
Overview of classes and Implementation
TeamsController
Inherits From: ApplicationController
Purpose: The TeamsController is our main interface for handling team-related requests. It orchestrates creating, showing, updating, and removing teams while also providing actions for specific operations like copying teams to assignments. By extending ApplicationController, it leverages Rails conventions for RESTful endpoints.
Key Actions (as referenced in the diagram):
- Teams:
- index: Fetches all teams and renders them.
- show: Retrieves and displays a team’s details.
- create: Persists a new team record.
- validate_team_type: Validates the team type before team creation to ensure it's among allowed types.
- Team members:
- members: Lists all members of a specific team
- add_member: Prepares data for adding a new team or adding members to an existing team.
- remove_member: Handles deletion of teams or the removal of a specific member from a team.
- Join requests:
- create_join_request: Creates a new join request for a team.
- join_requests: Lists all join requests for the team.
- update_join_request: Updates the status or details of a specific join request
TeamOperationsHelper
Purpose:
TeamOperationsHelper provides shared view or utility methods that can be reused across different views related to teams. This might include form helpers, formatting functions, or any specialized logic that doesn’t belong directly in the controller or model.
By extracting these methods into a helper, we keep our controllers lean and our views consistent.
Validation / Utility
Purpose: These are modules or classes that encapsulate common validation logic or utility functions. For example, methods may ensure that team size constraints are met or that certain data formats are respected. The TeamsController can call these utilities to keep business logic separate from controller actions.
Team
Purpose: Team is our base model, defining attributes and behaviors common to all team types. It maintains core relationships (like having many members) and implements fundamental methods that child classes can inherit or override.
Key Methods:
- add_member(user): Adds a user to the team, performing basic checks like duplicate membership.
- remove_member(user): Removes a user from the team.
- full?: Checks if team if full and returns a boolean.
- empty?: Checks whether the team has no members, useful for validating if a team is still active or viable.
- member?: Checks if a user is a member of the team.
- team_size: Returns the current count of team members.
- validate_membership: To be used by the subclasses.
Because Team is the parent class, it keeps the shared logic centralized, ensuring consistency across specialized team models.
AssignmentTeam
Inherits From: Team
Purpose: AssignmentTeam is designed for short-term or one-off teams formed specifically for an assignment. It enforces membership rules based on assignment criteria, such as whether a user is actually participating in that assignment.
Possible Additions/Overrides:
- copy_to_course_team(course): Copies details if the assignment team to a course team. Includes team name, team members and team size.
- validate_membership: Checks if user is enrolled in the assignment.
- type_must_be_assignment_or_mentored_team: Checks if the team type is either assignment team or mentored team.
By keeping assignment-specific logic here, we avoid mixing it with course-level concerns.
CourseTeam
Inherits From: Team
Purpose: CourseTeam is designed for teams that persist across an entire course. It validates the course membership of a user.
Additions:
- add_member(user): Ensures the user is eligible for the course team before joining.
- copy_to_assignment_team: Copies the details of a course team, consisting of team name, team size and team members to a new assignment team.
- validate_membership: Checks if user is enrolled in any assignment in the course.
- type_must_be_course_team: Checks if the team type is 'CourseTeam'
MentoredTeam
Inherits From: AssignmentTeam
Purpose: MentoredTeam extends AssignmentTeam by adding a designated mentor role. This can be especially helpful for assignments requiring expert oversight or guidance.
Additions:
- add_member(user): Ensures the user being added to the team is not already a mentor.
- assign_mentor(user): Sets a mentor for the team after confirming they meet certain criteria (e.g., mentor role).
- remove_mentor: Allows for unassigning a mentor if needed.
- mentor_must_have_mentor_role: Ensures that the chosen mentor is valid for the assignment and has the role 'mentor'.
By placing mentor logic in its own subclass, we keep assignment-level functionality clean while MentoredTeam handles the extra mentorship features.
Participant
Associations:
- belongs_to :team
- belongs_to :user
- belongs_to :assignment
Purpose: Participant acts as a linking model in some contexts, ensuring we can track which user belongs to which team for a given assignment or course. This model helps us keep membership records organized and may include additional data (like submission status or peer reviews).
Testing Plan
Implemented RSpec tests to validate all team-related operations. Positive and negative test cases have been covered through these test cases.
To successfully run the test cases, we would need to bypass the authentication controller, otherwise we will end up getting a 404 Unauthorized Error!
- Command to run tests for TeamsController:
bundle exec rspec ./spec/requests/api/v1/teams_spec.rb
- RSpec output:
- Command to run tests for AssignmentTeam model:
bundle exec rspec spec/models/assignment_team_spec.rb
- RSpec output:
- Command to run tests for CourseTeam model:
bundle exec rspec spec/models/course_team_spec.rb
- RSpec output:
- Command to run tests for MentoredTeam model:
bundle exec rspec spec/models/mentored_team_spec.rb
- RSpec output:
Team
Mentor
Sahithi Ammana
Team Members
- Dhruv Soni (dbsoni)
- Ananya Doshi (avdoshi)
- Udita Raychaudhury (uraycha)
Relevant Links
Repository: https://github.com/valorant-dhruv/reimplementation-back-end
Pull request: https://github.com/expertiza/reimplementation-back-end/pull/193
Demo Video: https://youtu.be/gKZXYk8HNWc