Code Generation
Automating the creation of boilerplate or repetitive code from templates or specs.
Overview
Code generation is the automatic production of source or binary code from a higher-level specification, template, or model. It eliminates repetitive boilerplate, ensures consistency, and enables a single source of truth to drive multiple outputs.
Origin
Code generation has been used since early macro assemblers (1950s). It became prominent with YACC (1970s) for parser generation, and later with ORM schema generators, GraphQL codegen, and OpenAPI client generators.
Examples
Rails generator scaffold
# rails generate scaffold Order user:references total:decimal status:string
# Produces:
# db/migrate/20240101_create_orders.rb
# app/models/order.rb
# app/controllers/orders_controller.rb
# app/views/orders/ (index, show, new, edit, _form)
# spec/models/order_spec.rb
# spec/requests/orders_spec.rb
# config/routes.rb (resources :orders added)
# Custom generator
class ServiceGenerator < Rails::Generators::NamedBase
source_root File.expand_path('templates', __dir__)
def create_service_file
template 'service.rb.tt', "app/services/#{file_name}_service.rb"
end
endWriting generators for repeated patterns (service objects, API adapters, presenters) enforces architectural conventions and speeds up feature development.
TypeScript type generation from OpenAPI spec
// openapi-typescript generates types from a spec file:
// npx openapi-typescript openapi.yaml -o src/types/api.ts
// Generated output (excerpt):
export interface paths {
'/users/{id}': {
get: {
parameters: { path: { id: number } }
responses: {
200: { content: { 'application/json': components['schemas']['User'] } }
404: { content: { 'application/json': components['schemas']['Error'] } }
}
}
}
}
// Consuming it with type safety:
const user: paths['/users/{id}']['get']['responses'][200]['content']['application/json']
= await api.getUser(id)The spec is the single source of truth. Backend changes regenerate types. TypeScript errors surface immediately when the frontend accesses a removed or renamed field.
Use Cases
- 01Generating API clients from OpenAPI/Swagger specs
- 02ORM migration files from model definitions
- 03Protobuf/gRPC service stubs from .proto files
- 04React component scaffolding with tests and stories
- 05Database seed files or test fixtures from schemas
When Not to Use
- //When the generated code requires heavy manual editing, the generation becomes a starting point, not an asset
- //When the template is more complex than the output it produces
- //When the team cannot read and understand the generated code, generated code must still be reviewable
Technical Notes
- Generated code should generally not be edited manually. If edits are needed, redesign the generator or use partial generation with extension points
- Commit generated code so CI can verify it is up to date: add a check that runs the generator and diffs the output
- AST manipulation (Babel plugins, Rubocop custom cops) is a form of code generation that transforms existing code rather than producing from scratch
More in Programming Techniques