Eliminate three feature-to-feature dependencies - #81
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Five feature modules depended directly on each other's implementations. That is the coupling this whole migration exists to remove: it means a feature cannot be built, tested or reasoned about without pulling in another feature's internals, and it is what the boundary check currently has to tolerate through a baseline.
This removes three of the five, each by the shape that actually fits it rather than by applying one pattern everywhere.
What changed
:feature:editorno longer depends on:feature:terminal. The editor's bottom panel now takes aterminalContentslot, and:appfills it withEditorEmbeddedTerminal. The editor describes where a terminal goes; the host decides which terminal. This needed no interface, no module and no DI lookup — for a single composable, an api module would have been ceremony.New
:feature:git:apimodule, holding the two things other features actually consume:GitPanelApi— the panel's composable contract, previously declared in the same file as its implementationgitErrorMessage— the git-exception-to-message mapper, pure Kotlin over a:domaintype:feature:editorand:feature:projectsnow depend on:feature:git:apiinstead of:feature:git. The implementation,GitPanelApiImpl, stays in:feature:gitand is bound in:app.The api module declares
api(projects.domain)rather thanimplementation, becauseGitDiffTargetandGitExceptionappear in its public signatures. Previously consumers only compiled because they happened to declare:domainthemselves.Boundary baseline reduced from 5 entries to 2. The check reported each entry as stale once its edge disappeared, and each was then deleted.
Behavior
No behavior change. The terminal renders in the same place with the same arguments; the git panel and error mapper are the same code reached through a contract instead of an implementation.
Scope
Two edges remain, both deliberately left for follow-ups because they need design rather than mechanical work:
:feature:editor→:feature:buildrun. Thirteen symbols cross this boundary, and only one of them is an interface. Extracting it means auditing the full type closure first — the models are spread across four files, andRunTargetResolveris behaviour rather than contract, so it should move behindBuildRunApirather than be exported alongside it.:feature:settings→:feature:git. Settings imports git's internal auth plumbing:GitAuthController,GitHubAuthDialogand their state and action types. This one should not be solved by exporting those types. Settings is not asking git to perform an operation — both features reuse a shared auth capability, and the honest fix is to extract that capability (or let settings own its account UI over the existing:domainrepositories). Exporting the current prompt state would bless the accidental coupling, and it would drag:designsysteminto a contract module.Both remain in the boundary baseline, so neither can grow while it waits.
Tests
GitAuthControllercharacterization tests added earlier are what will make the settings/git split safe when it happens.Verification
From a clean worktree at the branch tip:
./gradlew test detekt verifyModuleBoundaries :app:assembleDebug— BUILD SUCCESSFULNot verified: the terminal panel and git panel render correctly in the running app. The wiring is unchanged and the arguments are identical, but this was not exercised on a device. Worth a pass over editor → bottom panel → terminal tab, and editor → git panel → diff.
Note on the detekt baselines:
gitErrorMessage's complexity andGitPanelApi.Panel's parameter count were already baselined in:feature:git. Those two entries were moved to the new module's baseline rather than regenerated, so no other finding is absorbed silently.