Project Structure: Functional vs Feature Grouping

Arsitektur kode. Sebuah aspek fundamental yang seringkali terlupakan dalam kesibukan pengembangan software. Layaknya arsitektur sebuah kota, cara kita mengorganisir kode memiliki dampak jangka panjang terhadap pertumbuhan dan keberlanjutan sebuah proyek. Dalam artikel ini, kita akan menjelajahi dua paradigma utama dalam pengorganisasian kode: Functional Grouping dan Feature Grouping.

Bayangkan sebuah kota yang dibangun tanpa perencanaan. Rumah-rumah, toko, dan fasilitas publik tersebar tanpa pola yang jelas. Seiring pertumbuhan kota, masalah mulai bermunculan: kemacetan, polusi, dan ketidakefisienan dalam pelayanan publik.

Functional Groups

Functional Grouping, layaknya kota tua yang dibangun berdasarkan fungsi - area perdagangan, pemukiman, industri - mengorganisir kode berdasarkan peran teknisnya. Pendekatan ini telah menjadi standar de facto selama bertahun-tahun, didukung oleh framework-framework populer seperti Ruby on Rails dan Laravel.

project/
├── Controllers/
├── Models/
├── DataAccessLayer/
└── Utils/

Pendekatan ini memang terasa familiar dan mudah dipahami, terutama bagi developer pemula.

  • Mudah dipahami oleh developer baru karena mengikuti pola umum
  • Cocok untuk aplikasi kecil dengan fitur sederhana
  • Struktur yang predictable dan familiar

Namun, ketika aplikasi berkembang biasanya adopsi Functional Grouping akan mengalami beberapa masalah

  • Perubahan pada satu fitur bisa mempengaruhi banyak direktori
  • Sulit melacak file terkait saat mengerjakan fitur tertentu
  • Kohesi rendah karena kode terkait fitur tersebar
  • Kompleksitas meningkat seiring pertumbuhan aplikasi

Ruby on Rails Grouping

app/
├── controllers/
│   ├── users_controller.rb
│   └── products_controller.rb
├── models/
│   ├── user.rb
│   └── product.rb
├── views/
│   ├── users/
│   └── products/
└── services/
    ├── payment_service.rb
    └── notification_service.rb

Laravel Grouping

app/
├── Http/
│   └── Controllers/
├── Models/
├── Services/
└── Providers/

Feature Groups / Bounded Context (Pengelompokan Domain)

Bounded Context adalah pola sentral dalam Domain-Driven Design (DDD) yang diperkenalkan oleh Eric Evans. Konsep ini muncul dari pemahaman bahwa dalam sistem yang besar, membangun model domain yang sepenuhnya terpadu (unified) seringkali tidak feasible dan cost-effective.

Feature Grouping, atau yang lebih dikenal sebagai Bounded Context dalam Domain-Driven Design, membawa pendekatan yang berbeda dari Functional Grouping. Bayangkan sebuah kota modern dengan blok - blok apartemen, area yang mengintegrasikan tempat tinggal, perkantoran, dan fasilitas pendukung dalam satu kawasan.

Dalam konteks pengorganisasian kode, Feature Groups/Bounded Context mengorganisir kode berdasarkan batasan domain bisnis yang jelas. Setiap konteks memiliki model dan bahasa yang konsisten di dalamnya (Ubiquitous Language), dan memiliki interaksi yang terdefinisi dengan konteks lainnya.

Contoh struktur organisasi kode dengan pendekatan ini:

project/
├── Timesheet/
│   ├── TimesheetController.ts
│   ├── TimesheetService.ts
│   └── TimesheetRepository.ts
├── Attendance/
│   ├── AttendanceController.ts
│   ├── AttendanceService.ts
│   └── AttendanceRepository.ts
└── shared/
    ├── database/
    └── http/

Pendekatan ini membawa beberapa keunggulan signifikan

  • Kohesi tinggi karena kode terkait fitur terkumpul di satu tempat
  • Lebih mudah menemukan dan memodifikasi kode terkait fitur
  • Isolasi yang lebih baik antar fitur
  • Memudahkan pemahaman domain bisnis
  • Memudahkan pengembangan paralel oleh multiple tim
  • Berpotensi untuk diekstrak menjadi microservice

Bukan berarti pendekatan ini sempurna, ada beberapa hal yang sangat perlu diperhatikan

  • Membutuhkan pemahaman domain yang baik
  • Bisa ada duplikasi kode antar bounded context
  • Penentuan batas antar konteks bisa menantang, terutama ketika ada polisemi (istilah yang sama memiliki arti berbeda di konteks berbeda)
  • Memerlukan mekanisme integrasi antar bounded context
  • Butuh effort lebih dalam koordinasi tim untuk menjaga konsistensi model dalam satu konteks

NestJS (dengan Feature Modules) Grouping

src/
├── auth/
│   ├── auth.controller.ts
│   ├── auth.service.ts
│   └── auth.module.ts
├── users/
│   ├── users.controller.ts
│   ├── users.service.ts
│   └── users.module.ts
└── products/
    ├── products.controller.ts
    ├── products.service.ts
    └── products.module.ts

Angular (Feature Modules) Grouping

src/app/
├── dashboard/
│   ├── dashboard.component.ts
│   ├── widget.component.ts
│   └── dashboard.module.ts
├── admin/
│   ├── users.component.ts
│   ├── settings.component.ts
│   └── admin.module.ts
└── shared/
    └── shared.module.ts

Mengelola Hubungan Antar Bounded Context

Dalam sistem yang menggunakan Feature Groups/Bounded Context, penting untuk memperhatikan:

  1. Context Map
    • Dokumentasikan hubungan antar bounded context
    • Definisikan bagaimana data dan model diterjemahkan antar konteks
    • Tentukan pola integrasi yang digunakan (shared kernel, customer-supplier, conformist, etc.)
  2. Ubiquitous Language
    • Setiap bounded context memiliki bahasanya sendiri
    • Istilah yang sama bisa memiliki arti berbeda di konteks berbeda
    • Pastikan tim dalam satu bounded context menggunakan bahasa yang konsisten
  3. Integration Patterns
    • API Gateway untuk mengekspos bounded context ke dunia luar
    • Event-driven communication untuk loose coupling
    • Shared libraries untuk kode yang benar-benar umum

Memilih Pendekatan yang Tepat

Seperti halnya tidak ada kota yang sempurna untuk semua orang, tidak ada pendekatan yang sempurna untuk semua proyek. Pertimbangkan:

  1. Kompleksitas domain bisnis
    1. CRUD sederhana? Functional Grouping
    2. Business logic kompleks? Feature Grouping
  2. Ukuran tim dan organisasi. Apabila terdapat multiple team mengerjakan 1 platform, Feature Grouping akan sangat membantu.
  3. Kebutuhan skalabilitas
  4. Tingkat isolasi yang dibutuhkan
  5. Rencana evolusi sistem ke depan

  1. Kelebihan Functional Grouping
    • Lebih mudah untuk pemula karena mengikuti pola MVC klasik
    • Cocok untuk CRUD-heavy applications
    • Perubahan fitur membutuhkan modifikasi di banyak folder
    • Contoh: Aplikasi blog sederhana, CMS dasar
  2. Kelebihan Feature Grouping
    • Lebih scalable untuk aplikasi enterprise
    • Mendukung microservices dan modular monolith
    • Memudahkan parallel development oleh multiple teams
    • Contoh: E-commerce platform, SaaS applications''
  3. Pemilihan Framework
    • Kebanyakan framework modern mendukung kedua pendekatan
    • Pilihan struktur lebih tergantung pada kebutuhan proyek
    • Bisa mulai dengan functional grouping dan beralih ke feature grouping seiring pertumbuhan
  4. Hybrid Grouping
    • Functional grouping untuk shared code
    • Feature grouping untuk business logic
    • Contoh: Shared utilities tetap di folder terpisah, business logic dikelompokkan per fitur

Arsitektur kode, seperti halnya arsitektur kota, perlu beradaptasi dengan pertumbuhan dan perubahan. Functional Grouping dan Feature Grouping bukanlah tentang benar atau salah, melainkan tentang konteks dan kebutuhan. Yang terpenting adalah memahami kekuatan dan keterbatasan masing-masing pendekatan, dan memilih yang paling sesuai dengan kebutuhan proyek Anda.