Regardless of whether you use a statically or dynamically typed language, specifying your inputs and outputs is a very important step in system design. If you are not surgically precise in defining which data your program takes and produces, you are looking for trouble during the operation phase of the system lifecycle. Making guesses and undeclared assumptions might be easier when writing the code but will certainly bite you as your system lives in production.
Clojure, being dynamically typed, might not give you strong compile-time guarantees. But enforcing the shape of the data on system boundaries allows us to have an untyped data transformation layer and stay sane. Today, we will look into specific Clojure instruments for dealing with strongly shaped data, pitfalls, and hard lessons we’ve learned so far delivering reliable and maintainable systems in Clojure.