refactored to separate responsibilities