much simpler pipeline using first-class functions instead of an interface