And I think one of the approaches that helped me to write safer code is to parse, and not validate.
That way drastically limit the situations we can get into where we forget to validate certain conditions.
e.g. you have a User struct, and you want to do an action which requires you to validate whether the user is an admin.
2 options here
* validate whether the user is an admin (which could happen multiple times when you're invoking distinct functions as part of a workflow)
* parse the User into an AdminUser. If the user is an admin, the function will work, and then you can pass on your new struct into places that require an admin. If it fails, the user is not an admin. Now you have merged all your checks into 1 place.