Interview contents
Principle of Least Knowledge at Service Boundaries
Introduction
In large-scale distributed systems, services must collaborate to fulfill business workflows.
However, if services know too much about each other’s internals, the system becomes fragile:
- A change in one service breaks others.
- Deployments require coordination.
- Teams lose autonomy.
To prevent this, architects apply the Principle of Least Knowledge (also known as the Law of Demeter) at service boundaries.
The rule: A service should only talk to its direct collaborators through stable contracts, and know as little as possible about others.
Why the Principle of Least Knowledge Matters
- Reduced Coupling – Services interact through narrow, stable contracts.
- Team Autonomy – Each team can evolve its service without ripple effects.
- Resilience – Failures are contained; fewer dependencies mean fewer breakages.
- Security – Internal details remain hidden, minimizing attack surfaces.
The Law of Demeter Refresher (Class Level)
At the class level, Law of Demeter says:
- Don’t chain too many calls (
a.getB().getC().doSomething()). - Instead, interact with direct collaborators.
At the system level, this translates to:
- Don’t expose one service’s internals (schema, nested objects) to others.
- Only expose what’s necessary via APIs.
Bad Example – Violating the Principle
// OrderService calling PaymentService internalspublic class OrderService { private PaymentService paymentService;
public void placeOrder(Order order) { paymentService.getPaymentRepository() .getPaymentGateway() .charge(order); }}❌ OrderService knows about repository + gateway internals of PaymentService.
❌ Any internal refactor in PaymentService breaks OrderService.
Good Example – Following the Principle
// Contract exposed by PaymentServicepublic interface PaymentService { void charge(Order order);}
// OrderService only depends on the contractpublic class OrderService { private final PaymentService paymentService; public OrderService(PaymentService paymentService) { this.paymentService = paymentService; } public void placeOrder(Order order) { paymentService.charge(order); }}✅ OrderService only knows about charge().
✅ Payment internals hidden.
✅ Payment team can refactor freely.
Service Boundaries in Microservices
Anti-Pattern: Shared Database
- OrderService queries Payment DB directly.
- Tight coupling to schema.
Correct Pattern: API Boundary
- OrderService calls Payment API
/charge. - Schema hidden behind API.
Real-World Case Studies
1. Amazon
- Teams not allowed to access each other’s DB.
- APIs enforced as boundaries.
- Result: Teams scale independently.
2. Netflix
- Recommendation service doesn’t query Viewing DB directly.
- Talks to Viewing API.
- Ensures independence and resilience.
3. Banking Systems
- Compliance APIs expose only what’s required.
- Internal rules hidden.
- Prevents accidental violations.
Common Pitfalls
-
Leaky APIs
- Expose DB schema or nested objects.
- Violates least knowledge.
-
Chatty APIs
- Require too many fine-grained calls.
- Leads to performance issues.
-
Tight Coupling via Libraries
- Services share the same internal library.
- Breaks independence.
Extended Java Case Study
Without Least Knowledge
// InventoryService exposes nested structurespublic class InventoryService { public InventoryRepository getRepository() { return repo; }}
// OrderService chained calls into Inventory internalsorderService.getInventoryService() .getRepository() .getStockDAO() .checkStock(id);❌ OrderService depends on Inventory internals.
With Least Knowledge
// InventoryService contractpublic interface InventoryService { boolean hasStock(String productId);}
// OrderService depends only on the APIpublic class OrderService { private final InventoryService inventoryService; public OrderService(InventoryService inventoryService) { this.inventoryService = inventoryService; } public void placeOrder(Order order) { if (inventoryService.hasStock(order.getId())) { ... } }}✅ OrderService only depends on hasStock().
✅ Inventory can refactor internals freely.
Interview Prep
Q1: What is the Principle of Least Knowledge?
Answer: A service should only talk to its direct collaborators via stable contracts, and not depend on internal details of other services.
Q2: Why is it important in microservices?
Answer: Prevents tight coupling across services, enabling team autonomy and independent evolution.
Q3: What’s an example of violating it?
Answer: Service A querying Service B’s database directly.
Q4: How can you enforce it in Java?
Answer: Define contracts via interfaces or APIs, hide implementation details, and avoid exposing nested structures.
Q5: What’s the relationship with Law of Demeter?
Answer: Law of Demeter at class level → Least Knowledge at system/service level. Both reduce coupling by avoiding dependency on indirect details.
Visualizing Least Knowledge
graph TD A[Order Service] -->|"charge()"| B[Payment API] B --> C["(Payment DB)"] A -.->|Does NOT see DB| C✅ Order talks only to Payment API.
✅ Payment DB hidden.
Key Takeaways
- Principle of Least Knowledge = services should only depend on minimal, stable contracts.
- Prevents fragile coupling across services.
- Builds resilience, autonomy, and security.
- Strongly enforced at Amazon, Netflix, and banks.
Next Lesson
Next, we’ll explore Security Principles in Architecture — least privilege, defense in depth, and failing securely.
Continue to Security Principles →