Repository navigation
Proposal: Enforce Backend Boundaries Through Project Separation #968
hypnotoad08
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Introduction
While reviewing the backend, I noticed two areas where the current project boundaries could be clearer.
First, some code in
Listenarr.Applicationdoes work that would normallybelong in Infrastructure. For example,
AudibleServicemakes HTTP requests toAudible from the Application project.
Second,
Listenarr.Infrastructurealready separates external integrations,persistence, filesystem access, and download clients by namespace. Promoting
those namespaces into projects would allow the compiler to enforce the
boundaries that are currently maintained through code organization.
Proposed Changes
Step 1: Move the Existing Application Contracts into Their Own Project
Listenarr.Applicationalready organizes its contracts by feature underlistenarr.application/<Feature>/Contracts/. Move those contracts into a newListenarr.Application.Contractsproject while keeping their featureownership.
The project name supplies the
Contractsboundary, so the existing folderstructure should be flattened instead of repeating
Contractsbeneath everyfeature:
For example, the resulting namespaces would be
Listenarr.Application.Contracts.Common,Listenarr.Application.Contracts.Audiobooks, andListenarr.Application.Contracts.Audiobooks.Repositories—notListenarr.Application.Contracts.Audiobooks.Contracts.This includes service contracts, repository contracts currently under
Contracts/Repositories, and the request, result, or projection models used bythose contracts.
This lets Infrastructure projects implement Application contracts without
referencing the full
Listenarr.Applicationproject.Interfaces used only inside one project stay with that project.
Step 2: Promote Infrastructure Namespaces into Projects
Listenarr.Infrastructurealready organizes several responsibilities bynamespace. I'd propose promoting those boundaries into projects:
Listenarr.Infrastructure.ExternalServices: Audible, metadata providers, indexers, notification services.Listenarr.Infrastructure.Persistence: database access.Listenarr.Infrastructure.Filesystem: local file operations.Listenarr.Infrastructure.DownloadClients: downloader integrations.Listenarr.Infrastructure.Http: shared HTTP configuration and policies used by projects that make outbound requests.Listenarr.Infrastructurewould remain for shared infrastructure and concernsthat do not need a separate project. It would become smaller as the larger,
well-defined responsibilities move out.
Code inside each project would remain organized by feature first and technical
role second, following the existing backend convention.
End State
Current project dependencies:
Proposed project dependencies:
Listenarr.Domainhas no project dependencies in either structure.Listenarr.Infrastructureremains the API's single entry point forinfrastructure registration. It delegates each responsibility to the focused
Infrastructure project that owns it, while the API remains responsible for
wiring the application together at startup.
Expected Benefits
infrastructure code.
filesystem.
Finding and Migrating Existing Code
A common approach to a refactor like this is to define code that crosses the
agreed boundaries as named anti-patterns and use analyzers to identify it. This
creates an inventory of code that needs to be cleaned up and gives contributors
clear guidance for migrating each occurrence to the new pattern without
requiring one large refactor.
For example:
A small analyzer could show these as warnings. Each anti-pattern would link to
a Markdown page containing an incorrect example, a correct example, and steps
for resolving it.
This would make the existing debt visible and give contributors enough context
to remove an anti-pattern when they are already working in that area. The
warnings could remain advisory unless there is later agreement to enforce a
rule after its existing uses have been removed.
All reactions