How abstraction can reduce complexity, and increase testability and maintainability