CSC/ECE 517 Spring 2024 - E2418. Reimplement of due date.rb (Phase 2)

From Expertiza_Wiki
Jump to navigation Jump to search

E2418. Reimplement due_date.rb (Phase 2)

This page provides a description of the Expertiza based OSS project.



About Expertiza

Expertiza is an open source project based on Ruby on Rails framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages.

Introduction

We're refactoring the due_dates.rb in Expertiza, enhancing its codebase to adhere to DRY and design principles, improving readability, and reducing redundancy. Our focus includes changing class methods to instance methods and further testing.


Problem Statement

The reimplementation project entails:

  1. Refactoring due_date.rb: Enhancing code clarity, optimizing, and adding comments for unclear lines of code to improve maintainability and readability.
  2. Class to Instance Methods: Changing as many class methods to instance methods as possible.
  3. Testing with Rspec: Writing comprehensive tests using Rspec for each method to ensure functionality and integration, followed by a video demonstration showcasing the functionality of the reimplementation.

Class Diagram

Plan for Reimplementation of DueDate

Refactoring due_date.rb:

  1. Our refactoring initiative encompassed specific actions to improve code clarity, optimize performance, and bolster maintainability across our application.
  2. Firstly, we embarked on adding descriptive comments throughout the codebase. For instance, within the teammate_review_allowed? method, we included comments explaining the logic behind determining whether teammate review is allowed, making it easier for developers to understand the function's purpose and behavior.
  3. Secondly, we focused on enhancing variable and method names. In the done_in_assignment_round method, we renamed variables like due_dates to assignment_due_dates for clarity. Additionally, we renamed the copy method to duplicate_due_dates to better convey its functionality. Breaking down complex methods into smaller, focused functions was another key aspect. For example, in the done_in_assignment_round method, we extracted the logic for sorting and filtering due dates into separate helper methods, improving readability and maintainability.
  4. Optimization efforts involved reviewing database queries for efficiency. In the get_next_due_date method, we optimized the query by using ActiveRecord query methods or adding appropriate database indexes to speed up retrieval of due dates, especially in cases where assignments had staggered deadlines or multiple topics.
  5. Robustness enhancements included refining error handling mechanisms. For instance, in the due_at_is_valid_datetime method, we provided more informative error messages to guide developers in identifying and resolving invalid datetime inputs.
  6. Adherence to Ruby and Rails best practices was ensured throughout the refactoring process. We leveraged Rails conventions and built-in functionalities wherever possible. For example, in the set_flag method, we utilized ActiveRecord's update method with attribute names instead of update_attribute for improved code clarity and safety.
  7. To mitigate against regressions, we implemented thorough unit tests using frameworks like RSpec or Minitest. For instance, we wrote tests to verify the behavior of the set_flag method and ensured it correctly updated the flag attribute.
  8. Lastly, we documented our progress and collaborated effectively using version control systems like Git. Code reviews provided valuable feedback on adherence to coding standards and best practices, ensuring consistency and quality across the codebase. By undertaking these specific actions, we aimed to transform our codebase into a more readable, efficient, and maintainable state, facilitating ongoing development and enhancement of our application.

Class Methods to Instance Methods:

Transforming class methods to instance methods in the DueDate class requires considering how these methods will interact with the individual state of each instance, rather than operating at the class level. This transformation ensures that methods directly utilize the properties of an individual instance of the class. Here's a structured plan for each class method identified in the provided code:

  1. set_flag: Currently, as a class method, this might work by accepting an identifier for a DueDate instance (such as id) to locate and update a specific record. To convert it to an instance method, remove the need for an identifier parameter, and allow the method to directly manipulate the attribute of the instance it's called on. The signature would change from set_flag(id) to just set_flag, utilizing the instance's own data.
  2. due_at_is_valid_datetime: This validation method might currently be designed to accept a datetime string at the class level. Converting this to an instance method involves removing the parameter and directly checking the instance's due_at attribute to see if it is a valid datetime. This aligns better with Rails conventions where validations typically operate on instance data, ensuring that each object maintains its integrity before saving or updating.
  3. For the <=> (spaceship operator) method, converting this from a class method to an instance method aligns with its conventional use. The spaceship operator is intended to compare two instances of the same class. As an instance method, it would naturally compare the calling instance to another instance passed as a parameter, facilitating direct and intuitive comparison of attributes like due dates within the same class.

The transformation from class methods to instance methods typically means moving from a broad, generalized operation to focusing on the specific attributes and behavior of individual instances. This change often simplifies method signatures by eliminating the need for additional parameters to identify specific instances since the method naturally operates on the instance from which it is called. For functionalities like validations or comparisons (spaceship operator), this shift enhances practicality and aligns well with object-oriented programming principles in Rails, improving code readability and maintainability.

Old Code:

def self.teammate_review_allowed?(student)
	# time when teammate review is allowed
	due_date = current(student.assignment.due_dates)
	..

New Code:

def teammate_review_allowed?(student)
	# time when teammate review is allowed
    	due_date = self.class.current(student.assignment.due_dates)

Design Principles

Single Responsibility Principle (SRP):

Each method in the DueDate class was responsible for a specific task related to managing due dates. Methods were refactored to separate concerns such as setting due dates, retrieving due dates, and performing operations on due dates. For example, the set_duedate method focused solely on setting the due date for a task.

Don't Repeat Yourself (DRY) Principle:

Code duplication in the DueDate class was eliminated by extracting common functionality into helper methods or modules. Repetitive logic, such as date calculations or formatting, was refactored to promote code reusability and maintainability.

Encapsulation:

Data and behavior within the DueDate class were encapsulated within appropriate instance methods and attributes to minimize dependencies. Access to instance variables and methods was limited, promoting encapsulation and separation of concerns.

Dependency Inversion Principle (DIP):

The DueDate class depended on abstractions, interfaces, or higher-level modules instead of concrete implementations. Dependency injection or inversion of control was used to decouple the class from specific date manipulation implementations, allowing for flexibility and easier testing.

Testing

Testing with Rspec:

At our last testing iteration, we enhanced the readability, maintainability, and coverage of our DueDate model tests using RSpec. We achieved this by implementing several key strategies.

  1. Firstly, we organized our tests into contextual groupings using descriptive describe blocks. Each block encapsulated different aspects of the model's functionality, such as validation, manipulation, and behavior under specific conditions. This approach improved the readability of our test suite by providing clear and logical groupings. Additionally, we employed helper methods within the before(:each) block to streamline setup logic. These methods handled common setup tasks, such as creating due dates with various attributes, reducing repetition, and making the test setup more concise and understandable.
  2. To ensure test efficiency and isolation, we leveraged mocking techniques to simulate dependencies where necessary. For methods relying on complex associations or external data, we mocked the required dependencies rather than relying on real database records. This approach sped up tests and isolated the behavior under test.
  3. Furthermore, we paid attention to edge cases, ensuring comprehensive test coverage by including scenarios such as nil due dates, absence of response maps, and staggered deadline variations. By testing these edge cases, we ensured the robustness of our model and handled unexpected scenarios gracefully.
  4. Our test assertions were reviewed to ensure clarity and completeness. We verified that each test covered all expected outcomes and that assertions were clear and concise. For instance, in tests like copying due dates to a new assignment, we not only checked the count but also verified that due dates in the new assignment matched the originals.
  5. We also focused on error handling, testing both error and success paths thoroughly. For methods like due_at_is_valid_datetime, we ensured that error handling scenarios were covered comprehensively, guaranteeing robustness in the face of unexpected inputs. As our test suite grew, we monitored test performance using RSpec's profiling tools and optimized slow tests as needed. Additionally, we documented our tests with comments or descriptions to clarify the purpose of each test, aiding understanding for future maintainers and contributing to overall code quality.
  6. By implementing these strategies, we created a comprehensive, maintainable, and efficient test suite for our DueDate model using RSpec.


Team

Mentor
  • Kalyan Karnatı
Members
  • Atharva Patil (aspatil2@ncsu.edu)
  • Deepika Choudhary Patibandla (@ncsu.edu)
  • Dhruv Kolhatkar (dukolhat@ncsu.edu)

References

  1. Expertiza on GitHub
  2. GitHub Project Repository Fork
  3. The live Expertiza website
  4. Expertiza project documentation wiki
  5. Rspec Documentation
  6. Clean Code: A handbook of agile software craftsmanship. Author: Robert C Martin