Dependency injection gives a component its collaborators when the component is created, rather than having it construct them. In a Go Order service, the application accepts a database through `ports.DBPort`. `PlaceOrder` can save an order without knowing which database adapter implements that port. section 4.2.3
package api
import (
"github.com/huseyinbabal/microservices/order/internal/application/core/
domain" #1
"github.com/huseyinbabal/microservices/order/internal/ports" #2
)
type Application struct {
db ports.DBPort #3
}
func NewApplication(db ports.DBPort) *Application {
return &Application{
db: db, #4
}
}
func (a Application) PlaceOrder(order domain.Order) (domain.Order, error) {
err := a.db.Save(&order) #5
if err != nil {
return domain.Order{}, err
}
return order, nil
}
`NewApplication` receives the database port and stores it on `Application`; `PlaceOrder` uses that dependency to save the order. section 4.2.3
Wire the service at startup:
- Read the database URL and application port from environment variables. Reject missing values rather than starting with empty configuration. section 4.2.7
- Create the database adapter, pass it to `NewApplication`, then pass the application and port to the gRPC adapter before running the server. section 4.2.7
- When order creation also needs payment, initialize a payment adapter from `PAYMENT_SERVICE_URL` and pass both adapters to `NewApplication`. Initialization fails if the payment stub cannot be created. section 5.2.5
func main() {
dbAdapter, err := db.NewAdapter(config.GetDataSourceURL())
if err != nil {
log.Fatalf("Failed to connect to database. Error: %v", err)
}
paymentAdapter, err :=
payment.NewAdapter(config.GetPaymentServiceUrl())
if err != nil {
log.Fatalf("Failed to initialize payment stub. Error: %v", err)
}
application := api.NewApplication(dbAdapter, paymentAdapter) #1
grpcAdapter := grpc.NewAdapter(application,
config.GetApplicationPort())
grpcAdapter.Run()
}
The expanded `main` function is the composition point: it constructs database and payment adapters, injects them into the application, and starts the gRPC adapter. section 5.2.5
A port defines the contract; an adapter supplies a matching implementation. Keeping that choice at startup separates application behavior from database and payment integration. The same boundary runs in the other direction: the gRPC adapter receives an API port and calls `PlaceOrder` when it handles a create request. This layering supports a testable application core, but it requires explicit construction and configuration of its collaborators. section 4.3 section 4.2.6




















