refactor, with tests