def function_spec bleh blah := math_blargh
def function_impl bleh blah := code_blargh
theorem function_correct: forall bleh blah, function_impl bleh blah = function_spec bleh blah := by { long proof }
or whatever. That way the function's spec and implementation remain separate and readable. In my limited experience, Lean code usually works more this way rather than having the whole function and its spec in a giant dependently-typed object. For imperative code you can also use Hoare triples and vcgen, but that's currently only partly baked (i.e. proving things is a giant pain).Maintenance is still a headache. If you change a small piece of your code, you would then need to change all the proofs that refer to it, and then if the specs also changed then you need to change all proofs that refer to those specs, etc.