The Go Code You Didn’t Write
Day-2 Engineering in a Post-Human Codebase
Imagine working on a project where
- 100% of code is generated by AI
- you have paying customers
- you are responsible about new features
- you are responsible about production incidents
AI agents are everywhere
- Code generation
- Docs generation
- Testing
- Troubleshooting
- Automation
- Research
## Many companies want even more AI
- Teams organize token usage competitions
- Others delegate code reviews to AI agents to ship even faster
- Some even try to handle production incidents with AI agents
- Worst of all - AI generated postmortems
Using AI for the sake of using AI makes little sense.
AI helps us move fast
- Lead time from idea to PR is reduced
- The number of PRs is skyrocketing
- The size of the PRs is also increasing
Speed Has a Price
- Complexity
- Tech debt
- Spaghetti code
- (Lack of) readability
- Cognitive load
Delegate all the things

## AI Writes It. You Sign It.
- You can delegate the writing of the code
- You can **NOT** delegate the **ownership**
---
## Faster Writing, Slower Reading
- Writing code is no longer the bottleneck
- Reading (and understanding) it is
---
## AI generates code that works
It doesn't address complexity, tech debt and readability.
{ .fragment }
---
## Focus on code readability
- Every layer of abstraction is a layer of obscurity
- Simple code is readable code
- Readable code is easier to change
---
## How to improve readability?
- choose names carefully
- holistic thinking
- deep modules (packages, types)
- design your interfaces
- line of sight
- stick to the stdlib
- write table-driven tests (compare full objects)
---
## Carefully name things
- the shorter the scope, the shorter the name
- name packages after what they do, not what they contain
- do not repeat package name in funcs/types
- do not repeat type in var names
- think how your users would use it
Example pkg names
sync/once-once.Doio-io.Reader,io.Writer, etc.regexp- Doesn’t stealregexvar name
## Don't repeat the pkg name
```go
// BAD. This reads as `chubby.ChubbyFile` from outside.
package chubby
type ChubbyFile struct {}
```
// GOOD. This reads as `chubby.File` from the outside world.
package chubby
type File struct {}
## Don't repeat the type in the name
```go {.fragment}
// BAD.
usersMap := map[string]User{}
```
```go {.fragment}
// GOOD.
users := map[string]User{}
```
```go {.fragment}
// BETTER.
exists := map[string]User{}
if _, ok := exists[u.ID]; ok {
```
Think about the scope
// BAD.
var customerInvoiceResult billing.Invoice
// GOOD.
var invoice billing.Invoice
// BETTER.
var inv billing.Invoice
## Use consistent names
- For example, in testing - `args`, `got`, `want`, `tt`.
- Common variables - `svc`, `srv`, `db`, `req`, `resp`, `opts`
---
## Systems thinking
- think of your project as a system of components
- define your domain types in the root of your repo (library)
- design your architecture before writing any code
- think about failure modes
- identify business rules
Imagine you have to design and build an e-commerce app
- Should be accessible on web, tablet, phone, voice and MCP.
- Allow users to navigate products, add to cart, checkout.
- Allow admin to add products, categories, sale events.
## Domain types
- Define in the lib root `Product`, `Collection`, `Order`, etc.
- Should not have external dependencies
- Should not "know" where they are coming from
Don’t skip design phase
- Design helps you avoid complexity
- Design decisions live in your repo
## Think about your failure modes
- Each failure mode is an error
- Expect it
- Handle it
- Don't log AND return an error
Example - Product out of stock
- User 1 adds last item to the cart
- User 2 also adds last item to the cart
- User 1 checks out
- User 2 - no availability
```go
// BAD. DON'T DO THIS.
if err != nil {
logger.Error("operation failed", "error", err)
return err
}
```
```go {.fragment}
// GOOD.
if err != nil {
return fmt.Errorf("operation failed: %w", err)
}
```
Business rules
- This is where most of your bugs are
- Spaghetti code is also here
- Move it to a separate service if possible
## Handling (Christmas) Sale Events
```go {.fragment}
// BAD. DON'T DO THIS!
func (s Service) ChristmasSaleProducts(ctx context.Context) ([]Product, error) {
```
```go {.fragment}
// BAD. DON'T DO THIS!
func (s Service) BlackFridaySaleProducts(ctx context.Context) ([]Product, error) {
```
Engineers shouldn’t be involved in new sales events ideally 🤔
Deep modules
from Philosophy of Software Design by John Osterhout

Best practices
- Carefully design the public API
- Think from the users’ PoV
- Hide implementation details
## Design public API
- API surface - the (complexity) cost you pay
- Implementation - the value you get
How can we get maximum value for minimum cost?
- Minimal API surface (narrow interface)
- General implementation (maximum benefit)
## Q: What is common between
- Men's shoes
- Kids t-shirts
- Christmas sale
- Related products
- Recommended for you
A: All of these are collections of products
## What good looks instead?
```go {.fragment}
// GOOD. (ctx skipped for brevity)
type ProductService interface {
Product(id ProductID) (*Product, error)
Products(id CollectionID, po PageOpts) ([]Product, error)
}
```
What if requirements change?
Imagine this e-commerce app becomes multi-tenanted. Instead of one shop - there needs to be many shop owners.
Product interface still doesn’t need any refactoring.
Cover your features with tests
- Code covered with tests gives confidence
- Use table driven tests
- Compare full objects (use
cmp.Diff) - Use
_testpackage name for tests - Avoid test frameworks/libs
- Use executable examples
- Fast feedback loop for AI agents
```go {hl_lines=["7-11"]}
func TestService_Product(t *testing.T) {
type test struct{}
tests := []test{}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
svc := products.NewService(tt.db)
got, err := svc.Product(t.Context(), tt.id)
// handle error
if diff := cmp.Diff(tt.want, got); diff != "" {
t.Errorf("Product(%v), res (+got,-want)\n%s\n", tt.id, diff)
}
}
}
}
```
---
## Design your interfaces
- Make your interfaces as generic as possible
- With API surface as narrow as possible
- Defining your interface is faster than typing your prompt
---
## Line of sight
- avoid unnecessary indentation
- every indented code is error handling
- avoid `else` keyword
- prefer `switch` to many `else if` statements
- happy path is last
---
## (Avoid) Dependencies
- Best code = no code. Best dep = no dep.
- A dependency is only imported from 1 package.
- More dependencies = increased cognitive load + more tokens
For each dependency
- Ask - can the stdlib do that
- If yes - delete the dep
## Some dependencies are good
- Only ever import them from one package
- Don't leak dependency types outside of that package
Example - feature toggle
package feature
type Client struct {
// fields
}
func (c *Client) Enabled(ctx Context, name string, def bool) bool {
//impl
}
## Usage
Interface is declared by the consumer.
```go
type FeatureToggle interface {
Enabled(ctx context.Context, feature string, def bool) bool
}
```
// GOOD. Feature toggle provider isolated.
func MyFunc(ctx context.Context, ft FeatureToggle) {
if ft.Enabled(ctx, "new-feature", false) {
// new implementation
return
}
// old implementation
}
Go review checklist for generated code
- Is the code readable
- Does it increase complexity
- Is there room for refactoring (shallow -> deep module)
Managing tech debt
- Bad code compounds (so does good one)
- Ensure regular refactoring sessions
- Pay tech debt, before it grows out of the context window
AI is a multiplier
- … when used correctly
- Unfortunately, same applies when used incorrectly
(Go) Engineering Fundamentals have never been more relevant.
- Effective Go - https://go.dev/doc/effective_go
- Code Review Comments - https://go.dev/wiki/CodeReviewComments
- Test Comments - https://go.dev/wiki/TestComments
Final takeaway
AI can generate code.
Engineering teams must generate confidence.
