factored out gradient calculation and made it testable