Skip to content

refactor(internal/sidekick/surfer): remove remaining builder boiler plate#5800

Closed
sarahheacock wants to merge 4 commits into
googleapis:mainfrom
sarahheacock:surfer-builder
Closed

refactor(internal/sidekick/surfer): remove remaining builder boiler plate#5800
sarahheacock wants to merge 4 commits into
googleapis:mainfrom
sarahheacock:surfer-builder

Conversation

@sarahheacock
Copy link
Copy Markdown
Contributor

@sarahheacock sarahheacock commented May 4, 2026

Replace object-oriented builders with stateless functions that pass context objects when needed

  • Reduce boiler plate: Original Builder structs added unnecessary boiler plate and allowed for possible state. Removing structs limits confusion and elimintates possible state.
  • Parameter reduction: Context structs are only passed whenever 3 or more arguments are passed. Structs reduce cognitive friction by introducing named parameters and add additional type safety.
  • Consistent pattern: Code is functionally the same but allows for same pattern through out

Finish implementation of operations commands.
- Infers resource from operation method patterns to populate resource argument.
- Adds new mixins file to provide missing information such as documentation.
- Build wait command from get method
- Skip return_partial_success field since not available on all APIs

Fixes googleapis#5485
Remove object-oriented builders with stateless functions that pass context objects when needed
- Original Builder structs added unnecessary boiler plate and allowed for possible state
- Parameter reduction: Context structs are only passed whenever 3 or more arguments are passed allowing for easy mistakes

Code is functionally the same but allows for same pattern through out
@sarahheacock sarahheacock requested a review from jameslynnwu May 4, 2026 17:35
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for synthesizing 'wait' commands for long-running operations (LRO) and improves the handling of LRO resources. It refactors the builder logic to use context objects (ArgumentContext, CommandContext, GroupContext) and adds a new mixin.go provider to handle LRO-specific logic like resource inference and fallback documentation. Feedback was provided regarding the performance of GetAllResources, which performs a full scan of the API model and is currently called repeatedly during the surface building process; it is recommended to pre-compute or cache this list to avoid potential degradation on large API models.

Comment on lines +340 to +368
func GetAllResources(model *api.API) []*api.Resource {
var resources []*api.Resource
resources = append(resources, model.ResourceDefinitions...)

// Add message-level resources if not already present
for _, m := range model.Messages {
if m.Resource != nil {
resources = append(resources, m.Resource)
}
}

// Infer operations resources from GetOperation methods
for _, s := range model.Services {
for _, m := range s.Methods {
if m.Name == GetOperation && IsOperationsMethod(m) {
res, err := InferOperationResource(m)
if err != nil {
log.Printf("WARNING: failed to infer operations resource for method %q: %v", m.ID, err)
continue
}
if res != nil {
resources = append(resources, res)
}
}
}
}

return resources
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The GetAllResources function performs a full scan of the API model (resource definitions, messages, and services) to aggregate all resources, including inferred operations resources. This function is called repeatedly within loops when building the command surface (e.g., for every field of every method). For large API models, this repeated computation could lead to significant performance degradation during code generation. Consider computing the full list of resources once at the beginning of the surface building process (e.g., in buildSurface) and passing this pre-computed list down through the context objects, or caching the result of GetAllResources if the model object is immutable.

Comment on lines 41 to 44
for _, method := range service.Methods {
if err := insert(root, gb, method); err != nil {
if err := insert(root, ctx, method); err != nil {
return nil, err
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The insert function, and consequently the functions it calls (like buildCommand, newArguments, categorizeFields, GetResourceForMethod), implicitly trigger repeated calls to provider.GetAllResources(ctx.Model). As noted in the comment on provider/resource.go, GetAllResources performs a full scan of the API model. Calling it for every method and potentially every field within a method can be inefficient for large API definitions. To improve performance, consider computing the complete list of resources (using provider.GetAllResources) once at the start of buildSurface and then passing this pre-computed list through the GroupContext and CommandContext objects. This would avoid redundant model scans.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant