Programming is the discipline of translating problems into working software. At the level covered here, that means choosing the right abstractions, managing complexity, and writing code that other engineers can maintain and extend. The focus in this section is on the .NET ecosystem — C# language features, runtime behavior, web API development, and concurrency patterns — because that is where most production backend work happens for .NET-focused teams.

Good programming judgment means knowing when not to use a pattern, understanding runtime costs such as allocations, GC pressure, and synchronization, and choosing maintainable code over unnecessary cleverness.

API contracts and SDK tooling

An API is a contract between software components. For a service API, a client SDK packages the wire contract into language-specific types, authentication, serialization, helpers, documentation, examples, and sometimes build or diagnostic tools. Calling an HTTP API directly exposes the transport and wire schema. Calling it through an SDK buys ergonomics and consistency while adding package lifecycle, generated-code, and abstraction costs.

The same call two ways

For GET /v1/widgets/{id}, a manual .NET client owns every HTTP detail:

using var request = new HttpRequestMessage(HttpMethod.Get, $"v1/widgets/{id}");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
 
using HttpResponseMessage response = await httpClient.SendAsync(request, ct);
response.EnsureSuccessStatusCode();
 
Widget widget = (await response.Content.ReadFromJsonAsync<Widget>(ct))!;
Widget widget = await widgets.GetAsync(id, cancellationToken: ct);

The short call did not remove HTTP. The SDK still chooses a base URL, sends credentials, serializes parameters, maps non-success responses, and deserializes the representation. Good SDKs leave escape hatches for response headers, cancellation, raw errors, custom transports, and new server fields.

The visual shows a common HTTP API and client-toolkit relationship, not a definition. APIs are not limited to HTTP, and an SDK may wrap several APIs, local libraries, emulators, generators, and tools. The contract remains the authority; the SDK is one packaged consumer surface.

Costs and versioning

ConcernDirect API callSDK
Transport exposureMethod, URI, headers, status, and wire schema stay visibleAbstraction is easier to use but can hide useful protocol details
Language couplingAny client that speaks the contract can call itEach supported language needs design, generation, release, and support
CompatibilityClient chooses when to adopt contract changesPackage releases must track additive and breaking API changes
RetriesCaller chooses policy per operationCentral policy is consistent but unsafe if it retries non-replayable operations blindly
ErrorsWire-level errors are explicitTyped errors help, but lossy mappings make diagnosis harder
MaintenanceRepeated auth, serialization, pagination, and error codeGenerated surface drift, package security, docs, examples, and deprecations

Version the API contract and SDK package separately. An additive server field may need no API version but still justify an SDK release with a new property. A package major version does not make a breaking wire change safe for old clients. Generated SDKs reduce mechanical work only when the OpenAPI description is accurate and generation is reproducible; handwritten layers still earn their keep for idiomatic workflows, pagination, long-running operations, and better errors.

Put retries at the layer that understands replay safety. A generated client can retry a timed-out GET; it must not silently replay a charge-creation POST unless the API defines an idempotency contract. Keep retry counts, backoff, Retry-After, cancellation, and final failure observable to callers.

References

5 items under this folder.