Skip to content

refactor: extract phase-specific helpers from get_state() (closes #453)#461

Merged
mholzi merged 1 commit intomainfrom
fix/issue-453
Mar 31, 2026
Merged

refactor: extract phase-specific helpers from get_state() (closes #453)#461
mholzi merged 1 commit intomainfrom
fix/issue-453

Conversation

@mholzi
Copy link
Copy Markdown
Owner

@mholzi mholzi commented Mar 31, 2026

Fixes #453 β€” extracts _state_playing(), _state_reveal(), and _state_end() helpers from the 142-line get_state() method.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the get_state method by delegating phase-specific state construction to new private methods: _state_playing, _state_reveal, and _state_end. This change improves the modularity of the game state logic. Reviewers suggested optimizing the _state_end method by caching terminal calculations and recommended using a dictionary comprehension to streamline the extraction of localized song metadata.

Comment on lines +500 to +524
def _state_end(self) -> dict[str, Any]:
"""Return END phase-specific state fragment."""
fragment: dict[str, Any] = {
# Final leaderboard with all player stats (Story 5.6)
"leaderboard": self.get_final_leaderboard(),
"game_stats": {
"total_rounds": self.round,
"total_players": len(self.players),
},
# Superlatives - fun awards (Story 15.2)
"superlatives": self.calculate_superlatives(),
# Issue #75: Game highlights reel
"highlights": self.highlights_tracker.to_dict(),
# Issue #120: Shareable result cards
"share_data": build_share_data(self),
}
# Include winner info
if self.players:
winner = max(self.players.values(), key=lambda p: p.score)
fragment["winner"] = {"name": winner.name, "score": winner.score}
# Game performance comparison for end screen (Story 14.4 AC5, AC6)
game_performance = self.get_game_performance()
if game_performance:
fragment["game_performance"] = game_performance
return fragment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The _state_end method performs several expensive calculations every time it is called, including get_final_leaderboard(), calculate_superlatives(), and build_share_data(self). Since the END phase is terminal and these values do not change once the game is over, they should be calculated once and cached to avoid redundant processing during state broadcasts or client refreshes.

Comment on lines +467 to +471
"fun_fact": self.current_song.get("fun_fact", ""),
"fun_fact_de": self.current_song.get("fun_fact_de", ""),
"fun_fact_es": self.current_song.get("fun_fact_es", ""),
"fun_fact_fr": self.current_song.get("fun_fact_fr", ""),
"fun_fact_nl": self.current_song.get("fun_fact_nl", ""),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The extraction of fun fact translations is repetitive. This can be simplified using a dictionary comprehension to improve maintainability and reduce boilerplate.

Suggested change
"fun_fact": self.current_song.get("fun_fact", ""),
"fun_fact_de": self.current_song.get("fun_fact_de", ""),
"fun_fact_es": self.current_song.get("fun_fact_es", ""),
"fun_fact_fr": self.current_song.get("fun_fact_fr", ""),
"fun_fact_nl": self.current_song.get("fun_fact_nl", ""),
**{k: self.current_song.get(k, "") for k in ["fun_fact", "fun_fact_de", "fun_fact_es", "fun_fact_fr", "fun_fact_nl"]},

Copy link
Copy Markdown
Owner Author

@mholzi mholzi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: Extract phase-specific helpers from get_state() (#453)

Verdict: LGTM βœ…

Checked the diff against main across four dimensions:

1. Logic split β€” no data lost or duplicated

Each helper (_state_playing, _state_reveal, _state_end) extracts exactly the keys from its original elif block. Every key present in the old inline code appears exactly once in the corresponding helper. No keys were dropped or duplicated across helpers.

2. state.update() merge β€” correct

The base state dict includes common fields (game_id, phase, player_count, players, language, etc.). Each helper returns a fragment dict that update() merges in. Notably, _state_reveal() returns a "players" key (get_reveal_players_state()) that overwrites the base "players" (get_players_state()) β€” this matches the original behavior where state["players"] was reassigned directly in the REVEAL block.

3. Phase boundaries β€” correct

  • LOBBY: inline join_url (unchanged)
  • PLAYING: _state_playing() β€” deadline, songs_remaining, submission tracking, song without year, challenges hidden
  • REVEAL: _state_reveal() β€” song with year + fun facts, reveal players, analytics, difficulty, challenges revealed, early_reveal flag
  • PAUSED: inline pause_reason (unchanged)
  • END: _state_end() β€” final leaderboard, game stats, winner, superlatives, highlights, share data

No overlap, no gaps.

4. No state mutation or side effects moved

All three helpers are pure reads β€” they call getters, access attributes, and do computations but never modify self. No side effects were introduced or relocated.

Clean refactor, get_state() reads much better now.

πŸ€– Generated with Claude Code

@mholzi mholzi merged commit 21094ec into main Mar 31, 2026
5 checks passed
@mholzi mholzi deleted the fix/issue-453 branch March 31, 2026 09:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Code Review: code-quality] get_state() is 142 lines β€” phase-specific blocks should be helper methods

1 participant