Files
obsidian-livesync/docs/adr/2026_06_refactoring_modules.md
T

5.5 KiB

Architectural Decision Record: Modularity Refactoring via serviceFeature

Status

Decided / Work in Progress

Release

Not yet (at 26th June 2026) / Not yet tested

Context

Previously, many modules in the codebase relied on monolithic base classes, such as 'LiveSyncCommands', 'AbstractObsidianModule', and the foundational 'AbstractModule'. These base classes implicitly granted access to a large global context, which created tight coupling, made unit testing difficult, and hampered maintenance.

While we initially considered migrating these to 'ServiceModule's, doing so would have bloated the 'ServiceModules' registry in 'ServiceHub' with features, dialogue managers, and user interface (UI) bindings that do not need to be globally accessible.

Decision

We have decided to refactor these modules into **'serviceFeature'**s and **'ObsidianServiceFeature'**s:

  1. 'serviceFeature': A feature (defined via createServiceFeature) that receives injected dependencies (such as services and serviceModules) but does not register itself onto the ServiceHub. State and logic are encapsulated within the function closure, providing excellent testability and loose coupling without polluting the global registry.
  2. 'createObsidianServiceFeature': To support Obsidian-specific plug-in features that require direct access to the Obsidian application context (app, plugin, or liveSyncPlugin), we introduced the createObsidianServiceFeature helper and the NecessaryObsidianFeature utility type. This enables type-safe injection of the Obsidian context without casting to any.
  3. Core Types Relocation: All service feature utility types (LiveSyncCore, NecessaryObsidianFeature, ObsidianServiceFeatureFunction, and createObsidianServiceFeature) were moved to src/types.ts to prevent circular dependencies.

Implementation Details

Phase 1: Core Commands ('LiveSyncCommands' Inheritors)

These contain significant state and business logic. They have been refactored into pure functional modules under src/serviceFeatures/:

  • hiddenFileSync/: Split monolithic file tracking and state variables into focused functional files.
  • configSync/: Decoupled periodic synchronisation, customisation scanning, and commands.
  • databaseMaintenance/: Refactored garbage collection, compaction, and diagnostics into pure modules.

Phase 2: Obsidian UI & Events ('AbstractObsidianModule' Inheritors)

These modules handle Obsidian-specific event bindings, UI registrations (views, dialogue modals, and ribbon commands), and user preferences. They have been refactored into 'ObsidianServiceFeature' functions:

Phase 3: Core Modules Evaluation

Foundational modules (replicators and conflict resolver engines) will be evaluated in subsequent stages to decide if they should be true services on 'ServiceHub' or standalone features.

Consequences

  • Encapsulated State: Key state variables now live safely in feature closures rather than as global class properties.
  • Improved Testability: We introduced robust unit test suites (*.unit.spec.ts) for all newly refactored features. Features can be easily tested by injecting mocked services and modules.
  • Eliminated Global Pollution: The 'ServiceHub' remains lightweight, only carrying services that must be globally shared.
  • Type Safety: Obsidian-specific contexts (app, plugin, and liveSyncPlugin) are strictly typed through the NecessaryObsidianFeature shape, minimising unsafe type assertions.