Context for Live Code Review
You are asked to review the design of a library/SDK for a feature that will be used in different apps, and improve it in collaboration with the interviewer. It's a basic Daily Workout Engine and this library will be responsible for handling the state of a daily workout.
In this code below, you will find out the domain logic to be reviewed. It was created by a junior engineer (the interviewer :)) and this engineer is not yet confident and wants your feedback before opening a pull/merge request.
Times
Mandatory rest between exercises
Rest between reps (2-3 seconds)
Detailed Requirements of the Task
1. It should guarantee workout lifecycle:
1 - WORKOUT_CREATED
2 - WORKOUT_EXERCISE_X_STARTED (X = 1 TO [3-10])
3 - WORKOUT_EXERCISE_X_COMPLETED (X = 1 TO [3-10])
4 - WORKOUT_FINISHED
2. A daily workout has a minimum of 3 exercises and maximum 10.
3. A daily workout has a mandatory rest time between the exercises, in seconds.
4. An exercise has a number of repetitions to be done and a minimal and max time to complete it, after it has started.
5. Minimal and max time depends on the number of repetitions. Minimal time is 2 seconds per repetition and max is 3.
6. If the exercise is completed outside the minimal and max time, it's flagged as failed.
7. When it ends, a score is given to the workout. The score is integer between 0 and 10. Round(non-failed exercises / total exercises) * 10
# workout_controller.py
from datetime import datetime
def main():
controller = WorkoutController()
controller.create_workout(1, 60)
controller.add_exercise(10)
controller.add_exercise(5)
controller.start_exercise(0)
controller.complete_exercise(0)
controller.start_exercise(1)
controller.complete_exercise(1)
controller.finish_workout()
class WorkoutController:
def __init__(self):
self.workout_id = 0
self.rest_time = 0
self.exercises = []
self.score = 0
self.status = "NOT_STARTED"
def create_workout(self, id, rest_time):
self.workout_id = id
self.rest_time = rest_time
self.status = "WORKOUT_CREATED"
print(f"Workout {self.workout_id} created with {rest_time} seconds rest time")
def add_exercise(self, repetitions):
exercise = self.Exercise(repetitions)
self.exercises.append(exercise)
print(f"Added exercise number {self.exercises[exercise] + 1} with {repetitions} repetitions")
def start_exercise(self, index):
if 0 <= index < len(self.exercises):
exercise = self.exercises[index]
exercise.start()
print(f"Started exercise {index}")
else:
print(f"No exercise found at index {index}")
def complete_exercise(self, index):
if 0 <= index < len(self.exercises):
exercise = self.exercises[index]
end_time = datetime.now()
exercise.complete(end_time)
print(f"Completed exercise {index}.")
else:
print(f"No exercise found at index {index}")
def finish_workout(self):
self.status = "WORKOUT_FINISHED"
self.calculate_score()
print(f"Workout finished with score: {self.score}")
def calculate_score(self):
passed_exercises = sum([1 for exercise in self.exercises if exercise.is_passed()])
self.score = 0 if not self.exercises else int((passed_exercises / len(self.exercises)) * 10)
class Exercise:
def __init__(self, repetitions):
self.repetitions = repetitions
self.start_time = None
self.min_time = repetitions * 2
self.max_time = repetitions * 3
self.status = "NOT_STARTED"
def start(self):
self.start_time = datetime.now()
self.status = "STARTED"
def complete(self, end_time):
if self.start_time:
duration = (end_time - self.start_time).total_seconds()
if self.min_time <= duration <= self.max_time:
self.status = "COMPLETED"
else:
self.status = "FAILED"
def is_passed(self):
return self.status == "COMPLETE"
if __name__ == "__main__":
main()