Algebraic Foundations of Software Engineering