The Go Implementation Contract Before Benchmark Results

Key Takeaways

  • This fourth article in our ten-part single-machine Linux benchmark series defines the Go net/http contract before any Go-versus-Java results are published.

  • The Go service must match the Article 02 HTTP behavior at the external boundary: endpoints, JSON rules, validation, error envelopes, deterministic payload generation, and extraWork checksum semantics.

  • Go does not need to imitate the Helidon SE implementation from Article 03. It does need to prove that it performs the same declared work and reports enough runtime evidence to make later results auditable.

  • Runtime tuning is part of the benchmark input. Defaults come first; any GOMAXPROCS, GOMEMLIMIT, GOGC, diagnostics, profiling, CPU, or memory variation needs a clear run label and manifest evidence.


Before we believe a future Go-versus-Java chart, we need to know exactly what the Go service is doing.

Not “it is a small Go program.” Not “it uses the standard library.” Not “it looks equivalent.” We need to know where the request is decoded, how validation fails, whether unknown JSON fields are rejected, whether duplicate fields are caught, what extraWork contributes to the response, whether one side silently enables a timeout or protocol mode, and which runtime settings were active when the run was measured.

That is the job of this article.

This is a contract article, not a results article. It defines the Go net/http service shape and the runtime evidence required before any Go result can be compared with the Java/Helidon variants from Article 03. We are not producing Go benchmark numbers here. We are not generating the benchmark source package here. We are defining what must be true before Go net/http results can be compared defensibly with the Java side.

If you build Oracle AI Database-backed services, this matters even before a database call enters the benchmark. A retrieval API, embedding gateway, reranking service, feature-enrichment layer, or vector-search facade often spends real CPU and memory in ordinary application-tier work: HTTP handling, JSON decoding, validation, enrichment, response shaping, logging boundaries, and runtime scheduling.

This article does not measure Oracle AI Database. It defines the Go service boundary so later database-backed workloads do not blur service-tier behavior with database behavior.

Short Answer: The Go Contract

The Go benchmark side must be a declared net/http service that implements the Article 2 HTTP contract and aligns with the Java/Helidon plan from Article 3 at the external behavior level.

The final Go service exposes the same GET /health, HEAD /health, and POST /work behavior; applies the same JSON media-type policy, request body limit, validation rules, duplicate-field and unknown-field rejection, deterministic payload generation, extraWork checksum semantics, success response, and JSON error envelope; and keeps primary-run logging, TLS, compression, and tracing off unless a later labeled slice enables them symmetrically.

The Go implementation does not need to imitate Helidon internals. It does need to prove that it is doing the same declared work. extraWork is a first-class equivalence gate because it affects the returned checksum and must not be skipped, reduced, duplicated, reordered, or optimized away.

The runtime side needs the same discipline. Defaults come first. Tuned runs are allowed only under clear labels, with GOMAXPROCS, CPU context, memory limits, GOMEMLIMIT, GOGC, server settings, allocation evidence, GC evidence, runtime/metrics snapshots, and pprof artifacts tied to the benchmark manifest.

Exact Go, Java, OS, kernel, CPU, memory, and tool versions will be recorded in the benchmark manifest when accepted runs are executed.

What Articles 1 to 3 Established

Article 1 set the series rule: method first, measurement later. We are not trying to make a language-war claim. We are building an evidence chain strong enough that later results can be challenged on method, source, runtime identity, load-generator validity, execution protocol, and analysis rules.

Article 2 defined the language-neutral service behavior that both implementations must follow. For the Go implementation, that means using the Article 2 endpoint list, request schema, response schema, body-limit policy, JSON media-type rules, validation rules, error envelope, deterministic payload-generation rules, and extraWork semantics without alteration.

The relevant service shape is intentionally small. GET /health returns stable JSON:

{
"status": "ok"
}

POST /work accepts a JSON object containing requestId, payloadSize, seed, and extraWork, subject to the Article 2 media-type, body-size, field, and numeric-validation rules. The service enforces the /work request-body limit, rejects unknown fields, rejects duplicate top-level fields, validates integer bounds and types strictly, generates deterministic payload bytes from payloadSize and seed, applies deterministic repeated SHA-256 work controlled by extraWork, and returns a stable success response containing requestId, payloadSize, extraWork, checksum, and ok.

Failures that use response bodies return the agreed JSON error envelope. Framework-default HTML pages, stack traces, plain-text errors, extra runtime metadata, and implementation-specific error documents are contract failures.

Article 03 defined the Java-side implementation plan and the evidence that the Java run must provide. This article uses that plan as the continuity point for external behavior and runtime evidence; it does not require Go to mirror Java internals.

The Java-side manifest must identify the exact JDK distribution, vendor, build, version, JVM mode, and relevant flags rather than treating Java, OpenJDK, and Oracle JDK as interchangeable runtime labels.

What This Article Covers

This article covers the Go net/http service shape, Article 2 equivalence, Article 3 alignment, extraWork review, runtime knobs, allocation and GC evidence, runtime/metrics, pprof, and acceptance gates.

It does not cover benchmark results. It does not define the load generator; Article 05 owns that. It does not define the full run protocol, CPU governor handling, warmup windows, repeat rules, invalid-run policy, or statistical analysis; those belong in later methodology and analysis articles.

It also does not move the series into Kubernetes or production orchestration. This ten-part series is scoped first to a controlled single-machine Linux benchmark. Host OS, kernel, CPU topology, CPU affinity or cgroup quota, memory limits, and runtime versions must be recorded in the manifest. The primary pure-service benchmark does not introduce Oracle AI Database driver behavior, SQL, vector-search execution, or database latency.

That boundary is deliberate. If implementation, tuning, load generation, execution, and analysis collapse into one step, the later chart becomes hard to trust. The Go side needs to pass its contract gates before source generation and benchmark execution.

Infographic outlining contract guidelines for software development, including shared contract rules, Go service specifications, and runtime evidence metrics.

We define the Go side as a contract gate: Article 2 supplies the external service behavior, Article 3 supplies the Java/Helidon alignment point, and Article 4 defines the Go gates that must pass before later source generation, benchmark execution, and analysis.

Why net/http Is the Go Baseline

The Go side uses the standard-library net/http package as the baseline. That is a good fit for this benchmark because it keeps the service path visible. Handler boundaries, request decoding, response writing, server settings, and diagnostics can be reviewed without also reviewing a third-party router, middleware framework, validation package, or alternate HTTP engine.

That is a reviewability argument, not a performance claim.

Go developers have good reasons to use frameworks and routers such as Gin, chi, Echo, Fiber, or fasthttp-based stacks in real services. Some provide better ergonomics for route grouping, middleware, validation, OpenAPI integration, structured errors, or specialized performance goals. Those choices can be useful production decisions. They are simply not the primary baseline for this series.

net/http is the right first baseline here because it is familiar, standard-library-based, and inspectable. The standard library keeps the baseline small, but it does not make the benchmark fair by itself. Fairness comes from matching the Article 2 contract, controlling runtime settings, capturing evidence, and rejecting runs that violate the rules.

The Go Service Shape

The Go service should be a single explicit net/http server shape for the primary pure-service benchmark. The exact source package comes later, but the implementation contract is already clear.

The route map comes from Article 2:

  • GET /health returns 200 OK and {"status":"ok"} as JSON.
  • HEAD /health follows HEAD behavior for the health resource.
  • POST /work is the measured work endpoint.
  • Unsupported methods and unknown routes follow the Article 02 status and JSON error rules. When Article 02 requires 405 Method Not Allowed, the response must include the contract-defined Allow header.

For HEAD /health, the Go handler must return the same headers and status policy defined for the health resource while writing no response body.

The handler path for POST /work is fixed at the contract level. The service checks the route and method, validates the media type, enforces the /work request body limit, decodes JSON, rejects duplicate and unknown top-level fields, validates required fields and scalar bounds, generates the deterministic payload, applies extraWork, computes the checksum, and returns the success JSON. Failures map to the Article 2 error envelope.

Here is the shape we want the final source to preserve. This is an illustrative contract snippet, not the generated benchmark source package:

// Illustrative contract shape only.
// The benchmark source package will be generated later from the finalized contracts.
func main() {
server := &http.Server{
Addr: ":8080",
Handler: http.HandlerFunc(route),
// Addr, timeouts, header limits, body limits, TLS, and protocol settings
// are illustrative here. Final values must be declared in the benchmark manifest.
}
log.Fatal(server.ListenAndServe())
}
func route(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/health":
handleHealth(w, r)
case "/work":
handleWork(w, r)
default:
writeContractError(w, contractErrorForUnknownRoute(r))
}
}
func handleHealth(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet && r.Method != http.MethodHead {
writeContractError(w, contractErrorForUnsupportedMethod(r))
return
}
w.Header().Set("Content-Type", "application/json")
if r.Method == http.MethodHead {
w.WriteHeader(http.StatusOK)
return
}
_, _ = w.Write([]byte(`{"status":"ok"}`))
}
func handleWork(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
writeContractError(w, contractErrorForUnsupportedMethod(r))
return
}
req, err := decodeWorkRequest(r)
if err != nil {
writeContractError(w, err)
return
}
if err := validateWorkRequest(req); err != nil {
writeContractError(w, err)
return
}
checksum := performDeclaredWork(req.PayloadSize, req.Seed, req.ExtraWork)
resp := WorkResponse{
RequestID: req.RequestID,
PayloadSize: req.PayloadSize,
ExtraWork: req.ExtraWork,
Checksum: checksum,
OK: true,
}
body, err := json.Marshal(resp)
if err != nil {
writeContractError(w, contractErrorForInternalEncoding(err))
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(body)
}

The important part is not the number of lines. It is the request path:

request -> route -> media type/body limit -> JSON decode -> validation -> extraWork -> response/error contract

The final source should set response Content-Type exactly as Article 2 specifies. The illustrative snippet uses application/json only to show that Go must not fall back to framework or net/http default error documents.

The final source may use ServeMux or another standard-library routing shape, but it cannot let default net/http error documents define the benchmark behavior. Unknown routes, unsupported methods, oversized bodies, malformed JSON, and validation failures must all map to the Article 02 status and JSON error contract. If the final source uses ServeMux method/path patterns rather than explicit method checks inside handlers, the selected Go toolchain’s ServeMux matching semantics must be recorded because those semantics are version-sensitive.

JSON handling will likely use encoding/json, because it is the standard-library JSON package and keeps dependencies low. But encoding/json defaults are not the contract. The implementation must not rely on convenient decoder behavior to define benchmark behavior.

Plain struct unmarshalling does not prove duplicate-field rejection, and unknown fields are ignored unless the decoder is configured or the implementation checks them explicitly. Article 02 rejects unknown fields and duplicate top-level request fields, so the Go source needs a token-level pass, json.RawMessage inspection, or another explicit mechanism that records top-level field names before decoding into the typed request model.

The same applies to numeric handling. Article 2 requires integer JSON numbers with no fractional part and no exponent notation for payloadSize, seed, and extraWork. Numeric validation should be explicit for the chosen decode path so strings, fractional forms, exponent notation, missing values, and out-of-range values are rejected exactly as Article 02 requires.

Server configuration also belongs in the contract. If the Go service uses http.Server timeouts, header limits, handler-level body limits such as http.MaxBytesReader, TLS, HTTP/2 settings, compression, or diagnostics listeners, those settings must be declared. The primary pure-service benchmark keeps request logging, TLS, compression, and tracing off unless a later secondary slice enables them symmetrically.

Logging has the same boundary. Build and startup logs are useful. Error diagnostics are useful. Per-request access logging is off for the primary measured path unless a later logging slice includes it deliberately. A hidden log line on every request can become part of the workload.

How the Go Contract Pairs With the Java Contract

Go does not need to imitate Helidon SE internals. Java does not need to imitate Go internals.

That sounds obvious, but it is a common benchmark trap. If we try to make Go look like Java inside the process, or Java look like Go, we stop comparing real service shapes and start building an artificial hybrid.

The Java implementation uses the Helidon SE configuration defined in Article 03. The Go implementation uses net/http. They are compared at the external contract level, not by assuming identical routing, scheduling, or runtime internals. Any Helidon/JDK threading mode, including virtual-thread-related settings if used, must be recorded in the Java run manifest.

Both implementations must satisfy the same HTTP behavior from Article 02. Both must implement the same deterministic payload generation and extraWork checksum behavior. Both must use the same primary-run posture for logging, TLS, compression, and tracing. Both must report enough runtime identity and diagnostic evidence to make later results auditable.

Article 3 defines the Java/Helidon side with its request-handling plan, runtime policy, and diagnostic evidence. This article defines the Go side with net/http, Go runtime settings, allocation and GC observability, and pprof artifacts.

They align at the contract level, not by sharing internals.

The extraWork Equivalence Review

extraWork is the part of this benchmark that most deserves suspicion.

In Article 2, extraWork is not a sleep, a delay knob, or a decorative loop. The service generates deterministic payload bytes from payloadSize and seed, computes an initial SHA-256 state, then applies a deterministic repeated operation extraWork times:

buffer = generatePayload(payloadSize, seed)
state = SHA-256(buffer)
repeat extraWork times:
state = SHA-256(state || buffer)
checksum = lowercaseHex(state)

Because the final checksum is returned, extraWork has an observable effect for the benchmark’s conformance test vectors. If the loop is skipped, shortened, duplicated, reordered, or changed, the expected checksum for those vectors will not match.

The Go implementation must treat this as declared per-request work. It is not a hidden trick and not a place for clever local interpretation. The comparison does not require Java and Go to execute identical machine instructions. It does require both services to perform the same externally specified operation for the same accepted request.

The equivalence assertion should be this direct:

given payload P
and configured extraWork=N
when the Go service handles P
and the Java service handles an equivalent P
then both services:
- validate P before performing accepted work
- generate the same deterministic payload bytes
- execute the declared work factor N
- produce the same checksum
- reject the same invalid values
- record extraWork=N in the benchmark manifest

The ordering matters. Invalid requests should fail validation before accepted work is performed. extraWork = 0 is valid and means no repeated extra operation after the initial payload checksum. extraWork above the Article 2 maximum is invalid. A string, fractional value, exponent notation, missing value, or negative value is invalid.

A few mistakes would invalidate the comparison immediately:

The comparison is invalid if:
- Go skips extraWork for a valid request that Java processes.
- Go performs fewer iterations because of integer truncation or a loop-bound mistake.
- Go allocates large temporary buffers inside the loop when the contract does not require them.
- Java performs extra hidden request work that is not declared in the Java contract.
- One implementation accepts extraWork=0 and the other rejects it.
- The work is optimized away because it has no observable or retained effect.

The allocation example needs careful handling. Different runtimes have different allocation behavior, and the benchmark does not require identical allocator internals. But if the Go source creates avoidable temporary structures inside the extraWork loop while the Java source reuses state for the same logical operation, that may be a benchmark implementation bug rather than a runtime finding.

The fix is not to tune around it after seeing results. The fix is to inspect the implementation, decide what the contract requires, test it, and only then allow the source into the benchmark package.

Before results are published, the benchmark source or contract appendix must include canonical checksum test vectors for accepted combinations of payloadSize, seed, and extraWork. extraWork is admissible only when both implementations do the same declared work for the same accepted request and fail the same invalid requests in the same way.

Runtime Tuning Is a Controlled Hypothesis

The Go runtime settings are not incidental. They shape how the process uses CPU and memory, how garbage collection is paced, and how later profiles should be interpreted.

The default run comes first. That default run should use the selected Go toolchain’s runtime defaults under the declared Linux machine or container environment. Tuned variations can come later, but only under labels that explain the hypothesis.

For example, future run labels might distinguish:

  • go-nethttp-default
  • go-nethttp-gomaxprocs-2
  • go-nethttp-gomemlimit-labeled
  • go-nethttp-gogc-labeled
  • go-nethttp-profiled

Those names are examples, not final manifest labels. The rule is the point: a tuned Go run without a manifest label is not reproducible enough to compare.

A compact future-run manifest excerpt shows the level of evidence required:

run:
label: "go-nethttp-default"
benchmark_scope: "single-machine-linux"
results_in_this_article: false
service:
language: "go"
implementation: "net/http"
json_library: "encoding/json"
tls_primary_path: false
server_settings:
read_timeout: "required-if-set"
write_timeout: "required-if-set"
max_request_body_bytes: 4096
runtime:
go_version: "required"
effective_gomaxprocs: "required"
gomemlimit: "required-or-unset"
gogc: "required-or-default"
os: "required"
kernel: "required"
cpu_limit: "required-if-containerized-or-limited"
memory_limit: "required-if-containerized-or-limited"
workload_contract:
service_contract_version: "required"
extra_work: "required"
artifacts:
runtime_metrics: "required"
cpu_profile: "required-for-profiled-runs"
heap_profile: "required-for-profiled-runs"
alloc_profile: "required-for-profiled-runs"
goroutine_profile: "required-for-profiled-runs"

This manifest is not evidence that a benchmark has run. It is the contract for what later accepted Go runs must record.

Because Go runtime defaults can change across Go releases and execution environments, the manifest should record both configured environment values and effective values observed by the benchmark process. Shell environment alone is not enough. Accepted runs must capture the selected Go toolchain and the effective runtime values from inside the benchmark process or from a dedicated manifest probe built with the selected Go toolchain.

CPU and Memory Controls

GOMAXPROCS controls how many operating-system threads can execute Go code simultaneously. That setting matters because a service running with one effective CPU is not the same experiment as a service running with four, eight, or sixteen. It also matters when the process runs under CPU affinity, cgroup quota, or a container CPU limit.

The Go contract should record the observed GOMAXPROCS value, host CPU model, logical CPU count, CPU affinity if constrained, container CPU quota or limit if used, whether GOMAXPROCS was set manually, and the Go toolchain version that determined default behavior.

We should avoid advice like “set GOMAXPROCS to the number of cores.” That might be right in one environment and wrong in another. The benchmark question is simpler: what CPU budget did the process actually observe, what value did the runtime use, and was that value a default or a deliberate tuned variation?

Memory needs the same discipline. A container memory limit, host memory availability, process RSS, Go heap behavior, and Go runtime memory policy are related but not identical.

GOMEMLIMIT is a soft limit for memory managed by the Go runtime and garbage collector. It is not a hard cap on process RSS. If the benchmark uses GOMEMLIMIT, that setting must be recorded and labeled. If it is unset, that fact should also be recorded. The surrounding memory context still matters because a process can be constrained by an external memory limit even when the Go runtime setting is unset.

GOGC changes the garbage collector’s target percentage and represents a CPU/memory tradeoff. Changing it can reduce memory growth at the cost of more GC work, or reduce GC frequency at the cost of more memory, depending on direction and workload. This article does not recommend a universal GOGC value. The baseline uses defaults first; changing GOGC is a labeled hypothesis.

Allocation and GC Evidence

The Go implementation should avoid accidental allocations that are not required by the workload. That is not the same as over-optimizing Go.

For example, repeatedly rebuilding constant response metadata, copying request bodies unnecessarily, allocating a fresh large buffer inside every extraWork iteration, or formatting unused strings on the hot path can turn the benchmark into a measurement of source mistakes. Those are worth fixing before execution if they violate the contract or create avoidable asymmetry.

On the other hand, the Go side should not introduce exotic pooling, unsafe tricks, custom JSON encoders, or specialized buffer reuse unless those choices are declared and accepted as part of the benchmark. If we aggressively tune Go allocation behavior while leaving the Java side at a straightforward implementation, the comparison shifts from service-shape benchmarking into asymmetric hand-optimization.

The practical sequence is straightforward: implement the Article 02 contract plainly, measure allocation rate and GC behavior under representative conformance or diagnostic load, inspect whether allocation differences are contract-required, runtime-inherent, or source-level mistakes, fix source-level mistakes before benchmark execution, and label any deliberate optimization that changes the baseline service shape.

The later Go run artifacts should include allocation and heap evidence. That does not mean every primary measured run has to run with heavy profiling turned on. It means the benchmark plan must capture enough allocation and GC information to explain later throughput, latency, CPU, and memory shapes.

Allocation reductions are hypotheses. Profiles and metrics tell us whether the hypothesis is true.

Profiling and Observability

Go gives us useful built-in observability paths: runtime/metrics, runtime/pprof, net/http/pprof, and the broader Go diagnostics guidance. This article requires a plan for those artifacts before any result exists.

runtime/metrics snapshots should be captured using the supported metric list for the selected Go version. The exact metric names belong in the later source package and manifest because the supported set can evolve. At minimum, the run should capture enough runtime data to reason about goroutines, scheduler behavior, memory, heap allocation, GC settings, GC pauses or timing summaries, and observed runtime configuration. The manifest should store both the collected metric values and the supported metric-name list reported by the selected Go version, so later analysis can distinguish “metric was zero” from “metric did not exist in this toolchain.”

pprof artifacts should be planned for profiled runs. CPU, heap, allocation, and goroutine profiles are the obvious starting point. Block or mutex profiles can be useful if the workload suggests contention, but they require explicit sampling configuration and should not be casually enabled in the primary path.

pprof is evidence capture, not free instrumentation. Profiled runs need labels, and interpretation belongs later, after accepted runs exist. If profiling changes the measurement environment, the profiled run should be separate from the primary comparison run.

A future diagnostics listener might be isolated from the measured service path. This snippet shows the idea without defining final source:

// Illustrative only.
// The final benchmark package must decide whether pprof is enabled,
// how it is isolated, and how profiled runs are labeled.
if diagnosticsEnabled {
go func() {
diagMux := http.NewServeMux()
diagMux.HandleFunc("/debug/pprof/", pprof.Index)
diagMux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
diagMux.HandleFunc("/debug/pprof/profile", pprof.Profile)
diagMux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
diagMux.HandleFunc("/debug/pprof/trace", pprof.Trace)
log.Fatal(http.ListenAndServe("127.0.0.1:6060", diagMux))
}()
}

The important boundary is not port 6060; that is only a familiar local example. The important boundary is that diagnostics are declared, isolated where appropriate, and tied to the run label. The final source should define diagnostics-listener startup, failure, and shutdown behavior explicitly; the snippet above is not a production-ready or benchmark-ready lifecycle policy.

For each accepted Go run, the artifact plan should include the benchmark manifest, service configuration, runtime/metrics snapshot, allocation profile when profiling is enabled, heap profile when profiling is enabled, CPU profile when profiling is enabled, goroutine profile when profiling is enabled, and GC summary or trace setting if enabled.

Those artifacts do not replace results. They make later results diagnosable.

Overview diagram of Go runtime evidence, detailing request processing, runtime signals, and captured evidence.

We plan Go runtime evidence before results exist: request handling, allocation behavior, scheduler and GC signals, runtime/metrics, and pprof artifacts all tie back to the benchmark manifest.

Acceptance Gates for the Go Implementation

The Go implementation is not accepted because it compiles. It is accepted only when it satisfies the contract gates.

Before the Go service is allowed into later benchmark source generation, Article 2 endpoint behavior must be implemented exactly. Routes must match the contract methods and paths. Request validation must reject unknown fields, duplicate top-level fields, wrong numeric types, out-of-range values, malformed JSON, unsupported media types, oversized bodies, unsupported methods, and unknown routes according to the agreed status and JSON error behavior. Success responses must match the Article 2 JSON contract.

The Go and Java implementations must also satisfy the same externally visible behavior. The Article 03 alignment gate keeps the Java side in view without forcing Go to mirror Helidon internals. If Java/Helidon adds a framework behavior that affects the contract, that behavior has to be declared and either matched externally or removed from the primary comparison.

The extraWork gate proves that Go and Java compute the same checksum for the same valid request and reject the same invalid work factors. It also forces us to inspect allocation behavior around the work loop before performance results are allowed.

The runtime manifest gate rejects unlabeled tuning. If GOMAXPROCS, GOMEMLIMIT, GOGC, CPU limits, memory limits, server timeouts, TLS, diagnostics mode, or profiling settings change, the run label and manifest must say so.

The allocation, GC, and pprof gates make sure future results can be explained. A surprising Go result without allocation, GC, runtime, or profile evidence is not a strong result. It is a guess with numbers attached.

And one gate is intentionally simple: no benchmark results are published from this article.

Why There Are No Results Yet

Charts would be premature here.

A Go throughput number published before the Go service contract is locked would not answer the series question. It would answer a less useful question: “What happened when this particular Go program, with these settings, was run under a not-yet-final method?”

That is not enough.

No Go result should be compared with Java until the implementation contract, source package, validation checks, load-generator evidence, run protocol, captured artifacts, and analysis rules all line up.

That order can feel slow if you want the chart. It is faster if you want a chart you can trust.

Conclusion: Handoff to Article 5

The Go side is now a contract, not a result claim.

We have defined why net/http is the baseline, how the Go service must implement the Article 2 endpoint behavior, how it aligns with the Java/Helidon plan from Article 3, why extraWork needs its own equivalence review, and which runtime settings and observability artifacts future Go runs must capture.

The next weak point is the client side. A service benchmark is not valid if the load generator is saturated, misconfigured, or measuring latency in a way that hides pauses. Article 05 moves to load-generator validity: request scheduling, coordinated-omission risk, client headroom, backpressure, timeout accounting, and the evidence needed to prove that later results are about the service under test rather than the benchmark harness.

References

About Mark Nelson

Mark Nelson is a Developer Evangelist at Oracle, focusing on microservices and AI. Mark has served as a Section Leader in Stanford's Code in Place program that has introduced tens of thousands of people to the joy of programming, he is a published author, a reviewer and contributor, a content creator and a lifelong learner. He enjoys traveling, meeting people and learning about foods and cultures of the world. Mark has worked at Oracle since 2006 and before that at IBM since 1994.
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply