Instiq
Chapter 3 · Software design·v1.0.0·Updated 7/11/2026·~16 min

What's changed: Initial version

3.4Reuse and frameworks

Key points

Covers the difference in call direction among a library, a component, and a framework—your code calling the other versus the other calling your code, i.e. the Inversion of Control (IoC)—along with REST API design principles (resource orientation, statelessness, HTTP method semantics) and versioning strategy, together with judging how to choose a reuse approach for existing assets and how to preserve compatibility for a public API.

The decision to adopt a reusable asset is not "use it because it seems convenient"—the essence is discerning which direction control flows between that asset and your own code. What matters to a system architect is not confusing adopting a library with adopting a framework, and being able to design and version a publicly exposed API so it survives future change.

3.4.1Libraries, components, frameworks, and IoC

  • A library is a component that provides a specific function (string processing, numeric computation, etc.). Your code calls the library's functions whenever it needs them. Control always remains in your own code's hands.
  • A component is an independently deployable and replaceable unit of reuse that collaborates with other components through a well-defined interface. It is coarser-grained than a library and often completes a self-contained, meaningful piece of functionality on its own.
  • A framework holds the overall flow of control (the skeleton) for the application, and it is the framework that calls the developer's code (hooks/callbacks) at the appropriate time. This reversal of control—where "the code being called is your own code"—is called Inversion of Control (IoC).
  • A practical diagnostic question: "who owns main (startup and overall control flow)?" If your code starts up and calls the library, it is a library relationship; if the framework starts up and calls your code as hooks, it is a framework relationship (IoC). Misjudging this leads to a design that ignores the framework's control flow, forfeiting its benefits (centralized handling of cross-cutting concerns, etc.).

3.4.2API design (REST) and versioning

  • REST (Representational State Transfer) is a design principle that represents resources via URIs and expresses operations on those resources through HTTP method semantics (GET = retrieve, no side effects; POST = create; PUT = full update, idempotent; DELETE = delete). It is a core principle to avoid embedding verbs in the URI (GET /users/{id}, not /getUser).
  • Stateless means each request carries all the information needed to process it, without the server retaining session state between requests. This makes it easy to scale the server out horizontally.
  • Versioning is the strategy for introducing breaking changes to a public API (response-format changes, etc.) without affecting existing clients. Specifying the version in the URI path (/v1/, /v2/) or an HTTP header are representative approaches. The practical baseline policy is to keep the old-version endpoint that existing clients use alive during a migration window while offering the new version in parallel.
Exam point

Most-tested: "a framework embodies Inversion of Control (IoC)—the framework calls your code, whereas with a library your code calls the library," "REST represents resources via URIs and follows HTTP method semantics," "PUT is an idempotent full update," and "a breaking change should keep the old version alive while offering the new version in parallel." The key pitfall is reversing the direction of control between a library and a framework.

Suppose a system architect is asked to expose an internally used order-management API to an external partner company. The current API concentrates all order-processing logic (create, update, cancel, distinguished within one giant request body) behind a single endpoint, POST /processOrder, embedding a verb in the URI and using a flag inside the request body to distinguish the operation type. This departs from REST principles—resources (orders) should be represented via URIs, and the type of operation should be delegated to HTTP method semantics. The fix is to redesign the endpoints to be resource-oriented and aligned with HTTP method semantics: POST /orders (create), PUT /orders/{id} (full update, idempotent), DELETE /orders/{id} (cancel/delete), GET /orders/{id} (retrieve, no side effects). Next, because this API is now exposed externally to a partner, a concern arises: can the response format be changed in the future without breaking the existing partner's implementation? Rewriting the response format directly without planning would immediately break the existing partner's integration. The right response is to embed the version explicitly in the URI path, like /v1/orders, and build in from the start a versioning strategy where when a new format is offered later at /v2/orders, /v1/orders is kept alive and run in parallel during a migration window. Furthermore, suppose the internal implementation of this order-management system delegates order-confirmation validation logic to an external framework (a web application framework). This framework has a structure where the framework itself owns the flow of control—request received -> routing -> validation -> calling the developer's handler -> response generation—and calls the developer-written handler function at the appropriate point (Inversion of Control, IoC). This is the opposite direction of control from using a library, where "your code calls the library's function," and taking advantage of the cross-cutting concerns the framework provides (centralized authentication, logging, error handling) requires designing handlers that follow the framework's control flow. Judging, case by case, (1) who represents the resource and who determines the meaning of the operation (REST), (2) whether a change can be introduced without breaking existing clients (versioning), and (3) which side holds control (IoC) is the system architect's role.

KindWho holds controlExample
LibraryYour code calls the libraryString-processing/numeric-computation function sets
ComponentCollaborates as an equal peer through a well-defined interfaceAn independently deployable business-function unit
FrameworkThe framework calls your code (handlers) (IoC)A web application framework
Warning

Trap: "A framework and a library are essentially the same in that your code calls the other" is wrong—a framework fundamentally differs from a library in that it owns the flow of control itself and calls your code (Inversion of Control). Also wrong: "when it becomes necessary, you can simply rewrite the existing endpoint's response format for a public API"—to avoid breaking existing clients, a versioning strategy is needed that keeps the old version alive while offering the new version in parallel.

Components, API design.
Compose, do not rebuild

3.4.3Section summary

  • With a library, your code is the caller; with a framework, the framework calls your code (Inversion of Control, IoC)—the direction of control is reversed
  • REST represents resources via URIs and delegates the meaning of an operation to the HTTP method (GET/POST/PUT is idempotent/DELETE)
  • A breaking change to a public API is guarded against by a versioning strategy that keeps the old version alive during a migration window while offering the new version in parallel

Sign in to track progress — Log in.

Quick check

(just a quick review)

Q1. An external piece of software a team is considering adopting owns the entire flow of control—from receiving a request, through routing, validation, calling the team's own handler, to generating a response—and calls the team's code at the right time. What best describes this relationship?

Q2. An order-management API concentrates create/update/cancel logic behind a single endpoint, POST /processOrder, distinguishing the operation type via a flag in the request body. What is the most appropriate REST-aligned fix?

Q3. After exposing an internal API to an external partner, if the response format needs to change in the future, what is the most appropriate strategy to migrate without breaking the existing partner's implementation?

Check your understandingPractice questions for Chapter 3: Software design