<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/IfWUvQqsh" -->

---
title: A Dependency Is Not Just a Relationship Where One Piece...
description: A deep dive into what dependencies really represent in real-world services, going beyond the simple &#x27;one function calls another&#x27; definition. Using a TypeScript...
canonical: https://daily.dev/posts/a-dependency-is-not-just-a-relationship-where-one-piece-of-code-uses-another-ifwuvqqsh
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: A Dependency Is Not Just a Relationship Where One Piece of Code Uses Another | daily.dev
og:description: A deep dive into what dependencies really represent in real-world services, going beyond the simple &#x27;one function calls another&#x27; definition. Using a TypeScript...
og:url: https://daily.dev/posts/a-dependency-is-not-just-a-relationship-where-one-piece-of-code-uses-another-ifwuvqqsh
og:image: https://api.daily.dev/og/posts/IfWUvQqsh.png
og:image:alt: A Dependency Is Not Just a Relationship Where One Piece of Code Uses Another
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# A Dependency Is Not Just a Relationship Where One Piece of Code Uses Another

**[Medium](https://daily.dev/sources/medium_js)** · 18 min read · 2 upvotes · 1 comments

## Summary

A deep dive into what dependencies really represent in real-world services, going beyond the simple 'one function calls another' definition. Using a TypeScript coupon service example, it explores how dependencies carry implicit contracts (input/output, failure handling, performance, side effects, repeatability, lifecycle), how hidden dependencies like current time, environment variables, or global state can silently affect behavior, and how tightly coupling business logic to a specific technology like Prisma spreads change into unrelated code. It also covers dependency direction, why interfaces don't automatically reduce coupling unless expressed in the service's own language, when interfaces are unnecessary overhead, how to decide whether failures (like email delivery) should propagate synchronously or be decoupled via events, risks introduced by external service dependencies, signs that a long dependency list reveals an overly broad responsibility, lifecycle mismatches between shared and request-scoped state, and the importance of test doubles preserving real contract behavior (e.g., duplicate ID handling). Closes with a checklist of questions to ask before adding any dependency and a list of common mistakes with fixes.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://vxdeveloper.medium.com/a-dependency-is-not-just-a-relationship-where-one-piece-of-code-uses-another-bf81b90977e0>

## Questions this post answers

### Why doesn't adding an interface in front of a repository actually reduce coupling to an ORM like Prisma?

An interface only reduces coupling when its methods are expressed in the service's own language, not the ORM's types. If a repository interface's save method still accepts a Prisma.CouponCreateInput and returns a PrismaCoupon, the consumer still has to understand Prisma's types even though an interface technically exists, so the dependency isn't actually removed, just wrapped.

_daily.dev surfaces practical patterns like this for developers refining their dependency boundaries._

### Why can an in-memory repository used in tests give false confidence about production behavior?

An in-memory test double can silently behave differently from the real database, for example overwriting an existing entry with the same ID instead of throwing a duplicate-key error the way a real database would. If the fake doesn't replicate that failure behavior, tests pass while missing a real bug, so test doubles need to preserve important contract behaviors like duplication and failure handling, not just implement the same interface shape.

_developers hardening their test suites can track these design nuances by following testing content on daily.dev._

### Should coupon issuance fail if sending the confirmation email fails?

It depends on whether email delivery is an essential part of issuance or just follow-up work performed after it. If persistence is the core result and email can be retried later, the two operations can be decoupled by publishing an event (e.g. CouponIssued) and handling the email asynchronously in a separate event handler, avoiding a failed email from blocking or duplicating the coupon record.

_daily.dev helps developers weighing synchronous versus event-driven designs stay on top of these tradeoffs._

## Community discussion

Top comments from developers on daily.dev.

**@leonidbugaev** · 0 upvotes

> The Map.set is the part I'd actually fail. Real coupon table rejects a second id, InMemoryCouponRepository just overwrites, and issueCoupon still looks fine. I'd throw on coupons.has(id) in the fake even if it makes the test uglier.

## Similar posts on daily.dev

- [Microservice Dependencies: How @requires Makes Them Explicit](https://daily.dev/posts/microservice-dependencies-how-requires-makes-them-explicit-hejzg4lfe) · WunderGraph · 1 upvotes · 0 comments

---

Tags: [#testing](https://daily.dev/tags/testing), [#architecture](https://daily.dev/tags/architecture), [#typescript](https://daily.dev/tags/typescript), [#design-patterns](https://daily.dev/tags/design-patterns), [#dependency-injection](https://daily.dev/tags/dependency-injection)

[View this post on daily.dev](https://daily.dev/posts/a-dependency-is-not-just-a-relationship-where-one-piece-of-code-uses-another-ifwuvqqsh)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"A Dependency Is Not Just a Relationship Where One Piece of Code Uses Another","url":"https://daily.dev/posts/a-dependency-is-not-just-a-relationship-where-one-piece-of-code-uses-another-ifwuvqqsh","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/a-dependency-is-not-just-a-relationship-where-one-piece-of-code-uses-another-ifwuvqqsh"},"datePublished":"2026-09-10T01:02:22.825Z","dateModified":"2026-09-14T06:09:06.429Z","description":"A deep dive into what dependencies really represent in real-world services, going beyond the simple 'one function calls another' definition. Using a TypeScript...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/d6ab0a9a223ee01bc82d647f54feb2d2?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/d6ab0a9a223ee01bc82d647f54feb2d2?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Medium","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Medium","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/medium","url":"https://daily.dev/sources/medium_js"},"commentCount":1,"discussionUrl":"https://daily.dev/posts/a-dependency-is-not-just-a-relationship-where-one-piece-of-code-uses-another-ifwuvqqsh","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":2},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":1}],"keywords":"testing,architecture,typescript,design-patterns,dependency-injection","timeRequired":"PT18M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Medium","item":"https://daily.dev/sources/medium_js"},{"@type":"ListItem","position":3,"name":"A Dependency Is Not Just a Relationship Where One Piece of Code Uses Another"}]}
{"@context":"https://schema.org","@type":"WebPage","@id":"https://daily.dev/posts/a-dependency-is-not-just-a-relationship-where-one-piece-of-code-uses-another-ifwuvqqsh","comment":[{"@type":"Comment","text":"The Map.set is the part I’d actually fail. Real coupon table rejects a second id, InMemoryCouponRepository just overwrites, and issueCoupon still looks fine. I’d throw on coupons.has(id) in the fake even if it makes the test uglier.","datePublished":"2026-09-10T07:07:41.872Z","url":"https://daily.dev/posts/IfWUvQqsh#c-W2aufvmFg","author":{"@type":"Person","name":"Leonid Bugaev","url":"https://daily.dev/leonidbugaev","image":"https://lh3.googleusercontent.com/a/ACg8ocLhMgurwTmJElWaH9A8Ju8cHvZxgMCDt009jEYkmFCyUGAoaGSw=s96-c"}}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/a-dependency-is-not-just-a-relationship-where-one-piece-of-code-uses-another-ifwuvqqsh#faq","mainEntity":[{"@type":"Question","name":"Why doesn't adding an interface in front of a repository actually reduce coupling to an ORM like Prisma?","acceptedAnswer":{"@type":"Answer","text":"An interface only reduces coupling when its methods are expressed in the service's own language, not the ORM's types. If a repository interface's save method still accepts a Prisma.CouponCreateInput and returns a PrismaCoupon, the consumer still has to understand Prisma's types even though an interface technically exists, so the dependency isn't actually removed, just wrapped. daily.dev surfaces practical patterns like this for developers refining their dependency boundaries."}},{"@type":"Question","name":"Why can an in-memory repository used in tests give false confidence about production behavior?","acceptedAnswer":{"@type":"Answer","text":"An in-memory test double can silently behave differently from the real database, for example overwriting an existing entry with the same ID instead of throwing a duplicate-key error the way a real database would. If the fake doesn't replicate that failure behavior, tests pass while missing a real bug, so test doubles need to preserve important contract behaviors like duplication and failure handling, not just implement the same interface shape. developers hardening their test suites can track these design nuances by following testing content on daily.dev."}},{"@type":"Question","name":"Should coupon issuance fail if sending the confirmation email fails?","acceptedAnswer":{"@type":"Answer","text":"It depends on whether email delivery is an essential part of issuance or just follow-up work performed after it. If persistence is the core result and email can be retried later, the two operations can be decoupled by publishing an event (e.g. CouponIssued) and handling the email asynchronously in a separate event handler, avoiding a failed email from blocking or duplicating the coupon record. daily.dev helps developers weighing synchronous versus event-driven designs stay on top of these tradeoffs."}}]}
```

