76 karma · joined May 3, 2014
In the end, `Parsed` should only be handled whereever you receive the initial input, so the rest of your business logic will be free of it :)
In the end, this is just a tool and it's fine if it isn't fitting your particular style or use case ;)
If you validate at constructor level, then you have this problem. However if you actually parse it, then this will have to be external to the actual class and you are left with a simple Value Object. This means that you can apply constraints only when it makes sense. Most of the time, there is little reason to validate something coming from the DB, so I would rather skip it.
About unboxing, that depends. I would expect for the overall business logic to always use the more structured types, probably this will only be needed once you need to serialize them :)
That's said, if you are happy with your current way, please keep doing it! I would still suggest to give this style a try though :)
In the end, parsing is just a combination of what you described: ensure something fit a particular shape and constraints :)
I honestly think the two arguments are different though. We could say that Postel's Maxim is about "how much you should parse/validate", while the problem we are addressing is rather "how you should do it" :)
Allow me to disagree with the "tracking validation using typestate" bit. This is just one way, but using Parsix you can also go from a String to a more complex type like Email(local: Local, domain: Domain), where Local and Domain can also be other complex types. The point is, you should parse as much or as little as you need in your domain. That's why we call it "general-purpose parsing" ;)
By no means we want to pass the message that you have to use this library to benefit from the "Parse, don't validate" pattern. What we want is to make the pattern more mainstream and provide a nice set of functionalities out of the box :)
Also I would like to encourage everyone to get as much as you need from this library. If you don't like `focusedParse`, please don't use it! xD
1) Just to be clear, when I read "serialise" I understand that you want to parse some object into a format suitable for storage. I would honestly go with the common flow: use some library like kotlinx.serialization or whatever your database library support. If this isn't what you meant, please let me know.
2) I personally like well defined type. For example, if you have a case where Email must be like Email(local, domain, tld) and another where you just want a String out of your email, I would rather use two different types for the two different use cases and therefore different parsing logic (which will probably share most code, but still produce different results). On the other hand, if you want to model the fact that some piece of information could be provided or not by the external source, than yes, I would just go with nullable types, which in Kotlin is like `Something?`, but in other language are known as Maybe or Optional.
3) Just to be clear, I will strongly advice against having validation in object constructors. Once this is out of the picture, you are left with simple Value Objects: simple, immutable, bundle of data with a defined structure and semantic meaning. When you work with these simple objects, it's very easy to derive different views for whatever use case you need. I'm not familiar with SQLAlchemy and Python ecosystem in general, but I guess there will be some way of converting a specific type into one that is suitable for DB consumption.
4) Both Parse and Parsed are actually Monads ;) And we know something about Monads, is that composing different Monads together is usually not straightforward xD That's said, in your particular example of having an optional field, I would see the parser produce a Maybe<Something> (or Something? in Kotlin)
Let me know if I got you right and what you think about it :)
I think I would stress this point more in the README, thanks for sharing :thumbsup:
About missing interesting parsers, you are right, for now only the core part is done. Based on community interest, we will work on complementary packages, like more common parsers, easy integration with a web framework like ktor, effectful parsers based on coroutine, etc...
Lots of work ahead :D