4 ms·
It's because you can write these types: recognize : String -> UnverifiedEmail validate : UnverifiedEmail -> VerifiedEmail send : (VerifiedEmail, Me
by tel 4y ago
It's because you can write these types:
recognize : String -> UnverifiedEmail
validate : UnverifiedEmail -> VerifiedEmail
send : (VerifiedEmail, Message) -> ()
You can then use visibility controls to universally guarantee that recognize and validate must be called before send. No test can ensure this is true.
Under the presumption that send should only perform work on verified emails, the alternative is not being able to be confident that emails passed to send are pre-verified. This means that send must check this flag, and therefore have the ability to fail due to non-verification.
This isn't inherently a problem, but it can lead to a failure to separate concerns. If one part of your system is responsible for parsing and validation and a separate part responsible for interacting with the sending machinery, it's unfortunate if the latter part can fail due to a failure to verify the email. These systems have now implicitly shared responsibility.
You can try to guarantee that no email is passed from the first system to the second without being verified, but this can be challenging. It's a universal property. Tests can show the presence but not the absence of bugs.
But those types we showed at the beginning provide exactly that guarantee.
- gilbetron 4y agoBut then you can just have a "makeEmailVerified" that takes an UnverifiedEmail and converts it to a VerifiedEmail without verification. Then the "send" function still needs to check things.
- tel 4y agoTypically, the owner of the VerifiedEmail type restricts your ability to construct new values of that type by making the constructor private and then only "blessing" a small number of public constructors, each one performing that verification. If any type could be converted to any other (compatible) type for any reason whatsoever then types would have no semantic value. But fortunately, we can control how types are constructed and used.