✨ Features: - Simple dependency inversion following SOLID principles - Clean constructor injection without complex DI containers - Proper hexagonal architecture with driving/driven separation - Presentation layer moved to cmd/cli for correct application structure 🏗️ Architecture Changes: - Driving Adapters (Inbound): internal/adapters/driving/cli/ - Driven Adapters (Outbound): internal/adapters/driven/edgeconnect/ - Core Services: Dependency-injected via interface parameters - main.go relocated from root to cmd/cli/main.go 📦 Application Flow: 1. cmd/cli/main.go - Entry point and dependency wiring └── Creates EdgeConnect client based on environment └── Instantiates services with injected repositories └── Executes CLI with properly wired dependencies 2. internal/adapters/driving/cli/ - User interface layer └── Receives user commands and input validation └── Delegates to core services via driving ports └── Handles presentation logic and output formatting 3. internal/core/services/ - Business logic layer └── NewAppService(appRepo, instanceRepo) - Constructor injection └── NewAppInstanceService(instanceRepo) - Interface dependencies └── NewCloudletService(cloudletRepo) - Clean separation 4. internal/adapters/driven/edgeconnect/ - Infrastructure layer └── Implements repository interfaces for external API └── Handles HTTP communication and data persistence └── Provides concrete implementations of driven ports 🔧 Build & Deployment: - CLI Binary: make build → bin/edge-connect-cli - Usage: ./bin/edge-connect-cli --help - Tests: make test (all passing) - Clean: make clean (updated paths) 💡 Benefits: - Simple and maintainable dependency management - Testable architecture with clear boundaries - SOLID principles compliance without overengineering - Proper separation of concerns in hexagonal structure
4.1 KiB
Proposal: Refactor to Hexagonal Architecture
This document proposes a refactoring of the edge-connect-client project to a Hexagonal Architecture (also known as Ports and Adapters). This will improve the project's maintainability, testability, and flexibility.
Current Architecture
The current project structure is a mix of concerns. The cmd package contains both CLI handling and business logic, the sdk package is a client for the EdgeXR API, and the internal package contains some business logic and configuration handling. This makes it difficult to test the business logic in isolation and to adapt the application to different use cases.
Proposed Hexagonal Architecture
The hexagonal architecture separates the application's core business logic from the outside world. The core communicates with the outside world through ports (interfaces), which are implemented by adapters.
Here is the proposed directory structure:
.
├── cmd/
│ └── main.go
├── internal/
│ ├── core/
│ │ ├── domain/
│ │ │ ├── app.go
│ │ │ └── instance.go
│ │ ├── ports/
│ │ │ ├── driven/
│ │ │ │ ├── app_repository.go
│ │ │ │ └── instance_repository.go
│ │ │ └── driving/
│ │ │ ├── app_service.go
│ │ │ └── instance_service.go
│ │ └── services/
│ │ ├── app_service.go
│ │ └── instance_service.go
│ └── adapters/
│ ├── cli/
│ │ ├── app.go
│ │ └── instance.go
│ └── edgeconnect/
│ ├── app.go
│ └── instance.go
├── go.mod
└── go.sum
Core
internal/core/domain: Contains the core domain objects (e.g.,App,AppInstance). These are plain Go structs with no external dependencies.internal/core/ports: Defines the interfaces for communication with the outside world.driving: Interfaces for the services offered by the application (e.g.,AppService,InstanceService).driven: Interfaces for the services the application needs (e.g.,AppRepository,InstanceRepository).
internal/core/services: Implements thedrivingport interfaces. This is where the core business logic resides.
Adapters
internal/adapters/driving/cli: The CLI adapter. It implements the user interface and calls thedrivingports of the core.internal/adapters/driven/edgeconnect: The EdgeXR API adapter. It implements thedrivenport interfaces and communicates with the EdgeXR API.
cmd
cmd/cli/main.go: The main entry point of the CLI application. It is responsible for wiring everything together: creating the adapters, injecting them into the core services, and starting the CLI.
Refactoring Steps
- Define domain models: Create the domain models in
internal/core/domain. - Define ports: Define the
drivinganddrivenport interfaces ininternal/core/ports. - Implement core services: Implement the core business logic in
internal/core/services. - Create adapters:
- Move the existing CLI code from
cmdtointernal/adapters/driving/cliand adapt it to call the core services. - Move the existing
sdkcode tointernal/adapters/driven/edgeconnectand adapt it to implement the repository interfaces.
- Move the existing CLI code from
- Wire everything together: Update
cmd/cli/main.goto create the adapters and inject them into the core services.
Benefits
- Improved Testability: The core business logic can be tested in isolation, without the need for the CLI framework or the EdgeXR API.
- Increased Flexibility: The application can be easily adapted to different use cases by creating new adapters. For example, we could add a REST API by creating a new adapter.
- Better Separation of Concerns: The hexagonal architecture enforces a clear separation between the business logic and the infrastructure, making the code easier to understand and maintain.