Le dipendenze dei moduli ciclici spesso si verificano quando si ha un modulo che funge da interfaccia tra il codice utente e (diversi) moduli di implementazione.
Tipicamente, un tale modulo di interfaccia definisce tipi e funzionalità generiche per i moduli di implementazione da utilizzare, motivo per cui i moduli di implementazione dipendono dal modulo di interfaccia. Tuttavia, per fornire una vera astrazione al codice utente (= evitare le dipendenze del codice utente sui moduli di implementazione), il modulo di interfaccia deve interagire con i diversi moduli di implementazione e quindi dipendere da essi.
Se si sostituisce "module" con "class", questo diventa molto più chiaro: il modulo di interfaccia è una classe astratta che fornisce l'intera interfaccia utente. Le diverse implementazioni ereditano dalla classe astratta e quindi dipendono dall'interfaccia astratta. Tuttavia, per rendere invisibile all'utente l'esistenza stessa delle sottoclassi, la classe astratta deve anche fornire metodi di fabbrica che selezionino le diverse implementazioni sotto il cofano. Poiché le fabbriche hanno bisogno di instanziare le classi concrete, dipendono da loro.
Naturalmente, una tale architettura di classe verrebbe solitamente incapsulata all'interno di un singolo modulo, quindi non si avranno ancora le dipendenze dei moduli circolari. Tuttavia, la stessa struttura può essere applicata al codice in un contesto più ampio, portando a una situazione in cui si avrebbero reali dipendenze dei moduli ciclici.
Di solito, tali dipendenze cicliche possono essere suddivise dividendo l'interfaccia astratta in due parti, una da cui dipendono i moduli di implementazione e una che dipende dai moduli di implementazione. Questo di solito ha i lati negativi di 1. un modulo è troppo piccolo per giustificare che sia un modulo, e 2. aggiunge complessità all'interfaccia pubblica poiché il codice utente ora deve dipendere direttamente da due moduli.
Un altro approccio per rompere le dipendenze cicliche sarebbe che i moduli di implementazione si registrassero con il modulo di interfaccia. Anche questo ha due svantaggi: 1. Impone una singola interfaccia di callback nei moduli di implementazione, che potrebbe non essere appropriata, e 2. aggiunge in modo significativo la complessità per la registrazione e la gestione delle implementazioni registrate all'interno del modulo di interfaccia.
Quindi, sì, ci sono situazioni valide in cui la restrizione alle dipendenze dei moduli non-circolari porta a un codice più complesso, rendendo l'uso di un ciclo di dipendenze l'alternativa preferibile. E i buoni linguaggi di programmazione lo consentono.