do some refactoring and add some tests