Dependency Inversion
Dependency inversion aligns important technical logic with stable, own contracts. Technical adapters fulfill these contracts and thus depend on the specialist core.
- Own contractThe expert core defines what it needs.
- AdaptivesTechnically implements the contract and is interchangeable.
- DirectionThe source code shows from the technology to the specialist core.
Context
Why this is important
If the payment logic depends directly on the provider API, every change of the provider draws it; tests also need the real provider. Dependency inversion is the principle, dependency injection only a mechanism. Foreign terms translated by the building block ACL.
This building block explains the direction of technical dependencies. For the business translation of foreign models, see Anti-Corruption Layer.
At a glance · Adapters depend on the core domain
Reverse dependence on the payment provider
The payment module requires the ability to authorize an amount. It defines its own contract for this; an adapter translates it to an external payment provider.
This is how you read the picture
- Own contract The box authorize payment in the area specialist core.
- Adaptives Provider adapter and test adapter implement the same contract; the adapter calls the payment provider.
- Direction In the picture “This is how the direction is reversed”, the arrow crosses the border inwards, beforewards outwards.
Wide diagram · Move laterally if necessary
Read diagram as text
- Payment logic: Business status (Specialist core)
- Authorize payment: Own contract (Specialist core)
- Provider adapter: Translated call and answer (Technique)
- Payment provider: External API (External)
- Test adapters: Predictable answers (Test)
- Payment logic → Authorize payment: Used
- Provider adapter → Authorize payment: Implemented
- Provider adapter → Payment provider: Calls for
- Test adapters → Authorize payment: Implemented
Then the direction is reversed.
- Payment logicBusiness Rules and StatusPayment logic Knows SDK types Provider API.
- Provider APIforeign SDK, foreign types
The dependency points from the inside out over the border; every change of provider meets the payment logic.
Benefits & limitations
Helps if:
- Business rules are tightly coupled to specific database or network libraries.
- An independent test or replacement of an infrastructure component is a proven goal.
Boundaries
- An additional contract costs implementation and maintenance. Examine its usefulness based on Module boundaries and actual testing or exchange needs.
- A contract expressed in infrastructure terms can still tie business logic to infrastructure. Use domain language and preserve Separation of Concerns between the rule and its technical effects.
In practice
- Locate the concrete dependency. Identify infrastructure concepts in business logic that make tests harder. This shows whether a contract can remove a real source of coupling.
- Express the required capability as a contract. Define a business operation with clear inputs and results. Place it in the core and align the dependency with Module Boundaries.
- Add an adapter and an independent test. Implement the contract at the infrastructure boundary and test business behaviour with a controlled implementation. Hexagonal Architecture provides a suitable structural perspective.
Read the detailed explanation
Dependency Inversion arranges dependencies so that business logic defines the contracts it needs, while technical adapters integrate concrete libraries. Source code depends on a contract expressed in business terms. Adapters implement that contract outside the core. Hexagonal Architecture organises ports and adapters; Separation of Concerns separates reasons for change.
At runtime, the core can still call the technical implementation, while the source code dependency points from the adapter to the core contract. This allows business behaviour to be tested independently. Interfaces should provide a real testing or replacement benefit; excessive abstraction adds concepts without a corresponding gain.
Three terms are often confused. Dependency Inversion is the principle: business logic depends on its own abstractions rather than concrete infrastructure. Dependency Injection is a mechanism: the appropriate adapter is supplied from outside, for example by a framework such as Spring. Inversion of Control is the broader concept: the framework calls your code rather than the other way round. Injection alone does not provide dependency inversion. Injecting a provider SDK directly into payment logic still leaves the dependency pointing outwards; only the way the object is obtained has changed.
Check your understanding
Test yourself in three stages
ReadingCheck in the picture
In what direction does the arrow cross the border before and after?
View the solution with justification
Before that, it shows from the payment logic (inside) to the provider API (outside). Afterwards he shows from the provider adapter (outside) to the contract (inside).
ApplyingTransferred to a new situation
In the test, the payment of B-1042 Without a real provider. What are you doing?
View the solution with justification
You are using the test adapter. He fulfills the same contract and provides predictable answers; the payment logic remains unchanged.
EvaluateWeighing an alternative
The team injects the provider SDK directly into the payment logic via spring and calls it dependency inversion. Is that true?
View the solution with justification
No. This is injection without its own abstraction: The payment logic still knows SDK types, the dependency shows to the outside. Inversion only arises when the specialist core defines its own contract and the adapter fulfills it.
Explore further
These building blocks continue the thoughts of this page.
References
- Microsoft Architectural Principles (opens in new tab)Explains Separation of Concerns, Encapsulation and Dependency Inversion.
- Alistair Cockburn - Hexagonal Architecture (opens in new tab)Original description of ports, adapters and interchangeable external connections.
- Martin Fowler · Inversion of Control Containers and the Dependency Injection pattern (opens in new tab)Divides Inversion of Control and Dependency Injection from each other.