Mempelajari cara menulis kode yang bersih, aman, dan mengikuti standar industri dengan fokus pada aksesibilitas dan keamanan aplikasi web.
Kode yang bersih adalah kode yang mudah dibaca, dipahami, dan dimodifikasi oleh developer lain.
// Nama function yang deskriptif
function calculateMonthlyPayment(principal, interestRate, termInYears) {
const monthlyRate = interestRate / 12;
const numberOfPayments = termInYears * 12;
const monthlyPayment = principal *
(monthlyRate * Math.pow(1 + monthlyRate, numberOfPayments)) /
(Math.pow(1 + monthlyRate, numberOfPayments) - 1);
return Math.round(monthlyPayment * 100) / 100;
}
// Variable dengan nama yang jelas
const loanAmount = 250000;
const annualInterestRate = 0.045;
const loanTermYears = 30;
const payment = calculateMonthlyPayment(
loanAmount,
annualInterestRate,
loanTermYears
);
// Nama function tidak jelas
function calc(p, r, t) {
const mr = r / 12;
const n = t * 12;
// Magic numbers tanpa penjelasan
const mp = p * (mr * Math.pow(1 + mr, n)) / (Math.pow(1 + mr, n) - 1);
return Math.round(mp * 100) / 100;
}
// Variable dengan nama singkat
const l = 250000;
const i = 0.045;
const y = 30;
const p = calc(l, i, y);
if (user.isLoggedIn) {
if (user.hasPermission('admin')) {
showAdminPanel();
logActivity('admin_access');
} else {
showUserDashboard();
logActivity('user_access');
}
} else {
redirectToLogin();
}
// Maksimal 80-120 karakter per baris
const longCondition = (
user.isActive &&
user.hasValidSubscription &&
user.lastLoginDate > thirtyDaysAgo
);
// Method chaining yang panjang
const processedData = rawData
.filter(item => item.isValid)
.map(item => transformItem(item))
.sort((a, b) => a.priority - b.priority);
// Boolean variables: gunakan is, has, can, should
const isUserLoggedIn = checkUserStatus();
const hasValidLicense = validateLicense();
const canEditPost = checkPermissions('edit');
// Function names: gunakan verb + noun
function validateEmailAddress(email) { }
function calculateTotalPrice(items) { }
function renderUserProfile(user) { }
// Constants: gunakan UPPER_CASE
const MAX_RETRY_ATTEMPTS = 3;
const DEFAULT_TIMEOUT_MS = 5000;
const API_BASE_URL = 'https://api.example.com';
// Class names: gunakan PascalCase
class UserProfileManager { }
class PaymentProcessor { }
class EmailValidator { }
DRY adalah prinsip untuk menghindari duplikasi kode dengan mengabstraksi pola yang berulang.
// Validasi form login
if (!email || email.length === 0) {
showError('Email is required');
return false;
}
if (!email.includes('@')) {
showError('Invalid email format');
return false;
}
// Validasi form register
if (!email || email.length === 0) {
showError('Email is required');
return false;
}
if (!email.includes('@')) {
showError('Invalid email format');
return false;
}
// Validasi form newsletter
if (!email || email.length === 0) {
showError('Email is required');
return false;
}
if (!email.includes('@')) {
showError('Invalid email format');
return false;
}
// Reusable validation function
function validateEmail(email) {
if (!email || email.length === 0) {
showError('Email is required');
return false;
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
showError('Invalid email format');
return false;
}
return true;
}
// Usage in different forms
function validateLoginForm() {
return validateEmail(loginForm.email.value);
}
function validateRegisterForm() {
return validateEmail(registerForm.email.value);
}
function validateNewsletterForm() {
return validateEmail(newsletterForm.email.value);
}
// Utility functions untuk menghindari repetisi
const FormValidator = {
// Generic field validation
validateRequired(value, fieldName) {
if (!value || value.trim().length === 0) {
this.showError(`${fieldName} is required`);
return false;
}
return true;
},
// Email validation
validateEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
this.showError('Please enter a valid email address');
return false;
}
return true;
},
// Password strength validation
validatePassword(password) {
if (password.length < 8) {
this.showError('Password must be at least 8 characters');
return false;
}
const hasNumber = /\d/.test(password);
const hasUpper = /[A-Z]/.test(password);
const hasLower = /[a-z]/.test(password);
if (!hasNumber || !hasUpper || !hasLower) {
this.showError('Password must contain uppercase, lowercase, and number');
return false;
}
return true;
},
// Error display
showError(message) {
const errorDiv = document.getElementById('error-message');
errorDiv.textContent = message;
errorDiv.style.display = 'block';
},
// Clear errors
clearErrors() {
const errorDiv = document.getElementById('error-message');
errorDiv.style.display = 'none';
}
};
// Usage example
function validateRegistrationForm(formData) {
FormValidator.clearErrors();
return FormValidator.validateRequired(formData.name, 'Name') &&
FormValidator.validateEmail(formData.email) &&
FormValidator.validatePassword(formData.password);
}
/* Utility classes untuk spacing */
.m-1 { margin: 0.25rem; }
.m-2 { margin: 0.5rem; }
.m-3 { margin: 1rem; }
.p-1 { padding: 0.25rem; }
.p-2 { padding: 0.5rem; }
.p-3 { padding: 1rem; }
/* Reusable button styles */
.btn {
padding: 0.75rem 1.5rem;
border: none;
border-radius: 0.375rem;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-primary {
background-color: #007bff;
color: white;
}
.btn-primary:hover {
background-color: #0056b3;
}
/* Flex utilities */
.d-flex { display: flex; }
.justify-center { justify-content: center; }
.align-center { align-items: center; }
.flex-column { flex-direction: column; }
Web Content Accessibility Guidelines (WCAG) memberikan standar untuk membuat web yang dapat diakses semua orang.
Informasi dapat dipersepsi user
Interface dapat dioperasikan
Informasi mudah dipahami
Dapat diinterpretasi berbagai teknologi
<!-- Alt text untuk gambar -->
<img src="chart.jpg" alt="Sales increase 25% from Q1 to Q2 2025">
<!-- Labels untuk form input -->
<label for="username">Username:</label>
<input type="text" id="username" name="username" required
aria-describedby="username-help">
<span id="username-help">Must be at least 3 characters long</span>
<!-- ARIA labels untuk complex elements -->
<button aria-label="Close dialog" onclick="closeModal()">
<i class="fas fa-times"></i>
</button>
<!-- Heading hierarchy -->
<h1>Main Page Title</h1>
<h2>Section Title</h2>
<h3>Subsection Title</h3>
<!-- Keyboard navigation -->
<div tabindex="0" role="button" onkeydown="handleKeyDown(event)">
Custom Button
</div>
<!-- Skip links -->
<a href="#main-content" class="skip-link">Skip to main content</a>
Sanitasi input adalah langkah pertama untuk mencegah serangan injeksi dan XSS.
<?php
// Input sanitization function
function sanitizeInput($input) {
// Remove whitespace
$input = trim($input);
// Remove backslashes
$input = stripslashes($input);
// Convert special characters to HTML entities
$input = htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
return $input;
}
// Validate and sanitize form data
function processFormData($data) {
$cleanData = [];
foreach ($data as $key => $value) {
// Basic validation
if (empty($value)) {
throw new InvalidArgumentException("$key is required");
}
// Sanitize based on field type
switch ($key) {
case 'email':
$cleanData[$key] = filter_var($value, FILTER_VALIDATE_EMAIL);
if (!$cleanData[$key]) {
throw new InvalidArgumentException("Invalid email format");
}
break;
case 'age':
$cleanData[$key] = filter_var($value, FILTER_VALIDATE_INT, [
'options' => ['min_range' => 1, 'max_range' => 120]
]);
if ($cleanData[$key] === false) {
throw new InvalidArgumentException("Invalid age");
}
break;
default:
$cleanData[$key] = sanitizeInput($value);
break;
}
}
return $cleanData;
}
// Usage example
try {
$userData = processFormData($_POST);
// Safe to use $userData
} catch (InvalidArgumentException $e) {
echo "Error: " . $e->getMessage();
}
?>
// Safe DOM manipulation
function safeSetText(elementId, text) {
const element = document.getElementById(elementId);
if (element) {
// Use textContent instead of innerHTML to prevent XSS
element.textContent = text;
}
}
// Safe HTML insertion
function safeSetHTML(elementId, html) {
const element = document.getElementById(elementId);
if (element) {
// Create a temporary div to sanitize HTML
const tempDiv = document.createElement('div');
tempDiv.textContent = html; // This escapes HTML
element.innerHTML = tempDiv.innerHTML;
}
}
// Input validation
function validateInput(input, type) {
switch (type) {
case 'email':
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(input);
case 'phone':
const phoneRegex = /^\+?[\d\s\-\(\)]+$/;
return phoneRegex.test(input);
case 'alphanumeric':
const alphanumericRegex = /^[a-zA-Z0-9]+$/;
return alphanumericRegex.test(input);
default:
// Basic sanitization: remove HTML tags
return input.replace(/<[^>]*>/g, '');
}
}
// CSRF token handling
function getCSRFToken() {
const meta = document.querySelector('meta[name="csrf-token"]');
return meta ? meta.getAttribute('content') : '';
}
// Safe AJAX request
function secureAjaxRequest(url, data, method = 'POST') {
const headers = {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': getCSRFToken()
};
return fetch(url, {
method: method,
headers: headers,
body: JSON.stringify(data)
});
}
// Security utility functions
const SecurityUtils = {
// Escape HTML to prevent XSS
escapeHTML(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
},
// Validate email format
isValidEmail(email) {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
},
// Validate password strength
isStrongPassword(password) {
return password.length >= 8 &&
/[A-Z]/.test(password) &&
/[a-z]/.test(password) &&
/\d/.test(password) &&
/[!@#$%^&*]/.test(password);
},
// Rate limiting for form submissions
rateLimiter: {
attempts: {},
isAllowed(identifier, maxAttempts = 5, timeWindow = 300000) {
const now = Date.now();
const userAttempts = this.attempts[identifier] || [];
// Remove old attempts
const recentAttempts = userAttempts.filter(
time => now - time < timeWindow
);
if (recentAttempts.length >= maxAttempts) {
return false;
}
recentAttempts.push(now);
this.attempts[identifier] = recentAttempts;
return true;
}
}
};