5 ms·
> If the object is created without exceptions I can be sure it is valid. Without some kind of custom validation system in place (JSON schema, property attribut
by kgwxd 5y ago
> If the object is created without exceptions I can be sure it is valid.
Without some kind of custom validation system in place (JSON schema, property attributes, etc), that doesn't tell you much. With most serialization libraries I've used the default settings would let you deserialize {} into any class without an exception and all the properties would just have the default value for their type. Using stricter setting gets you a little more but definitely no guarantee of a logically valid state. If I want to go even one step past what little validation static typing provides, and I usually do, I'd rather just take the type noise completely out of my data and move all validation to a single place.
- TeMPOraL 5y agoYou implement your own custom validation. The point is to encode the fact that you've validated a value in its type. So you have e.g. DeserializeJSON<Foo>(String) -> Foo, and then ValidateFoo(Foo) -> ValidatedFoo. And then all the business code works on ValidatedFoo.
- kgwxd 5y agoI know the point, I'm a C# dev by trade, but if I'm going to implement validation that goes beyond static type checking, which is most of the time, I'd rather put it all in a single place and not have to deal with the type nuisance in every single line of code I write.
- lmm 5y agoTypes are a huge help for implementing validation in one place - by having separate types for non-validated and validated versions, you can get the compiler to ensure that every code path actually goes through validation. Static type checking isn't in opposition to custom validation code, it supports it.
- vbsteven 5y agoThat depends on the language and deserialisation library used. And that is also the reason why I have multiple classes. My CreateTaskRequest class which is used for deserialisation only does not have defaults (unless intentional) so it throws when required values are not present in the source json. It also takes care of dateformat/uuid parsing. The output is always fully valid typed or it throws. It’s a 1-to-1 mapping on what is described in the API docs. The service layer that takes CreateTaskRequest and converts to Task for persistence is where the business logic validation happens (valid foreign keys, date ranges, etc, unique checks). Cleanly separated from deserialization. For reference: I use Kotlin with Jackson which has great support for this.
- mumblemumble 5y agoAt the end of the day, when we're working with external data, no language is a silver bullet. But you can get pretty far by doing https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/ https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va... and yelling at your colleagues when they don't. FWIW, this sort of thing can be done with a dynamic language, too. It's true that some static languages happen to be really far ahead of the curve with this sort of thing. But it's also true that some dynamic languages put you in a better position on this front than many of the most popular static languages do. (And for those of us who really do love an intractable quagmire, there's always JavaScript.) For my part, I tend to find this debate to be mostly a distraction, because the influence of the language's type discipline is quite small relative to the influence of the programmer's coding discipline. In the group I'm working with currently, the most committed fans of static typing tend to also be the ones who have the greatest tendency to assume, "If it compiles, it works," and proceed to check in glaring bugs. I don't bring that up in order to point fingers at static typing proponents (I tend to prefer static myself, though my preference is not particularly strong) so much as to point out that we should be wary of memes that subtly encourage us to become complacent.
- stank345 5y agoThat's an interesting perspective (and now that you mention it I can think of someone at work who loves types and also tends to break stuff). I myself love static types because it allows me to avoid certain classes of errors and I try my hardest not to introduce bugs. Static typing also greatly informs my workflow. I tend to practice type driven development to the extent possible so when I go back to dynamic languages I feel like I'm coding with one hand tied behind my back since I can't encode my assumptions in types and rely on the type checker to help me validate them.
- jwhitlark 5y agoJust as bad are those that check in code that that works, but no longer makes logical sense when you read the code. The following is a simple case of what I'm talking about: var flag_is_unset = flag_is_set I generally land more on the dynamic side of things, but there are certainly problem domains where I love types. The more closed and "mathy" the domain, the better I think types fit. I just wish it was less an all-or-nothing choice, and that people were less religious about it.
- dan-robertson 5y agoStrongly depends on the language. If you have ML style data types (eg ML, Haskell, OCaml, Rust) ands some way to abstract types (ML structs, Haskell modules hiding type constructors, OCaml modules, Rust modules) then it is generally possible to design your data structures in such a way that invalid states cannot be represented. If a user has an optional first/last name but if one is specified then so is the other, your user type has a name of type (eg) Maybe (string, string) [1]. If your deserialisation framework just fills in default values for everything or let’s you have unused fields then it is, in my opinion, broken. If you have a field that should be a positive bumber, you should have a type for a positive number that fails to deserialise if you give it a negative number. [1] the caveat is that it somewhat sucks to change these restrictions and therefore the types. Compilers can hopefully make these refractors easier, but they may still suck. In languages like clojure, you mostly have to try to write programs/tests to be resilient to any reasonable changes to the data structures that you can imagine.