Welcome back to another exciting session where we learn about enhancing existing functionality without causing regressions. Our scenario today involves designing a voting system. We'll start with the basic implementation of the voting system and gradually introduce additional elements of complexity.
In our initial task, we created a simple voting system in Kotlin with a set of basic functionalities:
fun registerCandidate(candidateId: String): Boolean
: This function is used for adding new candidates to our system.fun vote(timestamp: Long, voterId: String, candidateId: String): Boolean
: This function facilitates users casting their votes. Each vote is given a timestamp.fun getVotes(candidateId: String): Int?
: This function retrieves the total number of votes for a given candidate.fun topNCandidates(n: Int): List<String>
: We also want to add a leaderboard functionality to our system. This function returns the topn
candidates sorted by the number of votes.
Let's jump into the Kotlin code and begin the implementation of our starter task. Here, we use Kotlin's mutableMapOf()
and mutableListOf()
as the core of our design. These collections allow us to have dynamic lists keyed based on candidate IDs and voter IDs, which will greatly simplify our design.
Now that we have a basic voting system, our goal is to enhance this system with additional functionalities:
fun getVotingHistory(voterId: String): Map<String, Int>?
: Provides a detailed voting history for a specified voter, returning a map with candidates and the number of votes they received from the voter. Returnsnull
if the voter ID does not exist.fun blockVoterRegistration(timestamp: Long): Boolean
: Implements a mechanism to halt any new voter registrations past a specified timestamp, effectively freezing the voter list as of that moment.fun changeVote(timestamp: Long, voterId: String, oldCandidateId: String, newCandidateId: String): Boolean
: Enables voters to change their vote from one candidate to another, given the change is made within a 24-hour window from their last vote, ensuring both the old and new candidates are registered, and that the voter initially voted for the old candidate.
We proceed to enhance our existing VotingSystem
class to accommodate the new functionalities.
First, let's incorporate the functions to get the voting history and to block further voter registrations:
With the introduction of the blockVoterRegistration
functionality, we must revisit our vote
function to ensure it respects the new rules set by this feature. Specifically, we need to ensure that no votes are cast after the voter registration has been blocked. This is critical in maintaining the integrity of the voting system, especially in scenarios where registration deadlines are enforced. Here's how we modify the vote
method to incorporate this change:
This update ensures that our voting system behaves as expected, even with the new functionality to block further voter registrations beyond a certain timestamp. It's a perfect demonstration of how new features can necessitate revisits and revisions to existing code to enhance functionality while ensuring backward compatibility.
The changeVote
method allows voters to change their vote, adhering to specific rules. Here's a step-by-step explanation of implementing this functionality:
-
Verify Candidate and Voter Validity: Check if both the old and new candidate IDs exist in the system, and verify that the voter has previously voted for the old candidate.
-
Timestamp Constraints: Ensure that the voter is trying to change their vote within an allowable timeframe after their initial vote.
-
Update Votes: If all conditions are met, subtract one vote from the old candidate, add one vote to the new candidate, and update the voter's voting record.
Congratulations! You've successfully enhanced the voting system by adding functionalities to view voting history, block new candidate registrations, and, most importantly, enable vote changes under specific conditions. Each of these features was developed with careful consideration to maintain the integrity and backward compatibility of the system. Continue exploring with practice sessions and further experimentation to refine your skills in developing complex, functionality-rich applications. Happy coding!
