<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Thwinter</id>
	<title>Expertiza_Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Thwinter"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Thwinter"/>
	<updated>2026-05-12T17:03:06Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133391</id>
		<title>CSC/ECE 517 E2024 Mentor management for assignments without topics</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133391"/>
		<updated>2020-04-14T00:13:36Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Project Goal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;CSC/ECE 517 E2024 Mentor management for assignments without topics&lt;br /&gt;
&lt;br /&gt;
== Problem Statement == &lt;br /&gt;
&lt;br /&gt;
Currently, Expertiza has no way to associate mentors with teams.  For assignments with topics, like the OSS project, mentors are associated with topics, and then whichever team is assigned to the topic inherits the mentor for that topic, However, for assignments without topics (like Program 2), there is no good way to “automatically” assign mentors to projects.  The instructor needs to watch teams being formed, and every time a new team is formed, a new mentor needs to be assigned, outside of Expertiza. This leads to a lot of work for the instructor, as well as sometimes long delays before a team is assigned a mentor.&lt;br /&gt;
&lt;br /&gt;
== Project Goal == &lt;br /&gt;
&lt;br /&gt;
Develop a trigger that: &amp;lt;br&amp;gt;&lt;br /&gt;
# Is activated when any team has been formed that has k members, where k is greater than 50% of the maximum team capacity &amp;lt;br&amp;gt;&lt;br /&gt;
#* ex. max members = 4, trigger activated when the team size reaches 3&lt;br /&gt;
# Assign a mentor to the team. Mentors should be evenly assigned to teams, so a good strategy is to assign the mentor who has the fewest teams to mentor so far.&lt;br /&gt;
# Notify the mentor via email that they are now assigned to a specific team, and provide the email addresses of the team members.&lt;br /&gt;
# Possibly notify the team members that they have been assigned the mentor with contact information.&lt;br /&gt;
&lt;br /&gt;
== Previous Work == &lt;br /&gt;
=== Design Pattern ===&lt;br /&gt;
&lt;br /&gt;
Since the trigger they implemented would need multiple handlers and each of the responses in different actions, they decided to use Chain of Responsibility as the design pattern. Chain of Responsibility is a behavioural design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.&lt;br /&gt;
[[File:Cor.PNG]]&lt;br /&gt;
&lt;br /&gt;
=== Work Flow Diagram ===&lt;br /&gt;
[[File:Orig flow mentor.jpg]]&lt;br /&gt;
[[File:Orig flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Improvement on the Previous Work ==&lt;br /&gt;
=== Change in Work Flow Diagram ===&lt;br /&gt;
[[File:New flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
'''Refactor Code to follow good coding practices''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# Rename method names more meaningfully and intuitive like, from able_to_review to can_review.&lt;br /&gt;
# Reduce the number of conditional statements checking for mentor.&lt;br /&gt;
# Rename variable names to reduce confusion like changing lowest_team_no to lowest_number_of_teams.&lt;br /&gt;
&lt;br /&gt;
'''Correct Previous Design'''&lt;br /&gt;
# Remove mentors from being included in a team's number of members count&lt;br /&gt;
&lt;br /&gt;
'''Code placed in the wrong locations to be moved to the desired locations.''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# The email code has to be moved to the email module.&lt;br /&gt;
# Code written in team file has to be moved to the assignment team file.&lt;br /&gt;
&lt;br /&gt;
'''Remove Duplicate Functions'''&amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
Though there is a method &amp;quot;team&amp;quot; to list the members of a team, a new method has been created, which is to be removed. &lt;br /&gt;
&lt;br /&gt;
[[File:Check.png]]&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
# Some existing test cases have been modified, which has to be reverted. &amp;lt;br&amp;gt;&lt;br /&gt;
# RSpec tests for the email functionality will be added. &amp;lt;br&amp;gt;&lt;br /&gt;
# Run and pass the existing RSpec Tests. &amp;lt;br&amp;gt;&lt;br /&gt;
# Develop New RSpec Tests for the new code additions (additional features). &amp;lt;br&amp;gt;&lt;br /&gt;
# Test the UI for the deployed project.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Functionalities to be added ==&lt;br /&gt;
 &lt;br /&gt;
# The mentor should be able to check submissions of his team.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133390</id>
		<title>CSC/ECE 517 E2024 Mentor management for assignments without topics</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133390"/>
		<updated>2020-04-14T00:13:25Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Project Goal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;CSC/ECE 517 E2024 Mentor management for assignments without topics&lt;br /&gt;
&lt;br /&gt;
== Problem Statement == &lt;br /&gt;
&lt;br /&gt;
Currently, Expertiza has no way to associate mentors with teams.  For assignments with topics, like the OSS project, mentors are associated with topics, and then whichever team is assigned to the topic inherits the mentor for that topic, However, for assignments without topics (like Program 2), there is no good way to “automatically” assign mentors to projects.  The instructor needs to watch teams being formed, and every time a new team is formed, a new mentor needs to be assigned, outside of Expertiza. This leads to a lot of work for the instructor, as well as sometimes long delays before a team is assigned a mentor.&lt;br /&gt;
&lt;br /&gt;
== Project Goal == &lt;br /&gt;
&lt;br /&gt;
Develop a trigger that: &amp;lt;br&amp;gt;&lt;br /&gt;
# Is activated when any team has been formed that has k members, where k is greater than 50% of the maximum team capacity &amp;lt;br&amp;gt;&lt;br /&gt;
** ex. max members = 4, trigger activated when the team size reaches 3&lt;br /&gt;
# Assign a mentor to the team. Mentors should be evenly assigned to teams, so a good strategy is to assign the mentor who has the fewest teams to mentor so far.&lt;br /&gt;
# Notify the mentor via email that they are now assigned to a specific team, and provide the email addresses of the team members.&lt;br /&gt;
# Possibly notify the team members that they have been assigned the mentor with contact information.&lt;br /&gt;
&lt;br /&gt;
== Previous Work == &lt;br /&gt;
=== Design Pattern ===&lt;br /&gt;
&lt;br /&gt;
Since the trigger they implemented would need multiple handlers and each of the responses in different actions, they decided to use Chain of Responsibility as the design pattern. Chain of Responsibility is a behavioural design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.&lt;br /&gt;
[[File:Cor.PNG]]&lt;br /&gt;
&lt;br /&gt;
=== Work Flow Diagram ===&lt;br /&gt;
[[File:Orig flow mentor.jpg]]&lt;br /&gt;
[[File:Orig flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Improvement on the Previous Work ==&lt;br /&gt;
=== Change in Work Flow Diagram ===&lt;br /&gt;
[[File:New flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
'''Refactor Code to follow good coding practices''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# Rename method names more meaningfully and intuitive like, from able_to_review to can_review.&lt;br /&gt;
# Reduce the number of conditional statements checking for mentor.&lt;br /&gt;
# Rename variable names to reduce confusion like changing lowest_team_no to lowest_number_of_teams.&lt;br /&gt;
&lt;br /&gt;
'''Correct Previous Design'''&lt;br /&gt;
# Remove mentors from being included in a team's number of members count&lt;br /&gt;
&lt;br /&gt;
'''Code placed in the wrong locations to be moved to the desired locations.''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# The email code has to be moved to the email module.&lt;br /&gt;
# Code written in team file has to be moved to the assignment team file.&lt;br /&gt;
&lt;br /&gt;
'''Remove Duplicate Functions'''&amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
Though there is a method &amp;quot;team&amp;quot; to list the members of a team, a new method has been created, which is to be removed. &lt;br /&gt;
&lt;br /&gt;
[[File:Check.png]]&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
# Some existing test cases have been modified, which has to be reverted. &amp;lt;br&amp;gt;&lt;br /&gt;
# RSpec tests for the email functionality will be added. &amp;lt;br&amp;gt;&lt;br /&gt;
# Run and pass the existing RSpec Tests. &amp;lt;br&amp;gt;&lt;br /&gt;
# Develop New RSpec Tests for the new code additions (additional features). &amp;lt;br&amp;gt;&lt;br /&gt;
# Test the UI for the deployed project.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Functionalities to be added ==&lt;br /&gt;
 &lt;br /&gt;
# The mentor should be able to check submissions of his team.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133389</id>
		<title>CSC/ECE 517 E2024 Mentor management for assignments without topics</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133389"/>
		<updated>2020-04-14T00:13:16Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Project Goal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;CSC/ECE 517 E2024 Mentor management for assignments without topics&lt;br /&gt;
&lt;br /&gt;
== Problem Statement == &lt;br /&gt;
&lt;br /&gt;
Currently, Expertiza has no way to associate mentors with teams.  For assignments with topics, like the OSS project, mentors are associated with topics, and then whichever team is assigned to the topic inherits the mentor for that topic, However, for assignments without topics (like Program 2), there is no good way to “automatically” assign mentors to projects.  The instructor needs to watch teams being formed, and every time a new team is formed, a new mentor needs to be assigned, outside of Expertiza. This leads to a lot of work for the instructor, as well as sometimes long delays before a team is assigned a mentor.&lt;br /&gt;
&lt;br /&gt;
== Project Goal == &lt;br /&gt;
&lt;br /&gt;
Develop a trigger that: &amp;lt;br&amp;gt;&lt;br /&gt;
# Is activated when any team has been formed that has k members, where k is greater than 50% of the maximum team capacity &amp;lt;br&amp;gt;&lt;br /&gt;
* ex. max members = 4, trigger activated when the team size reaches 3&lt;br /&gt;
# Assign a mentor to the team. Mentors should be evenly assigned to teams, so a good strategy is to assign the mentor who has the fewest teams to mentor so far.&lt;br /&gt;
# Notify the mentor via email that they are now assigned to a specific team, and provide the email addresses of the team members.&lt;br /&gt;
# Possibly notify the team members that they have been assigned the mentor with contact information.&lt;br /&gt;
&lt;br /&gt;
== Previous Work == &lt;br /&gt;
=== Design Pattern ===&lt;br /&gt;
&lt;br /&gt;
Since the trigger they implemented would need multiple handlers and each of the responses in different actions, they decided to use Chain of Responsibility as the design pattern. Chain of Responsibility is a behavioural design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.&lt;br /&gt;
[[File:Cor.PNG]]&lt;br /&gt;
&lt;br /&gt;
=== Work Flow Diagram ===&lt;br /&gt;
[[File:Orig flow mentor.jpg]]&lt;br /&gt;
[[File:Orig flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Improvement on the Previous Work ==&lt;br /&gt;
=== Change in Work Flow Diagram ===&lt;br /&gt;
[[File:New flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
'''Refactor Code to follow good coding practices''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# Rename method names more meaningfully and intuitive like, from able_to_review to can_review.&lt;br /&gt;
# Reduce the number of conditional statements checking for mentor.&lt;br /&gt;
# Rename variable names to reduce confusion like changing lowest_team_no to lowest_number_of_teams.&lt;br /&gt;
&lt;br /&gt;
'''Correct Previous Design'''&lt;br /&gt;
# Remove mentors from being included in a team's number of members count&lt;br /&gt;
&lt;br /&gt;
'''Code placed in the wrong locations to be moved to the desired locations.''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# The email code has to be moved to the email module.&lt;br /&gt;
# Code written in team file has to be moved to the assignment team file.&lt;br /&gt;
&lt;br /&gt;
'''Remove Duplicate Functions'''&amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
Though there is a method &amp;quot;team&amp;quot; to list the members of a team, a new method has been created, which is to be removed. &lt;br /&gt;
&lt;br /&gt;
[[File:Check.png]]&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
# Some existing test cases have been modified, which has to be reverted. &amp;lt;br&amp;gt;&lt;br /&gt;
# RSpec tests for the email functionality will be added. &amp;lt;br&amp;gt;&lt;br /&gt;
# Run and pass the existing RSpec Tests. &amp;lt;br&amp;gt;&lt;br /&gt;
# Develop New RSpec Tests for the new code additions (additional features). &amp;lt;br&amp;gt;&lt;br /&gt;
# Test the UI for the deployed project.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Functionalities to be added ==&lt;br /&gt;
 &lt;br /&gt;
# The mentor should be able to check submissions of his team.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133388</id>
		<title>CSC/ECE 517 E2024 Mentor management for assignments without topics</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133388"/>
		<updated>2020-04-14T00:12:57Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Project Goal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;CSC/ECE 517 E2024 Mentor management for assignments without topics&lt;br /&gt;
&lt;br /&gt;
== Problem Statement == &lt;br /&gt;
&lt;br /&gt;
Currently, Expertiza has no way to associate mentors with teams.  For assignments with topics, like the OSS project, mentors are associated with topics, and then whichever team is assigned to the topic inherits the mentor for that topic, However, for assignments without topics (like Program 2), there is no good way to “automatically” assign mentors to projects.  The instructor needs to watch teams being formed, and every time a new team is formed, a new mentor needs to be assigned, outside of Expertiza. This leads to a lot of work for the instructor, as well as sometimes long delays before a team is assigned a mentor.&lt;br /&gt;
&lt;br /&gt;
== Project Goal == &lt;br /&gt;
&lt;br /&gt;
Develop a trigger that: &amp;lt;br&amp;gt;&lt;br /&gt;
# Is activated when any team has been formed that has k members, where k is greater than 50% of the maximum team capacity &amp;lt;br&amp;gt;&lt;br /&gt;
ex. max members = 4, trigger activated when the team size reaches 3&lt;br /&gt;
# Assign a mentor to the team. Mentors should be evenly assigned to teams, so a good strategy is to assign the mentor who has the fewest teams to mentor so far.&lt;br /&gt;
# Notify the mentor via email that they are now assigned to a specific team, and provide the email addresses of the team members.&lt;br /&gt;
# Possibly notify the team members that they have been assigned the mentor with contact information.&lt;br /&gt;
&lt;br /&gt;
== Previous Work == &lt;br /&gt;
=== Design Pattern ===&lt;br /&gt;
&lt;br /&gt;
Since the trigger they implemented would need multiple handlers and each of the responses in different actions, they decided to use Chain of Responsibility as the design pattern. Chain of Responsibility is a behavioural design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.&lt;br /&gt;
[[File:Cor.PNG]]&lt;br /&gt;
&lt;br /&gt;
=== Work Flow Diagram ===&lt;br /&gt;
[[File:Orig flow mentor.jpg]]&lt;br /&gt;
[[File:Orig flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Improvement on the Previous Work ==&lt;br /&gt;
=== Change in Work Flow Diagram ===&lt;br /&gt;
[[File:New flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
'''Refactor Code to follow good coding practices''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# Rename method names more meaningfully and intuitive like, from able_to_review to can_review.&lt;br /&gt;
# Reduce the number of conditional statements checking for mentor.&lt;br /&gt;
# Rename variable names to reduce confusion like changing lowest_team_no to lowest_number_of_teams.&lt;br /&gt;
&lt;br /&gt;
'''Correct Previous Design'''&lt;br /&gt;
# Remove mentors from being included in a team's number of members count&lt;br /&gt;
&lt;br /&gt;
'''Code placed in the wrong locations to be moved to the desired locations.''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# The email code has to be moved to the email module.&lt;br /&gt;
# Code written in team file has to be moved to the assignment team file.&lt;br /&gt;
&lt;br /&gt;
'''Remove Duplicate Functions'''&amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
Though there is a method &amp;quot;team&amp;quot; to list the members of a team, a new method has been created, which is to be removed. &lt;br /&gt;
&lt;br /&gt;
[[File:Check.png]]&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
# Some existing test cases have been modified, which has to be reverted. &amp;lt;br&amp;gt;&lt;br /&gt;
# RSpec tests for the email functionality will be added. &amp;lt;br&amp;gt;&lt;br /&gt;
# Run and pass the existing RSpec Tests. &amp;lt;br&amp;gt;&lt;br /&gt;
# Develop New RSpec Tests for the new code additions (additional features). &amp;lt;br&amp;gt;&lt;br /&gt;
# Test the UI for the deployed project.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Functionalities to be added ==&lt;br /&gt;
 &lt;br /&gt;
# The mentor should be able to check submissions of his team.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133387</id>
		<title>CSC/ECE 517 E2024 Mentor management for assignments without topics</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133387"/>
		<updated>2020-04-14T00:12:30Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Project Goal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;CSC/ECE 517 E2024 Mentor management for assignments without topics&lt;br /&gt;
&lt;br /&gt;
== Problem Statement == &lt;br /&gt;
&lt;br /&gt;
Currently, Expertiza has no way to associate mentors with teams.  For assignments with topics, like the OSS project, mentors are associated with topics, and then whichever team is assigned to the topic inherits the mentor for that topic, However, for assignments without topics (like Program 2), there is no good way to “automatically” assign mentors to projects.  The instructor needs to watch teams being formed, and every time a new team is formed, a new mentor needs to be assigned, outside of Expertiza. This leads to a lot of work for the instructor, as well as sometimes long delays before a team is assigned a mentor.&lt;br /&gt;
&lt;br /&gt;
== Project Goal == &lt;br /&gt;
&lt;br /&gt;
Develop a trigger that: &amp;lt;br&amp;gt;&lt;br /&gt;
# Is activated when any team has been formed that has k members, where k is greater than 50% of the maximum team capacity &amp;lt;br&amp;gt;&lt;br /&gt;
          ex. max members = 4, trigger activated when the team size reaches 3&lt;br /&gt;
# Assign a mentor to the team. Mentors should be evenly assigned to teams, so a good strategy is to assign the mentor who has the fewest teams to mentor so far.&lt;br /&gt;
# Notify the mentor via email that they are now assigned to a specific team, and provide the email addresses of the team members.&lt;br /&gt;
# Possibly notify the team members that they have been assigned the mentor with contact information.&lt;br /&gt;
&lt;br /&gt;
== Previous Work == &lt;br /&gt;
=== Design Pattern ===&lt;br /&gt;
&lt;br /&gt;
Since the trigger they implemented would need multiple handlers and each of the responses in different actions, they decided to use Chain of Responsibility as the design pattern. Chain of Responsibility is a behavioural design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.&lt;br /&gt;
[[File:Cor.PNG]]&lt;br /&gt;
&lt;br /&gt;
=== Work Flow Diagram ===&lt;br /&gt;
[[File:Orig flow mentor.jpg]]&lt;br /&gt;
[[File:Orig flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Improvement on the Previous Work ==&lt;br /&gt;
=== Change in Work Flow Diagram ===&lt;br /&gt;
[[File:New flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
'''Refactor Code to follow good coding practices''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# Rename method names more meaningfully and intuitive like, from able_to_review to can_review.&lt;br /&gt;
# Reduce the number of conditional statements checking for mentor.&lt;br /&gt;
# Rename variable names to reduce confusion like changing lowest_team_no to lowest_number_of_teams.&lt;br /&gt;
&lt;br /&gt;
'''Correct Previous Design'''&lt;br /&gt;
# Remove mentors from being included in a team's number of members count&lt;br /&gt;
&lt;br /&gt;
'''Code placed in the wrong locations to be moved to the desired locations.''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# The email code has to be moved to the email module.&lt;br /&gt;
# Code written in team file has to be moved to the assignment team file.&lt;br /&gt;
&lt;br /&gt;
'''Remove Duplicate Functions'''&amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
Though there is a method &amp;quot;team&amp;quot; to list the members of a team, a new method has been created, which is to be removed. &lt;br /&gt;
&lt;br /&gt;
[[File:Check.png]]&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
# Some existing test cases have been modified, which has to be reverted. &amp;lt;br&amp;gt;&lt;br /&gt;
# RSpec tests for the email functionality will be added. &amp;lt;br&amp;gt;&lt;br /&gt;
# Run and pass the existing RSpec Tests. &amp;lt;br&amp;gt;&lt;br /&gt;
# Develop New RSpec Tests for the new code additions (additional features). &amp;lt;br&amp;gt;&lt;br /&gt;
# Test the UI for the deployed project.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Functionalities to be added ==&lt;br /&gt;
 &lt;br /&gt;
# The mentor should be able to check submissions of his team.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133385</id>
		<title>CSC/ECE 517 E2024 Mentor management for assignments without topics</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133385"/>
		<updated>2020-04-14T00:11:52Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Project Goal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;CSC/ECE 517 E2024 Mentor management for assignments without topics&lt;br /&gt;
&lt;br /&gt;
== Problem Statement == &lt;br /&gt;
&lt;br /&gt;
Currently, Expertiza has no way to associate mentors with teams.  For assignments with topics, like the OSS project, mentors are associated with topics, and then whichever team is assigned to the topic inherits the mentor for that topic, However, for assignments without topics (like Program 2), there is no good way to “automatically” assign mentors to projects.  The instructor needs to watch teams being formed, and every time a new team is formed, a new mentor needs to be assigned, outside of Expertiza. This leads to a lot of work for the instructor, as well as sometimes long delays before a team is assigned a mentor.&lt;br /&gt;
&lt;br /&gt;
== Project Goal == &lt;br /&gt;
&lt;br /&gt;
Develop a trigger that: &amp;lt;br&amp;gt;&lt;br /&gt;
# Is activated when any team has been formed that has k members, where k is greater than 50% of the maximum team capacity &amp;lt;br&amp;gt;&lt;br /&gt;
ex. max members = 4, trigger activated when the team size reaches 3&lt;br /&gt;
# Assign a mentor to the team. Mentors should be evenly assigned to teams, so a good strategy is to assign the mentor who has the fewest teams to mentor so far.&lt;br /&gt;
# Notify the mentor via email that they are now assigned to a specific team, and provide the email addresses of the team members.&lt;br /&gt;
# Possibly notify the team members that they have been assigned the mentor with contact information.&lt;br /&gt;
&lt;br /&gt;
== Previous Work == &lt;br /&gt;
=== Design Pattern ===&lt;br /&gt;
&lt;br /&gt;
Since the trigger they implemented would need multiple handlers and each of the responses in different actions, they decided to use Chain of Responsibility as the design pattern. Chain of Responsibility is a behavioural design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.&lt;br /&gt;
[[File:Cor.PNG]]&lt;br /&gt;
&lt;br /&gt;
=== Work Flow Diagram ===&lt;br /&gt;
[[File:Orig flow mentor.jpg]]&lt;br /&gt;
[[File:Orig flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Improvement on the Previous Work ==&lt;br /&gt;
=== Change in Work Flow Diagram ===&lt;br /&gt;
[[File:New flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
'''Refactor Code to follow good coding practices''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# Rename method names more meaningfully and intuitive like, from able_to_review to can_review.&lt;br /&gt;
# Reduce the number of conditional statements checking for mentor.&lt;br /&gt;
# Rename variable names to reduce confusion like changing lowest_team_no to lowest_number_of_teams.&lt;br /&gt;
&lt;br /&gt;
'''Correct Previous Design'''&lt;br /&gt;
# Remove mentors from being included in a team's number of members count&lt;br /&gt;
&lt;br /&gt;
'''Code placed in the wrong locations to be moved to the desired locations.''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# The email code has to be moved to the email module.&lt;br /&gt;
# Code written in team file has to be moved to the assignment team file.&lt;br /&gt;
&lt;br /&gt;
'''Remove Duplicate Functions'''&amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
Though there is a method &amp;quot;team&amp;quot; to list the members of a team, a new method has been created, which is to be removed. &lt;br /&gt;
&lt;br /&gt;
[[File:Check.png]]&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
# Some existing test cases have been modified, which has to be reverted. &amp;lt;br&amp;gt;&lt;br /&gt;
# RSpec tests for the email functionality will be added. &amp;lt;br&amp;gt;&lt;br /&gt;
# Run and pass the existing RSpec Tests. &amp;lt;br&amp;gt;&lt;br /&gt;
# Develop New RSpec Tests for the new code additions (additional features). &amp;lt;br&amp;gt;&lt;br /&gt;
# Test the UI for the deployed project.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Functionalities to be added ==&lt;br /&gt;
 &lt;br /&gt;
# The mentor should be able to check submissions of his team.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133384</id>
		<title>CSC/ECE 517 E2024 Mentor management for assignments without topics</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133384"/>
		<updated>2020-04-14T00:11:08Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Functionalities to be added */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;CSC/ECE 517 E2024 Mentor management for assignments without topics&lt;br /&gt;
&lt;br /&gt;
== Problem Statement == &lt;br /&gt;
&lt;br /&gt;
Currently, Expertiza has no way to associate mentors with teams.  For assignments with topics, like the OSS project, mentors are associated with topics, and then whichever team is assigned to the topic inherits the mentor for that topic, However, for assignments without topics (like Program 2), there is no good way to “automatically” assign mentors to projects.  The instructor needs to watch teams being formed, and every time a new team is formed, a new mentor needs to be assigned, outside of Expertiza. This leads to a lot of work for the instructor, as well as sometimes long delays before a team is assigned a mentor.&lt;br /&gt;
&lt;br /&gt;
== Project Goal == &lt;br /&gt;
&lt;br /&gt;
Develop a trigger that: &amp;lt;br&amp;gt;&lt;br /&gt;
1) Is activated when any team has been formed that has k members, where k is greater than 50% of the maximum team capacity &amp;lt;br&amp;gt;&lt;br /&gt;
ex. max members = 4, trigger activated when the team size reaches 3 &amp;lt;br&amp;gt;&lt;br /&gt;
2) Assign a mentor to the team. Mentors should be evenly assigned to teams, so a good strategy is to assign the mentor who has the fewest teams to mentor so far. &amp;lt;br&amp;gt;&lt;br /&gt;
3) Notify the mentor via email that they are now assigned to a specific team, and provide the email addresses of the team members. &amp;lt;br&amp;gt;&lt;br /&gt;
4) Possibly notify the team members that they have been assigned the mentor with contact information. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Previous Work == &lt;br /&gt;
=== Design Pattern ===&lt;br /&gt;
&lt;br /&gt;
Since the trigger they implemented would need multiple handlers and each of the responses in different actions, they decided to use Chain of Responsibility as the design pattern. Chain of Responsibility is a behavioural design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.&lt;br /&gt;
[[File:Cor.PNG]]&lt;br /&gt;
&lt;br /&gt;
=== Work Flow Diagram ===&lt;br /&gt;
[[File:Orig flow mentor.jpg]]&lt;br /&gt;
[[File:Orig flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Improvement on the Previous Work ==&lt;br /&gt;
=== Change in Work Flow Diagram ===&lt;br /&gt;
[[File:New flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
'''Refactor Code to follow good coding practices''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# Rename method names more meaningfully and intuitive like, from able_to_review to can_review.&lt;br /&gt;
# Reduce the number of conditional statements checking for mentor.&lt;br /&gt;
# Rename variable names to reduce confusion like changing lowest_team_no to lowest_number_of_teams.&lt;br /&gt;
&lt;br /&gt;
'''Correct Previous Design'''&lt;br /&gt;
# Remove mentors from being included in a team's number of members count&lt;br /&gt;
&lt;br /&gt;
'''Code placed in the wrong locations to be moved to the desired locations.''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# The email code has to be moved to the email module.&lt;br /&gt;
# Code written in team file has to be moved to the assignment team file.&lt;br /&gt;
&lt;br /&gt;
'''Remove Duplicate Functions'''&amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
Though there is a method &amp;quot;team&amp;quot; to list the members of a team, a new method has been created, which is to be removed. &lt;br /&gt;
&lt;br /&gt;
[[File:Check.png]]&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
# Some existing test cases have been modified, which has to be reverted. &amp;lt;br&amp;gt;&lt;br /&gt;
# RSpec tests for the email functionality will be added. &amp;lt;br&amp;gt;&lt;br /&gt;
# Run and pass the existing RSpec Tests. &amp;lt;br&amp;gt;&lt;br /&gt;
# Develop New RSpec Tests for the new code additions (additional features). &amp;lt;br&amp;gt;&lt;br /&gt;
# Test the UI for the deployed project.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Functionalities to be added ==&lt;br /&gt;
 &lt;br /&gt;
# The mentor should be able to check submissions of his team.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133382</id>
		<title>CSC/ECE 517 E2024 Mentor management for assignments without topics</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133382"/>
		<updated>2020-04-14T00:10:55Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;CSC/ECE 517 E2024 Mentor management for assignments without topics&lt;br /&gt;
&lt;br /&gt;
== Problem Statement == &lt;br /&gt;
&lt;br /&gt;
Currently, Expertiza has no way to associate mentors with teams.  For assignments with topics, like the OSS project, mentors are associated with topics, and then whichever team is assigned to the topic inherits the mentor for that topic, However, for assignments without topics (like Program 2), there is no good way to “automatically” assign mentors to projects.  The instructor needs to watch teams being formed, and every time a new team is formed, a new mentor needs to be assigned, outside of Expertiza. This leads to a lot of work for the instructor, as well as sometimes long delays before a team is assigned a mentor.&lt;br /&gt;
&lt;br /&gt;
== Project Goal == &lt;br /&gt;
&lt;br /&gt;
Develop a trigger that: &amp;lt;br&amp;gt;&lt;br /&gt;
1) Is activated when any team has been formed that has k members, where k is greater than 50% of the maximum team capacity &amp;lt;br&amp;gt;&lt;br /&gt;
ex. max members = 4, trigger activated when the team size reaches 3 &amp;lt;br&amp;gt;&lt;br /&gt;
2) Assign a mentor to the team. Mentors should be evenly assigned to teams, so a good strategy is to assign the mentor who has the fewest teams to mentor so far. &amp;lt;br&amp;gt;&lt;br /&gt;
3) Notify the mentor via email that they are now assigned to a specific team, and provide the email addresses of the team members. &amp;lt;br&amp;gt;&lt;br /&gt;
4) Possibly notify the team members that they have been assigned the mentor with contact information. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Previous Work == &lt;br /&gt;
=== Design Pattern ===&lt;br /&gt;
&lt;br /&gt;
Since the trigger they implemented would need multiple handlers and each of the responses in different actions, they decided to use Chain of Responsibility as the design pattern. Chain of Responsibility is a behavioural design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.&lt;br /&gt;
[[File:Cor.PNG]]&lt;br /&gt;
&lt;br /&gt;
=== Work Flow Diagram ===&lt;br /&gt;
[[File:Orig flow mentor.jpg]]&lt;br /&gt;
[[File:Orig flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Improvement on the Previous Work ==&lt;br /&gt;
=== Change in Work Flow Diagram ===&lt;br /&gt;
[[File:New flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
'''Refactor Code to follow good coding practices''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# Rename method names more meaningfully and intuitive like, from able_to_review to can_review.&lt;br /&gt;
# Reduce the number of conditional statements checking for mentor.&lt;br /&gt;
# Rename variable names to reduce confusion like changing lowest_team_no to lowest_number_of_teams.&lt;br /&gt;
&lt;br /&gt;
'''Correct Previous Design'''&lt;br /&gt;
# Remove mentors from being included in a team's number of members count&lt;br /&gt;
&lt;br /&gt;
'''Code placed in the wrong locations to be moved to the desired locations.''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# The email code has to be moved to the email module.&lt;br /&gt;
# Code written in team file has to be moved to the assignment team file.&lt;br /&gt;
&lt;br /&gt;
'''Remove Duplicate Functions'''&amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
Though there is a method &amp;quot;team&amp;quot; to list the members of a team, a new method has been created, which is to be removed. &lt;br /&gt;
&lt;br /&gt;
[[File:Check.png]]&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
# Some existing test cases have been modified, which has to be reverted. &amp;lt;br&amp;gt;&lt;br /&gt;
# RSpec tests for the email functionality will be added. &amp;lt;br&amp;gt;&lt;br /&gt;
# Run and pass the existing RSpec Tests. &amp;lt;br&amp;gt;&lt;br /&gt;
# Develop New RSpec Tests for the new code additions (additional features). &amp;lt;br&amp;gt;&lt;br /&gt;
# Test the UI for the deployed project.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Functionalities to be added ==&lt;br /&gt;
 &lt;br /&gt;
1) The mentor should be able to check submissions of his team.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133380</id>
		<title>CSC/ECE 517 E2024 Mentor management for assignments without topics</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_E2024_Mentor_management_for_assignments_without_topics&amp;diff=133380"/>
		<updated>2020-04-14T00:10:21Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Improvement on the Previous Work */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;CSC/ECE 517 E2024 Mentor management for assignments without topics&lt;br /&gt;
&lt;br /&gt;
== Problem Statement == &lt;br /&gt;
&lt;br /&gt;
Currently, Expertiza has no way to associate mentors with teams.  For assignments with topics, like the OSS project, mentors are associated with topics, and then whichever team is assigned to the topic inherits the mentor for that topic, However, for assignments without topics (like Program 2), there is no good way to “automatically” assign mentors to projects.  The instructor needs to watch teams being formed, and every time a new team is formed, a new mentor needs to be assigned, outside of Expertiza. This leads to a lot of work for the instructor, as well as sometimes long delays before a team is assigned a mentor.&lt;br /&gt;
&lt;br /&gt;
== Project Goal == &lt;br /&gt;
&lt;br /&gt;
Develop a trigger that: &amp;lt;br&amp;gt;&lt;br /&gt;
1) Is activated when any team has been formed that has k members, where k is greater than 50% of the maximum team capacity &amp;lt;br&amp;gt;&lt;br /&gt;
ex. max members = 4, trigger activated when the team size reaches 3 &amp;lt;br&amp;gt;&lt;br /&gt;
2) Assign a mentor to the team. Mentors should be evenly assigned to teams, so a good strategy is to assign the mentor who has the fewest teams to mentor so far. &amp;lt;br&amp;gt;&lt;br /&gt;
3) Notify the mentor via email that they are now assigned to a specific team, and provide the email addresses of the team members. &amp;lt;br&amp;gt;&lt;br /&gt;
4) Possibly notify the team members that they have been assigned the mentor with contact information. &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Previous Work == &lt;br /&gt;
=== Design Pattern ===&lt;br /&gt;
&lt;br /&gt;
Since the trigger they implemented would need multiple handlers and each of the responses in different actions, they decided to use Chain of Responsibility as the design pattern. Chain of Responsibility is a behavioural design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.&lt;br /&gt;
[[File:Cor.PNG]]&lt;br /&gt;
&lt;br /&gt;
=== Work Flow Diagram ===&lt;br /&gt;
[[File:Orig flow mentor.jpg]]&lt;br /&gt;
[[File:Orig flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Improvement on the Previous Work ==&lt;br /&gt;
=== Change in Work Flow Diagram ===&lt;br /&gt;
[[File:New flow mentor1.jpg]]&lt;br /&gt;
&lt;br /&gt;
'''Refactor Code to follow good coding practices''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# Rename method names more meaningfully and intuitive like, from able_to_review to can_review.&lt;br /&gt;
# Reduce the number of conditional statements checking for mentor.&lt;br /&gt;
# Rename variable names to reduce confusion like changing lowest_team_no to lowest_number_of_teams.&lt;br /&gt;
&lt;br /&gt;
'''Correct Previous Design'''&lt;br /&gt;
# Remove mentors from being included in a team's number of members count&lt;br /&gt;
&lt;br /&gt;
'''Code placed in the wrong locations to be moved to the desired locations.''' &amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
# The email code has to be moved to the email module.&lt;br /&gt;
# Code written in team file has to be moved to the assignment team file.&lt;br /&gt;
&lt;br /&gt;
'''Remove Duplicate Functions'''&amp;lt;br&amp;gt;&lt;br /&gt;
Example:&amp;lt;br&amp;gt;&lt;br /&gt;
Though there is a method &amp;quot;team&amp;quot; to list the members of a team, a new method has been created, which is to be removed. &lt;br /&gt;
&lt;br /&gt;
[[File:Check.png]]&lt;br /&gt;
&lt;br /&gt;
== Testing ==&lt;br /&gt;
1)Some existing test cases have been modified, which has to be reverted. &amp;lt;br&amp;gt;&lt;br /&gt;
2)RSpec tests for the email functionality will be added. &amp;lt;br&amp;gt;&lt;br /&gt;
3)Run and pass the existing RSpec Tests. &amp;lt;br&amp;gt;&lt;br /&gt;
4)Develop New RSpec Tests for the new code additions (additional features). &amp;lt;br&amp;gt;&lt;br /&gt;
5)Test the UI for the deployed project.&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Functionalities to be added ==&lt;br /&gt;
 &lt;br /&gt;
1) The mentor should be able to check submissions of his team.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132278</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132278"/>
		<updated>2020-03-30T23:56:55Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Test Cases */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand, and write new tests to improve test coverage.&lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Added 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represent a specific and meaningful step&lt;br /&gt;
# Replaced large chunks of code with a small number of method calls&lt;br /&gt;
# Reduced the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimized the performance by moving conditional checking and input filtering outside of loops, where appropriate&lt;br /&gt;
# Renamed some variable names to make their purpose clearer&lt;br /&gt;
# Refactored the parameter list to give each method the least amount of information needed to complete its task&lt;br /&gt;
# Added addition comments and fixed some typos&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out and put into helper methods with more meaningful method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Put lines 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash for students on a team who haven't signed up for a topic yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude lines 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude lines 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods only do one thing. For these methods, one can keep them simple with alternative language syntax and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing a new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that, like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works by pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow a good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is not safe to apply such a change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing more beyond just what the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary looping can be avoided by moving the conditional check out. For example, consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, it pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because at this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of Problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
The main objective of improving the current Lottery Controller testing is to increase the code coverage as much as possible. To achieve this object, tests will be written for each newly added method in the controller. The initial tests for these methods will assume expected normal conditions that the controller would face.&lt;br /&gt;
&lt;br /&gt;
The next step to bolster the testing section is to make sure that the tests catch unexpected inputs, so additional tests to account for edge cases and invalid inputs will be implemented. These edge cases include an unintelligent assignment being passed to match_new_teams_to_topics, no teams being passed to the different methods that require teams, and no topics available when there are users still unassigned.&lt;br /&gt;
&lt;br /&gt;
Finally, the last goal is to allow other users to be able to manually test the Lottery Controller themselves. This will be accomplished my implementing User Interface Testing. Users will be able to create their own testing scenarios by creating their testable objects.&lt;br /&gt;
&lt;br /&gt;
Using these steps, the goal is to achieve total test coverage or as much coverage as possible and provide a testable framework for other users to test their own scenarios.&lt;br /&gt;
&lt;br /&gt;
=== Test Case Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
Testing the Lottery Controller requires setting up Factory objects that will be used for each of the test cases. The following steps were taken to set up the test objects:&lt;br /&gt;
&lt;br /&gt;
# Created an intelligent assignment for the students to complete.&lt;br /&gt;
# Created 6 students that were assigned this assignment.&lt;br /&gt;
# Created 4 topics for the assignment that will be bid on by the students.&lt;br /&gt;
# Created 4 teams that the students may form to work cooperatively and bid as one team.&lt;br /&gt;
# Created a bid based on a topic each student wants to work on.&lt;br /&gt;
&lt;br /&gt;
=== Test Cases ===&lt;br /&gt;
&lt;br /&gt;
The following test cases were made for each respective method in the Lottery Controller:&lt;br /&gt;
&lt;br /&gt;
# Run_intelligent_assignment: &lt;br /&gt;
#* Create an intelligent assignment and expect a successful redirection to the controller’s tree display.&lt;br /&gt;
#* Input an invalid case where there are no signed-up teams and expect an error message&lt;br /&gt;
# Action_allowed:&lt;br /&gt;
#* Login in as an Instructor, Teaching Assistant, and Administrator and expect them to be able to run the bidding operation.&lt;br /&gt;
#* Login as a student and visitor and expect them not to be able to run the bidding operation.&lt;br /&gt;
# Construct_users_bidding_info:&lt;br /&gt;
#* Set up topics for teams to bid on. Set up teams with bids for those topics. Execute the method. Expect to return the bidding information of the teams with bids.&lt;br /&gt;
#* Setup teams without any bids. Setup teams that are not signed up. Execute the method. Expect to exclude the teams that are not signed-up.&lt;br /&gt;
# Construct_teams_bidding_info:&lt;br /&gt;
#* Setup unassigned teams. Setup topics for those teams. Execute the method. Expect that information to be stored in a hash table.&lt;br /&gt;
# Create_new_teams_for_bidding_response:&lt;br /&gt;
#* Set up 3 students. Set up bids for those students. Set those students to two separate teams. Execute the method. Expect the user count to remain the same. Expect team count to increase by 2.&lt;br /&gt;
# Match_new_teams_to_topics:&lt;br /&gt;
#* Set up an unintelligent assignment. Set up a team. Set up that team’s bidding information. Execute the method. Expect the assignment to become intelligent.&lt;br /&gt;
#* Set up an unintelligent assignment. Set up a team. Set up that team’s bidding information. Set up an invalid path. Execute the method. Expect an error message and assignment to remain unintelligent.&lt;br /&gt;
# Remove_user_from_previous_team:&lt;br /&gt;
#* Set up users. Set up a team with those users. Execute the method. Expect the team’s user count to decrease. Expect the removed user’s path to return nil. Expect the remaining users’ paths to return their path.&lt;br /&gt;
# Remove_empty_teams:&lt;br /&gt;
#* Create 1 team that has no users. Execute the method. Expect the team to be deleted. Expect the team count to decrease.&lt;br /&gt;
# Assign_available_slots:&lt;br /&gt;
#* Set up a topic. Set up a team with bidding information. Execute the method. Expect the number of signed up teams to increase.&lt;br /&gt;
# Merge_bids_from_different_previous_teams:&lt;br /&gt;
#* Set up topics. Set up teams. Set up users on those teams. Set up user bids for each created user. Execute the method. Expect bid count to increase. Expect the new bid information to be a combined bid of the new team.&lt;br /&gt;
&lt;br /&gt;
== RSpec Testing ==&lt;br /&gt;
&lt;br /&gt;
=== Existing Tests ===&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only provided about 10% coverage of the code in the controller. The test coverage was determined by the Coveralls gem. Most of the existing tests actually didn't even test the functionality of the lottery controller. The existing tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing an http get request to google.com and expecting a 200 response code with the content-type of application/json&amp;lt;br&amp;gt;This was an attempt at testing the web service used by the lottery controller&lt;br /&gt;
# Checking if an assignment had a correctly set is_intelligent attribute, but it didn't call any methods of the lottery controller&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams, but it didn't call any methods of the lottery controller&lt;br /&gt;
&lt;br /&gt;
=== After Refactoring ===&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created from the factories.rb file using the factory_bot_rails gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 99%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
These tests can be executed by utilizing the RSpec command in the Command Prompt window by entering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; user:expertiza $rspec spec/controllers/lottery_controller_spec.rb &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== UI Testing (For Reviewers) ==&lt;br /&gt;
&lt;br /&gt;
By following the below steps, you can manually test our refactored &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The previous implementation does the intelligent assignment on a team basis. That is, students who do not belong to any team will not get assigned to topics (see method &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;). We intended not to disrupt this behavior since it's beyond the scope of this refactoring.&lt;br /&gt;
&lt;br /&gt;
# Visit [xxx]. Enter the credentials:&amp;lt;br&amp;gt;'''Username:''' instructor6&amp;lt;br&amp;gt;'''Password:''' password&lt;br /&gt;
# From the menubar, hover on the '''Manage''' tab, and select '''Assignments'''.&lt;br /&gt;
# Scroll down the page and find the assignment with the name '''New test assignment'''. The orange book icon on the right links to the &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class.&amp;lt;br&amp;gt;[[File:E2012_4.png]]&amp;lt;br&amp;gt;When you click on that, you should receive an error message claiming &amp;quot;500 Internal Server Error&amp;quot;. This is because this assignment has not properly set up its participants. To get the intelligent assignment to run, you should click on the pencil icon, navigate to &amp;quot;Other stuff -&amp;gt; Add participant&amp;quot;, and add the student by entering its user_id to the textbox next to the label &amp;quot;Enter a user login:&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
'''Additional configuring:''' &lt;br /&gt;
&lt;br /&gt;
# Under the '''General''' tab, mark the checkbox '''Has teams''' as true and set the maximum number of members per team to number that makes sense (e.g. our demonstration uses 3).&lt;br /&gt;
# You may also want to login to the account of each student you add (they all have &amp;quot;**password**&amp;quot; as their passwords), and help that student bid the topics just like how you did with our OSS project! The algorithm works more effectively when there are bids presented in the system. And by signing up topics, you indirectly create teams for them. We know this process can be very tedious, so thank you ahead for your patience!&lt;br /&gt;
&lt;br /&gt;
Here are some data we used in our recording, you are free to come up with your own!&lt;br /&gt;
&lt;br /&gt;
   | User id                            | First Choice | Second Choice | Third Choice |&lt;br /&gt;
   | ---------------------------------- | ------------ | ------------- | ------------ |&lt;br /&gt;
   | student558                         | 1            |               |              |&lt;br /&gt;
   | student559, student562, student563 | 2            | 3             | 1            |&lt;br /&gt;
   | student560, student561             | 2            | 1             |              |&lt;br /&gt;
   | student564                         | 1            | 2             |              |&lt;br /&gt;
   | student565                         | 3            |               |              |&lt;br /&gt;
   | student566                         | 2            |               |              |&lt;br /&gt;
&lt;br /&gt;
Return to the '''Assignments''' page after you set up the New test assignment, and retry the orange book icon. You should be indicated that the intelligent assignment has run successfully. You can check the teaming result under the '''Topics''' tab of the edit page. The above data generate the teaming result of the following.&lt;br /&gt;
&lt;br /&gt;
[[File:E2012_5.png]]&lt;br /&gt;
&lt;br /&gt;
= Future Improvements =&lt;br /&gt;
&lt;br /&gt;
# Improving the RSpec test for assigning open topics for teams without topics. The new test only checks for 1 open assignment and 1 unassigned team. The method is capable of assigning multiple open topics for multiple unassigned teams, but testing for this would require more Factory objects for assignments and teams. While the new test provides code coverage for the entire method, the nested loops currently only run through a single time before completion, which is not always the case in a realistic setting.&lt;br /&gt;
# Improving the time-space complexity for the method that merges bids from teams that are merging together. The existing method requires iterating through each member's bidding information to create a hash map. Then there is a nest iteration for the included topics. Afterwards there is an additional iterations through to exclude topics without bids.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132277</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132277"/>
		<updated>2020-03-30T23:51:49Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Test Plan */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand, and write new tests to improve test coverage.&lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Added 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represent a specific and meaningful step&lt;br /&gt;
# Replaced large chunks of code with a small number of method calls&lt;br /&gt;
# Reduced the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimized the performance by moving conditional checking and input filtering outside of loops, where appropriate&lt;br /&gt;
# Renamed some variable names to make their purpose clearer&lt;br /&gt;
# Refactored the parameter list to give each method the least amount of information needed to complete its task&lt;br /&gt;
# Added addition comments and fixed some typos&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out and put into helper methods with more meaningful method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Put lines 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash for students on a team who haven't signed up for a topic yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude lines 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude lines 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods only do one thing. For these methods, one can keep them simple with alternative language syntax and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing a new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that, like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works by pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow a good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is not safe to apply such a change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing more beyond just what the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary looping can be avoided by moving the conditional check out. For example, consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, it pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because at this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of Problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
The main objective of improving the current Lottery Controller testing is to increase the code coverage as much as possible. To achieve this object, tests will be written for each newly added method in the controller. The initial tests for these methods will assume expected normal conditions that the controller would face.&lt;br /&gt;
&lt;br /&gt;
The next step to bolster the testing section is to make sure that the tests catch unexpected inputs, so additional tests to account for edge cases and invalid inputs will be implemented. These edge cases include an unintelligent assignment being passed to match_new_teams_to_topics, no teams being passed to the different methods that require teams, and no topics available when there are users still unassigned.&lt;br /&gt;
&lt;br /&gt;
Finally, the last goal is to allow other users to be able to manually test the Lottery Controller themselves. This will be accomplished my implementing User Interface Testing. Users will be able to create their own testing scenarios by creating their testable objects.&lt;br /&gt;
&lt;br /&gt;
Using these steps, the goal is to achieve total test coverage or as much coverage as possible and provide a testable framework for other users to test their own scenarios.&lt;br /&gt;
&lt;br /&gt;
=== Test Case Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
Testing the Lottery Controller requires setting up Factory objects that will be used for each of the test cases. The following steps were taken to set up the test objects:&lt;br /&gt;
&lt;br /&gt;
# Created an intelligent assignment for the students to complete.&lt;br /&gt;
# Created 6 students that were assigned this assignment.&lt;br /&gt;
# Created 4 topics for the assignment that will be bid on by the students.&lt;br /&gt;
# Created 4 teams that the students may form to work cooperatively and bid as one team.&lt;br /&gt;
# Created a bid based on a topic each student wants to work on.&lt;br /&gt;
&lt;br /&gt;
=== Test Cases ===&lt;br /&gt;
&lt;br /&gt;
== RSpec Testing ==&lt;br /&gt;
&lt;br /&gt;
=== Existing Tests ===&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only provided about 10% coverage of the code in the controller. The test coverage was determined by the Coveralls gem. Most of the existing tests actually didn't even test the functionality of the lottery controller. The existing tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing an http get request to google.com and expecting a 200 response code with the content-type of application/json&amp;lt;br&amp;gt;This was an attempt at testing the web service used by the lottery controller&lt;br /&gt;
# Checking if an assignment had a correctly set is_intelligent attribute, but it didn't call any methods of the lottery controller&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams, but it didn't call any methods of the lottery controller&lt;br /&gt;
&lt;br /&gt;
=== After Refactoring ===&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created from the factories.rb file using the factory_bot_rails gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 99%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
These tests can be executed by utilizing the RSpec command in the Command Prompt window by entering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; user:expertiza $rspec spec/controllers/lottery_controller_spec.rb &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== UI Testing (For Reviewers) ==&lt;br /&gt;
&lt;br /&gt;
By following the below steps, you can manually test our refactored &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The previous implementation does the intelligent assignment on a team basis. That is, students who do not belong to any team will not get assigned to topics (see method &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;). We intended not to disrupt this behavior since it's beyond the scope of this refactoring.&lt;br /&gt;
&lt;br /&gt;
# Visit [xxx]. Enter the credentials:&amp;lt;br&amp;gt;'''Username:''' instructor6&amp;lt;br&amp;gt;'''Password:''' password&lt;br /&gt;
# From the menubar, hover on the '''Manage''' tab, and select '''Assignments'''.&lt;br /&gt;
# Scroll down the page and find the assignment with the name '''New test assignment'''. The orange book icon on the right links to the &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class.&amp;lt;br&amp;gt;[[File:E2012_4.png]]&amp;lt;br&amp;gt;When you click on that, you should receive an error message claiming &amp;quot;500 Internal Server Error&amp;quot;. This is because this assignment has not properly set up its participants. To get the intelligent assignment to run, you should click on the pencil icon, navigate to &amp;quot;Other stuff -&amp;gt; Add participant&amp;quot;, and add the student by entering its user_id to the textbox next to the label &amp;quot;Enter a user login:&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
'''Additional configuring:''' &lt;br /&gt;
&lt;br /&gt;
# Under the '''General''' tab, mark the checkbox '''Has teams''' as true and set the maximum number of members per team to number that makes sense (e.g. our demonstration uses 3).&lt;br /&gt;
# You may also want to login to the account of each student you add (they all have &amp;quot;**password**&amp;quot; as their passwords), and help that student bid the topics just like how you did with our OSS project! The algorithm works more effectively when there are bids presented in the system. And by signing up topics, you indirectly create teams for them. We know this process can be very tedious, so thank you ahead for your patience!&lt;br /&gt;
&lt;br /&gt;
Here are some data we used in our recording, you are free to come up with your own!&lt;br /&gt;
&lt;br /&gt;
   | User id                            | First Choice | Second Choice | Third Choice |&lt;br /&gt;
   | ---------------------------------- | ------------ | ------------- | ------------ |&lt;br /&gt;
   | student558                         | 1            |               |              |&lt;br /&gt;
   | student559, student562, student563 | 2            | 3             | 1            |&lt;br /&gt;
   | student560, student561             | 2            | 1             |              |&lt;br /&gt;
   | student564                         | 1            | 2             |              |&lt;br /&gt;
   | student565                         | 3            |               |              |&lt;br /&gt;
   | student566                         | 2            |               |              |&lt;br /&gt;
&lt;br /&gt;
Return to the '''Assignments''' page after you set up the New test assignment, and retry the orange book icon. You should be indicated that the intelligent assignment has run successfully. You can check the teaming result under the '''Topics''' tab of the edit page. The above data generate the teaming result of the following.&lt;br /&gt;
&lt;br /&gt;
[[File:E2012_5.png]]&lt;br /&gt;
&lt;br /&gt;
= Future Improvements =&lt;br /&gt;
&lt;br /&gt;
# Improving the RSpec test for assigning open topics for teams without topics. The new test only checks for 1 open assignment and 1 unassigned team. The method is capable of assigning multiple open topics for multiple unassigned teams, but testing for this would require more Factory objects for assignments and teams. While the new test provides code coverage for the entire method, the nested loops currently only run through a single time before completion, which is not always the case in a realistic setting.&lt;br /&gt;
# Improving the time-space complexity for the method that merges bids from teams that are merging together. The existing method requires iterating through each member's bidding information to create a hash map. Then there is a nest iteration for the included topics. Afterwards there is an additional iterations through to exclude topics without bids.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132248</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132248"/>
		<updated>2020-03-30T20:20:18Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Existing Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand, and write new tests to improve test coverage.&lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Added 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represent a specific and meaningful step&lt;br /&gt;
# Replaced large chunks of code with a small number of method calls&lt;br /&gt;
# Reduced the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimized the performance by moving conditional checking and input filtering outside of loops, where appropriate&lt;br /&gt;
# Renamed some variable names to make their purpose clearer&lt;br /&gt;
# Refactored the parameter list to give each method the least amount of information needed to complete its task&lt;br /&gt;
# Added addition comments and fixed some typos&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out and put into helper methods with more meaningful method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Put lines 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash for students on a team who haven't signed up for a topic yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude lines 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude lines 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods only do one thing. For these methods, one can keep them simple with alternative language syntax and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing a new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that, like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works by pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow a good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is not safe to apply such a change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing more beyond just what the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary looping can be avoided by moving the conditional check out. For example, consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, it pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because at this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of Problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
The main objective of improving the current Lottery Controller testing is to increase the code coverage as much as possible. To achieve this object, tests will be written for each newly added method in the controller. The initial tests for these methods will assume expected normal conditions that the controller would face.&lt;br /&gt;
&lt;br /&gt;
The next step to bolster the testing section is to make sure that the tests catch unexpected inputs, so additional tests to account for edge cases and invalid inputs will be implemented. These edge cases include an unintelligent assignment being passed to match_new_teams_to_topics, no teams being passed to the different methods that require teams, and no topics available when there are users still unassigned.&lt;br /&gt;
&lt;br /&gt;
Finally, the last goal is to allow other users to be able to manually test the Lottery Controller themselves. This will be accomplished my implementing User Interface Testing. Users will be able to create their own testing scenarios by creating their testable objects.&lt;br /&gt;
&lt;br /&gt;
Using these steps, the goal is to achieve total test coverage or as much coverage as possible and provide a testable framework for other users to test their own scenarios.&lt;br /&gt;
&lt;br /&gt;
== RSpec Testing ==&lt;br /&gt;
&lt;br /&gt;
=== Existing Tests ===&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only provided about 10% coverage of the code in the controller. The test coverage was determined by the Coveralls gem. Most of the existing tests actually didn't even test the functionality of the lottery controller. The existing tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing an http get request to google.com and expecting a 200 response code with the content-type of application/json&amp;lt;br&amp;gt;This was an attempt at testing the web service used by the lottery controller&lt;br /&gt;
# Checking if an assignment had a correctly set is_intelligent attribute, but it didn't call any methods of the lottery controller&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams, but it didn't call any methods of the lottery controller&lt;br /&gt;
&lt;br /&gt;
=== After Refactoring ===&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created from the factories.rb file using the factory_bot_rails gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 99%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
These tests can be executed by utilizing the RSpec command in the Command Prompt window by entering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; user:expertiza $rspec spec/controllers/lottery_controller_spec.rb &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== UI Testing (For Reviewers) ==&lt;br /&gt;
&lt;br /&gt;
By following the below steps, you can manually test our refactored &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The previous implementation does the intelligent assignment on a team basis. That is, students who do not belong to any team will not get assigned to topics (see method &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;). We intended not to disrupt this behavior since it's beyond the scope of this refactoring.&lt;br /&gt;
&lt;br /&gt;
# Visit [xxx]. Enter the credentials:&amp;lt;br&amp;gt;'''Username:''' instructor6&amp;lt;br&amp;gt;'''Password:''' password&lt;br /&gt;
# From the menubar, hover on the '''Manage''' tab, and select '''Assignments'''.&lt;br /&gt;
# Scroll down the page and find the assignment with the name '''New test assignment'''. The orange book icon on the right links to the &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class.&amp;lt;br&amp;gt;[[File:E2012_4.png]]&amp;lt;br&amp;gt;When you click on that, you should receive an error message claiming &amp;quot;500 Internal Server Error&amp;quot;. This is because this assignment has not properly set up its participants. To get the intelligent assignment to run, you should click on the pencil icon, navigate to &amp;quot;Other stuff -&amp;gt; Add participant&amp;quot;, and add the student by entering its user_id to the textbox next to the label &amp;quot;Enter a user login:&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
'''Additional configuring:''' &lt;br /&gt;
&lt;br /&gt;
# Under the '''General''' tab, mark the checkbox '''Has teams''' as true and set the maximum number of members per team to number that makes sense (e.g. our demonstration uses 3).&lt;br /&gt;
# You may also want to login to the account of each student you add (they all have &amp;quot;**password**&amp;quot; as their passwords), and help that student bid the topics just like how you did with our OSS project! The algorithm works more effectively when there are bids presented in the system. And by signing up topics, you indirectly create teams for them. We know this process can be very tedious, so thank you ahead for your patience!&lt;br /&gt;
&lt;br /&gt;
Here are some data we used in our recording, you are free to come up with your own!&lt;br /&gt;
&lt;br /&gt;
   | User id                            | First Choice | Second Choice | Third Choice |&lt;br /&gt;
   | ---------------------------------- | ------------ | ------------- | ------------ |&lt;br /&gt;
   | student558                         | 1            |               |              |&lt;br /&gt;
   | student559, student562, student563 | 2            | 3             | 1            |&lt;br /&gt;
   | student560, student561             | 2            | 1             |              |&lt;br /&gt;
   | student564                         | 1            | 2             |              |&lt;br /&gt;
   | student565                         | 3            |               |              |&lt;br /&gt;
   | student566                         | 2            |               |              |&lt;br /&gt;
&lt;br /&gt;
Return to the '''Assignments''' page after you set up the New test assignment, and retry the orange book icon. You should be indicated that the intelligent assignment has run successfully. You can check the teaming result under the '''Topics''' tab of the edit page. The above data generate the teaming result of the following.&lt;br /&gt;
&lt;br /&gt;
[[File:E2012_5.png]]&lt;br /&gt;
&lt;br /&gt;
= Future Improvements =&lt;br /&gt;
&lt;br /&gt;
# Improving the RSpec test for assigning open topics for teams without topics. The new test only checks for 1 open assignment and 1 unassigned team. The method is capable of assigning multiple open topics for multiple unassigned teams, but testing for this would require more Factory objects for assignments and teams. While the new test provides code coverage for the entire method, the nested loops currently only run through a single time before completion, which is not always the case in a realistic setting.&lt;br /&gt;
# Improving the time-space complexity for the method that merges bids from teams that are merging together. The existing method requires iterating through each member's bidding information to create a hash map. Then there is a nest iteration for the included topics. Afterwards there is an additional iterations through to exclude topics without bids.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132241</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132241"/>
		<updated>2020-03-30T18:14:21Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Test Plan */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand, and write new tests to improve test coverage.&lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Added 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represent a specific and meaningful step&lt;br /&gt;
# Replaced large chunks of code with a small number of method calls&lt;br /&gt;
# Reduced the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimized the performance by moving conditional checking and input filtering outside of loops, where appropriate&lt;br /&gt;
# Renamed some variable names to make their purpose clearer&lt;br /&gt;
# Refactored the parameter list to give each method the least amount of information needed to complete its task&lt;br /&gt;
# Added addition comments and fixed some typos&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out and put into helper methods with more meaningful method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Put lines 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash for students on a team who haven't signed up for a topic yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude lines 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude lines 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods only do one thing. For these methods, one can keep them simple with alternative language syntax and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing a new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that, like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works by pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow a good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is not safe to apply such a change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing more beyond just what the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary looping can be avoided by moving the conditional check out. For example, consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, it pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because at this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of Problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
The main objective of improving the current Lottery Controller testing is to increase the code coverage as much as possible. To achieve this object, tests will be written for each newly added method in the controller. The initial tests for these methods will assume expected normal conditions that the controller would face.&lt;br /&gt;
&lt;br /&gt;
The next step to bolster the testing section is to make sure that the tests catch unexpected inputs, so additional tests to account for edge cases and invalid inputs will be implemented. These edge cases include an unintelligent assignment being passed to match_new_teams_to_topics, no teams being passed to the different methods that require teams, and no topics available when there are users still unassigned.&lt;br /&gt;
&lt;br /&gt;
Finally, the last goal is to allow other users to be able to manually test the Lottery Controller themselves. This will be accomplished my implementing User Interface Testing. Users will be able to create their own testing scenarios by creating their testable objects.&lt;br /&gt;
&lt;br /&gt;
Using these steps, the goal is to achieve total test coverage or as much coverage as possible and provide a testable framework for other users to test their own scenarios.&lt;br /&gt;
&lt;br /&gt;
== RSpec Testing ==&lt;br /&gt;
&lt;br /&gt;
=== Existing Tests ===&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only provided about 10% coverage of the code in the controller. The test coverage was determined by the Coveralls gem. Most of the existing tests actually didn't even test the functionality of the lottery controller. The existing tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing an http get request to google.com and expecting a 200 response code with the content-type of application/json&amp;lt;br&amp;gt;This was an attempt at testing the web service used by the lottery controller&lt;br /&gt;
# Checking if an assignment had a correctly set is_intelligent attribute&amp;lt;br&amp;gt;Didn't call any methods of the lottery controller&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams&amp;lt;br&amp;gt;Didn't call any methods of the lottery controller&lt;br /&gt;
&lt;br /&gt;
=== After Refactoring ===&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created from the factories.rb file using the factory_bot_rails gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 99%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
These tests can be executed by utilizing the RSpec command in the Command Prompt window by entering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; user:expertiza $rspec spec/controllers/lottery_controller_spec.rb &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== UI Testing (For Reviewers) ==&lt;br /&gt;
&lt;br /&gt;
By following the below steps, you can manually test our refactored &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The previous implementation does the intelligent assignment on a team basis. That is, students who do not belong to any team will not get assigned to topics (see method &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;). We intended not to disrupt this behavior since it's beyond the scope of this refactoring.&lt;br /&gt;
&lt;br /&gt;
# Visit [xxx]. Enter the credentials:&amp;lt;br&amp;gt;'''Username:''' instructor6&amp;lt;br&amp;gt;'''Password:''' password&lt;br /&gt;
# From the menubar, hover on the '''Manage''' tab, and select '''Assignments'''.&lt;br /&gt;
# Scroll down the page and find the assignment with the name '''New test assignment'''. The orange book icon on the right links to the &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class.&amp;lt;br&amp;gt;[[File:E2012_4.png]]&amp;lt;br&amp;gt;When you click on that, you should receive an error message claiming &amp;quot;500 Internal Server Error&amp;quot;. This is because this assignment has not properly set up its participants. To get the intelligent assignment to run, you should click on the pencil icon, navigate to &amp;quot;Other stuff -&amp;gt; Add participant&amp;quot;, and add the student by entering its user_id to the textbox next to the label &amp;quot;Enter a user login:&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
'''Additional configuring:''' &lt;br /&gt;
&lt;br /&gt;
# Under the '''General''' tab, mark the checkbox '''Has teams''' as true and set the maximum number of members per team to number that makes sense (e.g. our demonstration uses 3).&lt;br /&gt;
# You may also want to login to the account of each student you add (they all have &amp;quot;**password**&amp;quot; as their passwords), and help that student bid the topics just like how you did with our OSS project! The algorithm works more effectively when there are bids presented in the system. And by signing up topics, you indirectly create teams for them. We know this process can be very tedious, so thank you ahead for your patience!&lt;br /&gt;
&lt;br /&gt;
Here are some data we used in our recording, you are free to come up with your own!&lt;br /&gt;
&lt;br /&gt;
   | User id                            | First Choice | Second Choice | Third Choice |&lt;br /&gt;
   | ---------------------------------- | ------------ | ------------- | ------------ |&lt;br /&gt;
   | student558                         | 1            |               |              |&lt;br /&gt;
   | student559, student562, student563 | 2            | 3             | 1            |&lt;br /&gt;
   | student560, student561             | 2            | 1             |              |&lt;br /&gt;
   | student564                         | 1            | 2             |              |&lt;br /&gt;
   | student565                         | 3            |               |              |&lt;br /&gt;
   | student566                         | 2            |               |              |&lt;br /&gt;
&lt;br /&gt;
Return to the '''Assignments''' page after you set up the New test assignment, and retry the orange book icon. You should be indicated that the intelligent assignment has run successfully. You can check the teaming result under the '''Topics''' tab of the edit page. The above data generate the teaming result of the following.&lt;br /&gt;
&lt;br /&gt;
[[File:E2012_5.png]]&lt;br /&gt;
&lt;br /&gt;
= Future Improvements =&lt;br /&gt;
&lt;br /&gt;
# Improving the RSpec test for assigning open topics for teams without topics. The new test only checks for 1 open assignment and 1 unassigned team. The method is capable of assigning multiple open topics for multiple unassigned teams, but testing for this would require more Factory objects for assignments and teams. While the new test provides code coverage for the entire method, the nested loops currently only run through a single time before completion, which is not always the case in a realistic setting.&lt;br /&gt;
# Improving the time-space complexity for the method that merges bids from teams that are merging together. The existing method requires iterating through each member's bidding information to create a hash map. Then there is a nest iteration for the included topics. Afterwards there is an additional iterations through to exclude topics without bids.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132240</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132240"/>
		<updated>2020-03-30T18:09:48Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Test Plan */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand, and write new tests to improve test coverage.&lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Added 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represent a specific and meaningful step&lt;br /&gt;
# Replaced large chunks of code with a small number of method calls&lt;br /&gt;
# Reduced the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimized the performance by moving conditional checking and input filtering outside of loops, where appropriate&lt;br /&gt;
# Renamed some variable names to make their purpose clearer&lt;br /&gt;
# Refactored the parameter list to give each method the least amount of information needed to complete its task&lt;br /&gt;
# Added addition comments and fixed some typos&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out and put into helper methods with more meaningful method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Put lines 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash for students on a team who haven't signed up for a topic yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude lines 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude lines 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods only do one thing. For these methods, one can keep them simple with alternative language syntax and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing a new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that, like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works by pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow a good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is not safe to apply such a change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing more beyond just what the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary looping can be avoided by moving the conditional check out. For example, consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, it pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because at this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of Problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
The main objective of improving the current Lottery Controller testing is to increase the code coverage as much as possible. To achieve this object, tests will be written for each newly added method in the controller. The initial tests for these methods will assume expected normal conditions that the controller would face.&lt;br /&gt;
&lt;br /&gt;
The next step to bolster the testing section is to make sure that the tests catch unexpected inputs, so additional tests to account for edge cases and invalid inputs will be implemented. These edge cases include an unintelligent assignment being passed to match_new_teams_to_topics, no teams being passed to the different methods that require teams, and no topics available when there are users still unassigned.&lt;br /&gt;
&lt;br /&gt;
Using these steps, the goal is to achieve total test coverage or as much coverage as possible.&lt;br /&gt;
&lt;br /&gt;
== RSpec Testing ==&lt;br /&gt;
&lt;br /&gt;
=== Existing Tests ===&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only provided about 10% coverage of the code in the controller. The test coverage was determined by the Coveralls gem. Most of the existing tests actually didn't even test the functionality of the lottery controller. The existing tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing an http get request to google.com and expecting a 200 response code with the content-type of application/json&amp;lt;br&amp;gt;This was an attempt at testing the web service used by the lottery controller&lt;br /&gt;
# Checking if an assignment had a correctly set is_intelligent attribute&amp;lt;br&amp;gt;Didn't call any methods of the lottery controller&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams&amp;lt;br&amp;gt;Didn't call any methods of the lottery controller&lt;br /&gt;
&lt;br /&gt;
=== After Refactoring ===&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created from the factories.rb file using the factory_bot_rails gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 99%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
These tests can be executed by utilizing the RSpec command in the Command Prompt window by entering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; user:expertiza $rspec spec/controllers/lottery_controller_spec.rb &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== UI Testing (For Reviewers) ==&lt;br /&gt;
&lt;br /&gt;
By following the below steps, you can manually test our refactored &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The previous implementation does the intelligent assignment on a team basis. That is, students who do not belong to any team will not get assigned to topics (see method &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;). We intended not to disrupt this behavior since it's beyond the scope of this refactoring.&lt;br /&gt;
&lt;br /&gt;
# Visit [xxx]. Enter the credentials:&amp;lt;br&amp;gt;'''Username:''' instructor6&amp;lt;br&amp;gt;'''Password:''' password&lt;br /&gt;
# From the menubar, hover on the '''Manage''' tab, and select '''Assignments'''.&lt;br /&gt;
# Scroll down the page and find the assignment with the name '''New test assignment'''. The orange book icon on the right links to the &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class.&amp;lt;br&amp;gt;[[File:E2012_4.png]]&amp;lt;br&amp;gt;When you click on that, you should receive an error message claiming &amp;quot;500 Internal Server Error&amp;quot;. This is because this assignment has not properly set up its participants. To get the intelligent assignment to run, you should click on the pencil icon, navigate to &amp;quot;Other stuff -&amp;gt; Add participant&amp;quot;, and add the student by entering its user_id to the textbox next to the label &amp;quot;Enter a user login:&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
'''Additional configuring:''' &lt;br /&gt;
&lt;br /&gt;
# Under the '''General''' tab, mark the checkbox '''Has teams''' as true and set the maximum number of members per team to number that makes sense (e.g. our demonstration uses 3).&lt;br /&gt;
# You may also want to login to the account of each student you add (they all have &amp;quot;**password**&amp;quot; as their passwords), and help that student bid the topics just like how you did with our OSS project! The algorithm works more effectively when there are bids presented in the system. And by signing up topics, you indirectly create teams for them. We know this process can be very tedious, so thank you ahead for your patience!&lt;br /&gt;
&lt;br /&gt;
Here are some data we used in our recording, you are free to come up with your own!&lt;br /&gt;
&lt;br /&gt;
   | User id                            | First Choice | Second Choice | Third Choice |&lt;br /&gt;
   | ---------------------------------- | ------------ | ------------- | ------------ |&lt;br /&gt;
   | student558                         | 1            |               |              |&lt;br /&gt;
   | student559, student562, student563 | 2            | 3             | 1            |&lt;br /&gt;
   | student560, student561             | 2            | 1             |              |&lt;br /&gt;
   | student564                         | 1            | 2             |              |&lt;br /&gt;
   | student565                         | 3            |               |              |&lt;br /&gt;
   | student566                         | 2            |               |              |&lt;br /&gt;
&lt;br /&gt;
Return to the '''Assignments''' page after you set up the New test assignment, and retry the orange book icon. You should be indicated that the intelligent assignment has run successfully. You can check the teaming result under the '''Topics''' tab of the edit page. The above data generate the teaming result of the following.&lt;br /&gt;
&lt;br /&gt;
[[File:E2012_5.png]]&lt;br /&gt;
&lt;br /&gt;
= Future Improvements =&lt;br /&gt;
&lt;br /&gt;
# Improving the RSpec test for assigning open topics for teams without topics. The new test only checks for 1 open assignment and 1 unassigned team. The method is capable of assigning multiple open topics for multiple unassigned teams, but testing for this would require more Factory objects for assignments and teams. While the new test provides code coverage for the entire method, the nested loops currently only run through a single time before completion, which is not always the case in a realistic setting.&lt;br /&gt;
# Improving the time-space complexity for the method that merges bids from teams that are merging together. The existing method requires iterating through each member's bidding information to create a hash map. Then there is a nest iteration for the included topics. Afterwards there is an additional iterations through to exclude topics without bids.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132223</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132223"/>
		<updated>2020-03-30T16:15:32Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Test Plan */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand, and write new tests to improve test coverage.&lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Added 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represent a specific and meaningful step&lt;br /&gt;
# Replaced large chunks of code with a small number of method calls&lt;br /&gt;
# Reduced the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimized the performance by moving conditional checking and input filtering outside of loops, where appropriate&lt;br /&gt;
# Renamed some variable names to make their purpose clearer&lt;br /&gt;
# Refactored the parameter list to give each method the least amount of information needed to complete its task&lt;br /&gt;
# Added addition comments and fixed some typos&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out and put into helper methods with more meaningful method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Put lines 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash for students on a team who haven't signed up for a topic yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude lines 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude lines 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods only do one thing. For these methods, one can keep them simple with alternative language syntax and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing a new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that, like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works by pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow a good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is not safe to apply such a change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing more beyond just what the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary looping can be avoided by moving the conditional check out. For example, consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, it pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because at this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of Problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
The main objective of improving the current Lottery Controller testing is to increase the code coverage as much as possible. To achieve this object, tests will be written for each newly added method in the controller. The initial tests for these methods will assume expected normal conditions that the controller would face.&lt;br /&gt;
&lt;br /&gt;
The next step to bolster the testing section is to make sure that the tests catch unexpected inputs, so additional tests to account for edge cases and invalid inputs will be implemented. These invalid inputs include an unintelligent assignment being passed to match_new_teams_to_topics,&lt;br /&gt;
&lt;br /&gt;
== RSpec Testing ==&lt;br /&gt;
&lt;br /&gt;
=== Existing Tests ===&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only provided about 10% coverage of the code in the controller. The test coverage was determined by the Coveralls gem. Most of the existing tests actually didn't even test the functionality of the lottery controller. The existing tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing an http get request to google.com and expecting a 200 response code with the content-type of application/json&amp;lt;br&amp;gt;This was an attempt at testing the web service used by the lottery controller&lt;br /&gt;
# Checking if an assignment had a correctly set is_intelligent attribute&amp;lt;br&amp;gt;Didn't call any methods of the lottery controller&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams&amp;lt;br&amp;gt;Didn't call any methods of the lottery controller&lt;br /&gt;
&lt;br /&gt;
=== After Refactoring ===&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created from the factories.rb file using the factory_bot_rails gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 99%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
These tests can be executed by utilizing the RSpec command in the Command Prompt window by entering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; user:expertiza $rspec spec/controllers/lottery_controller_spec.rb &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== UI Testing (For Reviewers) ==&lt;br /&gt;
&lt;br /&gt;
By following the below steps, you can manually test our refactored &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The previous implementation does the intelligent assignment on a team basis. That is, students who do not belong to any team will not get assigned to topics (see method &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;). We intended not to disrupt this behavior since it's beyond the scope of this refactoring.&lt;br /&gt;
&lt;br /&gt;
# Visit [xxx]. Enter the credentials:&amp;lt;br&amp;gt;'''Username:''' instructor6&amp;lt;br&amp;gt;'''Password:''' password&lt;br /&gt;
# From the menubar, hover on the '''Manage''' tab, and select '''Assignments'''.&lt;br /&gt;
# Scroll down the page and find the assignment with the name '''New test assignment'''. The orange book icon on the right links to the &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class. When you click on that, you should receive an error message claiming &amp;quot;500 Internal Server Error&amp;quot;. This is because this assignment has not properly set up its participants. To get the intelligent assignment to run, you should click on the pencil icon, navigate to &amp;quot;Other stuff -&amp;gt; Add participant&amp;quot;, and add the student by entering its user_id to the textbox next to the label &amp;quot;Enter a user login:&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
'''Additional configuring:''' &lt;br /&gt;
&lt;br /&gt;
# Under the '''General''' tab, mark the checkbox '''Has teams''' as true and set the maximum number of members per team to number that makes sense (e.g. our demonstration uses 3).&lt;br /&gt;
# You may also want to login to the account of each student you add (they all have &amp;quot;**password**&amp;quot; as their passwords), and help that student bid the topics just like how you did with our OSS project! The algorithm works more effectively when there are bids presented in the system. And by signing up topics, you indirectly create teams for them. We know this process can be very tedious, so thank you ahead for your patience!&lt;br /&gt;
&lt;br /&gt;
Here are some data we used in our recording, you are free to come up with your own!&lt;br /&gt;
&lt;br /&gt;
   | User id                            | First Choice | Second Choice | Third Choice |&lt;br /&gt;
   | ---------------------------------- | ------------ | ------------- | ------------ |&lt;br /&gt;
   | student558                         | 1            |               |              |&lt;br /&gt;
   | student559, student562, student563 | 2            | 3             | 1            |&lt;br /&gt;
   | student560, student561             | 2            | 1             |              |&lt;br /&gt;
   | student564                         | 1            | 2             |              |&lt;br /&gt;
   | student565                         | 3            |               |              |&lt;br /&gt;
   | student566                         | 2            |               |              |&lt;br /&gt;
&lt;br /&gt;
Return to the '''Assignments''' page after you set up the New test assignment, and retry the orange book icon. You should be indicated that the intelligent assignment has run successfully. You can check the teaming result under the '''Topics''' tab of the edit page. The above data generate the teaming result of the following.&lt;br /&gt;
&lt;br /&gt;
= Future Improvements =&lt;br /&gt;
&lt;br /&gt;
# Improving the RSpec test for assigning open topics for teams without topics. The new test only checks for 1 open assignment and 1 unassigned team. The method is capable of assigning multiple open topics for multiple unassigned teams, but testing for this would require more Factory objects for assignments and teams. While the new test provides code coverage for the entire method, the nested loops currently only run through a single time before completion, which is not always the case in a realistic setting.&lt;br /&gt;
# Improving the time-space complexity for the method that merges bids from teams that are merging together. The existing method requires iterating through each member's bidding information to create a hash map. Then there is a nest iteration for the included topics. Afterwards there is an additional iterations through to exclude topics without bids.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132216</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132216"/>
		<updated>2020-03-30T15:44:19Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand, and write new tests to improve test coverage.&lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Added 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represent a specific and meaningful step&lt;br /&gt;
# Replaced large chunks of code with a small number of method calls&lt;br /&gt;
# Reduced the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimized the performance by moving conditional checking and input filtering outside of loops, where appropriate&lt;br /&gt;
# Renamed some variable names to make their purpose clearer&lt;br /&gt;
# Refactored the parameter list to give each method the least amount of information needed to complete its task&lt;br /&gt;
# Added addition comments and fixed some typos&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out and put into helper methods with more meaningful method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Put lines 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash for students on a team who haven't signed up for a topic yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude lines 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude lines 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods only do one thing. For these methods, one can keep them simple with alternative language syntax and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing a new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that, like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works by pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow a good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is not safe to apply such a change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing more beyond just what the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary looping can be avoided by moving the conditional check out. For example, consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, it pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because at this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of Problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== RSpec Testing ==&lt;br /&gt;
&lt;br /&gt;
=== Existing Tests ===&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only provided about 10% coverage of the code in the controller. The test coverage was determined by the Coveralls gem. Most of the existing tests actually didn't even test the functionality of the lottery controller. The existing tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing an http get request to google.com and expecting a 200 response code with the content-type of application/json&amp;lt;br&amp;gt;This was an attempt at testing the web service used by the lottery controller&lt;br /&gt;
# Checking if an assignment had a correctly set is_intelligent attribute&amp;lt;br&amp;gt;Didn't call any methods of the lottery controller&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams&amp;lt;br&amp;gt;Didn't call any methods of the lottery controller&lt;br /&gt;
&lt;br /&gt;
=== After Refactoring ===&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created from the factories.rb file using the factory_bot_rails gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 99%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
These tests can be executed by utilizing the RSpec command in the Command Prompt window by entering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; user:expertiza $rspec spec/controllers/lottery_controller_spec.rb &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== UI Testing (For Reviewers) ==&lt;br /&gt;
&lt;br /&gt;
By following the below steps, you can manually test our refactored &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The previous implementation does the intelligent assignment on a team basis. That is, students who do not belong to any team will not get assigned to topics (see method &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;). We intended not to disrupt this behavior since it's beyond the scope of this refactoring.&lt;br /&gt;
&lt;br /&gt;
# Visit [xxx]. Enter the credentials:&amp;lt;br&amp;gt;'''Username:''' instructor6&amp;lt;br&amp;gt;'''Password:''' password&lt;br /&gt;
# From the menubar, hover on the '''Manage''' tab, and select '''Assignments'''.&lt;br /&gt;
# Scroll down the page and find the assignment with the name '''New test assignment'''. The orange book icon on the right links to the &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class. When you click on that, you should receive an error message claiming &amp;quot;500 Internal Server Error&amp;quot;. This is because this assignment has not properly set up its participants. To get the intelligent assignment to run, you should click on the pencil icon, navigate to &amp;quot;Other stuff -&amp;gt; Add participant&amp;quot;, and add the student by entering its user_id to the textbox next to the label &amp;quot;Enter a user login:&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
'''Additional configuring:''' &lt;br /&gt;
&lt;br /&gt;
# Under the '''General''' tab, mark the checkbox '''Has teams''' as true and set the maximum number of members per team to number that makes sense (e.g. our demonstration uses 3).&lt;br /&gt;
# You may also want to login to the account of each student you add (they all have &amp;quot;**password**&amp;quot; as their passwords), and help that student bid the topics just like how you did with our OSS project! The algorithm works more effectively when there are bids presented in the system. And by signing up topics, you indirectly create teams for them. We know this process can be very tedious, so thank you ahead for your patience!&lt;br /&gt;
&lt;br /&gt;
Here are some data we used in our recording, you are free to come up with your own!&lt;br /&gt;
&lt;br /&gt;
   | User id                            | First Choice | Second Choice | Third Choice |&lt;br /&gt;
   | ---------------------------------- | ------------ | ------------- | ------------ |&lt;br /&gt;
   | student558                         | 1            |               |              |&lt;br /&gt;
   | student559, student562, student563 | 2            | 3             | 1            |&lt;br /&gt;
   | student560, student561             | 2            | 1             |              |&lt;br /&gt;
   | student564                         | 1            | 2             |              |&lt;br /&gt;
   | student565                         | 3            |               |              |&lt;br /&gt;
   | student566                         | 2            |               |              |&lt;br /&gt;
&lt;br /&gt;
Return to the '''Assignments''' page after you set up the New test assignment, and retry the orange book icon. You should be indicated that the intelligent assignment has run successfully. You can check the teaming result under the '''Topics''' tab of the edit page. The above data generate the teaming result of the following.&lt;br /&gt;
&lt;br /&gt;
= Future Improvements =&lt;br /&gt;
&lt;br /&gt;
# Improving the RSpec test for assigning open topics for teams without topics. The new test only checks for 1 open assignment and 1 unassigned team. The method is capable of assigning multiple open topics for multiple unassigned teams, but testing for this would require more Factory objects for assignments and teams. While the new test provides code coverage for the entire method, the nested loops currently only run through a single time before completion, which is not always the case in a realistic setting.&lt;br /&gt;
# Improving the time-space complexity for the method that merges bids from teams that are merging together. The existing method requires iterating through each member's bidding information to create a hash map. Then there is a nest iteration for the included topics. Afterwards there is an additional iterations through to exclude topics without bids.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132215</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132215"/>
		<updated>2020-03-30T15:38:25Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Testing */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand, and write new tests to improve test coverage.&lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Added 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represent a specific and meaningful step&lt;br /&gt;
# Replaced large chunks of code with a small number of method calls&lt;br /&gt;
# Reduced the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimized the performance by moving conditional checking and input filtering outside of loops, where appropriate&lt;br /&gt;
# Renamed some variable names to make their purpose clearer&lt;br /&gt;
# Refactored the parameter list to give each method the least amount of information needed to complete its task&lt;br /&gt;
# Added addition comments and fixed some typos&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out and put into helper methods with more meaningful method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Put lines 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash for students on a team who haven't signed up for a topic yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude lines 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude lines 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods only do one thing. For these methods, one can keep them simple with alternative language syntax and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing a new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that, like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works by pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow a good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is not safe to apply such a change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing more beyond just what the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary looping can be avoided by moving the conditional check out. For example, consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, it pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because at this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of Problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
== Test Plan ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== RSpec Testing ==&lt;br /&gt;
&lt;br /&gt;
=== Existing Tests ===&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only provided about 10% coverage of the code in the controller. The test coverage was determined by the Coveralls gem. Most of the existing tests actually didn't even test the functionality of the lottery controller. The existing tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing an http get request to google.com and expecting a 200 response code with the content-type of application/json&amp;lt;br&amp;gt;This was an attempt at testing the web service used by the lottery controller&lt;br /&gt;
# Checking if an assignment had a correctly set is_intelligent attribute&amp;lt;br&amp;gt;Didn't call any methods of the lottery controller&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams&amp;lt;br&amp;gt;Didn't call any methods of the lottery controller&lt;br /&gt;
&lt;br /&gt;
=== After Refactoring ===&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created from the factories.rb file using the factory_bot_rails gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 97%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
These tests can be executed by utilizing the RSpec command in the Command Prompt window by entering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; user:expertiza $rspec spec/controllers/lottery_controller_spec.rb &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== UI Testing (For Reviewers) ==&lt;br /&gt;
&lt;br /&gt;
By following the below steps, you can manually test our refactored &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The previous implementation does the intelligent assignment on a team basis. That is, students who do not belong to any team will not get assigned to topics (see method &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;). We intended not to disrupt this behavior since it's beyond the scope of this refactoring.&lt;br /&gt;
&lt;br /&gt;
# Visit [xxx]. Enter the credentials:&amp;lt;br&amp;gt;'''Username:''' instructor6&amp;lt;br&amp;gt;'''Password:''' password&lt;br /&gt;
# From the menubar, hover on the '''Manage''' tab, and select '''Assignments'''.&lt;br /&gt;
# Scroll down the page and find the assignment with the name '''New test assignment'''. The orange book icon on the right links to the &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class. When you click on that, you should receive an error message claiming &amp;quot;500 Internal Server Error&amp;quot;. This is because this assignment has not properly set up its participants. To get the intelligent assignment to run, you should click on the pencil icon, navigate to &amp;quot;Other stuff -&amp;gt; Add participant&amp;quot;, and add the student by entering its user_id to the textbox next to the label &amp;quot;Enter a user login:&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
'''Additional configuring:''' &lt;br /&gt;
&lt;br /&gt;
# Under the '''General''' tab, mark the checkbox '''Has teams''' as true and set the maximum number of members per team to number that makes sense (e.g. our demonstration uses 3).&lt;br /&gt;
# You may also want to login to the account of each student you add (they all have &amp;quot;**password**&amp;quot; as their passwords), and help that student bid the topics just like how you did with our OSS project! The algorithm works more effectively when there are bids presented in the system. And by signing up topics, you indirectly create teams for them. We know this process can be very tedious, so thank you ahead for your patience!&lt;br /&gt;
&lt;br /&gt;
Here are some data we used in our recording, you are free to come up with your own!&lt;br /&gt;
&lt;br /&gt;
   | User id                            | First Choice | Second Choice | Third Choice |&lt;br /&gt;
   | ---------------------------------- | ------------ | ------------- | ------------ |&lt;br /&gt;
   | student558                         | 1            |               |              |&lt;br /&gt;
   | student559, student562, student563 | 2            | 3             | 1            |&lt;br /&gt;
   | student560, student561             | 2            | 1             |              |&lt;br /&gt;
   | student564                         | 1            | 2             |              |&lt;br /&gt;
   | student565                         | 3            |               |              |&lt;br /&gt;
   | student566                         | 2            |               |              |&lt;br /&gt;
&lt;br /&gt;
Return to the '''Assignments''' page after you set up the New test assignment, and retry the orange book icon. You should be indicated that the intelligent assignment has run successfully. You can check the teaming result under the '''Topics''' tab of the edit page. The above data generate the teaming result of the following.&lt;br /&gt;
&lt;br /&gt;
= Future Improvements =&lt;br /&gt;
&lt;br /&gt;
# Improving the RSpec test for assigning open topics for teams without topics. The new test only checks for 1 open assignment and 1 unassigned team. The method is capable of assigning multiple open topics for multiple unassigned teams, but testing for this would require more Factory objects for assignments and teams. While the new test provides code coverage for the entire method, the nested loops currently only run through a single time before completion, which is not always the case in a realistic setting.&lt;br /&gt;
# Improving the time-space complexity for the method that merges bids from teams that are merging together. The existing method requires iterating through each member's bidding information to create a hash map. Then there is a nest iteration for the included topics. Afterwards there is an additional iterations through to exclude topics without bids.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132214</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132214"/>
		<updated>2020-03-30T15:37:46Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Running the Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand, and write new tests to improve test coverage.&lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Added 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represent a specific and meaningful step&lt;br /&gt;
# Replaced large chunks of code with a small number of method calls&lt;br /&gt;
# Reduced the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimized the performance by moving conditional checking and input filtering outside of loops, where appropriate&lt;br /&gt;
# Renamed some variable names to make their purpose clearer&lt;br /&gt;
# Refactored the parameter list to give each method the least amount of information needed to complete its task&lt;br /&gt;
# Added addition comments and fixed some typos&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out and put into helper methods with more meaningful method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Put lines 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash for students on a team who haven't signed up for a topic yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude lines 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude lines 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods only do one thing. For these methods, one can keep them simple with alternative language syntax and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing a new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that, like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works by pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow a good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is not safe to apply such a change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing more beyond just what the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary looping can be avoided by moving the conditional check out. For example, consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, it pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because at this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of Problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= Testing =&lt;br /&gt;
&lt;br /&gt;
== RSpec Testing ==&lt;br /&gt;
&lt;br /&gt;
=== Existing Tests ===&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only provided about 10% coverage of the code in the controller. The test coverage was determined by the Coveralls gem. Most of the existing tests actually didn't even test the functionality of the lottery controller. The existing tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing an http get request to google.com and expecting a 200 response code with the content-type of application/json&amp;lt;br&amp;gt;This was an attempt at testing the web service used by the lottery controller&lt;br /&gt;
# Checking if an assignment had a correctly set is_intelligent attribute&amp;lt;br&amp;gt;Didn't call any methods of the lottery controller&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams&amp;lt;br&amp;gt;Didn't call any methods of the lottery controller&lt;br /&gt;
&lt;br /&gt;
=== After Refactoring ===&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created from the factories.rb file using the factory_bot_rails gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 97%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
These tests can be executed by utilizing the RSpec command in the Command Prompt window by entering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; user:expertiza $rspec spec/controllers/lottery_controller_spec.rb &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== UI Testing (For Reviewers) ==&lt;br /&gt;
&lt;br /&gt;
By following the below steps, you can manually test our refactored &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The previous implementation does the intelligent assignment on a team basis. That is, students who do not belong to any team will not get assigned to topics (see method &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;). We intended not to disrupt this behavior since it's beyond the scope of this refactoring.&lt;br /&gt;
&lt;br /&gt;
# Visit [xxx]. Enter the credentials:&amp;lt;br&amp;gt;'''Username:''' instructor6&amp;lt;br&amp;gt;'''Password:''' password&lt;br /&gt;
# From the menubar, hover on the '''Manage''' tab, and select '''Assignments'''.&lt;br /&gt;
# Scroll down the page and find the assignment with the name '''New test assignment'''. The orange book icon on the right links to the &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class. When you click on that, you should receive an error message claiming &amp;quot;500 Internal Server Error&amp;quot;. This is because this assignment has not properly set up its participants. To get the intelligent assignment to run, you should click on the pencil icon, navigate to &amp;quot;Other stuff -&amp;gt; Add participant&amp;quot;, and add the student by entering its user_id to the textbox next to the label &amp;quot;Enter a user login:&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
'''Additional configuring:''' &lt;br /&gt;
&lt;br /&gt;
# Under the '''General''' tab, mark the checkbox '''Has teams''' as true and set the maximum number of members per team to number that makes sense (e.g. our demonstration uses 3).&lt;br /&gt;
# You may also want to login to the account of each student you add (they all have &amp;quot;**password**&amp;quot; as their passwords), and help that student bid the topics just like how you did with our OSS project! The algorithm works more effectively when there are bids presented in the system. And by signing up topics, you indirectly create teams for them. We know this process can be very tedious, so thank you ahead for your patience!&lt;br /&gt;
&lt;br /&gt;
Here are some data we used in our recording, you are free to come up with your own!&lt;br /&gt;
&lt;br /&gt;
   | User id                            | First Choice | Second Choice | Third Choice |&lt;br /&gt;
   | ---------------------------------- | ------------ | ------------- | ------------ |&lt;br /&gt;
   | student558                         | 1            |               |              |&lt;br /&gt;
   | student559, student562, student563 | 2            | 3             | 1            |&lt;br /&gt;
   | student560, student561             | 2            | 1             |              |&lt;br /&gt;
   | student564                         | 1            | 2             |              |&lt;br /&gt;
   | student565                         | 3            |               |              |&lt;br /&gt;
   | student566                         | 2            |               |              |&lt;br /&gt;
&lt;br /&gt;
Return to the '''Assignments''' page after you set up the New test assignment, and retry the orange book icon. You should be indicated that the intelligent assignment has run successfully. You can check the teaming result under the '''Topics''' tab of the edit page. The above data generate the teaming result of the following.&lt;br /&gt;
&lt;br /&gt;
= Future Improvements =&lt;br /&gt;
&lt;br /&gt;
# Improving the RSpec test for assigning open topics for teams without topics. The new test only checks for 1 open assignment and 1 unassigned team. The method is capable of assigning multiple open topics for multiple unassigned teams, but testing for this would require more Factory objects for assignments and teams. While the new test provides code coverage for the entire method, the nested loops currently only run through a single time before completion, which is not always the case in a realistic setting.&lt;br /&gt;
# Improving the time-space complexity for the method that merges bids from teams that are merging together. The existing method requires iterating through each member's bidding information to create a hash map. Then there is a nest iteration for the included topics. Afterwards there is an additional iterations through to exclude topics without bids.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132030</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=132030"/>
		<updated>2020-03-24T01:08:01Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* Future Improvements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand and write new tests to improve test coverage. &lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Add 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represents a specific and meaningful step&lt;br /&gt;
# Replace large chunks of code with a small number of method calls&lt;br /&gt;
# Reduce the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimize the performance by placing conditional checking and input filtering outside of the loop&lt;br /&gt;
# Rename some variable names to make it self-revealing&lt;br /&gt;
# Refactor the parameter list to give each method the least amount of information to complete its task&lt;br /&gt;
# Fix some typos in the comments&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out to distinct methods and be assigned with self-revealing method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Pull line 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash based on students who haven't signed up yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude line 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude line 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods are invested in doing only one thing. For these methods, one can keep them simple with alternative language syntaxes and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. How &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works are pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow the good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is safe to not apply such change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing beyond the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary loopings can be avoided by moving the checking condition out. For example, still consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because up to this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of the problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= RSpec Testing =&lt;br /&gt;
&lt;br /&gt;
== Existing Tests ==&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only coverage about 10% of the code in the controller. The test coverage was determined by the Coveralls gem. The existing tests were only testing small parts of the existing long methods. The current tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing the webservice call and the JSON response type for the users' bidding data&lt;br /&gt;
# Checking if an intelligent assignment is truly intelligent&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams&lt;br /&gt;
&lt;br /&gt;
== After Refactoring ==&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created using the Factory gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 97%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
These tests can be executed by utilizing the RSpec command in the Command Prompt window by entering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; user:expertiza $rspec spec/controllers/lottery_controller_spec.rb &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Future Improvements =&lt;br /&gt;
&lt;br /&gt;
# Improving the RSpec test for assigning open topics for teams without topics. The new test only checks for 1 open assignment and 1 unassigned team. The method is capable of assigning multiple open topics for multiple unassigned teams, but testing for this would require more Factory objects for assignments and teams. While the new test provides code coverage for the entire method, the nested loops currently only run through a single time before completion, which is not always the case in a realistic setting.&lt;br /&gt;
# Improving the time-space complexity for the method that merges bids from teams that are merging together. The existing method requires iterating through each member's bidding information to create a hash map. Then there is a nest iteration for the included topics. Afterwards there is an additional iterations through to exclude topics without bids.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=131991</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=131991"/>
		<updated>2020-03-24T00:18:30Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* After Refactoring */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand and write new tests to improve test coverage. &lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Add 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represents a specific and meaningful step&lt;br /&gt;
# Replace large chunks of code with a small number of method calls&lt;br /&gt;
# Reduce the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimize the performance by placing conditional checking and input filtering outside of the loop&lt;br /&gt;
# Rename some variable names to make it self-revealing&lt;br /&gt;
# Refactor the parameter list to give each method the least amount of information to complete its task&lt;br /&gt;
# Fix some typos in the comments&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out to distinct methods and be assigned with self-revealing method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Pull line 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash based on students who haven't signed up yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude line 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude line 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods are invested in doing only one thing. For these methods, one can keep them simple with alternative language syntaxes and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. How &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works are pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow the good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is safe to not apply such change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing beyond the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary loopings can be avoided by moving the checking condition out. For example, still consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because up to this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of the problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= RSpec Testing =&lt;br /&gt;
&lt;br /&gt;
== Existing Tests ==&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only coverage about 10% of the code in the controller. The test coverage was determined by the Coveralls gem. The existing tests were only testing small parts of the existing long methods. The current tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing the webservice call and the JSON response type for the users' bidding data&lt;br /&gt;
# Checking if an intelligent assignment is truly intelligent&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams&lt;br /&gt;
&lt;br /&gt;
== After Refactoring ==&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created using the Factory gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 97%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;br /&gt;
&lt;br /&gt;
=== Running the Tests ===&lt;br /&gt;
These tests can be executed by utilizing the RSpec command in the Command Prompt window by entering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; user:expertiza $rspec spec/controllers/lottery_controller_spec.rb &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Future Improvements =&lt;br /&gt;
&lt;br /&gt;
# Improving the RSpec test for assigning open topics for teams without topics. The new test only checks for 1 open assignment and 1 unassigned team. The method is capable of assigning multiple open topics for multiple unassigned teams, but testing for this would require more Factory objects for assignments and teams. While the new test provides code coverage for the entire method, the nested loops currently only run through a single time before completion, which is not always the case in a realistic setting.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=131987</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=131987"/>
		<updated>2020-03-24T00:16:23Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* After Refactoring */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand and write new tests to improve test coverage. &lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Add 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represents a specific and meaningful step&lt;br /&gt;
# Replace large chunks of code with a small number of method calls&lt;br /&gt;
# Reduce the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimize the performance by placing conditional checking and input filtering outside of the loop&lt;br /&gt;
# Rename some variable names to make it self-revealing&lt;br /&gt;
# Refactor the parameter list to give each method the least amount of information to complete its task&lt;br /&gt;
# Fix some typos in the comments&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out to distinct methods and be assigned with self-revealing method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Pull line 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash based on students who haven't signed up yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude line 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude line 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods are invested in doing only one thing. For these methods, one can keep them simple with alternative language syntaxes and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. How &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works are pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow the good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is safe to not apply such change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing beyond the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary loopings can be avoided by moving the checking condition out. For example, still consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because up to this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of the problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= RSpec Testing =&lt;br /&gt;
&lt;br /&gt;
== Existing Tests ==&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only coverage about 10% of the code in the controller. The test coverage was determined by the Coveralls gem. The existing tests were only testing small parts of the existing long methods. The current tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing the webservice call and the JSON response type for the users' bidding data&lt;br /&gt;
# Checking if an intelligent assignment is truly intelligent&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams&lt;br /&gt;
&lt;br /&gt;
== After Refactoring ==&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created using the Factory gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 97%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;br /&gt;
&lt;br /&gt;
These tests can be executed by utilizing the RSpec command in the Command Prompt window by entering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; user:expertiza $rspec spec/controllers/lottery_controller_spec.rb &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Future Improvements =&lt;br /&gt;
&lt;br /&gt;
# Improving the RSpec test for assigning open topics for teams without topics. The new test only checks for 1 open assignment and 1 unassigned team. The method is capable of assigning multiple open topics for multiple unassigned teams, but testing for this would require more Factory objects for assignments and teams. While the new test provides code coverage for the entire method, the nested loops currently only run through a single time before completion, which is not always the case in a realistic setting.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=131985</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=131985"/>
		<updated>2020-03-24T00:16:02Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* After Refactoring */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand and write new tests to improve test coverage. &lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Add 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represents a specific and meaningful step&lt;br /&gt;
# Replace large chunks of code with a small number of method calls&lt;br /&gt;
# Reduce the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimize the performance by placing conditional checking and input filtering outside of the loop&lt;br /&gt;
# Rename some variable names to make it self-revealing&lt;br /&gt;
# Refactor the parameter list to give each method the least amount of information to complete its task&lt;br /&gt;
# Fix some typos in the comments&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out to distinct methods and be assigned with self-revealing method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Pull line 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash based on students who haven't signed up yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude line 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude line 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods are invested in doing only one thing. For these methods, one can keep them simple with alternative language syntaxes and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. How &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works are pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow the good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is safe to not apply such change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing beyond the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary loopings can be avoided by moving the checking condition out. For example, still consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because up to this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of the problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= RSpec Testing =&lt;br /&gt;
&lt;br /&gt;
== Existing Tests ==&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only coverage about 10% of the code in the controller. The test coverage was determined by the Coveralls gem. The existing tests were only testing small parts of the existing long methods. The current tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing the webservice call and the JSON response type for the users' bidding data&lt;br /&gt;
# Checking if an intelligent assignment is truly intelligent&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams&lt;br /&gt;
&lt;br /&gt;
== After Refactoring ==&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created using the Factory gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 97%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;br /&gt;
&lt;br /&gt;
These tests can be executed by utilizing the RSpec command in the Command Prompt window by entering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; user:expertiza $rspec spec/controllers/lottery_controller_spec.rb&lt;br /&gt;
&lt;br /&gt;
= Future Improvements =&lt;br /&gt;
&lt;br /&gt;
# Improving the RSpec test for assigning open topics for teams without topics. The new test only checks for 1 open assignment and 1 unassigned team. The method is capable of assigning multiple open topics for multiple unassigned teams, but testing for this would require more Factory objects for assignments and teams. While the new test provides code coverage for the entire method, the nested loops currently only run through a single time before completion, which is not always the case in a realistic setting.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=131982</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=131982"/>
		<updated>2020-03-24T00:15:48Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: /* After Refactoring */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand and write new tests to improve test coverage. &lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Add 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represents a specific and meaningful step&lt;br /&gt;
# Replace large chunks of code with a small number of method calls&lt;br /&gt;
# Reduce the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimize the performance by placing conditional checking and input filtering outside of the loop&lt;br /&gt;
# Rename some variable names to make it self-revealing&lt;br /&gt;
# Refactor the parameter list to give each method the least amount of information to complete its task&lt;br /&gt;
# Fix some typos in the comments&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out to distinct methods and be assigned with self-revealing method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Pull line 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash based on students who haven't signed up yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude line 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude line 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods are invested in doing only one thing. For these methods, one can keep them simple with alternative language syntaxes and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. How &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works are pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow the good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is safe to not apply such change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing beyond the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary loopings can be avoided by moving the checking condition out. For example, still consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because up to this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of the problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= RSpec Testing =&lt;br /&gt;
&lt;br /&gt;
== Existing Tests ==&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only coverage about 10% of the code in the controller. The test coverage was determined by the Coveralls gem. The existing tests were only testing small parts of the existing long methods. The current tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing the webservice call and the JSON response type for the users' bidding data&lt;br /&gt;
# Checking if an intelligent assignment is truly intelligent&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams&lt;br /&gt;
&lt;br /&gt;
== After Refactoring ==&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created using the Factory gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 97%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;br /&gt;
&lt;br /&gt;
These tests can be executed by utilizing the RSpec command in the Command Prompt window by entering:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt; user:expertiza $rspec spec/controllers/lottery_controller_spec.rb &amp;lt;code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Future Improvements =&lt;br /&gt;
&lt;br /&gt;
# Improving the RSpec test for assigning open topics for teams without topics. The new test only checks for 1 open assignment and 1 unassigned team. The method is capable of assigning multiple open topics for multiple unassigned teams, but testing for this would require more Factory objects for assignments and teams. While the new test provides code coverage for the entire method, the nested loops currently only run through a single time before completion, which is not always the case in a realistic setting.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=131980</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=131980"/>
		<updated>2020-03-24T00:13:25Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: Future Improvements&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand and write new tests to improve test coverage. &lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Add 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represents a specific and meaningful step&lt;br /&gt;
# Replace large chunks of code with a small number of method calls&lt;br /&gt;
# Reduce the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimize the performance by placing conditional checking and input filtering outside of the loop&lt;br /&gt;
# Rename some variable names to make it self-revealing&lt;br /&gt;
# Refactor the parameter list to give each method the least amount of information to complete its task&lt;br /&gt;
# Fix some typos in the comments&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out to distinct methods and be assigned with self-revealing method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Pull line 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash based on students who haven't signed up yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude line 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude line 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods are invested in doing only one thing. For these methods, one can keep them simple with alternative language syntaxes and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. How &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works are pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow the good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is safe to not apply such change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing beyond the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary loopings can be avoided by moving the checking condition out. For example, still consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because up to this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of the problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= RSpec Testing =&lt;br /&gt;
&lt;br /&gt;
== Existing Tests ==&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only coverage about 10% of the code in the controller. The test coverage was determined by the Coveralls gem. The existing tests were only testing small parts of the existing long methods. The current tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing the webservice call and the JSON response type for the users' bidding data&lt;br /&gt;
# Checking if an intelligent assignment is truly intelligent&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams&lt;br /&gt;
&lt;br /&gt;
== After Refactoring ==&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created using the Factory gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 97%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Future Improvements =&lt;br /&gt;
&lt;br /&gt;
# Improving the RSpec test for assigning open topics for teams without topics. The new test only checks for 1 open assignment and 1 unassigned team. The method is capable of assigning multiple open topics for multiple unassigned teams, but testing for this would require more Factory objects for assignments and teams. While the new test provides code coverage for the entire method, the nested loops currently only run through a single time before completion, which is not always the case in a realistic setting.&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=131979</id>
		<title>CSC/ECE 517 Spring 2020/E2012. refactor lottery controller.rb</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Spring_2020/E2012._refactor_lottery_controller.rb&amp;diff=131979"/>
		<updated>2020-03-24T00:13:00Z</updated>

		<summary type="html">&lt;p&gt;Thwinter: RSpec Testing&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Introduction =&lt;br /&gt;
&lt;br /&gt;
== Expertiza Background ==&lt;br /&gt;
&lt;br /&gt;
Expertiza is an open-source project written using the Ruby on Rails framework.  The Expertiza platform aims to improve student learning by using active and cooperative learning, allowing distance education students to participate in active learning, and by discouraging plagiarism through the use of multiple deadlines. Expertiza helps to improve teaching and resource utilization by having students contribute to the creation of course materials and through peer-graded assignments. Expertiza manages objects related to a course such as instructors, TAs, students, and other users. It also manages assignments, teams, signup topics, rubrics, peer grading, and peer evaluations. &lt;br /&gt;
&lt;br /&gt;
== Lottery Controller Background ==&lt;br /&gt;
&lt;br /&gt;
An assignment can have a list of signup topics. The teams associated with the assignment can bid on the signup topics to try and get assigned one they find more favorable. At a high level, the lottery controller assigns teams to topics based on the priorities the team gave to each signup topic during the bidding process. &lt;br /&gt;
&lt;br /&gt;
In more detail, each student starts off on a team of size 1. They can bid on signup topics by arranging them in priority order. A team can invite other users to join their team. If student2 from Team B joins Team A which includes student1, student2 will lose their bids and take on the bids of TeamA and student1.&lt;br /&gt;
When the lottery controller is called to run its method run_intelligent_assignment, a web service takes the bidding data from each team and returns a new list of teams, each of which is closer to the maximum team size specified for the assignment. The web service combines teams together that have similar&lt;br /&gt;
bid data and then assigns those new teams to topics, giving each team their top bid on a topic that hasn't been assigned yet. Teams with larger team sizes and more bids are assigned their topics first. &lt;br /&gt;
&lt;br /&gt;
== Problem Statement ==&lt;br /&gt;
&lt;br /&gt;
Code Climate currently grades &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; at a C level, finding issues with the controller's long methods and complex statements. Most methods are around 40 lines and hard to decipher with a quick look. Also, the file currently has only 10% test coverage. Our goal is to resolve the Code Climate issues, make methods simpler to understand and write new tests to improve test coverage. &lt;br /&gt;
&lt;br /&gt;
== Tasks Identified ==&lt;br /&gt;
&lt;br /&gt;
# Cut down on code in run_intelligent_assignment method by moving some code to helper methods&lt;br /&gt;
# Cut down on code in create_new_teams_for_bidding_response by moving some code to helper methods&lt;br /&gt;
# Cut down on code in match_new_teams_to_topics by moving some code to helper methods&lt;br /&gt;
# Reduce cognitive complexity of merge_bids_from_different_previous_teams method&lt;br /&gt;
# Add additional comments to clarify newly written methods&lt;br /&gt;
# Add additional RSpec tests to increase the coverage percentage&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
&lt;br /&gt;
We did the following refactoring to the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt; class:&lt;br /&gt;
&lt;br /&gt;
# Add 6 helper methods (&amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_user_from_previous_team&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt;) that each represents a specific and meaningful step&lt;br /&gt;
# Replace large chunks of code with a small number of method calls&lt;br /&gt;
# Reduce the cognitive complexity by reducing the level of nested loops&lt;br /&gt;
# Optimize the performance by placing conditional checking and input filtering outside of the loop&lt;br /&gt;
# Rename some variable names to make it self-revealing&lt;br /&gt;
# Refactor the parameter list to give each method the least amount of information to complete its task&lt;br /&gt;
# Fix some typos in the comments&lt;br /&gt;
&lt;br /&gt;
Here are some examples of the problems we identified and the solutions we found to these problems.&lt;br /&gt;
&lt;br /&gt;
=== Problem 1: Long Methods ===&lt;br /&gt;
&lt;br /&gt;
The code climate analysis tool identified two long methods exceeding 25 lines of code per method, &amp;lt;code&amp;gt;run_intelligent_assignment&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt;. While some chunks of code are short and intuitive, others can be pulled out to distinct methods and be assigned with self-revealing method names.&lt;br /&gt;
&lt;br /&gt;
====Solutions ====&lt;br /&gt;
&lt;br /&gt;
=====run_intelligent_assignment=====&lt;br /&gt;
&lt;br /&gt;
1. Pull line 19-29 into a separate method called &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating user bidding information hash based on students who haven't signed up yet&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_1.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
2. Place the code closest to where it is needed. e.g. place line 32 (the &amp;lt;code&amp;gt;url&amp;lt;/code&amp;gt; variable initialization)  inside the &amp;lt;code&amp;gt;begin/rescue&amp;lt;/code&amp;gt; block because it is considered an integral part of the REST API call.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_2.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
===== match_new_teams_to_topics =====&lt;br /&gt;
&lt;br /&gt;
1. Conclude line 147-157 with a new method &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; that is responsible for generating team bidding information needed for the  &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
2. Conclude line 161-169 with a new method &amp;lt;code&amp;gt;assign_available_slots&amp;lt;/code&amp;gt; that uses the result returned from &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt; to match unassigned teams to available topics.&lt;br /&gt;
&lt;br /&gt;
These two steps greatly shorten the &amp;lt;code&amp;gt;match_new_teams_to_topics&amp;lt;/code&amp;gt; method and make the workflow more intuitive to code maintainers.&lt;br /&gt;
&lt;br /&gt;
[[Media:E2012_3.png| view code changes]]&lt;br /&gt;
&lt;br /&gt;
=== Problem 2: Verbose Code ===&lt;br /&gt;
&lt;br /&gt;
Verbosity contributes to more lines of codes and increases the cognitive complexity, which is the measure of how difficult a unit of code is to intuitively understand. Method extraction can't be applied to every long method as some methods are invested in doing only one thing. For these methods, one can keep them simple with alternative language syntaxes and other ways of thinking of the behavior.&lt;br /&gt;
&lt;br /&gt;
==== Solutions ====&lt;br /&gt;
&lt;br /&gt;
===== Example 1 =====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix = {}&lt;br /&gt;
    assignment.sign_up_topics.each_with_index do |topic, index|	&lt;br /&gt;
      bidding_matrix[topic.id] = [] unless bidding_matrix[topic.id]	&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
The above code segment ensures that &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; returns an array object before pushing new value to it.  It is inelegant both in its readability and the time wasted to visit each &amp;lt;code&amp;gt;bidding_matrix[topic.id]&amp;lt;/code&amp;gt; twice. The same behavior can be accomplished by constructing a Hash object that knows what default value to return when the key has not been seen before. &lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix = Hash.new {|hash, key| hash[key] = [] }&lt;br /&gt;
    sign_up_topics.each_with_index do |topic, index|&lt;br /&gt;
      bidding_matrix[topic.id] &amp;lt;&amp;lt; bids[index]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=====Example 2=====&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    teams.each do |team|&lt;br /&gt;
      next if SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any?&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
This block is extracted from the original implementation that like many places in the &amp;lt;code&amp;gt;LotteryController&amp;lt;/code&amp;gt;, uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip any elements that don't fulfill the imposed condition. It's more reasonable to eliminate out unwanted elements outside of the loop using either &amp;lt;code&amp;gt;select&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;reject&amp;lt;/code&amp;gt; call. Below is the modification made to this block.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    teams_not_signed_up = teams.reject {|team| SignedUpTeam.where(team_id: team.id, is_waitlisted: 0).any? }&lt;br /&gt;
    teams_not_signed_up.each do |team|&lt;br /&gt;
      ... (rest of code omitted)&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
===== Example 3 =====&lt;br /&gt;
&lt;br /&gt;
Same as example 1, the following block uses &amp;lt;code&amp;gt;next&amp;lt;/code&amp;gt; to skip unwanted &amp;lt;code&amp;gt;team_user&amp;lt;/code&amp;gt;s until the one that meets the condition, that is, who belongs to the specified assignment. This code does the filtering twice, which can be combined with one query.&lt;br /&gt;
​&lt;br /&gt;
    # Before&lt;br /&gt;
    TeamsUser.where(user_id: user_id).each do |team_user|	&lt;br /&gt;
      next unless team_user.team.parent_id == assignment.id	&lt;br /&gt;
      team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
      team_user.destroy rescue nil	&lt;br /&gt;
      break	&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
We first tried to use &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; with two parameters. How &amp;lt;code&amp;gt;find_by&amp;lt;/code&amp;gt; works are pulling column values from the model object. Since the &amp;lt;code&amp;gt;TeamsUser&amp;lt;/code&amp;gt; model does not have a &amp;lt;code&amp;gt;team&amp;lt;/code&amp;gt; attribute (it only stores &amp;lt;code&amp;gt;team_id&amp;lt;/code&amp;gt;), this attempt is syntactically illegal.&lt;br /&gt;
&lt;br /&gt;
    team_user = TeamsUser.find_by(user_id: user_id, team.parent_id: assignment_id)&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil	&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
The way we refactored the code is to use the &amp;lt;code&amp;gt;find&amp;lt;/code&amp;gt; method from the &amp;lt;code&amp;gt;Enumerable&amp;lt;/code&amp;gt; mixin to get the first element for which the block is not false. In this way, the loop will no longer be necessary since the only thing it does is finding the first matching object.&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team_user = TeamsUser.where(user_id: user_id).find{|team_user| team_user.team.parent_id == assignment_id }&lt;br /&gt;
    team_user.team_user_node.destroy rescue nil&lt;br /&gt;
    team_user.destroy rescue nil&lt;br /&gt;
&lt;br /&gt;
===== Example 4 =====&lt;br /&gt;
&lt;br /&gt;
Besides pulling unwanted elements out before entering the loop, one can further reduce the verbosity of the code by replacing &amp;lt;code&amp;gt;next if&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;unless&amp;lt;/code&amp;gt; and adding this checking step to the only statement that's inside the loop.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      next if value.inject(:+).zero?&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id]&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    bidding_matrix.each do |topic_id, value|&lt;br /&gt;
      bidding_matrix_summary &amp;lt;&amp;lt; [value.count {|i| i != 0 }, value.inject(:+), topic_id] unless value.inject(:+).zero?&lt;br /&gt;
    end&lt;br /&gt;
&lt;br /&gt;
=== Problem 3: Ambiguous Identifiers ===&lt;br /&gt;
&lt;br /&gt;
There were many puzzling variable names in the original &amp;lt;code&amp;gt;lottery_controller.rb&amp;lt;/code&amp;gt; file. For example, copied from line 30, the slot with the label &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt; accepts an input of &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt;. &lt;br /&gt;
    bidding_data = {users: priority_info, max_team_size: assignment.max_team_size}&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; is an array of hashes, each hash stores a pair of user id and bids that the user has made so far. This variable name is not descriptive enough to visualize its content. It is refactored into a new name, &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, and the corresponding construction method is therefore named &amp;lt;code&amp;gt;construct_users_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
​&lt;br /&gt;
There is another array that has a very similar structure to the &amp;lt;code&amp;gt;users_bidding_info&amp;lt;/code&amp;gt;, except that it holds bidding information for teams rather than users. To follow the good naming consistency,  this array is granted a new name called &amp;lt;code&amp;gt;teams_bidding_info&amp;lt;/code&amp;gt; (previously named &amp;lt;code&amp;gt;team_bids&amp;lt;/code&amp;gt;) and the name of the corresponding construction method is changed to &amp;lt;code&amp;gt;construct_teams_bidding_info&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Notes'''&lt;br /&gt;
&lt;br /&gt;
We originally considered to change the label &amp;lt;code&amp;gt;ranks&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; because the same identity has been presented in three different forms throughout the file: &amp;lt;code&amp;gt;rank&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;bid&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;priority&amp;lt;/code&amp;gt;. &lt;br /&gt;
    |user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids}&lt;br /&gt;
However, such a change could have an impact on the later REST API call to the web service that uses students' bidding data to build teams automatically. We are uncertain about how the bidding data is actually used at the other end so it is safe to not apply such change.&lt;br /&gt;
&lt;br /&gt;
=== Problem 4: Multi-Purposed Methods ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method does more than 1 thing, both creating new teams and deleting residual teams that none of their team members remained in their teams. Since it is doing beyond the name implies, it is reasonable to extract the removing part of the code to a new method and place the method call after the call to the &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; method.&lt;br /&gt;
&lt;br /&gt;
    # Before&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, priority_info)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;create_new_teams_for_bidding_response&amp;lt;/code&amp;gt; is responsible for both creation and deletion of AssignmentTeam objects&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    create_new_teams_for_bidding_response(teams, assignment, users_bidding_info)&lt;br /&gt;
    remove_empty_teams(assignment)&lt;br /&gt;
    # ^^ &amp;lt;code&amp;gt;remove_empty_teams&amp;lt;/code&amp;gt; becomes a separate method&lt;br /&gt;
    match_new_teams_to_topics(assignment)&lt;br /&gt;
&lt;br /&gt;
=== Problem 5: Unnecessary Looping ===&lt;br /&gt;
&lt;br /&gt;
Many unnecessary loopings can be avoided by moving the checking condition out. For example, still consider this piece of code.&lt;br /&gt;
&lt;br /&gt;
    #Before&lt;br /&gt;
    bids = []	&lt;br /&gt;
    topics.each do |topic|	&lt;br /&gt;
      bid_record = Bid.find_by(team_id: team.id, topic_id: topic.id)	&lt;br /&gt;
      bids &amp;lt;&amp;lt; (bid_record.nil? ? 0 : bid_record.priority ||= 0)	&lt;br /&gt;
    end&lt;br /&gt;
    team.users.each {|user| priority_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} if bids.uniq != [0] }&lt;br /&gt;
&lt;br /&gt;
The last line shows a looping on the team users that for each user in the team, pushes its user id along with the generated bids to the &amp;lt;code&amp;gt;priority_info&amp;lt;/code&amp;gt; array. If there are 3 users in a team, then the comparison &amp;lt;code&amp;gt;if bids.uniq != [0]&amp;lt;/code&amp;gt; always gets executed 3 times while it should only be executed once because up to this point the &amp;lt;code&amp;gt;bids&amp;lt;/code&amp;gt; variable will not be changed anymore. The solution to this performance drawback would be to change the last line to the code below:&lt;br /&gt;
&lt;br /&gt;
    # After&lt;br /&gt;
    team.users.each {|user| users_bidding_info &amp;lt;&amp;lt; {pid: user.id, ranks: bids} } unless bids.uniq == [0]&lt;br /&gt;
    # Note that priority_info has been renamed to users_bidding_info&lt;br /&gt;
&lt;br /&gt;
Other fixes on the unnecessary looping are demonstrated in examples 2 and 3 of the problem 2. Instead of moving the checking condition out, they each move the filter out so the loop runs in a minimum number of times.&lt;br /&gt;
&lt;br /&gt;
= RSpec Testing =&lt;br /&gt;
&lt;br /&gt;
== Existing Tests ==&lt;br /&gt;
There were existing RSpec tests for the Lottery Controller, but the tests only coverage about 10% of the code in the controller. The test coverage was determined by the Coveralls gem. The existing tests were only testing small parts of the existing long methods. The current tests included the following:&lt;br /&gt;
&lt;br /&gt;
# Testing the webservice call and the JSON response type for the users' bidding data&lt;br /&gt;
# Checking if an intelligent assignment is truly intelligent&lt;br /&gt;
# Creating new team for a bid&lt;br /&gt;
# Sorting unassigned teams&lt;br /&gt;
&lt;br /&gt;
== After Refactoring ==&lt;br /&gt;
&lt;br /&gt;
After refactoring the Lottery Controller, the long methods were broken down into smaller, more simpler methods. This required a new RSpec test for each of the new methods, but it allowed for increased code coverage. In order to effectively test the rest of the controller, testing objects that mimic the expected application objects were created. The testing objects were created using the Factory gem and the double feature of the RSpec gem. The objects are also recreated before each test so that the tests are independent from one another to truly validate the different testing sections. The added tests were able to expand the code coverage from about 10% to 97%. The new tests that were added for each of the newly condensed methods include testing for the following:&lt;br /&gt;
&lt;br /&gt;
# Constructing the hash table for the users' bidding information&lt;br /&gt;
# A more exhaustive running Intelligent Assignment method&lt;br /&gt;
# Generate the hash for a whole team's bidding information&lt;br /&gt;
# Match new teams to a topic based on their bids&lt;br /&gt;
# Remove a user from a team&lt;br /&gt;
# Destroying teams that have no users&lt;br /&gt;
# Merging the bids from teams that have merged together so that they have a weighted uniform bid&lt;br /&gt;
# Assigning open topics to teams that do not have a topic yet&lt;br /&gt;
# Matching teams to topics based on their weighted bids&lt;/div&gt;</summary>
		<author><name>Thwinter</name></author>
	</entry>
</feed>