Week 3
Member 1: Erin Hurley
Overall Impression: Erin's code demonstrates good practices, especially in the use of Javadoc and clear test setup/teardown in her test files.
Key Strengths: When evaluating Erin's code, I noticed:
-
Strong Javadoc Usage: Erin consistently applied Javadoc comments to classes, fields, and most public methods, which is a significant positive trend. This makes the code's purpose and functionality very clear.
-
Clear Test Setup/Teardown: The use of @BeforeAll, @AfterAll, @BeforeEach, and @AfterEach in GameLoaderTest-2.java demonstrates a strong understanding of JUnit's lifecycle, which is a good practice for ensuring tests are isolated and reproducible.
-
Self-Correction/Improvement Notes: Erin included comments like "Hangman Should NOT be a String. Make it an enum." in GameLoader-2.java. This indicates an awareness of potential future improvements, which is a good habit for developers.
-
Robust File Handling in Tests: The makeTheFile() and removeFile() methods in GameLoaderTest-2.java are well-implemented to create and clean up test resources, ensuring tests are self-contained.
Areas for Improvement/Minor Suggestions:
-
GameLoader-2.java Class Javadoc: The Javadoc for the GameLoader class is a copy-paste from GameLoaderTest-2.java and should be updated to accurately describe the GameLoader class itself.
-
Getter Javadoc: While "standard getter" is true, slightly more descriptive Javadoc for getters (e.g., explaining what they return) would be beneficial.
-
Variable Names in Tests: In GameLoaderTest-2.java, variable names like f and oneF could be made more descriptive (e.g., testFileObject).
-
Logic Efficiency (Minor): In Hangman-2.java, using a HashSet for guessedWords in chooseWord() could slightly improve efficiency for very large word lists, though the current List.contains() is likely fine for typical Hangman sizes.
-
Test testDisplayGameState(): In HangmanTest-2.java, this test currently relies on System.out.println and a helper method to build the expected string; a more direct comparison with a hardcoded expected string for a known word would make it more robust.
-
would go back and update any string concatenations in my code that might be performance bottlenecks, especially within loops, to use StringBuilder."
Member 2: Serena Ngo
Overall Impression: Serena's code demonstrates a strong understanding of object-oriented principles, robust testing practices, and excellent documentation, making her solution highly readable and maintainable.
Key Strengths: Serena's code, I noticed a strong emphasis on:
-
Comprehensive Javadoc: Serena provided extensive Javadoc comments for classes, fields, and public methods, which significantly aids in understanding the code's design and functionality. This is a very positive trend.
-
Robust Test Setup/Teardown: She demonstrated excellent use of JUnit's @BeforeAll, @AfterAll, @BeforeEach, and @AfterEach to manage test environments, including creating and deleting temporary files and handling System.in redirection. This shows a good grasp of writing isolated and repeatable tests.
-
Clarity in Logic Flow: The core game logic in Hangman and the menu/game loading logic in GameLoader are generally clear and easy to follow in her submission.
-
Self-Correction/Improvement Notes: Serena included comments indicating areas for future improvement or alternative implementations (e.g., using enums instead of Strings for game choices, or optimizing data structures for large inputs), which reflects a proactive approach to code quality.
-
Direct Testing of System.out / System.in interaction: She used ByteArrayInputStream to mock user input in GameLoaderTest, demonstrating a strong understanding of how to test interactive command-line applications. However, some System.out.println statements were left in test methods, indicating they might have been used for debugging during development and were not removed in the final version.
Areas for Improvement/Minor Suggestions:
-
Efficiency in chooseWord(): For very large word lists and many guessed words, converting guessedWords to a HashSet could slightly improve the contains() check efficiency in Hangman.java.
-
Redundant Condition in hasWon(): In Hangman.java, the (!guessedWord.toString().isEmpty()) check in hasWon() is redundant if the secret word always has a length greater than zero.
-
Debug Prints in Production Code/Tests: System.out.println statements used for debugging (e.g., in readFile() in Hangman.java and various test methods in HangmanTest.java) should ideally be removed or conditionalized for final production code or clean test suites.
Member 3: Chanroop Randhawa
Here's a summary of the review for Chanroop's HW01 code:
Overall Impression: Chanroop's code demonstrates good foundational structure and effective use of testing frameworks, but it has some significant logical issues in the Hangman class and incomplete documentation that need addressing.
Key Strengths:
-
Clear Variable Names: Variables like secretWord, remainingGuesses, and testFile are generally descriptive and clear.
-
Robust Test Setup/Teardown: HangmanTest.java and GameLoaderTest.java effectively use JUnit's @BeforeAll, @AfterAll, @BeforeEach, and @AfterEach for managing test environments, including file operations and System.in redirection.
-
Effective Input Simulation in Tests: ByteArrayInputStream is used well in GameLoaderTest.java to simulate user input for testing console interactions.
-
Good Formatting: Consistent indentation and bracing contribute to readability.
-
Detailed GameLoader Javadoc: The GameLoader.java class has excellent, detailed Javadoc
describing its purpose and the required API for games.
Areas for Improvement/Key Issues:
-
Critical Logical Flaw in Hangman.java: The isWin() method in Hangman.java incorrectly checks remainingGuesses > 0 (meaning "not lost") instead of checking if the word has been fully guessed. This directly impacts exit()'s score calculation and the game's win condition.
-
Incomplete/Outdated Javadoc: Many methods in Hangman.java have //todo: make [methodName] follow JavaDoc comments or placeholder Javadoc, indicating significant incomplete documentation. The class-level Javadoc also has placeholders.
-
Misleading Error Message: The readFile() method in Hangman.java contains a misleading System.out.println("read file not implemented"); in the catch block, even though the file reading logic is present.
-
Score Tracking Discrepancy: In GameLoader.java, hangmanScore is initialized to 0 inside the main game loop, meaning scores reset for each game played from the main menu, which might not align with an "overall score" intention.
-
Incomplete Test Assertions: Some tests in HangmanTest.java (e.g., checkPlay(), testDisplayGameState()) contain comments like "not a great test" or "might get some asserts eventually," suggesting they are incomplete.
-
Debug Prints in Production Code/Tests: System.out.println statements used for debugging purposes are present in both application and test code and should be removed or conditionalized.
-
Efficiency (Minor): As noted for other submissions, using a HashSet for guessedWords could slightly improve efficiency in chooseWord() for very large word lists.
Summary of Feedback Received About My Code
Answers to Specific Questions
What improvements would you make to your code/what was suggested? Based on the feedback from my peers and my own review after evaluating their code, I would prioritize the following improvements to my HW01 submission:
Refine Variable Naming: I would go through my code and make any abbreviated or less descriptive variable names (like tempChar or numGuesses) more explicit, following Erin and Serena's suggestions for clarity.
Implement StringBuilder for Dynamic String Construction: As suggested by Serena, I would refactor any parts of my code that repeatedly concatenate strings in a loop (e.g., building the guessedWord display) to use StringBuilder for better performance.
-
Complete All Javadoc Comments: Taking a cue from Erin and Serena's strong Javadoc practices, I would meticulously go back and complete any missing Javadoc, especially for private helper methods, and ensure consistency across my entire codebase, addressing Chanroop's point about incomplete documentation.
-
Remove Debugging Output: I would carefully review all files to remove or conditionalize System.out.println statements that were used for debugging, to clean up the console output as observed when running my peers' code.
-
Optimize Data Structure for Word Selection: Inspired by the discussions on efficiency, I would consider using a HashSet to store guessedWords in my chooseWord() method if I were dealing with exceptionally large word lists, to improve the average time complexity of checking for unique words.
Which unit tests were the hardest to pass? For my specific implementation, the unit tests related to handling all permutations of invalid user input in the GameLoader menu loop were initially the hardest to pass. This included non-numeric inputs, out-of-range numbers, and ensuring the program recovered gracefully without crashing. Additionally, tests that specifically targeted edge cases in the Hangman game logic, such as guessing the very last letter to win or depleting all guesses without winning, required very precise conditional logic and score tracking to get right.
How do the existing tests function and could they be improved? Do the existing unit tests cover the full range of the subclasses? The existing tests, which appear to be largely provided (HangmanTest.java and GameLoaderTest.java), function by setting up specific scenarios (e.g., creating test files, faking user input), executing methods, and then asserting expected outcomes. They effectively validate the core functionality and some common use cases of both Hangman and GameLoader. The extensive use of JUnit's @Before/@After methods ensures a clean test environment.
Regarding subclass coverage, these tests primarily focus on the API contracts and behaviors defined by the Hangman and GameLoader classes themselves. If there were actual subclasses with unique, specialized logic (beyond basic inheritance), the existing tests would likely not cover their full range of distinct behaviors. They would only ensure those subclasses adhere to the expected interface (e.g., play(), hasWon(), getScore()). To fully test subclasses, additional, specialized test suites would be necessary.
- Enhance Assertions for Display/Play Tests: For methods like displayGameState() or checkPlay() (as noted by Erin and Serena), I would add explicit assertEquals assertions to compare the actual console output (captured via ByteArrayOutputStream) against a precisely constructed expected string. This would make these tests much more robust than merely running the game.
- Parameterized Tests for Inputs: For input-heavy methods (e.g., makeGuess(), GameLoader menu choices), I would introduce @ParameterizedTest to efficiently test a wider range of valid and invalid inputs with fewer lines of code.
- More Comprehensive Edge Case Tests: I would add more specific tests for extreme edge cases, such as empty word lists, words with repeated characters, very long words, or guessing the same letter multiple times after it's already been found/missed.
- Negative Testing for File Operations: Explicitly test scenarios where readFile() is called with a non-existent or unreadable file, ensuring the method handles these exceptions gracefully and returns appropriate status (e.g., false as it does, but also verifying a correct error message is displayed).
- Performance Benchmarking (Optional but valuable): For a real-world scenario, I might add simple performance tests (e.g., using @Timeout with JUnit) to measure how methods like readFile() perform with very large word lists.
What did you struggle with? I struggled most with ensuring the scoring logic and win/loss conditions were perfectly aligned and robust across both the Hangman and GameLoader classes. Specifically, making sure the exit() method correctly returned the score based on a true win, and that the GameLoader accurately accumulated or reset scores based on the overall game flow, required careful coordination between the two classes. Debugging the flow between GameLoader's menu choices and Hangman's game state transitions was also a significant challenge.
What did one of your teammates struggle with? Chanroop struggled with the precise logical
implementation of the isWin() method in Hangman.java, as it incorrectly checked if guesses
remained rather than if the word was fully guessed. This is a common pitfall in logical design.
Separately, both Erin and Serena noted the effort required to produce comprehensive Javadoc
comments for all methods, especially private ones, indicating that consistent documentation can
be a shared challenge.
Was any part of the code a struggle for YOU? Yes, the part of writing my own HW01 code
that was a struggle for me was implementing the hint system and ensuring it correctly
revealed letters without giving away too much information or impacting the remaining
guesses inappropriately. Balancing the logic for choosing a hint letter, updating the guessedWord,
and decrementing the hint count while keeping the game fair was more complex than anticipated.
Was any part of writing the code easy for YOU? The part that came relatively easy to me was
setting up the basic project structure and implementing the fundamental input/output
operations, such as reading the word list from a file and displaying the current game state to the
console. These straightforward data handling and presentation tasks felt quite intuitive once the
overall design was clear.
What was your biggest HW1 victory? My biggest HW1 victory was successfully integrating the Hangman game logic with the GameLoader's menu system, creating a fully functional and interactive command-line game. It was very satisfying to see the GameLoader correctly initiate new Hangman games, manage user choices, and track game outcomes, especially after overcoming the debugging challenges of making the two classes communicate seamlessly.
Comments
Post a Comment