Clean Architecture dan Pendekatan Domain-Driven Design pada Golang

Salman Abdulqohar
5 min readJul 13, 2020

Disclaimer

  • Saya bukan expert, mari berdiskusi bersama.
  • Saya tidak merekomendasikan library dan framework yang digunakan pada project ini, kalian dapat menggantinya sesuai kebutuhan.

Clean Architecture

Clean Architecture sudah menjadi salah satu arsitektur yang sangat populer belakangan ini. Kalau kalian pernah baca artikelnya Uncle Bob tentang Clean Architecture, beberapa ide arsitektur software yang dicetuskan tahun-tahun kebelakang kurang lebih memiliki satu tujuan yang sama, yaitu Separation of Concern (Pemisahan Urusan), caranya dengan memisahkan aplikasi kedalam beberapa layer (lapisan), yang mana paling tidak memiliki satu layer untuk business logic, dan layer lain untuk interface.

Aturan-aturan dalam mendesain clean architecture:

  1. Independent of Frameworks — Asitektur tidak tergantung dari framework atau library. Kita menggunakan framework dan library sebagai tools, daripada membatasi dan memaksa kita mengikuti pola framework tersebut.
  2. Testable — Business logic dapat di unit test tanpa UI, Database, Web Server, dll.
  3. Independent of UI — Interface dari aplikasi kita dapat diganti dengan mudah tanpa perlu mengubah keseluruhan sistem. UI Website misalnya dapat kita ganti dengan Console, atau Mobile tanpa mengganti business logic.
  4. Independent of Database — Kita dapat mengganti database kita tanpa mengganti apapun pada business logic yang sudah kita buat.
  5. Independent of any external agency — Business logic sebisa mungkin tidak boleh tergantung pada library external.
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

Pada desain arsitektur software Uncle Bob, aplikasi dipisahkan kedalam 4 layer:

Entities

Entity membungkus interface business logic sebuah aplikasi. Entity bersifat sangat abstrak, umum, stabil dan konsisten. Biasanya berisi class/type model yang kita gunakan dan abstraksi atau interface dari service-service yang ada didalam aplikasi kita.

Use Cases

Aplikasi pada layer ini berisi business logic pada aplikasi. Disini kita mengimplementasikan semua business logic sesuai dengan abstraksi yang telah kita buat pada layer Entity. Use case ini mengatur alur data dari Entity, dan mengarahkan Entity tersebut untuk mencapai tujuan dari business logic yang ingin kita capai.

Controllers

Pada layer ini kita menyimpan objek konkrit seperti handler API Endpoint, Repository ke Database, Memory Storage Accessor, RPC, dan lain-lain.

Frameworks and Drivers

Layer paling luar, berisi framework, driver, library yang kita gunakan dalam pembuatan software. Sebisa mungkin disimpan hanya ditempat yang benar-benar membutuhkan.

Pelajari lebih lanjut: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html

DDD (Domain-Driven Design)

Ayo kita mulai dari wikipedia

Domain-driven design (DDD) is the concept that the structure and language of your code (class names, class methods, class variables) should match the business domain. For example, if your software processes loan applications, it might have classes such as LoanApplication and Customer, and methods such as AcceptOffer and Withdraw. (https://en.wikipedia.org/wiki/Domain-driven_design)

Ok, tidak begitu sempurna tapi cukup menjelaskan. Simpelnya adalah, dalam DDD kita memastikan bahwa kita fokus menyelesaikan masalah bisnis yang real dengan cara yang optimal dan efisien. Service dan method yang kita buat untuk menyelesaikan masalah dibuat sangat spesifik untuk menyelesaikan masalah bisnis. Oke masih bingung, lanjut ke contoh real dibawah.

Sesuaikan dengan bisnis logic, literally

Saat mengimplementasikan business logic, jangan berpikir tentang attributes, setter dan getter setiap attribute tersebut. Ketika kita berbicara kebutuhan bisnis dengan stakeholders, mereka akan bilang dengan cerita “Saya mengaktifkan produk Salon Maknyus”, dan bukan “Saya set attribute active pada produk Salon Maknyus dengan nilai true”, bukan Product.setActiveStatus(true) tapi Product.activate() .

Contoh gampangnya, ketika kita membuat API untuk Activate Product , Archive Product , Edit Product , Kita tidak membuat hanya satu API updateProduct untuk menyelesaikan ketiga kebutuhan tersebut, tapi menyesuaikan dengan konteks bisnis dan menyamakan pola pikir pemecahan masalahnya. Dari kebutuhan bisnis tersebut, kita akan membuat 3 API dengan bahasa yang sama dengan bahasa bisnis, activateProduct , archiveProduct , editProduct.

Atau ketika kita membuatnya dalam microservice misal untuk penjualan voucher, dimana major entity yang kita gunakan adalah Merchant, Product , dan Voucher . Kita tidak membuat service seperti data-service , search-service , integration-service Tapi memisahkan service-service tersebut sesuai dengan domain bisnisnya menjadi merchant-service , product-service , voucher-service dimana didalam masing-masing service ini terdapat sub-service sesuai kebutuhannya misal untuk mengambil data, untuk search, untuk integrasi dengan service lain. Ini juga dapat mengurangi resiko cyclic-dependency.

Konsep Model DDD

  • Context — The setting in which a word or statement appears that determines its meaning;
  • Domain — A sphere of knowledge (ontology), influence, or activity. The subject area to which the user applies a program is the domain of the software;
  • Model — A system of abstractions that describes selected aspects of a domain and can be used to solve problems related to that domain;
  • Ubiquitous Language — A language structured around the domain model and used by all team members to connect all the activities of the team with the software.

Pelajari lebih lanjut: https://domainlanguage.com/wp-content/uploads/2016/05/DDD_Reference_2015-03.pdf

Implementasi

Okay, setelah intro yang (sangat) panjang, kita akan coba implementasi teori-teori tadi kedalam real code pada Golang. Project kecil yang saya buat disini adalah movie service.

Struktur

├── domain
│ └── movie.go
├── main.go
└── movie
├── controller
│ └── http
│ └── movie_controller.go
├── repository
│ └── movie_repository.go
└── usecase
└── movie_usecase.go

Layers

Diurutkan dari yang paling dalam ke paling luar.

Domain Disini kita akan menyimpan models dan interfaces dari usecase, masing-masing domain hanya akan mengetahui model dan interface dari domain lainnya tapi tidak dengan implementasinya, kemungkinan besar akan dipakai di semua layer.

Repository — Sedikit berbeda dengan clean architecture yang memanggil database secara langsung dari controller, disini kita akan menambahkan satu layer Repository. Di layer ini kita akan menyimpan semua logic untuk mengakses resource yang dibutuhkan pada business logic kita, seperti mengakses database, memory, HTTP Request untuk API atau RPC, dll.

Pada layer ini aplikasi bertindak sebagai repository, hanya melakukan operasi CRUD, mengambil dari database lalu langsung dikembalikan sesuai dengan model yang sudah di definisikan, tidak ada pengolahan dan mutasi data. Layer usecase tidak perlu tahu data itu diakses darimana (sql, http request, rpc, dll.)

Use Case — Layer ini akan dipakai untuk memproses semua business logic yang dibutuhkan. Fungsi-fungsi yang dibuat disini harus merepresentasikan kebutuhan dari pemecahan masalah bisnis.

Controller — Handler untuk API Endpoint, RPC Server, CLI atau Website.

Penutup

Okay, kurang lebih seperti itu yang bisa saya jelasin buat sekarang. Masih banyak PR sebenernya untuk membuktikan rule-rule nya clean architecture seperti unit testing, dll. Doakan saya punya waktu buat update tulisannya dalam waktu dekat ;)

Thank You,

Salman

--

--