Code Generators
It’s a quite common pattern in Go projects to use code generators. Code generators or in short term, codegens are used to provide type safety and eliminate runtime unnecessary processing. Without codegens, we need to use reflect package at runtime.
Our Problem
Imagine we have a json
serialized byte stream received from a user or read from a file.
How can we Unmarshal this arbitrary data structure into a struct
?
In this article, we discuss two different approaches to unmarshal this serialized binary into
corresponding struct
.
We also compare three different stages for generating codes, on developer’s machine, on CI or every time before build
process begins.
Unmarshalling
We can unmarshal our json into a struct using reflection.
The reflection API provides the developer with a few function to iterate over a struct
exported fields and inspect
their
data types.
We also can use codegens to generate codes for unmarshalling our data into a struct.
There are a few open source modules available on GitHub which we’ll mention later on.
Unmarshalling JSON using the reflection API
This is how builtin json package works.
Here’s an example usage of reflect
to iterate through an arbitrary struct:
|
|
Output:
Marshalling struct to JSON using generated code
To eliminate this overhead at runtime, there are a number of third-party module to preprocess to be marshaled/unmarshalled structures. We use easyjson as an example here. Code generate for nearly the same struct mentioned above looks like this:
|
|
This generated code saves a lot of CPU time at runtime, instead takes a while to generate this code and needs a few extra steps to develop go code.
You can see easyjson’s benchmarks here compared to a few other popular tools.
lib | json size | MB/s | allocs/op | B/op |
---|---|---|---|---|
standard | regular | 22 | 218 | 10229 |
standard | small | 9.7 | 14 | 720 |
easyjson | regular | 125 | 128 | 9794 |
easyjson | small | 67 | 3 | 128 |
ffjson | regular | 66 | 141 | 9985 |
ffjson | small | 17.6 | 10 | 488 |
codec | regular | 55 | 434 | 19299 |
codec | small | 29 | 7 | 336 |
ujson | regular | 103 | N/A | N/A |
Code Generation Stage
Generation on the Developer’s Machine
TODO
Generation on CI and Commit on Another Repository
Generation before Build Process
Conclusion
Stage | Suitable for |
---|---|
Local | - small projects - generated codes only used by the same module |
CI | - another repository is needed for the generated code to be committed at - add extra complexity and generated code are available with a delay |
Build | - clone repository can not be built without generating codes - there is no change history for generated codes in git |