CSC/ECE 517 Spring 2024 - E2406 Refactor review mapping helper.rb: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 91: Line 91:
* Even though we tried hard in project 3, we couldn't cover all the code. In project 4, we're going to write more tests and use the test skeleton better.
* Even though we tried hard in project 3, we couldn't cover all the code. In project 4, we're going to write more tests and use the test skeleton better.


'''This section contains combined changes of project 3 and 4'''
'''This section contains changes and contributions to Project 4'''
----
----


* '''Issue #1:''' make a separate file for for chart related elements in <code>review_mapping_helper.rb</code><br>
* '''Issue #6:''' make a separate file for for chart related elements in <code>review_mapping_helper.rb</code><br>
'''Methods involved:''' <code>initialize_chart_elements()</code>, <code>display_volume_metric_chart()</code>, <code>display_tagging_interval_chart()</code>, <code>calculate_key_chart_information()</code><br><br>
'''Methods involved:''' <code>initialize_chart_elements()</code>, <code>display_volume_metric_chart()</code>, <code>display_tagging_interval_chart()</code>, <code>calculate_key_chart_information()</code><br><br>
'''Previous Code:''' All these methods were previously a part of the <code>review_mapping_helper.rb</code> when it should have its separate helper file<br>
'''Previous Code:''' All these methods were previously a part of the <code>review_mapping_helper.rb</code> when it should have its separate helper file<br>
Line 113: Line 113:
[https://github.com/expertiza/expertiza/pull/2663/files#diff-e2d994d01ebf485444d434603035df8e07eb9db7e625cfc42e7ad83f5b5c333e review_mapping_charts_helper.rb] <br>[https://github.com/expertiza/expertiza/pull/2663/files#diff-c41058c9caa3baa134bad689e28b7903d372d6a64388daccbb2e0ced964da568 review_mapping_helper.rb] <br>  
[https://github.com/expertiza/expertiza/pull/2663/files#diff-e2d994d01ebf485444d434603035df8e07eb9db7e625cfc42e7ad83f5b5c333e review_mapping_charts_helper.rb] <br>[https://github.com/expertiza/expertiza/pull/2663/files#diff-c41058c9caa3baa134bad689e28b7903d372d6a64388daccbb2e0ced964da568 review_mapping_helper.rb] <br>  
[https://github.com/expertiza/expertiza/pull/2663/files#diff-ab7a32a37c43b8681f146d9e7e420aee006c8a435e11c45944ac8a13f941c969 data_mapping_helper.rb]<br>
[https://github.com/expertiza/expertiza/pull/2663/files#diff-ab7a32a37c43b8681f146d9e7e420aee006c8a435e11c45944ac8a13f941c969 data_mapping_helper.rb]<br>
'''Contributor:''' Harsh Mauny
'''Contributor:''' Ravi Ghevariya
<br><br>
<br><br>
----
----


*'''Issue #2:''' change methods names starting with "get" to something appropriate<br/>
'''Methods involved:''' <code> get_data_for_review_report()</code>, <code> get_team_color()</code>, <code> get_link_updated_at()</code>, <code> get_team_reviewed_link_name()</code>, <code> get_awarded_review_score()</code>, <code> get_each_review_and_feedback_response_map()</code>, <code> get_certain_review_and_feedback_response_map()</code>, <code> get_css_style_for_calibration_report()</code><br/>
'''Previous Code:''' previous code used "get" in method names<br/>
'''Problem:''' All these methods used "get_" which is not ruby-like.  <br/>
'''Solution:''' change method names to a more ruby-like name that was appropriate for the given context<br/>
'''Contributor:''' Connor Davidson
<br><br>
----
----
*'''Issue #3:''' Several methods for feedback_response_maps, check docs to manage this confusion<br/>
*'''Issue #7:''' Several methods for feedback_response_maps, check docs to manage this confusion<br/>
'''Methods involved:''' <code> feedback_response_for_author()</code><br/>
'''Methods involved:''' <code> feedback_response_for_author()</code><br/>
'''Previous Code:''' previous code had an ambiguous variable name<br/>
'''Previous Code:''' previous code had an ambiguous variable name<br/>
Line 132: Line 124:
'''Solution:''' refactor the variable name to be more easily understood and add comments to give a clear explanation for why it exists<br/>
'''Solution:''' refactor the variable name to be more easily understood and add comments to give a clear explanation for why it exists<br/>


'''Contributor:''' Connor Davidson
'''Contributor:''' Manan Patel
<br><br>
<br><br>
----
----


*'''Issue #4:''' The method <code>sort_reviewer_by_review_volume_desc</code> should be generalized so that it can sort by any metric, not just review volume. Other metrics might include number of suggestions, or number of suggestions + number of problems detected. This method should not be counting the number of review rounds! Since other places in the code will need to know the number of review rounds, it should be calculated somewhere else in the system.<br/>
*'''Issue #5:''' The method <code>sort_reviewer_by_review_volume_desc</code> should be generalized so that it can sort by any metric, not just review volume. Other metrics might include number of suggestions, or number of suggestions + number of problems detected. This method should not be counting the number of review rounds! Since other places in the code will need to know the number of review rounds, it should be calculated somewhere else in the system.<br/>
'''Methods involved:''' <code>sort_reviewer_by_review_volume_desc</code><br/>
'''Methods involved:''' <code>sort_reviewer_by_review_volume_desc</code><br/>
'''Problem:''' Currently the method sort_reviewer_by_review_volume_desc sorts the reviewers in descending order but only considers one metric which is review volume which makes it very specific and it cannot be used if we want to sort by other metrics<br/>
'''Problem:''' Currently the method sort_reviewer_by_review_volume_desc sorts the reviewers in descending order but only considers one metric which is review volume which makes it very specific and it cannot be used if we want to sort by other metrics<br/>
Line 150: Line 142:
[https://github.com/expertiza/expertiza/pull/2663/files#diff-10395a909ed1f2034b4a4c8f57c0e30382d9492e0b16bb6fe6fb91a424f6f034 _review_report.html.erb] <br>
[https://github.com/expertiza/expertiza/pull/2663/files#diff-10395a909ed1f2034b4a4c8f57c0e30382d9492e0b16bb6fe6fb91a424f6f034 _review_report.html.erb] <br>
[https://github.com/expertiza/expertiza/pull/2663/files#diff-1f05f505eaa5edaf0790cdeb6e774cc499685cce4edf12b253ecd358ce710582 review_mapping_helper_spec.rb]<br><br>
[https://github.com/expertiza/expertiza/pull/2663/files#diff-1f05f505eaa5edaf0790cdeb6e774cc499685cce4edf12b253ecd358ce710582 review_mapping_helper_spec.rb]<br><br>
'''Contributor:''' Harsh Mauny
'''Contributor:''' Kanishk Harde
<br><br>
<br><br>
----
*'''Issue #5:''' The method <code>list_review_submissions</code> is not clear in terms of its utility
'''Methods involved:''' <code>list_review_submissions</code><br/>
'''Problem:''' It is not clear what the method does, where its used and if it can be replaced.<br/>
'''Solution:''' Comments (shown below) have been added to explain the usage of the method both at the method call in the partial <code>_review_report.html.erb</code> and the method definition in <code>review_mapping_helper.rb</code>
<code>review_mapping_helper</code> code snippet
<pre>
# Extracts the files submitted for a particular pair of participant and reviewee
  def list_review_submissions(participant_id, reviewee_team_id, response_map_id)
    participant = Participant.find(participant_id)
    team = AssignmentTeam.find(reviewee_team_id)
    html = ''
    unless team.nil? || participant.nil?
      # Build a path to the review submissions using the team's path and the response map ID
      review_submissions_path = team.path + '_review' + '/' + response_map_id.to_s
      files = team.submitted_files(review_submissions_path)
      html += display_review_files_directory_tree(participant, files) if files.present?
</pre>
<code>_review_report</code> code snippet
<pre>
# Following Table entry displays review submissions for specific reviewer and reviewee
<%= list_review_submissions(reviewer.id, reviewer_map.reviewee_id, reviewer_map.id) %>
<!--Hard-coded Dr.Kidd's question in order to display link.-->
<!--later we can create a hyperlink question type to deal with this situation.-->
<%= list_hyperlink_submission(reviewer_map.id, 5386) if Assignment.find_by(id: @id.to_i).try(:course).try(:instructor).try(:name) == 'Jkidd'%>
</div>
</pre>
'''Justification for keeping the method:''' <br>
-> The method has been added to the helper to reduce the complexity of logic in the views which is inherently good programming practice<br>
-> It builds the parameters required to feed into <code>display_review_files_directory_tree</code> method - a piece of logic that otherwise would have reduced the readability of the code in the partial<br>
-> Although the helper is just used at one place, its necessary to generate review report tables and hence seems to be the appropriate solution in terms of both functionality and code readability<br>
'''All links related to these changes:'''<br>
[https://github.com/expertiza/expertiza/pull/2663/files#diff-c41058c9caa3baa134bad689e28b7903d372d6a64388daccbb2e0ced964da568 review_mapping_helper.rb] <br>
[https://github.com/expertiza/expertiza/pull/2663/files#diff-10395a909ed1f2034b4a4c8f57c0e30382d9492e0b16bb6fe6fb91a424f6f034 _review_report.html.erb]<br><br>
'''Contributor:''' Aditya Joshi
<br><br>
----
*'''Issue #6:''' The Last 3 Classes in review_helper need to be reviewed<br/>
'''Methods involved:''' <code>initialize</code>, <code>reviews_needed</code>, <code>reviews_per_team</code>, <code>reviews_per_student</code> (separate methods for both the sub classes)<br>
'''Problem:''' The file ends with three small classes being defined. There are no comments at all to explain what is being done<br/>
'''Solution:'''The usage of the three classes was traced back to assignment views and ReviewMappingController. It is evident that these classes have been used to encapsulate the logic for different review strategies in the system. Some comments have been added to explain the functionality of these classes.<br><br>
'''review_strategy classes'''<br><br>
[[File:E2353-Issue-6.png|900px]] <br><br>
'''Further explanation of the methods:'''<br>
<code>reviews_needed</code> :  Calculates the total number of reviews needed for all teams/participants<br>
<code>reviews_per_team</code> : Calculates the number of reviews each team should receive<br>
<code>reviews_per_student</code> (for StudentReviewStrategy) : Specifies the number of reviews each student should perform<br>
<code>reviews_per_student</code> (for TeamReviewStrategy) : Specifies the number of reviews each student should perform based on team assignments<br><br>
'''All links related to these changes:'''<br>
[https://github.com/expertiza/expertiza/pull/2663/files#diff-c41058c9caa3baa134bad689e28b7903d372d6a64388daccbb2e0ced964da568 review_mapping_helper.rb] <br><br>
'''Contributor:''' Aditya Joshi
<br><br>
----
'''Issue #7''': method get_data_for_review_report marshals a lot of data together and passes back a data structure. It is used in views/reports/_review_report.html.erb, but it is quite difficult to see how the data is being displayed.
'''Methods involved:''' <code> get_data_for_review_report </code>
'''Problem:''' The method is returning two values and the purpose for the method is ambiguous<br/>
'''Solution:''' Break this method into two separate methods that return each of the component parts of the ambiguous return value<br><br>
'''Further explanation of the methods:'''<br>
<code> get_data_for_review_report </code> : Returned an array of two distinct values. This method was refactored into two separate methods that each return one of the values from the initial state. <br>
'''All links related to these changes:'''<br>
[https://github.com/adityajoshi1114/expertiza/pull/16] <br><br>
'''Contributor:''' Connor Davidson
<br><br>
----
*'''Issue #8:''' Refactoring the methods providing color coding in review report<br/>
'''Methods involved:''' <code>team_color</code>, <code>obtain_team_color</code>, <code>check_submission_state</code><br/>
'''Problem:''' following are the problems here as stated by the task <br/>
* American work color has to be used everywhere instead of colour
* The readability and understandability of the code is less
* no proper comments to explain what is going on in the code
* The color coding requirements are met that are, team review is coded as red if review is not completed and blue indicates that the review grade is not assigned or updated. In case the reviewer did not have anything to review in the latest round, and should not be downgraded for not re-reviewing the work, these reviews should be coded green.
Below is the original code
<pre>
def team_color(response_map)
    # Storing redundantly computed value in a variable
    assignment_created = @assignment.created_at
    # Storing redundantly computed value in a variable
    assignment_due_dates = DueDate.where(parent_id: response_map.reviewed_object_id)
    # Returning color based on conditions
    if Response.exists?(map_id: response_map.id)
      if !response_map.try(:reviewer).try(:review_grade).nil?
        'brown'
      elsif response_for_each_round?(response_map)
        'blue'
      else
        obtain_team_color(response_map, assignment_created, assignment_due_dates)
      end
    else
      'red'
    end
  end
  # loops through the number of assignment review rounds and obtains the team color
  def obtain_team_color(response_map, assignment_created, assignment_due_dates)
    color = []
    (1..@assignment.num_review_rounds).each do |round|
      check_submission_state(response_map, assignment_created, assignment_due_dates, round, color)
    end
    color[-1]
  end
  # checks the submission state within each round and assigns team color
  def check_submission_state(response_map, assignment_created, assignment_due_dates, round, color)
    if submitted_within_round?(round, response_map, assignment_created, assignment_due_dates)
      color.push 'purple'
    else
      link = submitted_hyperlink(round, response_map, assignment_created, assignment_due_dates)
      if link.nil? || (link !~ %r{https*:\/\/wiki(.*)}) # can be extended for github links in future
        color.push 'green'
      else
        link_updated_at = get_link_updated_at(link)
        color.push link_updated_since_last?(round, assignment_due_dates, link_updated_at) ? 'purple' : 'green'
      end
    end
  end
</pre>
<br/><br/>
'''Solution:''' First we understood the color coding scheme based on the references provided to us and based on which the code was refactored to address the problem. Below are the changes that were made
* The colour word was replaced by color for consistency
* In order to improve the readability  the cognitive complexity and branching was reduced by using less if-else block and further dividing the method into multiple block.
* comments were added providing an explanation of what the code does
* making sure proper color get assigned based on the review status
* better variable and method names wherever needed.<br><br>
[[File:E2353-issue-8-updated-team-color.png|700px]]<br/><br/>
'''All links related to these changes:'''<br><br>
[https://github.com/expertiza/expertiza/pull/2663/files#diff-c41058c9caa3baa134bad689e28b7903d372d6a64388daccbb2e0ced964da568 review_mapping_helper.rb] <br> <br>
'''Contributor:''' Harsh Mauny
----
----



Revision as of 23:51, 23 April 2024

Team

Mentor

  • Ananya Mantravadi (amantra)

Team Members

  • Ravi Ghevariya (rghevar)
  • Manan Patel (mrpatel8)
  • Kanishk Harde (knharde)

Relevant Links

Expertiza Background

Expertiza is a Ruby on Rails framework-based open-source web application. It is kept up by NC State University employees and students. With the help of this program, instructors can fully manage the assignments and responsibilities assigned in their classes. Expertiza provides many strong features, such as subject addition, group creation, and peer review administration. It is a flexible platform that can manage many kinds of tasks. Users can consult the Expertiza wiki to get more in-depth details about the many capabilities that Expertiza offers.

About Helper

The Ruby on Rails review_mapping_helper module offers a number of helper methods to make the peer review process easier in assignments. It has the capacity to calculate review scores, manage submission statuses, generate review reports, and visualize review metrics; however, it needs to be refactored in order to make the code more readable and maintainable.

Problem Statement

The existing codebase derived from E2301 suffers from lack of clarity, violating the Expert pattern, and inefficient methods, hindering code understandability and maintainability. Key issues include convoluted data handling in views, unclear color-coding methods, and inefficient sorting functions. Additionally, redundant methods and unclear feedback_response_maps further obscure the code's purpose.

Tasks

1. Refactor get_data_for_review_report to use partials for clearer code in views/reports.
2. Refactor color-related methods for clarity and consistency, using American spelling.
3. Rename methods starting with "get" to adhere to Ruby conventions.
4. Update get_awarded_review_score to utilize standardized score-calculation code.
5. Generalize sort_reviewer_by_review_volume_desc for sorting by various metrics.
6. Extracting chart-generating methods into their own module or evaluating the necessity of list_review_submissions
7. Review and clarify the purpose of feedback_response_maps methods.
8. Add comments or refactor small classes for clarity and documentation.

Phase 1

We have concentrated our efforts on addressing the following difficulties throughout the project's first phase:
1. Refactor get_data_for_review_report to use partials for clearer code in views/reports.
2. Refactor color-related methods for clarity and consistency, using American spelling.
3. Rename methods starting with "get" to adhere to Ruby conventions.
8. Add comments or refactor small classes for clarity and documentation.

Phase 2

We have planned our efforts on addressing the following difficulties throughout the project's second phase:
4. Update get_awarded_review_score to utilize standardized score-calculation code.
5. Generalize sort_reviewer_by_review_volume_desc for sorting by various metrics.
6. Extracting chart-generating methods into their own module or evaluating the necessity of list_review_submissions
7. Review and clarify the purpose of feedback_response_maps methods.


Implementation

Phase 1

Refactor the `get_data_for_review_report` method

Refactor the `color-related` methods

Rename methods starting with `get` to adhere to Ruby conventions methods

Design Pattern

The Refactoring pattern is essential to enhance code readability, maintainability, and adherence to best practices. By systematically restructuring code components, eliminating redundancies, and applying standard conventions, the Refactoring pattern ensures improved code quality and easier future modifications.

Plan of work

We began our work by examining the review_mapping_helper.rb file to understand its connection to the rest of the codebase. We then had detailed discussions with our mentor about the project's flow and structure. We organized our project requirements by difficulty levels, assigned tasks among the team, and began refactoring existing methods and creating new files as needed. We made sure to preserve the integrity of existing test cases while adding new ones where needed.

Project 4 - DESIGN DOC

We have been assigned below-cited changes to do after project 3

4. Refactoring get_awarded_review_score Method:

  • Standardize the score-calculation logic to ensure consistency and readability.
  • Break down complex calculations into smaller, more understandable components.
  • Improve method documentation and clarity to enhance understanding.

5. Generalizing sort_reviewer_by_review_volume_desc:

  • Modify the method to accept flexible sorting metrics, enabling customization based on various criteria.
  • Update method documentation to reflect the changes and provide usage guidelines.

6. Code Organization Enhancements:

  • Extract chart-generating methods into separate modules or classes for better organization and reusability.
  • Evaluate the necessity of list_review_submissions method based on insights from the Expertiza wiki and refactor accordingly.

7. Documentation and Clarity Improvements:

  • Review methods related to feedback_response_maps and add comments or refactor small classes to enhance clarity and documentation.
  • Ensure consistent naming conventions and adherence to coding standards throughout the codebase.


  • We're going to make confusing variables easier to understand by rearranging them.
  • Even though we tried hard in project 3, we couldn't cover all the code. In project 4, we're going to write more tests and use the test skeleton better.

This section contains changes and contributions to Project 4


  • Issue #6: make a separate file for for chart related elements in review_mapping_helper.rb

Methods involved: initialize_chart_elements(), display_volume_metric_chart(), display_tagging_interval_chart(), calculate_key_chart_information()

Previous Code: All these methods were previously a part of the review_mapping_helper.rb when it should have its separate helper file
Problem: These methods perform similar tasks of generating graphs and can have there separate module or a mixin and also each of the methods more than 30 lines inside them making them too large
Solution: distributed this code among 2 newly created files named review_mapping_charts_helper.rb and data_mapping_helper.rb within helper folder. This way the chart helper methods are separated from review_mapping_helper where they are out of place and difficult for any developer to find. review_mapping_charts_helper.rb contains the original methods and data_mapping_helper.rb manages the data need by these chart methods

review_mapping_charts_helper.rb

module  ReviewMappingChartsHelper
...
    def initialize_chart_elements()
    def display_volume_metric_chart()
    def display_tagging_interval_chart()
    def calculate_key_chart_information()


all link related to these changes:
review_mapping_charts_helper.rb
review_mapping_helper.rb
data_mapping_helper.rb
Contributor: Ravi Ghevariya



  • Issue #7: Several methods for feedback_response_maps, check docs to manage this confusion

Methods involved: feedback_response_for_author()
Previous Code: previous code had an ambiguous variable name
Problem: It wasn't clear what the variable was used for.
Solution: refactor the variable name to be more easily understood and add comments to give a clear explanation for why it exists

Contributor: Manan Patel


  • Issue #5: The method sort_reviewer_by_review_volume_desc should be generalized so that it can sort by any metric, not just review volume. Other metrics might include number of suggestions, or number of suggestions + number of problems detected. This method should not be counting the number of review rounds! Since other places in the code will need to know the number of review rounds, it should be calculated somewhere else in the system.

Methods involved: sort_reviewer_by_review_volume_desc
Problem: Currently the method sort_reviewer_by_review_volume_desc sorts the reviewers in descending order but only considers one metric which is review volume which makes it very specific and it cannot be used if we want to sort by other metrics
Solution:The solution here is make this a generalized method by renaming sort_reviewer_by_review_volume_desc to sort_reviewer_desc and accepting a metric as argument on which we can sort the the reviewers as shown below. Since it was used in review_report partial the implementation was changed there as well

review_mapping_helper.rb


app/views/reports/_review_report.html.erb



review_mapping_helper_spec.rb



All link related to these changes:

review_mapping_helper.rb
_review_report.html.erb
review_mapping_helper_spec.rb

Contributor: Kanishk Harde


  • Issue #9: Method get_awarded_review_score needs to be refactored

Methods involved: get_awarded_review_score
Solution: Post tackling of Issue 2, the name of the method was changed to compute_awarded_review_score to make it more ruby like. Further on, the code which involved redundant setting of instance variables was placed inside the loop to make it more concise. The explicit check for nil or -1.0 was removed and added to the instance_variable_set line.

Before

def compute_awarded_review_score(reviewer_id, team_id)
    # Storing redundantly computed value in num_rounds variable
    num_rounds = @assignment.num_review_rounds
    # Setting values of instance variables
    (1..num_rounds).each { |round| instance_variable_set('@score_awarded_round_' + round.to_s, '-----') }
    # Iterating through list
    (1..num_rounds).each do |round|
      # Changing values of instance variable based on below condition
      if @review_scores[reviewer_id] && @review_scores[reviewer_id][round] && @review_scores[reviewer_id][round][team_id] && @review_scores[reviewer_id][round][team_id] != -1.0
        instance_variable_set('@score_awarded_round_' + round.to_s, @review_scores[reviewer_id][round][team_id].to_s + '%')
      end
    end
  end


After

def compute_awarded_review_score(reviewer_id, team_id)
    num_rounds = @assignment.num_review_rounds

    (1..num_rounds).each do |round|
      score = @review_scores && @review_scores[reviewer_id] && @review_scores[reviewer_id][round] && @review_scores[reviewer_id][round][team_id]
      instance_variable_set("@score_awarded_round_#{round}", "#{score}%") unless score.nil? || score == -1.0
    end
end

All links related to these changes:

review_mapping_helper.rb

Contributor: Aditya Joshi



Test Plan

This project involves refactoring, meaning that the original functionality should remain unchanged. Tasks included adding comments to existing code, altering variable names, and similar adjustments that didn't affect the test cases. When method names were modified or moved to different files, corresponding changes were made in the relevant RSpec files. All test cases passed successfully, indicating that the refactoring didn't break the existing functionality.


The image below shows the test cases are passing as well as most of the code climate issues were resolved.

Github Links

Link to Expertiza Repository

https://github.com/expertiza/expertiza

Link to Forked Repository

https://github.com/kanishkharde/expertiza

Link to Pull Request

https://github.com/expertiza/expertiza/pull/?