Field Notes: Go and “Parse, don’t validate”
What a Go currency example reminded me about API design
A couple of weeks ago I read the fantastic post Parse, don’t validate by Alexis King. It is a longer post and worth reading, but I want to summarize what I got out of it. For me, the core ideas were:
It is better to parse input into valid values rather than validate
People will forget to use your validation.
After parsing, the rest of the code must be able to rely on it being correct.
These ideas came back to my mind recently while learning Go for a new project at work.
An example in Go
I decided to pick up Learn Go with Pocket-Sized Projects1 since I like a “closed source” as the starting point when learning something new. While reading chapter 6, I remembered reading King’s article and thought this was exactly the situation she described. In that chapter, the project is a currency converter. It contains the type Amount.
type Amount struct {
quantity Decimal
currency Currency
}The details of the type are not important, it is used to save monetary amounts in minor units of the currency (to avoid rounding errors with float). The authors notice a thing: you can create invalid instances of Amount:
[…] it seems wise to check that we’ll get the expected output […] Following are the limitations:
The number can’t be higher than 1012, or it will lose precision due to the floats.
The number’s precision must be compatible with the currency’s precision.
The chapter goes on by creating a validate() method on Amount:
func (a Amount) validate() errorThere is nothing inherently wrong with that, but there is a flaw: you can create invalid Amount in first place.
So in the sense of Parse, don’t validate, it would be wiser to introduce a Parse() method as the only way to create Amount:
func Parse(quantity Decimal, currency Currency) (Amount, error) {
switch {
case quantity.subunits > maxDecimal:
return Amount{}, ErrTooLarge
case quantity.precision > currency.precision:
return Amount{}, ErrTooPrecise
}
return Amount{quantity: quantity, currency: currency}, nil
}
The code itself is simple, but it shows how moving checks to the point of construction can remove an entire class of problems from the rest of the program.
Closing
This post only scratches the surface, and Alexis King does the heavy lifting in the original article. I highly recommend reading Parse, don’t validate in full.
I hope you got something useful out of this field note. If you have thoughts, questions, or similar examples, feel free to reply or reach out!
✍️ About these field notes
This newsletter is my notebook for things I learn and find useful. Not everything needs a long post, so from time to time I will publish short “field notes” like this one instead of letting them sit unread in my notes app.
I can recommend that book. It is a bit wordy, but experienced devs can just skip the fluff around the actual important parts.

![@startuml ' ---------- Hand-drawn style ---------- skinparam backgroundColor #FFFFFF skinparam shadowing false skinparam roundcorner 18 skinparam defaultFontSize 14 skinparam padding 12 !option handwritten true skinparam ArrowThickness 1.5 ' Wide layout for header (16:9-ish) left to right direction ' ---------- Nodes ---------- rectangle "External Input" as Input #EEEEEE rectangle "<b>Validate</b>" as Validate #FFF4E5 { rectangle "Create value" as V1 #FFE8CC rectangle "Use value" as V2 #FFE8CC rectangle "Forget to validate" as V3 #FFCCCC } rectangle "<b>Parse</b>" as Parse #EAFBF3 { rectangle "Parse input" as P1 #D1FAE5 rectangle "Valid value\n(by construction)" as P2 #A7F3D0 rectangle "Use guaranteed valid value" as P3 #D1FAE5 } ' ---------- Connections ---------- Input -[#CC7A00]-> V1 V1 -[#CC7A00]-> V2 V2 -[#CC0000]-> V3 Input -[#047857]-> P1 P1 -[#047857]-> P2 P2 -[#047857]-> P3 @enduml @startuml ' ---------- Hand-drawn style ---------- skinparam backgroundColor #FFFFFF skinparam shadowing false skinparam roundcorner 18 skinparam defaultFontSize 14 skinparam padding 12 !option handwritten true skinparam ArrowThickness 1.5 ' Wide layout for header (16:9-ish) left to right direction ' ---------- Nodes ---------- rectangle "External Input" as Input #EEEEEE rectangle "<b>Validate</b>" as Validate #FFF4E5 { rectangle "Create value" as V1 #FFE8CC rectangle "Use value" as V2 #FFE8CC rectangle "Forget to validate" as V3 #FFCCCC } rectangle "<b>Parse</b>" as Parse #EAFBF3 { rectangle "Parse input" as P1 #D1FAE5 rectangle "Valid value\n(by construction)" as P2 #A7F3D0 rectangle "Use guaranteed valid value" as P3 #D1FAE5 } ' ---------- Connections ---------- Input -[#CC7A00]-> V1 V1 -[#CC7A00]-> V2 V2 -[#CC0000]-> V3 Input -[#047857]-> P1 P1 -[#047857]-> P2 P2 -[#047857]-> P3 @enduml](https://substackcdn.com/image/fetch/$s_!Y5X3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b5b1571-9a01-45b2-bd0d-9ebee305bbee_884x322.png)