Vou pegar essa questão do ponto de vista da modelagem.
Desde que você não adicione nenhum relacionamento que não esteja realmente presente, você estará seguro. Se você adicioná-los, você terá menos integridade nos dados (porque há uma redundância) e um código mais acoplado.
A coisa com as referências circulares especificamente é que eu não vi um caso em que elas seriam realmente necessárias, exceto uma auto-referência. Se você modelar árvores ou gráficos, você precisará disso e estará perfeitamente correto, pois a auto-referência é inofensiva do ponto de vista da qualidade do código (sem dependência adicionada).
Acredito que, no momento em que você começar a precisar de uma referência não-própria, imediatamente você deve perguntar se não é possível modelá-lo como um gráfico (reduzir as várias entidades em um nó). Talvez exista um caso entre o qual você faz uma referência circular, mas modelá-lo como gráfico não é apropriado, mas duvido muito disso.
Existe o perigo de as pessoas acharem que precisam de uma referência circular, mas na verdade não precisam. O caso mais comum é "O caso um-de-muitos". Por exemplo, você tem um cliente com vários endereços, dos quais um deve ser marcado como o endereço principal. É muito tentador modelar essa situação como dois relacionamentos separados has_address e is_primary_address_of , mas isso não está correto. A razão é que sendo o endereço primário não é um relacionamento separado entre usuários e endereços, mas sim um atributo do relacionamento tem endereço . Por que é que? Porque o seu domínio é limitado aos endereços do usuário e não a todos os endereços que existem. Você escolhe um dos links e o marca como o mais strong (primário).
(Indo falar sobre bancos de dados agora) Muitas pessoas optam pela solução de dois relacionamentos porque entendem como "primária" como sendo um ponteiro único e uma chave estrangeira é uma espécie de ponteiro. Então chave estrangeira deve ser a coisa a usar, certo? Errado. Chaves estrangeiras representam relacionamentos, mas "primário" não é um relacionamento. É um caso degenerado de uma ordenação onde um elemento é acima de tudo e o resto não é ordenado. Se você precisasse modelar um pedido total, você o consideraria como um atributo de relacionamento, porque basicamente não há outra escolha. Mas no momento em que você degenera, há uma escolha e uma horrível - modelar algo que não é um relacionamento como um relacionamento. Então aqui vem - redundância de relacionamento que certamente não é algo a ser subestimado. O requisito de exclusividade deve ser imposto de outra maneira, por exemplo, por índices parciais únicos.
Então, eu não permitiria que uma referência circular ocorresse, a menos que seja absolutamente claro que vem da coisa que estou modelando.
(nota: isso é um pouco tendencioso para o design do banco de dados, mas eu apostaria que é bastante aplicável a outras áreas também)