Episode ini membahas arsitektur aplikasi Remix yang skalabel: struktur folder untuk fitur dan route, organisasi feature modules, shared utilities dan typed contracts, serta cara menjaga kode terpelihara dengan loader dan action yang bertipe kuat.

Aplikasi kecil mudah dirawat karena semua orang ingat semua kode. Masalahnya, aplikasi jarang berhenti kecil. Tanpa arsitektur yang disengaja, folder berantakan, file raksasa, dan setiap perubahan baru terasa menakutkan. Episode 18 adalah pelajaran arsitektur untuk Remix.
Kabar baiknya, struktur route Remix memberi fondasi yang baik: setiap URL punya file sendiri. Tugas kalian tinggal memperluas pola itu ke kode yang mendukung route — fungsi data, komponen, dan utilitas bersama — dengan aturan yang konsisten dan mudah dipahami.
Episode 18 akan membahas struktur folder, organisasi feature modules, shared utilities dengan typed contracts, dan praktik menjaga loader serta action tetap ramping.
Alih-alih menumpuk semua file di satu folder, pisahkan berdasarkan tanggung jawab. Pola umum di project Remix yang sehat:
app/
routes/ <- file route, kurus dan fokus
components/ <- komponen yang dipakai lintas route
lib/
db.server.ts <- akses database, hanya server
session.server.ts
validators.ts <- schema validasi
modules/
posts/
post.model.ts
post.service.tsFile yang berakhiran .server.ts dijamin tidak pernah terkirim ke client. Nama file adalah kontrak sekaligus pengaman — pisahkan kode server dari kode client secara eksplisit.
File route idealnya tipis: memanggil fungsi dari modul, bukan berisi semua logika. Route yang kurus berarti logika ada di tempat yang bisa diuji dan dipakai ulang, bukan di dalam file route.
Kelompokkan kode per fitur. Untuk fitur "posting", taruh model, service, dan komponen spesifik fitur di folder modules/posts, sementara route hanya menjadi titik masuk URL. Perubahan pada satu fitur tidak merembet ke fitur lain karena batas folder sudah jelas.
Nested routes bukan hanya soal layout — mereka juga batas arsitektur. Route induk memuat data bersama; route anak memuat data spesifik. Hierarki route yang baik membuat aliran data mengikuti hierarki UI, sehingga mudah dilacak. Struktur route adalah peta arsitektur yang bisa dibaca dari nama file.
Utilitas yang dipakai banyak tempat — format tanggal, slug, pagination — taruh di lib dengan nama yang deskriptif. Hindari utilitas rahasia yang hanya dipakai satu file; taruh itu di dekat pemakainya.
TypeScript memberi kontrak antar modul: tipe data yang dikembalikan loader harus cocok dengan yang diterima komponen. Dengan tipe yang tepat, refactor menjadi aman karena compiler menangkap ketidakcocokan lebih awal.
export type Post = {
id: string;
judul: string;
konten: string;
};
export async function loader() {
const posts: Post[] = await ambilSemuaPost();
return { posts };
}Tipe Post didefinisikan sekali dan dipakai loader, komponen, dan test. Contract ini mencegah data yang tidak konsisten berjalan di aplikasi.
Tipe TypeScript hilang saat runtime. Untuk data yang datang dari luar — form, API, database — Zod memberi validasi sekaligus inferensi tipe. Schema Zod dan tipe TypeScript didefinisikan di satu tempat, dipakai di banyak lapisan. Ini kontrak runtime dan compile-time sekaligus.
Loader yang panjang biasanya mencampur beberapa hal: autentikasi, validasi, query, transformasi. Pecah menjadi fungsi kecil yang bisa diuji. Fungsi kecil dengan satu tanggung jawab lebih mudah dites dan diubah tanpa efek samping.
Pola yang berulang — membaca session, memeriksa akses, mem-parse form — menjadi helper di lib. Guard autentikasi dari episode 11 bisa diubah menjadi requireUser(request) yang dipakai semua route. Satu helper yang diuji sekali lebih baik daripada logika yang disalin berkali-kali.
Kode yang baik menjelaskan dirinya sendiri, tetapi keputusan penting layak dicatat. README per modul yang menjelaskan mengapa, bukan apa, membantu anggota tim baru. Komunikasi arsitektur lewat struktur dan nama lebih tahan lama daripada dokumen terpisah.
Arsitektur tidak hidup sendiri — ia dijaga oleh kebiasaan tim. Code review yang memperhatikan batas folder, ukuran file route, dan penggunaan tipe menjaga arsitektur tetap sesuai rencana. Jadikan checklist arsitektur sederhana bagian dari proses review: apakah perubahan ini menambah logika di tempat yang seharusnya, dan apakah tipe sudah dipakai dengan benar.
Episode 18 memberi kalian arsitektur yang bisa bertumbuh: struktur folder berbasis fitur dengan route yang kurus, feature modules yang membatasi ruang perubahan, shared utilities dengan typed contracts, dan kebiasaan menjaga loader serta action tetap ramping. Kode kalian kini mudah dirawat oleh siapa pun, termasuk kalian sendiri enam bulan lagi.
Inti yang harus dibawa pulang:
Di episode 19 selanjutnya kita akan membahas tooling modern dan build automation — Remix CLI, bundling dan deploy targets, dukungan TypeScript dan schema typing, pipeline CI/CD untuk aplikasi Remix, serta linting, formatting, dan build validation. Arsitektur sudah rapi; sekarang otomatiskan semuanya.