✨ 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
76 lines
4.1 KiB
Markdown
76 lines
4.1 KiB
Markdown
# 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 the `driving` port interfaces. This is where the core business logic resides.
|
|
|
|
### Adapters
|
|
|
|
* `internal/adapters/driving/cli`: The CLI adapter. It implements the user interface and calls the `driving` ports of the core.
|
|
* `internal/adapters/driven/edgeconnect`: The EdgeXR API adapter. It implements the `driven` port 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
|
|
|
|
1. **Define domain models:** Create the domain models in `internal/core/domain`.
|
|
2. **Define ports:** Define the `driving` and `driven` port interfaces in `internal/core/ports`.
|
|
3. **Implement core services:** Implement the core business logic in `internal/core/services`.
|
|
4. **Create adapters:**
|
|
* Move the existing CLI code from `cmd` to `internal/adapters/driving/cli` and adapt it to call the core services.
|
|
* Move the existing `sdk` code to `internal/adapters/driven/edgeconnect` and adapt it to implement the repository interfaces.
|
|
5. **Wire everything together:** Update `cmd/cli/main.go` to 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.
|