CompSci 307
Spring 2019
Software Design and Implementation

Code Critique and Refactoring

This exercise is intended to help you to learn to critically read code, understand its purpose, and identify ways to improve its design. Along the way, you should start to build a sense of the reader's expectations about code and what makes one piece of code better than another given a specific set of design goals. In pairs, examine the code from the perspective of how readable it is (i.e., is it easy to find or understand important parts of the code, does it do what you expect, does it require more or fewer comments). While studying this code, also note any good things about the code, that you might keep in the final version as well as smells in the code.

CompSci 101 currently, and CompSci 201 previously, give an assignment based on the game of Hangman. It is typically given in multiple parts based on what concept students are learning in the course, but the instructions tend to be the same: copy your previous version and update it to implement new kinds of players (either a guesser or executioner). To simulate this, there are three versions of the game that each play slightly differently. The goal of this exercise is to use the differences between the three versions of Hangman games to identify what code is specific to the players and extract those differences into guesser and executioner classes with methods that can be called from the game code instead of being part of the game class. In the end, instead of three classes that represent one concept within the project and have significant duplication, you should have three classes (game, guesser, and executioner) with no duplication that represent distinct concepts in the project. Removing the duplication and decomposing one conceptual class into three will also improve the overall design by separating the game logic from the player logic so that they can be changed independently.

To work on this lab exercise, fork the original project lab_hangman into your own repository so you can edit, commit, and push your group's own changes.

Discussion

In pairs, read over the code to see if you have any questions about how it works.

To begin discussing the code's design, spend some time evaluating the code using the following questions as a guide:

Then spend some time separating the game logic from the player logic by identifying candidate code within each game that could be turned into methods to represent a player's behavior within the game. For each potential method, think of a general name and parameters that would work across all three games. As part of your discussion, consider the following questions:

Use Gitlab's markdown format to record the group's answers in the file called DISCUSSION.md that is included with the example code. IntelliJ includes a markdown editor that provides a preview or here is a web-based editor that provides similar functionality and can be shared like Google Docs.

Pair Programming

Another goal is for you to try Pair Programming: working closely with another student and sharing a single computer (a common practice in industry). To ensure both people try driving, switch the person who types on the primary computer every 10-15 minutes. You may use a second computer to look up documentation or search the Internet for solutions related to the exercises, but not to do your own work or socialize.

Refactoring

Refactoring is the practice of updating a program to improve its design and maintainability without changing its current functionality significantly. An example of refactoring is creating a single method or class that replaces two or more sections of similar code because it reduces the amount of redundant code within the program and makes the code easier to debug and test. You do not have to worry about updating the algorithmic code itself, instead your goal is primarily about reorganizing the existing code to make it more readable and improve the overall design.

Examine the given program and refactor it based on your group's discussion. As a first step, choose one game to refactor and try to extract the methods you identified in your discussion that represent potential player code within that game (this will make the next steps of extracting a class for each kind of player easier). Note, within your general player class methods, you may need to use if statements to choose between different player algorithms (e.g., between interactive or algorithmic or random) — this is not an ideal solution and we will address that separately in the next few weeks.

Your group may create (and comment why you choose to create them) any new methods or classes you want to help improve the program. Try to justify each change you make by explaining specifically how it improves the code. Justifications should refer specifically to principles discussed in class or the reading rather than using terms like "clearly/obviously", "good/sucks", or "like/hate".

After you have done as much as you think is reasonable, consider the following questions.

Version Control Workflow

As a group, periodically discuss when you think it is appropriate to create a commit to represents a set of changes (i.e., not just at the end of the lab). After you think you have completed a reasonable goal, make a GIT commit with an appropriate comment (there should be at least four commits in your project history). After every two commits, push your changes up to Gitlab so your online repository reflects the work you have done in lab today.

Here is a review of the steps you will use to work with GIT during labs (as distinct from assigned team projects):

  1. On Gitlab, fork the original project lab_hangman into your own repository so you can edit, commit, and push your group's own changes
  2. In Terminal, use git clone to copy the code from your forked SSH location
  3. In IntelliJ, create a Java project in the same folder you cloned the project to
  4. As a group, discuss the design issues above
  5. In IntelliJ, refactor the code to improve its design (i.e., edit the code)
  6. In Terminal, use GIT to
    • git add changed files
    • git commit -m to describe your changes
    • git push changes back to Gitlab
    • Repeat as many times as needed, letting each person try the changes/GIT steps in related chunks
  7. On Gitlab, when you are done, use Gitlab's Merge Request from your forked repository to the original. Do not worry about potential merge conflicts, your request will not be approved.

Submission

At the end of class, use Gitlab's Merge Request to submit your group's answers to the discussion questions above and refactored code to the original organization repository. Make sure the NetIDs of everyone in the group are in the title of your Merge Request and in the markdown file.