Model-View-Controller asli vs web-MVC modern, varian MTV MVP MVVM, controller tipis vs view model — MVC klasik Laravel Blade, NestJS API M+C, dan Fiber dengan html/template — praktik satu halaman CRUD di Laravel dan Fiber serta API-only NestJS

MVC adalah pola arsitektur paling terkenal — sekaligus paling sering disalahpahami. Yang dipakai framework web hari ini bukanlah MVC Smalltalk tahun 1979, melainkan turunan yang disesuaikan untuk HTTP. Episode ini meluruskan sejarahnya, memetakan variannya (MTV/MVP/MVVM), lalu menjawab pertanyaan arsitektural penting untuk era API: kenapa aplikasi JSON hanya butuh M+C?
MVC asli (Reenskaug, Smalltalk): Model (state domain), View (render state), Controller (penerima input perangkat) — dengan observasi langsung Model→View.
Web-MVC modern mengadaptasinya ke siklus request-response tanpa koneksi persisten:
Perbedaan kunci: di web, controller yang memilih view dan mengirim hasilnya; tidak ada update otomatis. Nama "Model" juga melebar makna — bisa berarti entity domain ATAU layer data access; kejelasan istilah internal tim lebih penting daripada puritanisme sejarah.
| Varian | Inti Perbedaan | Dipakai Di |
|---|---|---|
| MTV | Template sebagai View, sama semangatnya | Django |
| MVP | Presenter aktif mendorong View via interface (testable UI) | Aplikasi desktop/mobile klasik |
| MVVM | ViewModel expose state yang di-bind dua arah | WPF, Vue/Angular secara konsep |
Untuk backend API, ketiganya menyusut: tak ada template yang perlu bind — response JSON adalah "view" yang sudah jadi. Maka muncul insight penting: API JSON = Model + Controller saja, dengan serializer sebagai view minimalis.
Dua disiplin yang menjaga MVC tetap sehat:
OrderResource, OrderResponseDto) — bukan dump entity mentah (disiplin dari episode 8).// routes/web.php -> controller -> model -> blade view:
class ProductController extends Controller {
public function index() {
$products = Product::with('category')->paginate(20); // M
return view('products.index', ['products' => $products]); // V
}
}
{{-- resources/views/products/index.blade.php --}}
@foreach($products as $product)
<tr><td>{{ $product->name }}</td><td>Rp{{ number_format($product->price) }}</td></tr>
@endforeachBandingkan: Laravel & Fiber merender HTML sungguhan (V nyata); NestJS mengganti V dengan DTO+serializer — dan itulah kenapa struktur direktori NestJS tidak punya folder views.
Note
Pertanyaan wawancara favorit: "di REST API, mana View-nya?" Jawaban matang: response DTO/serializer — bentuk representasi tetap dipisahkan dari domain, meski tak lagi berupa template.
Target outline: satu halaman CRUD dengan MVC di Laravel & Fiber, dan API-only di NestJS.
Fitur: daftar produk (list) + tambah produk (create form + submit)
Laravel :
[x] Route resource, ProductController, Eloquent Product, Blade index+create
[x] Validasi FormRequest, redirect dengan flash message
Fiber :
[x] GET /products (c.Render), POST /products (redirect),
GORM repo, html/template views/products_index.html + _form.html
NestJS :
[x] @Controller('products'): GET list + POST create,
CatalogService, CreateProductDto + ProductDto (view=DTO)
Ujian parity: alur data & validasi IDENTIK; hanya representasi keluar beda.
Commit ketiga lab: "ep12: MVC CRUD".Tip
Saat menulis Blade/template Go, hindari logika bisnis di view — hitung diskon/format uang di model/service/view-model. Template hanya memformat apa yang diberikan.
Rangkuman episode ini:
Episode 13 menyusun semua bagian menjadi bangunan utuh pertama: Layered Architecture (N-Tier) — aturan dependensi satu arah, horizontal slicing, dan lint dependency rule. Sampai jumpa!