Dokumen ini berisi kumpulan prinsip, konsep, dan istilah penting yang wajib dipahami oleh setiap developer. Prinsip-prinsip ini akan membantu Anda menulis kode yang lebih baik, mudah dipelihara, dan profesional.
Jangan Ulangi Dirimu Sendiri
Prinsip ini mengajarkan untuk menghindari duplikasi kode. Setiap bagian pengetahuan atau logika harus memiliki satu representasi yang jelas dan otoritatif dalam sistem.
Mengapa penting?
- Mengurangi kesalahan saat update (cukup ubah di satu tempat)
- Mempermudah maintenance
- Menghemat waktu dan usaha
Contoh Buruk:
# Menghitung diskon untuk berbagai produk
harga_buku = 100000
diskon_buku = harga_buku * 0.1
harga_akhir_buku = harga_buku - diskon_buku
harga_pensil = 5000
diskon_pensil = harga_pensil * 0.1
harga_akhir_pensil = harga_pensil - diskon_pensil
Contoh Baik:
def hitung_diskon(harga, persentase_diskon=0.1):
return harga - (harga * persentase_diskon)
harga_akhir_buku = hitung_diskon(100000)
harga_akhir_pensil = hitung_diskon(5000)
Buat Sesederhana Mungkin
Kompleksitas adalah musuh dari eksekusi. Selalu pilih solusi yang paling sederhana yang dapat menyelesaikan masalah.
Mengapa penting?
- Kode sederhana lebih mudah dipahami
- Lebih sedikit bug
- Lebih mudah di-debug dan di-maintain
Contoh Buruk:
// Mengecek apakah angka genap
function isEven(num) {
if (num === 0) return true;
else if (num === 1) return false;
else if (num < 0) return isEven(-num);
else return isEven(num - 2);
}
Contoh Baik:
function isEven(num) {
return num % 2 === 0;
}
Kamu Tidak Akan Membutuhkannya
Jangan tambahkan fungsionalitas sampai benar-benar diperlukan. Hindari over-engineering.
Mengapa penting?
- Menghemat waktu development
- Mengurangi kompleksitas yang tidak perlu
- Fokus pada fitur yang benar-benar dibutuhkan
Contoh: Jangan buat sistem authentication yang super canggih dengan 10 metode login berbeda jika aplikasi Anda hanya butuh login dengan email dan password.
Kumpulan 5 prinsip desain berorientasi objek yang membuat software lebih mudah dipahami, fleksibel, dan maintainable.
Setiap class harus memiliki satu dan hanya satu alasan untuk berubah.
Contoh Buruk:
class User {
void createUser() { /* ... */ }
void deleteUser() { /* ... */ }
void sendEmail() { /* ... */ }
void generateReport() { /* ... */ }
}
Contoh Baik:
class User {
void createUser() { /* ... */ }
void deleteUser() { /* ... */ }
}
class EmailService {
void sendEmail() { /* ... */ }
}
class ReportGenerator {
void generateReport() { /* ... */ }
}
Software entities harus terbuka untuk ekstensi, tapi tertutup untuk modifikasi.
Objek dari subclass harus bisa menggantikan objek dari superclass tanpa merusak fungsionalitas.
Client tidak boleh dipaksa bergantung pada interface yang tidak mereka gunakan.
Modul high-level tidak boleh bergantung pada modul low-level. Keduanya harus bergantung pada abstraksi.
Kode harus mudah dibaca seperti membaca cerita
Kode ditulis sekali tapi dibaca berkali-kali. Developer lain (termasuk Anda di masa depan) harus bisa memahami kode dengan cepat.
Ciri-ciri kode yang Readable:
- Nama variabel dan fungsi yang deskriptif
- Struktur yang konsisten
- Indentasi yang benar
- Komentar yang menjelaskan "why" bukan "what"
Contoh Buruk:
def p(x,y):
return x*y*0.1
Contoh Baik:
def calculate_discount_price(original_price, discount_percentage):
"""Calculate the final price after applying discount."""
discount_amount = original_price * discount_percentage * 0.01
return original_price - discount_amount
Kode harus mudah diubah dan diperbaiki
Maintainability adalah seberapa mudah kode dapat dimodifikasi untuk memperbaiki bug, menambah fitur, atau meningkatkan performa.
Karakteristik:
- Well-documented
- Mengikuti coding standards
- Memiliki test coverage yang baik
- Tidak ada duplikasi kode
- Dependencies yang jelas
Tips untuk Maintainable Code:
// Gunakan constants untuk magic numbers
const MAX_RETRY_ATTEMPTS = 3; // Mudah diubah
const CONNECTION_TIMEOUT = 5000; // dalam milliseconds
// Daripada
if (retries > 3) { // Magic number, susah di-maintain
// ...
}
Kode dipecah menjadi modul-modul independent
Modularitas memungkinkan kode dibagi menjadi komponen-komponen yang dapat digunakan kembali dan ditest secara terpisah.
Contoh Modular Structure:
project/
├── auth/
│ ├── login.js
│ ├── register.js
│ └── validation.js
├── payment/
│ ├── process.js
│ ├── refund.js
│ └── gateway.js
└── utils/
├── date.js
└── format.js
Contoh Laravel Blade Views Structure:
Note
Berikut adalah contoh struktur modular Laravel Blade dengan layout modern menggunakan komponen
Struktur ini menggunakan:
- Modern Blade Components dengan x-component syntax
- Props dan Slots untuk fleksibilitas
- Attribute Merging untuk customization
- Anonymous Components untuk komponen sederhana
- Class-based Components untuk komponen kompleks
resources/views/
├── components/
│ ├── layouts/
│ │ ├── app.blade.php
│ │ ├── guest.blade.php
│ │ └── admin.blade.php
│ ├── ui/
│ │ ├── button.blade.php
│ │ ├── card.blade.php
│ │ ├── modal.blade.php
│ │ ├── alert.blade.php
│ │ ├── badge.blade.php
│ │ └── dropdown.blade.php
│ ├── forms/
│ │ ├── input.blade.php
│ │ ├── textarea.blade.php
│ │ ├── select.blade.php
│ │ ├── checkbox.blade.php
│ │ ├── radio.blade.php
│ │ └── file-upload.blade.php
│ ├── navigation/
│ │ ├── navbar.blade.php
│ │ ├── sidebar.blade.php
│ │ ├── breadcrumb.blade.php
│ │ └── pagination.blade.php
│ ├── dashboard/
│ │ ├── stats-card.blade.php
│ │ ├── chart-widget.blade.php
│ │ ├── recent-activity.blade.php
│ │ └── quick-actions.blade.php
│ └── table/
│ ├── data-table.blade.php
│ ├── table-header.blade.php
│ ├── table-row.blade.php
│ └── table-actions.blade.php
├── auth/
│ ├── login.blade.php
│ ├── register.blade.php
│ ├── forgot-password.blade.php
│ └── verify-email.blade.php
├── dashboard/
│ ├── index.blade.php
│ ├── analytics.blade.php
│ └── reports.blade.php
├── profile/
│ ├── edit.blade.php
│ ├── show.blade.php
│ └── settings.blade.php
└── pages/
├── home.blade.php
├── about.blade.php
└── contact.blade.php
React.js Component Structure (untuk FE/Frontend):
src/
├── components/
│ ├── common/
│ │ ├── Header/
│ │ │ ├── Header.jsx
│ │ │ ├── Header.module.css
│ │ │ └── index.js
│ │ ├── Button/
│ │ │ ├── Button.jsx
│ │ │ ├── Button.test.js
│ │ │ └── index.js
│ │ └── Modal/
│ │ ├── Modal.jsx
│ │ └── Modal.module.css
│ ├── forms/
│ │ ├── LoginForm/
│ │ │ ├── LoginForm.jsx
│ │ │ └── validation.js
│ │ └── ContactForm/
│ │ ├── ContactForm.jsx
│ │ └── schema.js
│ └── pages/
│ ├── Dashboard/
│ │ ├── Dashboard.jsx
│ │ ├── components/
│ │ │ ├── StatsCard.jsx
│ │ │ └── ChartWidget.jsx
│ │ └── hooks/
│ │ └── useDashboard.js
│ └── Profile/
│ ├── Profile.jsx
│ └── ProfileSettings.jsx
├── hooks/
│ ├── useAuth.js
│ ├── useApi.js
│ └── useLocalStorage.js
├── services/
│ ├── api.js
│ ├── auth.js
│ └── storage.js
└── utils/
├── helpers.js
├── constants.js
└── validators.js
Svelte Component Structure:
src/
├── lib/
│ ├── components/
│ │ ├── ui/
│ │ │ ├── Button.svelte
│ │ │ ├── Card.svelte
│ │ │ ├── Modal.svelte
│ │ │ └── Toast.svelte
│ │ ├── forms/
│ │ │ ├── Input.svelte
│ │ │ ├── Select.svelte
│ │ │ └── FileUpload.svelte
│ │ └── navigation/
│ │ ├── Navbar.svelte
│ │ ├── Sidebar.svelte
│ │ └── Breadcrumb.svelte
│ ├── stores/
│ │ ├── auth.js
│ │ ├── notifications.js
│ │ └── theme.js
│ ├── services/
│ │ ├── api.js
│ │ ├── auth.service.js
│ │ └── storage.service.js
│ └── utils/
│ ├── helpers.js
│ ├── validators.js
│ └── formatters.js
├── routes/
│ ├── +layout.svelte
│ ├── +page.svelte
│ ├── auth/
│ │ ├── login/
│ │ │ └── +page.svelte
│ │ └── register/
│ │ └── +page.svelte
│ ├── dashboard/
│ │ ├── +page.svelte
│ │ └── +layout.svelte
│ └── profile/
│ ├── +page.svelte
│ └── settings/
│ └── +page.svelte
└── app.html
Manfaat:
- Reusability tinggi - Komponen dapat digunakan di berbagai tempat
- Easier testing - Setiap modul dapat ditest secara independen
- Parallel development - Tim dapat bekerja pada modul berbeda secara bersamaan
- Clear separation of concerns - Setiap modul memiliki tanggung jawab yang jelas
- Maintainability - Mudah untuk debugging dan update
- Scalability - Mudah menambah fitur baru tanpa mengganggu yang lama
Kode dapat menangani pertumbuhan tanpa perlu ditulis ulang
Scalability bukan hanya tentang performa, tapi juga tentang bagaimana mudahnya menambah fitur baru.
Prinsip Scalable Code:
# Non-scalable
def process_user_data(user1, user2, user3):
# Bagaimana kalau ada 100 users?
pass
# Scalable
def process_user_data(users_list):
for user in users_list:
process_single_user(user)
Kode mudah untuk ditulis unit test-nya
Karakteristik Testable Code:
- Fungsi pure (tidak ada side effects)
- Dependency injection
- Single responsibility
- Avoid global state
Contoh:
// Hard to test (tergantung external state)
function calculateTotal() {
return window.cartItems.reduce((sum, item) =>
sum + item.price, 0) * window.taxRate;
}
// Easy to test (pure function)
function calculateTotal(items, taxRate) {
return items.reduce((sum, item) =>
sum + item.price, 0) * taxRate;
}
Kode dapat digunakan di berbagai tempat tanpa modifikasi
Tips untuk Reusable Code:
# Non-reusable (too specific)
def send_email_to_admin():
send_mail("admin@example.com", "Alert", "System error")
# Reusable (generic)
def send_email(recipient, subject, body):
# Implementation
pass
# Bisa digunakan untuk berbagai keperluan
send_email("admin@example.com", "Alert", "System error")
send_email("user@example.com", "Welcome", "Thanks for joining")
Kode berjalan efisien tanpa memboroskan resource
Aspek Performance:
- Time complexity yang optimal
- Memory usage yang efisien
- Minimal database queries
- Proper caching strategy
Contoh Optimization:
// Poor performance - O(n²)
function findDuplicates(array) {
const duplicates = [];
for (let i = 0; i < array.length; i++) {
for (let j = i + 1; j < array.length; j++) {
if (array[i] === array[j]) {
duplicates.push(array[i]);
}
}
}
return duplicates;
}
// Better performance - O(n)
function findDuplicates(array) {
const seen = new Set();
const duplicates = new Set();
for (const item of array) {
if (seen.has(item)) {
duplicates.add(item);
}
seen.add(item);
}
return Array.from(duplicates);
}
Kode terlindung dari vulnerabilities umum
Security Best Practices:
- Input validation
- SQL injection prevention
- XSS protection
- Proper authentication & authorization
- Encryption untuk data sensitif
# Vulnerable to SQL injection
query = f"SELECT * FROM users WHERE id = {user_input}"
# Secure (using parameterized queries)
query = "SELECT * FROM users WHERE id = ?"
cursor.execute(query, (user_input,))
Kode dapat berjalan di berbagai environment
Characteristics:
- Minimal external dependencies
- Configuration through environment variables
- Platform-agnostic code
- Containerization ready
# Non-portable (hardcoded paths)
file_path = "C:\\Users\\Admin\\data.txt"
# Portable
import os
file_path = os.path.join(os.getcwd(), "data.txt")
Mudah menambah fitur baru tanpa merusak yang sudah ada
Design for Extensibility:
# Using Strategy Pattern for extensibility
class PaymentProcessor:
def __init__(self, strategy):
self.strategy = strategy
def process(self, amount):
return self.strategy.process(amount)
# Easy to add new payment methods
class CreditCardPayment:
def process(self, amount):
# Credit card logic
pass
class PayPalPayment:
def process(self, amount):
# PayPal logic
pass
# Menambah payment method baru tanpa mengubah existing code
class CryptoPayment:
def process(self, amount):
# Cryptocurrency logic
pass
Kode mudah untuk ditelusuri ketika ada masalah
Tips untuk Debuggable Code:
- Meaningful error messages
- Proper logging
- Clear stack traces
- Avoid deep nesting
import logging
def process_transaction(transaction):
logging.info(f"Processing transaction: {transaction.id}")
try:
validate_transaction(transaction)
result = execute_transaction(transaction)
logging.info(f"Transaction {transaction.id} successful")
return result
except ValidationError as e:
logging.error(f"Validation failed for {transaction.id}: {e}")
raise
except Exception as e:
logging.error(f"Unexpected error in {transaction.id}: {e}")
raise
Operasi yang dijalankan berkali-kali menghasilkan hasil yang sama
Penting untuk API dan sistem distributed.
# Non-idempotent
def add_to_counter():
global counter
counter += 1
return counter
# Idempotent
def set_user_status(user_id, status):
user = get_user(user_id)
user.status = status
user.save()
return user
Komponen-komponen tidak terlalu bergantung satu sama lain
# Tightly coupled
class EmailSender:
def send(self, message):
smtp = SMTPServer() # Direct dependency
smtp.send(message)
# Loosely coupled
class EmailSender:
def __init__(self, server):
self.server = server # Dependency injection
def send(self, message):
self.server.send(message)
Pola dan style yang seragam di seluruh codebase
Area Konsistensi:
- Naming conventions
- File structure
- Error handling patterns
- API design
- Code formatting
// Inconsistent
function getUserName() { }
function fetch_user_email() { }
function GetUserAge() { }
// Consistent
function getUserName() { }
function getUserEmail() { }
function getUserAge() { }
Kode yang jelas tanpa perlu komentar berlebihan
# Needs comments (not self-documenting)
def calc(x, y, z):
# Calculate monthly payment
# x is principal, y is rate, z is time
return x * y * (1 + y)**z / ((1 + y)**z - 1)
# Self-documenting
def calculate_monthly_payment(principal, annual_rate, years):
monthly_rate = annual_rate / 12
num_payments = years * 12
if monthly_rate == 0:
return principal / num_payments
return principal * monthly_rate * (1 + monthly_rate)**num_payments / \
((1 + monthly_rate)**num_payments - 1)
Tinggalkan kode lebih bersih dari yang Anda temukan
Setiap kali Anda menyentuh kode, perbaiki sedikit demi sedikit. Refactor nama variabel yang buruk, pecah fungsi yang terlalu panjang, atau hapus kode yang tidak terpakai.
Prinsip Kejutan Minimal
Kode harus berperilaku sesuai dengan yang diharapkan. Jangan buat fungsi atau fitur yang mengejutkan pengguna atau developer lain.
Contoh Buruk:
def add_numbers(a, b):
return a * b # Nama fungsi menyesatkan!
Pemisahan Kepentingan
Pisahkan program menjadi bagian-bagian yang berbeda, dimana setiap bagian menangani concern/kepentingan tertentu.
Contoh: Model-View-Controller (MVC) memisahkan:
- Model: Logika bisnis dan data
- View: Presentasi/tampilan
- Controller: Mengatur interaksi antara Model dan View
Gagal Cepat
Sistem harus segera melaporkan masalah sedekat mungkin dengan sumbernya. Jangan biarkan error tersembunyi.
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero") # Fail fast!
return a / b
Konvensi di Atas Konfigurasi
Framework atau library harus menyediakan default yang masuk akal, sehingga developer hanya perlu mengkonfigurasi hal-hal yang berbeda dari standar.
Contoh: Ruby on Rails otomatis mencari model User
di file app/models/user.rb
Komposisi di Atas Pewarisan
Lebih baik membuat objek dari kumpulan komponen kecil daripada membuat hierarki inheritance yang kompleks.
Hutang Teknis
Konsekuensi dari memilih solusi cepat/mudah sekarang dibanding solusi yang lebih baik yang membutuhkan waktu lebih lama. Seperti hutang finansial, technical debt menumpuk "bunga" berupa kerja ekstra di masa depan.
Bau Kode
Indikasi bahwa ada sesuatu yang mungkin salah dengan kode. Bukan bug, tapi tanda bahwa kode perlu di-refactor.
Contoh Code Smell:
- Fungsi terlalu panjang (>20 baris)
- Terlalu banyak parameter (>3-4)
- Komentar yang menjelaskan kode buruk
- Duplikasi kode
- God Class (class yang tahu/melakukan terlalu banyak)
Refaktorisasi
Proses restrukturisasi kode tanpa mengubah perilaku eksternalnya. Tujuannya membuat kode lebih bersih, readable, dan maintainable.
Produk Minimum yang Layak
Versi produk dengan fitur minimal yang cukup untuk memuaskan early adopters dan memberikan feedback untuk development selanjutnya.
Interface yang memungkinkan aplikasi berbeda untuk berkomunikasi satu sama lain. Seperti "kontrak" yang mendefinisikan bagaimana software components berinteraksi.
- CI (Continuous Integration): Praktik menggabungkan perubahan kode ke main branch sesering mungkin
- CD (Continuous Delivery/Deployment): Otomasi proses release software
Pengembangan Berbasis Test
Metodologi dimana Anda menulis test terlebih dahulu, baru kemudian menulis kode untuk membuat test tersebut pass.
Siklus TDD:
- Red: Tulis test yang fail
- Green: Tulis kode minimal untuk membuat test pass
- Refactor: Perbaiki kode tanpa merusak test
Agile: Metodologi pengembangan software iteratif dan incremental Scrum: Framework Agile dengan sprint, daily standup, dan retrospective
Sistem yang merekam perubahan file dari waktu ke waktu. Git adalah contoh paling populer.
- Monolithic: Aplikasi dibangun sebagai satu unit besar
- Microservices: Aplikasi dipecah menjadi services kecil yang independent
Optimasi Prematur
"Premature optimization is the root of all evil" - Donald Knuth
Jangan optimalkan performa sebelum Anda tahu dimana bottleneck-nya. Fokus dulu pada kode yang benar dan readable.
Cara mendeskripsikan kompleksitas waktu/ruang dari algoritma:
- O(1): Constant time
- O(log n): Logarithmic time
- O(n): Linear time
- O(n²): Quadratic time
Menyimpan hasil komputasi untuk digunakan kembali nanti, menghindari kalkulasi ulang yang mahal.
Prinsip Hak Akses Minimal
Berikan user atau proses hanya akses minimum yang diperlukan untuk menyelesaikan tugasnya.
Pertahanan Berlapis
Jangan andalkan satu layer security. Gunakan multiple layers untuk melindungi sistem.
Proses dimana developer lain memeriksa kode sebelum di-merge. Membantu menemukan bug, sharing knowledge, dan menjaga kualitas kode.
Kode yang baik adalah self-documenting, tapi dokumentasi tetap penting untuk:
- API documentation
- Setup instructions
- Architecture decisions
- Complex business logic
Gunakan nama yang deskriptif dan konsisten:
# Buruk
def calc(x, y):
return x * 0.1 + y
# Baik
def calculate_total_with_tax(price, tax_amount):
return price * 0.1 + tax_amount
Komentar harus menjelaskan "mengapa", bukan "apa":
// Buruk: Menambah 1 ke counter
counter++;
// Baik: Increment counter untuk menghindari race condition
// saat multiple threads mengakses resource yang sama
counter++;
Selalu handle error dengan graceful. Jangan biarkan aplikasi crash tanpa penjelasan.
try:
result = risky_operation()
except SpecificError as e:
log_error(e)
return default_value
Prinsip-prinsip ini bukan aturan kaku, melainkan panduan untuk membantu Anda menjadi developer yang lebih baik. Ingat:
- Konteks adalah raja - Tidak semua prinsip cocok untuk semua situasi
- Belajar terus menerus - Dunia tech selalu berkembang
- Praktik membuat sempurna - Terapkan prinsip-prinsip ini dalam proyek nyata
- Kolaborasi - Diskusikan dengan tim untuk best practices yang sesuai
"Any fool can write code that a computer can understand. Good programmers write code that humans can understand." - Martin Fowler
- Clean Code by Robert C. Martin
- The Pragmatic Programmer by David Thomas & Andrew Hunt
- Design Patterns: Elements of Reusable Object-Oriented Software
- Refactoring by Martin Fowler
- The Clean Coder by Robert C. Martin
Dokumen ini adalah living document yang akan terus diperbarui seiring perkembangan best practices dalam dunia software development.