Skip to content

Refactor backend architecture: replace interface chain with independent capability interfaces and composed backend #23

@Cadons

Description

@Cadons

Current state (as-is)

From the current codebase:

  • Capability interfaces are already present under docraft/include/docraft/backend/ (e.g. IDocraftLineRenderingBackend in docraft/include/docraft/backend/docraft_line_rendering_backend.h).
  • Concrete backend implementation is currently centered on Haru/PDF in docraft/src/docraft/backend/pdf/docraft_haru_backend.cc.
  • Backend responsibilities are still effectively concentrated in the concrete backend layer, and interface relationships/coupling should be simplified.

This issue proposes an incremental refactor from the current shape to a composition-first architecture.


Why

The current backend structure makes capability evolution harder than necessary:

  • capability concerns are not isolated enough at implementation level,
  • changes in one area can affect unrelated rendering code,
  • testing individual capabilities is harder,
  • future backends would inherit current coupling patterns.

Target architecture

  1. Keep capability interfaces independent (no inheritance chain between capability interfaces).
  2. Decompose the Haru backend implementation into smaller capability-focused components.
  3. Expose capability access from the backend root via:
    • immutable: <capability>() const
    • mutable: edit_<capability>()
  4. Migrate existing call sites to use capability accessors explicitly.

Accessor conventions (project style)

Use no get_ prefix for immutable accessors.

Naming

  • Immutable: line_rendering() const
  • Mutable: edit_line_rendering()
  • Apply same convention to all capabilities.

Return types

If capability is guaranteed:

  • const IDocraftLineRenderingBackend& line_rendering() const;
  • IDocraftLineRenderingBackend& edit_line_rendering();

If capability can be absent:

  • const IDocraftLineRenderingBackend* line_rendering() const;
  • IDocraftLineRenderingBackend* edit_line_rendering();

Pick one availability policy and apply it consistently.


Proposed incremental scope (aligned to current repo)

  • docraft/include/docraft/backend/
    • ensure each capability interface is standalone and chain-free.
  • docraft/src/docraft/backend/pdf/docraft_haru_backend.cc
    • split monolithic responsibilities into composed capability objects (line/text/shapes/etc.).
  • backend root interface/type (where defined)
    • add/standardize <capability>() const + edit_<capability>().
  • dependent renderer/pipeline code
    • update usage to explicit capability access.
  • tests/docs
    • add coverage for const/mutable accessor behavior and update API docs.

Tasks

  • Audit backend interfaces in docraft/include/docraft/backend/ and remove capability inheritance chaining.
  • Identify capability boundaries currently embedded in docraft/src/docraft/backend/pdf/docraft_haru_backend.cc.
  • Extract capability-specific components from Haru backend implementation.
  • Introduce/normalize backend root accessors:
    • <capability>() const
    • edit_<capability>()
  • Migrate call sites from direct monolithic backend usage to capability accessors.
  • Add tests for:
    • immutable vs mutable accessor contracts,
    • capability wiring consistency (same underlying component for const/mutable access),
    • no rendering regressions.
  • Update documentation in API/backend docs to reflect composition model.

Acceptance criteria

  • Capability interfaces under docraft/include/docraft/backend/ are independent (no chain inheritance).
  • Haru backend implementation is composed of smaller capability-oriented parts instead of a single concentrated responsibility center.
  • Backend root exposes consistent accessor pairs without get_ prefix.
  • Existing rendering behavior remains unchanged (regression tests pass).
  • Documentation reflects the new backend composition/access pattern.

Risk and rollout notes

  • This is a cross-cutting internal API refactor; prefer staged migration.
  • If needed, keep temporary adapter methods during transition and remove them in a follow-up cleanup issue.
  • Prioritize line-rendering capability first (already explicit via IDocraftLineRenderingBackend) as migration template for other capabilities.

Clarification: “smaller objects” means internal capability components

In this refactor, “smaller objects” does not mean introducing multiple standalone backends.
It means splitting the current Haru backend implementation into focused internal components, each implementing one capability interface.

Example direction:

  • HaruLineRenderingBackend implements IDocraftLineRenderingBackend
  • HaruTextRenderingBackend implements text capability interface
  • HaruShapeRenderingBackend implements shape capability interface

The backend root remains the single integration point, but acts as a thin composition/dispatch layer exposing:

  • <capability>() const
  • edit_<capability>()

This keeps responsibilities isolated while preserving one concrete backend entry point.

Metadata

Metadata

Assignees

Projects

Status

In progress

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions