At work, we are struggling with a MAJOR refactor. An underlying assumption made in the design of our data model makes the newest feature request from our product department a rewrite. That assumption shows up in implicit decisions made around the application.
Now, we need to change this assumption. And, predictably, the application breaks everywhere and in unpredictable ways.
In my free time, I have been picking up Elm and Haskell. And what I love about both of these languages is how hard it to make implicit assumptions about data - the type system REQUIRES you to be explicit about your data structures and where you are passing them around. By defining a type alias, you explicitly tell the application what data should look like and when you try to pass a function data that doesn't match the type alias the program doesn't compile.
The benefit of having the strict type system is that it alerts you to most of the areas where breaking changes exist in the application during compilation.
Yes, dealing with Haskell and Elm's type system can feel a little heavy at first. But I find that I write fewer tests and write better code in these languages than I do in dynamically typed or object-oriented languages.