Pattern-002: Service Pattern

Status

Proven

Context

Business logic scattered throughout controllers, repositories, or domain models creates maintenance challenges and violates single responsibility principle. The Service Pattern addresses:

Pattern Description

The Service Pattern encapsulates business logic in dedicated service classes, providing a clear separation between controllers/handlers and data access layers.

Core concept:

Implementation

Structure

class IntentService:
    """Service for intent processing business logic"""

    def __init__(self, project_repo: ProjectRepository, workflow_service: WorkflowService):
        self.project_repo = project_repo
        self.workflow_service = workflow_service

    async def process_intent(self, intent: Intent) -> WorkflowResult:
        """Business logic for intent processing"""
        # Validate intent
        if not self._is_valid_intent(intent):
            raise InvalidIntentError("Intent validation failed")

        # Load project context
        project = await self.project_repo.get_by_id(intent.project_id)
        if not project:
            raise ProjectNotFoundError("Project not found")

        # Orchestrate workflow
        workflow = await self.workflow_service.create_workflow(intent, project)
        return await self.workflow_service.execute(workflow)

    def _is_valid_intent(self, intent: Intent) -> bool:
        """Private business logic helper"""
        return intent.message and intent.project_id

Service Dependency Injection

class ServiceContainer:
    """Dependency injection for services"""

    def __init__(self, session: AsyncSession):
        self.session = session
        self._services = {}

    def get_intent_service(self) -> IntentService:
        if 'intent' not in self._services:
            project_repo = ProjectRepository(self.session)
            workflow_service = self.get_workflow_service()
            self._services['intent'] = IntentService(project_repo, workflow_service)
        return self._services['intent']

    def get_workflow_service(self) -> WorkflowService:
        if 'workflow' not in self._services:
            self._services['workflow'] = WorkflowService(self.session)
        return self._services['workflow']

Service Usage in Handlers

async def handle_intent_request(request: IntentRequest) -> IntentResponse:
    """Handler delegates business logic to service"""
    async with AsyncSessionFactory.session_scope() as session:
        container = ServiceContainer(session)
        intent_service = container.get_intent_service()

        try:
            result = await intent_service.process_intent(request.intent)
            return IntentResponse(success=True, result=result)
        except (InvalidIntentError, ProjectNotFoundError) as e:
            return IntentResponse(success=False, error=str(e))

Usage Guidelines

Benefits

Trade-offs

References

Migration Notes

Consolidated from: