Best Practice Golang: Penerapan Hexagonal Architecture pada Proyek Backend

Subscribe dengan Account Google untuk mendapatkan News Letter terbaru dari Halovina !
Best Practice Golang: Penerapan Hexagonal Architecture pada Proyek Backend

Dalam dunia pengembangan backend modern, menjaga kode agar tetap bersih, mudah diuji, dan independen dari framework atau database adalah tantangan utama. Di sinilah Hexagonal Architecture (atau Ports and Adapters) berperan.


Artikel ini akan membedah bagaimana mengimplementasikan arsitektur ini menggunakan bahasa pemrograman Go dengan bantuan framework GoFr, berdasarkan studi kasus sistem blog dari repositori Halovina.

Mengapa Hexagonal Architecture?


Sebelum masuk ke kode, mari kita pahami konsep dasarnya. Hexagonal Architecture membagi aplikasi Anda menjadi tiga lapisan utama:



  1. Core (Domain): Jantung aplikasi Anda. Berisi logika bisnis murni dan entitas (misal: struct Article atau User). Lapisan ini tidak boleh tahu tentang database, HTTP, atau API eksternal.




  2. Ports: Antarmuka (interface) yang mendefinisikan bagaimana dunia luar berkomunikasi dengan Core (Primary Port) dan bagaimana Core berkomunikasi dengan dunia luar (Secondary Port).




  3. Adapters: Implementasi konkret dari Ports. Contohnya: Handler HTTP, Repositori SQL, atau klien API pihak ketiga.




Studi Kasus: Blog System dengan GoFr


Proyek golang-gofr-example-blog-system adalah contoh sempurna bagaimana teori ini diterjemahkan menjadi kode nyata. Proyek ini menggunakan GoFr, sebuah framework Go yang "opiniated" dan kaya fitur (observability, database management, dll) untuk mempercepat pengembangan.

1. Struktur Folder yang Rapi


Implementasi Hexagonal Architecture biasanya tercermin dari struktur direktori:




├── cmd
│ └── main.go # Entry point aplikasi
├── internal
│ ├── core
│ │ ├── domain # Entitas bisnis (e.g., Post)
│ │ ├── services # Logika bisnis (e.g., CreatePost)
│ │ └── ports # Interface (Input & Output)
│ ├── repositories # Adapter ke Database (Secondary Adapter)
│ └── handlers # Adapter ke HTTP/Web (Primary Adapter)
└── configs # Konfigurasi env





2. Domain & Ports (The Core)


Di folder internal/core, kita mendefinisikan aturan mainnya.


Domain (domain/models.go): Struct sederhana untuk menjaga kemurnian data.




type Post struct {
ID uint `gorm:"primaryKey" json:"id"`
Title string `gorm:"not null" json:"title"`
Content string `gorm:"type:text" json:"content"`
...
}




Ports (ports/ports.go): Kita menggunakan interface untuk memisahkan logika.




// Output Port: Database Repository type BlogRepository interface { CreateUser(user *domain.User) error ... } // Input Port: Service Logic type BlogService interface { GetAllPosts() ([]domain.Post, error) ... }




3. Adapters: Menghubungkan ke Dunia Nyata


Di sinilah GoFr sangat membantu. Framework ini menyederhanakan pembuatan adapter database dan HTTP handler.


Repository Adapter (repositories/gorm_repo.go): Implementasi PostRepository menggunakan koneksi SQL yang disediakan Gorm.




type GormRepository struct {
db *gorm.DB
}

func NewGormRepository(db *gorm.DB) ports.BlogRepository {
return &GormRepository{db: db}
}

func (r *GormRepository) CreateUser(user *domain.User) error {
return r.db.Create(user).Error
}
....





HTTP Handler Adapter (handlers/http/post_handler.go): Handler ini menerima request HTTP, memanggil Service, dan mengembalikan respons JSON standar.




type HTTPHandler struct {
svc ports.BlogService
}

func NewHTTPHandler(svc ports.BlogService) *HTTPHandler {
return &HTTPHandler{svc: svc}
}

func (h *HTTPHandler) CreatePost(c *gofr.Context) (interface{}, error) {
....
}





4. Wiring: Menyatukan Semuanya di main.go


Bagian main.go berfungsi sebagai "lem" yang menyatukan dependensi (Dependency Injection).




func main() {
// 1. Init GoFr
app := gofr.New()

// 2. Database Setup (GORM)
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=5432 sslmode=disable",
os.Getenv("DB_HOST"), os.Getenv("DB_USER"), os.Getenv("DB_PASSWORD"), os.Getenv("DB_NAME"))

db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
app.Logger().Errorf("Failed to connect to DB: %v", err)
}

// Auto Migrate
db.AutoMigrate(&domain.User{}, &domain.Post{}, &domain.Comment{})

// 3. Dependency Injection (Hexagonal Architecture Wiring)
repo := repository.NewGormRepository(db)
secret := "very-secret" // Should ideally be from env
svc := services.NewService(repo, secret)
h := handlers.NewHTTPHandler(svc)

// 4. Routes

app.POST("/register", h.Register)
app.POST("/login", h.Login)

app.GET("/posts", h.GetAllPosts)
app.POST("/posts", h.CreatePost)
app.DELETE("/posts/{id}", h.DeletePost)

// 5. Swagger Configuration (GoFr will automatically serve openapi.json
// placed in the `static` folder at the path `/.well-known/swagger`)
// Ensure the `static/openapi.json` file exists in your project root.

// Start App
app.Run()
}





Keuntungan Menggunakan Pendekatan Ini




  1. Framework Agnostic (Sebagian): Meskipun kita menggunakan GoFr untuk routing dan database connection, logika bisnis di core sama sekali tidak tahu menahu tentang GoFr. Jika ingin ganti framework, Anda hanya perlu mengubah layer adapter.




  2. Mudah di-Test: Karena semua dependensi menggunakan interface (Ports), Anda bisa dengan mudah membuat mock untuk repository saat melakukan Unit Test pada Service.




  3. Observability Bawaan: Dengan GoFr, endpoint yang Anda buat otomatis memiliki fitur tracing, metrics, dan logging tanpa perlu konfigurasi tambahan yang rumit.




Kesimpulan


Menggabungkan kekuatan Go, GoFr, dan Hexagonal Architecture menghasilkan aplikasi yang tidak hanya cepat secara performa, tetapi juga cepat dalam pengembangan (development speed) dan mudah dirawat.


Repositori halovina/golang-gofr-example-blog-system memberikan cetak biru yang solid bagi Anda yang ingin memulai perjalanan microservice dengan standar industri.



Untuk tutorial visual langkah demi langkah mengenai konfigurasi awal framework ini, simak video berikut:


Setup Golang Microservices in a Flash: GoFr Framework Configuration Tutorial


Video ini sangat relevan karena membahas dasar konfigurasi GoFr yang digunakan dalam arsitektur proyek di atas, membantu Anda memahami cara menyiapkan environment sebelum menulis kode logika bisnisnya.