Skip to content

Use Message Trait for Extensibility #127

Description

@josecelano

Overview

Implement a trait-based message system for the UserOutput module to achieve true extensibility following the Open/Closed Principle. This allows new message types to be added without modifying existing code by having each message type encapsulate its own formatting, verbosity requirements, and channel routing logic.

Current State: The codebase already has Theme support (Issue #124) and VerbosityFilter (Issue #103) implemented, providing the foundation for this refactoring.

Specification

See detailed specification: docs/issues/127-use-message-trait-for-extensibility.md

(Link will be updated after issue number assignment and file rename)

🏗️ Architecture Requirements

DDD Layer: Presentation
Module Path: src/presentation/user_output.rs
Pattern: Trait-based polymorphism with concrete message types

Key Changes

  • Define OutputMessage trait with methods: format(), required_verbosity(), channel()
  • Implement concrete message types: ProgressMessage, SuccessMessage, ErrorMessage, ResultMessage, StepsMessage, WarningMessage
  • Add write(&mut self, message: &dyn OutputMessage) method to UserOutput
  • Refactor convenience methods to use trait dispatch

Implementation Plan

Phase 1: Define Core Trait and Types (2 hours)

  • Define OutputMessage trait and Channel enum
  • Add comprehensive documentation
  • Write unit tests for trait definition

Phase 2: Implement Concrete Message Types (3 hours)

  • Implement all message types with trait implementations
  • Write unit tests for each message type

Phase 3: Refactor UserOutput (2.5 hours)

  • Add generic write() method
  • Update all convenience methods to use trait dispatch
  • Ensure backward compatibility

Phase 4: Testing and Validation (2 hours)

  • Run existing unit tests
  • Add new tests for trait-based dispatch
  • Add extensibility example (custom message type)
  • Run integration and E2E tests

Phase 5: Documentation and Cleanup (1 hour)

  • Update rustdoc comments
  • Add example of creating custom message type
  • Clean up unused code

Estimated Total Time: ~11 hours

Acceptance Criteria

Quality Checks:

  • Pre-commit checks pass: ./scripts/pre-commit.sh

Task-Specific Criteria:

  • OutputMessage trait is defined with all required methods
  • All existing message types implement the trait
  • UserOutput has a generic write() method that accepts trait objects
  • All existing convenience methods still work (backward compatibility)
  • Verbosity filtering works correctly for all message types
  • Channel routing (stdout vs stderr) works correctly
  • Adding a new message type requires ZERO changes to UserOutput struct
  • All existing tests pass without modification
  • New tests demonstrate extensibility with custom message type example
  • Code follows Open/Closed Principle

Related

Benefits

✅ True Open/Closed Principle - add new message types without touching existing code
✅ Encapsulation - each message knows how to format itself
✅ Single Responsibility - each message type has one clear purpose
✅ Testability - message types can be tested independently
✅ Extensibility - custom message types can be defined outside the module

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions