Journal

Angular Application Development: Core Concepts, Architecture, and Project Structure

Pelajari konsep dasar Angular, mulai dari components, dependency injection, services, data binding, dan routing hingga penerapan feature-based architecture, reusable components, serta lazy loading. Panduan ini juga membahas standar struktur

Hogy Pitersan Melsy
Hogy Pitersan Melsy

Learning and creating through code, but also values reflection and journaling as a way to grow. Writing helps me capture ideas, track progress, and make sense of my thoughts. This journal is a space where I share pieces of my journey—sometimes about tech.

Pelajari konsep dasar Angular, mulai dari components, dependency injection, services, data binding, dan routing hingga penerapan feature-based architecture, reusable components, serta lazy loading. Panduan ini juga membahas standar struktur folder dan alur pengembangan untuk membangun aplikasi frontend yang modular, konsisten, dan mudah dipelihara.

Panduan memahami fondasi Angular, membangun arsitektur frontend yang modular, dan menyusun struktur proyek yang konsisten untuk aplikasi web berskala besar.

1. Introduction: Building More Than Just a Web Interface

Mengembangkan aplikasi web bukan sekadar membuat halaman yang terlihat menarik dan memastikan tombol dapat diklik. Seiring bertambahnya fitur, kompleksitas aplikasi juga meningkat. Pengelolaan data, komunikasi dengan backend, navigasi, validasi formulir, hingga konsistensi antarmuka perlu dirancang agar aplikasi tetap mudah dikembangkan dan dipelihara.

Di sinilah Angular menjadi salah satu pilihan untuk membangun aplikasi frontend yang terstruktur.

Angular adalah framework pengembangan web yang dikembangkan dan dipelihara oleh Google. Framework ini menggunakan TypeScript dan menyediakan berbagai kemampuan terintegrasi, seperti component-based architecture, dependency injection, routing, pengelolaan formulir, serta HTTP Client.

Angular dirancang untuk mendukung pengembangan aplikasi dari skala kecil hingga aplikasi enterprise dengan banyak fitur dan anggota tim. Pendekatan yang terstruktur membantu developer memisahkan tanggung jawab, menggunakan kembali kode, dan menjaga konsistensi implementasi di seluruh aplikasi.

Namun, menggunakan Angular saja tidak otomatis menghasilkan arsitektur yang baik. Developer tetap perlu menentukan bagaimana fitur dikelompokkan, bagaimana komponen berkomunikasi, bagaimana layanan digunakan, dan bagaimana navigasi diatur.

Karena itu, memahami konsep dasar Angular perlu diikuti dengan pemahaman mengenai standar struktur proyek yang akan digunakan selama pengembangan.

2. Core Concepts of Angular

2.1 Components: The Building Blocks of an Application

Komponen (component) merupakan fondasi utama antarmuka aplikasi Angular. Setiap komponen bertanggung jawab atas bagian tertentu dari UI, misalnya halaman login, tabel pengguna, formulir, atau tombol yang dapat digunakan kembali.

Secara umum, sebuah komponen terdiri dari:

  • TypeScript class: Menyimpan data dan logika yang dibutuhkan komponen.

  • HTML template: Mendefinisikan struktur serta tampilan UI.

  • Component metadata: Menggunakan dekorator @Component() untuk menghubungkan kelas dengan template, selector, dependency, dan konfigurasi lainnya.

Contohnya, komponen sederhana dapat menampilkan nama pengguna melalui interpolasi:

import { Component } from '@angular/core';

@Component({
  selector: 'app-user-greeting',
  template: `<h1>Hello, {{ name }}!</h1>`,
})
export class UserGreetingComponent {
  name = 'Developer';
}

Pada contoh tersebut, kelas TypeScript menyimpan data name, sedangkan template menampilkan nilai tersebut kepada pengguna.

Dalam aplikasi yang lebih kompleks, komponen sebaiknya memiliki tanggung jawab yang jelas. Komponen halaman dapat menangani interaksi tingkat halaman, sementara komponen yang lebih kecil menangani bagian UI tertentu.

Pendekatan ini membuat komponen lebih mudah dipahami, diuji, dan digunakan kembali.

2.2 Modules and Standalone Components

Secara tradisional, Angular menggunakan NgModule untuk mengelompokkan komponen, directive, pipe, serta dependency terkait. Pendekatan ini banyak ditemukan pada aplikasi Angular yang lebih lama.

Angular modern juga mendukung standalone components, yaitu komponen yang dapat mengelola dependency-nya sendiri tanpa harus dideklarasikan dalam NgModule.

Contoh konfigurasi standalone component:

import { Component } from '@angular/core';

@Component({
  selector: 'app-dashboard',
  standalone: true,
  template: `<h1>Dashboard</h1>`,
})
export class DashboardComponent {}

Pada versi Angular modern, komponen secara default bersifat standalone sehingga properti standalone: true biasanya tidak perlu ditulis secara eksplisit.

Pemilihan pendekatan bergantung pada versi Angular dan arsitektur proyek. Aplikasi baru dapat memanfaatkan standalone APIs, sedangkan aplikasi lama tetap dapat menggunakan NgModule atau melakukan migrasi secara bertahap.

Hal yang terpenting adalah menjaga konsistensi arsitektur dan menghindari kompleksitas yang tidak diperlukan.

2.3 Dependency Injection: Managing Dependencies Properly

Dependency Injection (DI) merupakan mekanisme untuk menyediakan dependency kepada suatu kelas tanpa mengharuskan kelas tersebut membuat seluruh dependency-nya sendiri.

Dalam Angular, DI banyak digunakan untuk menyediakan service, konfigurasi, dan resource lain yang dibutuhkan komponen.

Terdapat dua konsep utama dalam DI:

  • Providers: Mendefinisikan bagaimana suatu dependency disediakan.

  • Injectors: Mengelola resolusi dependency dan menyediakan instance kepada bagian aplikasi yang membutuhkannya.

Contoh penggunaan DI:

import { Component, inject } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-user-list',
  template: `<p>User list</p>`,
})
export class UserListComponent {
  private userService = inject(UserService);
}

Pada contoh tersebut, komponen mendapatkan UserService melalui mekanisme DI Angular.

Dengan pendekatan ini, komponen tidak perlu bertanggung jawab atas proses pembuatan service. Dependency juga dapat dikonfigurasi pada scope tertentu, sesuai kebutuhan aplikasi.

DI membantu memisahkan tanggung jawab, meningkatkan kemudahan pengujian, dan mengurangi keterikatan langsung antarkelas.

2.4 Services: Separating Business Logic from UI

Service merupakan kelas yang digunakan untuk menampung logika atau kemampuan yang dibutuhkan oleh satu atau lebih bagian aplikasi.

Service dapat bertanggung jawab atas:

  • Mengambil dan mengirim data melalui API.

  • Mengelola operasi data tertentu.

  • Menyediakan fungsi bisnis yang digunakan oleh beberapa komponen.

  • Menangani proses yang tidak seharusnya berada langsung di dalam template.

Contoh service:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class UserService {
  getUsers() {
    // Implementasi pengambilan data pengguna
    return [];
  }
}

Dengan providedIn: 'root', Angular menyediakan service tersebut pada root injector sehingga dapat digunakan oleh bagian aplikasi yang membutuhkannya.

Komponen kemudian dapat menggunakan service untuk menjalankan operasi yang diperlukan, tanpa harus memuat seluruh logika bisnis di dalam kelas komponen.

Pemisahan ini membantu menjaga komponen tetap fokus pada presentasi dan interaksi pengguna, sementara service menangani tanggung jawab yang lebih spesifik.

2.5 Templates and Data Binding

Template Angular bukan sekadar HTML biasa. Angular menyediakan sintaks yang memungkinkan template menampilkan data, mengatur properti elemen, dan merespons interaksi pengguna.

Empat bentuk data binding yang umum adalah:

Interpolasi ({{ }})

Digunakan untuk menampilkan nilai dari kelas komponen.

<h1>{{ pageTitle }}</h1>

Property binding ([ ])

Digunakan untuk menghubungkan nilai dari komponen ke properti elemen atau komponen lain.

<button [disabled]="isLoading">
  Submit
</button>

Event binding (( ))

Digunakan untuk merespons event, seperti klik tombol.

<button (click)="save()">
  Save
</button>

Two-way binding ([( )])

Digunakan untuk menyinkronkan nilai antara komponen dan elemen yang mendukung pola tersebut, seperti [(ngModel)] pada formulir.

<input [(ngModel)]="username" />

Two-way binding menggunakan sintaks banana-in-a-box dan memerlukan konfigurasi yang sesuai, misalnya FormsModule untuk ngModel.

Pemilihan jenis binding yang tepat membantu menjaga alur data tetap jelas dan mengurangi logika manipulasi DOM secara manual.

2.6 Directives and Template Control Flow

Directive memungkinkan Angular mengubah perilaku atau tampilan elemen dalam template. Secara umum, directive dapat dibedakan menjadi dua kategori utama: attribute directives dan structural directives. Component juga memiliki karakteristik directive dengan template tersendiri.

  • Attribute directives: Mengubah tampilan atau perilaku elemen, misalnya ngClass dan ngStyle.

  • Structural directives: Secara tradisional digunakan untuk menambahkan, menghapus, atau mengubah struktur elemen, misalnya *ngIf dan *ngFor.

Angular modern menyediakan built-in control flow seperti @if dan @for sebagai alternatif sintaks yang lebih baru untuk mengatur tampilan berdasarkan kondisi atau melakukan iterasi.

Contoh:

@if (isLoggedIn) {
  <p>Welcome back!</p>
} @else {
  <p>Please sign in.</p>
}

@for (user of users; track user.id) {
  <p>{{ user.name }}</p>
}

Pada contoh tersebut, @if menentukan konten yang ditampilkan berdasarkan kondisi, sedangkan @for menampilkan daftar pengguna.

Penggunaan track user.id membantu Angular mengidentifikasi item dalam daftar secara konsisten ketika data berubah.

Memahami directive dan control flow penting untuk membangun template yang dinamis tanpa membuat logika tampilan menjadi sulit dipelihara.

2.7 Routing: Navigating Between Application Views

Angular Router mengatur navigasi berdasarkan URL dan menentukan komponen atau tampilan yang ditampilkan kepada pengguna.

Dalam single-page application (SPA), navigasi antarrute umumnya dilakukan tanpa memuat ulang seluruh dokumen HTML. Hal ini memungkinkan aplikasi memberikan pengalaman navigasi yang lebih mulus.

Contoh konfigurasi routing menggunakan standalone components:

import { Routes } from '@angular/router';

export const routes: Routes = [
  {
    path: 'dashboard',
    loadComponent: () =>
      import('./features/dashboard/pages/dashboard.component')
        .then((m) => m.DashboardComponent),
  },
  {
    path: 'users',
    loadChildren: () =>
      import('./features/users/users.routes')
        .then((m) => m.USER_ROUTES),
  },
];

Pada konfigurasi tersebut, halaman dashboard dimuat melalui loadComponent, sedangkan fitur users memuat konfigurasi rutenya melalui loadChildren.

Routing juga mendukung nested routes, route parameters, query parameters, navigation guards, dan berbagai kebutuhan navigasi lainnya.

Dengan routing yang terorganisasi, struktur URL dapat mencerminkan struktur fitur aplikasi dan membuat navigasi lebih mudah dikelola.

2.8 Integrated Libraries and Application Capabilities

Angular menyediakan berbagai API dan pustaka yang mendukung kebutuhan umum dalam pengembangan aplikasi web.

Beberapa di antaranya adalah:

HTTP Client

Digunakan untuk melakukan komunikasi HTTP dengan backend API, seperti mengambil data, membuat data baru, memperbarui data, dan menghapus data.

Form Management

Angular mendukung template-driven forms dan reactive forms. Reactive forms memberikan pendekatan berbasis model yang cocok untuk formulir kompleks, validasi, dan pengujian.

Signals and State Management

Angular Signals menyediakan mekanisme reaktivitas untuk mengelola serta membaca nilai yang dapat berubah. Untuk kebutuhan state yang lebih kompleks, aplikasi dapat menggunakan pendekatan atau pustaka tambahan seperti NgRx.

Penting untuk membedakan kebutuhan state lokal komponen, state yang digunakan bersama, dan state global aplikasi. Tidak semua aplikasi membutuhkan solusi state management yang kompleks sejak awal.

Pemilihan pustaka sebaiknya didasarkan pada kebutuhan nyata, bukan sekadar menambah teknologi ke dalam stack aplikasi.

3. Project Architecture and Development Standards

Memahami fitur Angular merupakan langkah awal. Langkah berikutnya adalah menerapkan struktur proyek yang konsisten agar aplikasi dapat berkembang tanpa membuat kode sulit ditemukan atau dimodifikasi.

Standar berikut menjadi pedoman dasar dalam menyusun aplikasi frontend berbasis Angular.

3.1 Prioritize Reusable Components

Komponen yang digunakan berulang kali sebaiknya dibuat sebagai reusable components.

Contohnya meliputi:

  • Custom button.

  • Text input.

  • Dropdown.

  • Modal atau dialog.

  • Data table.

  • Loading indicator.

  • Komponen notifikasi.

Alih-alih membuat tombol dengan implementasi berbeda pada setiap halaman, tim dapat menyediakan satu komponen tombol bersama yang memiliki API dan gaya visual konsisten.

Reusable components tidak berarti setiap elemen harus langsung dijadikan komponen terpisah. Komponen sebaiknya dibuat ketika ada kebutuhan penggunaan ulang, tanggung jawab yang jelas, atau manfaat nyata terhadap pemeliharaan kode.

Tujuan akhirnya adalah mengurangi duplikasi dan menjaga konsistensi UI tanpa menciptakan abstraksi yang berlebihan.

3.2 Apply Feature-Based Organization

Struktur kode sebaiknya menggunakan pendekatan feature-based, yaitu mengelompokkan kode berdasarkan fitur bisnis atau area fungsional aplikasi.

Sebagai contoh, fitur pengguna dapat memiliki halaman, konfigurasi routing, service, model, dan komponen pendukung yang berkaitan dengan pengguna.

Pendekatan ini membantu developer menemukan kode berdasarkan konteks fitur yang sedang dikerjakan, bukan harus menelusuri banyak folder global berdasarkan jenis file.

Sebagai contoh, seluruh kebutuhan fitur pengguna dapat dikelompokkan dalam folder features/users, sementara komponen yang digunakan lintas fitur ditempatkan dalam shared.

3.3 Component File Organization

Pemisahan file TypeScript dan HTML sebaiknya mengikuti kompleksitas serta peran komponen.

Untuk komponen kecil dan pendukung:

Template dan TypeScript dapat digabung dalam satu file apabila implementasinya sederhana dan tetap mudah dibaca. Inline template cocok untuk komponen kecil yang tidak memerlukan markup panjang.

Untuk komponen utama atau halaman fitur:

Pisahkan TypeScript dan HTML ke dalam file masing-masing agar struktur, logika, dan tampilan lebih mudah dipelihara.

Contoh pembuatan komponen menggunakan Angular CLI:

ng generate component features/users/pages/user-list

Angular CLI membantu menghasilkan struktur komponen sesuai konvensi proyek dan mengurangi pekerjaan boilerplate secara manual.

Untuk komponen yang kompleks, pertimbangkan pemecahan menjadi subkomponen berdasarkan tanggung jawabnya. Pemisahan sebaiknya membuat kode lebih mudah dipahami, bukan sekadar menambah jumlah file.

3.4 Use Lazy Loading for Feature Routes

Lazy loading merupakan strategi untuk menunda pemuatan kode suatu fitur sampai fitur tersebut dibutuhkan.

Dalam aplikasi dengan banyak halaman, memuat seluruh kode fitur pada awal aplikasi dapat memperbesar bundle JavaScript awal. Lazy loading memungkinkan sebagian kode dipisahkan menjadi chunk yang dimuat saat pengguna mengakses rute terkait.

Angular menyediakan loadComponent untuk memuat komponen secara lazy dan loadChildren untuk memuat konfigurasi rute anak.

Manfaat yang diharapkan meliputi:

  • Mengurangi jumlah kode yang perlu dimuat pada awal aplikasi.

  • Membantu mempercepat initial loading pada aplikasi dengan banyak fitur.

  • Memisahkan bundle berdasarkan area fungsional.

  • Mendukung pengembangan aplikasi yang lebih modular.

Lazy loading tidak otomatis membuat seluruh aplikasi lebih cepat dalam semua kondisi. Efeknya bergantung pada ukuran bundle, struktur rute, dan pola navigasi pengguna. Karena itu, implementasinya tetap perlu dievaluasi melalui pengukuran performa.

4. Recommended Project Structure

Berikut merupakan salah satu contoh struktur proyek yang dapat digunakan sebagai pedoman awal.

src/
├── app/
│   ├── features/
│   │   ├── users/
│   │   │   ├── pages/
│   │   │   │   ├── user-list/
│   │   │   │   │   ├── user-list.component.ts
│   │   │   │   │   └── user-list.component.html
│   │   │   │   └── user-detail/
│   │   │   ├── components/
│   │   │   ├── services/
│   │   │   ├── models/
│   │   │   └── users.routes.ts
│   │   └── dashboard/
│   │       ├── pages/
│   │       ├── services/
│   │       └── dashboard.routes.ts
│   ├── layout/
│   │   ├── main-layout/
│   │   └── auth-layout/
│   ├── shared/
│   │   ├── components/
│   │   ├── directives/
│   │   ├── pipes/
│   │   ├── configs/
│   │   ├── constants/
│   │   ├── entities/
│   │   ├── models/
│   │   ├── utils/
│   │   └── validators/
│   ├── app.routes.ts
│   └── app.config.ts
├── assets/
│   ├── fonts/
│   ├── images/
│   └── styles/
└── environments/

Struktur tersebut merupakan contoh konvensi tim, bukan struktur wajib yang ditentukan oleh Angular. Nama folder dan tingkat pengelompokan dapat disesuaikan dengan kebutuhan proyek, versi Angular, serta konvensi yang telah disepakati.

4.1 Features

Folder features menjadi tempat utama untuk mengelompokkan fitur aplikasi.

Setiap fitur dapat memiliki beberapa bagian:

  • Pages: Komponen halaman yang diakses melalui routing.

  • Components: Komponen pendukung yang hanya digunakan dalam fitur tersebut.

  • Services: Service yang menangani kebutuhan data atau logika fitur.

  • Models: Tipe data khusus fitur.

  • Routes: Konfigurasi navigasi fitur.

Tidak semua fitur harus memiliki seluruh folder tersebut. Buat folder ketika memang dibutuhkan agar struktur tidak dipenuhi folder kosong atau abstraksi yang belum memiliki fungsi.

4.2 Layout

Folder layout menyimpan struktur tampilan yang membungkus halaman, misalnya:

  • Main layout untuk halaman aplikasi setelah pengguna login.

  • Authentication layout untuk halaman login atau registrasi.

  • Layout khusus untuk area administratif.

Layout membantu menjaga struktur umum, seperti header, sidebar, navigation bar, dan content container, agar tidak perlu dibuat ulang di setiap halaman.

4.3 Shared

Folder shared berisi komponen dan utilitas yang digunakan oleh lebih dari satu fitur.

Pembagian yang dapat diterapkan meliputi:

  • Components: Button, input, dropdown, modal, dan komponen UI bersama.

  • Configs: Konfigurasi yang digunakan lintas fitur, seperti pemetaan pesan error.

  • Constants: Nilai konstan yang dipakai oleh beberapa bagian aplikasi.

  • Directives: Directive khusus yang digunakan kembali.

  • Entities: Representasi entitas domain atau data, jika pemisahan ini memang diperlukan.

  • Models: Tipe data umum yang digunakan lintas fitur.

  • Utils: Fungsi bantuan yang bersifat umum dan dapat digunakan kembali.

  • Validators: Validator khusus yang digunakan pada formulir.

Sebaiknya jangan memindahkan semua kode ke shared hanya karena ingin membuatnya tampak generik. Jika suatu service atau model hanya relevan bagi satu fitur, menempatkannya di dalam fitur tersebut biasanya membuat batas tanggung jawab lebih jelas.

4.4 Assets

Folder assets menyimpan aset statis yang diperlukan aplikasi, seperti font, gambar, ikon, dan file pendukung desain.

Aset yang digunakan secara global dapat dikelompokkan berdasarkan jenisnya agar mudah ditemukan dan dikelola.

4.5 Environments and Configuration

Folder environments dapat digunakan untuk menyimpan konfigurasi yang berbeda berdasarkan environment, misalnya base URL backend untuk development dan production.

Namun, konfigurasi frontend perlu memperhatikan aspek keamanan. File environment yang dibundel ke dalam aplikasi browser dapat dibaca oleh pengguna.

Karena itu, jangan menyimpan secret key, private API key, password, atau kredensial rahasia di dalam kode frontend maupun file environment yang dikirim ke browser. Rahasia tersebut harus disimpan dan digunakan di backend atau sistem penyimpanan rahasia yang sesuai.

Konfigurasi yang memang aman untuk diketahui publik, seperti URL API publik atau identifier aplikasi tertentu, dapat dikelola melalui mekanisme konfigurasi frontend.

5. General Angular Development Workflow

Pengembangan fitur Angular dapat mengikuti alur kerja berikut agar implementasi tetap konsisten dan mudah ditinjau.

Step 1: Build the Components

Identifikasi kebutuhan UI dan pecah menjadi komponen berdasarkan tanggung jawabnya.

Tentukan mana yang merupakan halaman utama, komponen khusus fitur, dan komponen yang layak digunakan kembali.

Step 2: Create the Services

Pisahkan operasi data dan logika yang tidak berkaitan langsung dengan tampilan ke dalam service yang sesuai.

Jika fitur membutuhkan komunikasi dengan backend, gunakan service untuk mengelola request dan respons API.

Step 3: Configure Dependency Injection

Sediakan service melalui mekanisme DI Angular. Tentukan scope provider berdasarkan kebutuhan agar lifecycle dan penggunaan dependency tetap terkontrol.

Step 4: Configure Routing

Tambahkan rute untuk halaman atau fitur baru. Untuk fitur yang sesuai, gunakan lazy loading melalui loadComponent atau loadChildren.

Step 5: Connect Data and Templates

Gunakan data binding untuk menampilkan data, menerima input, dan menangani event pengguna. Terapkan validasi serta pengelolaan formulir sesuai kompleksitas kebutuhan.

Step 6: Test, Build, and Validate

Lakukan pengujian pada logika dan komponen yang relevan, verifikasi alur navigasi, serta periksa interaksi dengan API.

Sebelum rilis, jalankan proses build production dan evaluasi performa serta konfigurasi aplikasi.

Dengan alur ini, setiap fitur dikembangkan secara bertahap tanpa mengabaikan konsistensi arsitektur dan kualitas implementasi.

6. Documentation and Learning Resources

Dokumentasi resmi merupakan referensi utama untuk memahami API, pola implementasi, dan perubahan yang diperkenalkan pada versi Angular tertentu.

Dokumentasi sebaiknya disesuaikan dengan versi framework dan pustaka yang digunakan proyek. Contoh implementasi dari versi lama tidak selalu mencerminkan praktik yang direkomendasikan untuk Angular modern.

7. Conclusion

Membangun aplikasi Angular yang mudah dikembangkan bukan hanya tentang memahami sintaks framework. Kualitas aplikasi juga ditentukan oleh bagaimana komponen dirancang, bagaimana dependency dikelola, bagaimana service memisahkan logika bisnis dari UI, serta bagaimana routing dan struktur folder disusun.

Pendekatan feature-based membantu menjaga kode tetap terorganisasi berdasarkan kebutuhan bisnis, sedangkan reusable components mendorong konsistensi dan mengurangi duplikasi. Lazy loading dapat membantu mengoptimalkan pemuatan fitur, sementara pengujian dan pengelolaan konfigurasi yang tepat mendukung kualitas serta keamanan aplikasi.

Standar struktur proyek dalam panduan ini dapat digunakan sebagai fondasi awal bagi tim frontend. Seiring berkembangnya aplikasi, struktur tersebut dapat disesuaikan berdasarkan kebutuhan nyata tanpa mengorbankan prinsip utama: tanggung jawab yang jelas, kode yang mudah ditemukan, dan arsitektur yang dapat dipelihara.

Pada akhirnya, tujuan arsitektur yang baik bukan membuat struktur proyek menjadi serumit mungkin, melainkan membuat developer lebih mudah memahami, mengembangkan, menguji, dan menjaga aplikasi dalam jangka panjang.