ЛЕКЦ 06: КОДЫН ЧАНАР БА ЦЭВЭР КОД (Code Quality & Clean Code)
Хичээлийн зорилго: Кодын чанарын ойлголт, цэвэр код бичих зарчмууд, нэрлэлтийн конвенци, функц/метод дизайн, алдаа зохицуулалт, кодын стандарт, статик анализ, Code Review зэргийг Java жишээнүүдтэйгээр эзэмшүүлэх.
Хамрах хүрээ: Clean Code зарчмууд (Robert C. Martin), нэрлэлт, функц дизайн, тайлбар, формат, алдаа зохицуулалт, кодын стандарт, статик анализын хэрэгслүүд, Code Review.
ХЭСЭГ 1: ОНОЛЫН СУУРЬ (Theory & Foundations)
1.1 Кодын чанар (Code Quality) гэж юу вэ?
Кодын чанар гэдэг нь код нь зорилгодоо хэр нийцэж, засвар хийхэд хэр хялбар, ойлгоход хэр тодорхой, алдаагүй, найдвартай ажиллаж байгааг илэрхийлдэг нэгдмэл ойлголт.
🔑 Robert C. Martin: "Цэвэр код гэдэг нь БУСАД хөгжүүлэгч хялбараар УНШИЖ, ОЙЛГОЖ, ӨӨРЧИЛЖ чаддаг код."
Зүйрлэл:
💡 Сайн бичмэл шиг — үг найруулга ойлгомжтой, бүтэц тодорхой, цэвэрхэн бичигдсэн. Муу кодыг уншихад "гүнзгий муу гар бичмэл" уншиж байгаа мэт.
Кодын чанарын хэмжигдэхүүнүүд:
| # | Чанарын шинж | Англи | Тайлбар |
|---|---|---|---|
| 1 | Уншигдах чанар | Readability | Код уншихад ойлгомжтой эсэх |
| 2 | Засварлах чанар | Maintainability | Код өөрчлөхөд хялбар эсэх |
| 3 | Найдвартай байдал | Reliability | Код зөв ажилладаг эсэх |
| 4 | Гүйцэтгэл | Performance | Код хурдан, оновчтой ажиллаж байгаа эсэх |
| 5 | Аюулгүй байдал | Security | Код аюулгүй эсэх |
| 6 | Тестлэх боломж | Testability | Код тестлэхэд хялбар эсэх |
| 7 | Дахин ашиглах | Reusability | Код өөр газар ашиглаж болох эсэх |
Яагаад кодын чанар чухал вэ?
Хөгжүүлэгчийн цагийн хуваарилалт:
┌────────────────────────────────────────┐
│ КОД УНШИХАД: ~70% ████████████████ │
│ КОД БИЧИХЭД: ~30% ███████ │
└────────────────────────────────────────┘
⚠️ Бодит байдал: Хөгжүүлэгч цагийнхаа ~70%-ийг КОД УНШИХАД, зөвхөн ~30%-ийг бичихэд зарцуулдаг. Тиймээс уншигдах чанар нь бүтээмжид шууд нөлөөлнө.
1.2 Clean Code — Цэвэр кодын зарчмууд
Robert C. Martin-ий "Clean Code" номны гол зарчмууд:
| # | Зарчим | Тайлбар |
|---|---|---|
| 1 | Утга учиртай нэрлэлт | Хувьсагч, функц, классын нэр нь зорилгоо илэрхийлэх |
| 2 | Функц жижиг байх | Нэг функц нэг зүйл хийх |
| 3 | Тайлбар бага байх | Код өөрөө тайлбарлагдах |
| 4 | Формат зөв байх | Тогтсон стиль, зохион байгуулалт |
| 5 | Алдаа зохицуулалт | Exception зөв ашиглах |
| 6 | DRY | Давхардал байхгүй |
| 7 | KISS | Энгийн байлга |
| 8 | YAGNI | Шаардлагагүй зүйл нэмэхгүй |
1.3 Нэрлэлт (Naming)
1.3.1 Утга учиртай нэр (Meaningful Names)
Нэр нь "юу хийдэг", "юу агуулдаг", "юунд зориулагдсан" гэдгийг тодорхой илэрхийлэх ёстой.
// ❌ БУРУУ — Юу гэсэн утга вэ?
int d;
String s;
List<int[]> list1;
public void doStuff() { ... }
// ✅ ЗӨӨВ — Нэр нь зорилгоо илэрхийлж байна
int daysSinceLastLogin;
String customerName;
List<int[]> flaggedCells;
public void calculateMonthlyReport() { ... }
1.3.2 Нэрлэлтийн дүрмүүд
| Дүрэм | Тайлбар | Жишээ |
|---|---|---|
| Зорилгыг илэрхийлэх | Нэрийг уншихад зорилго нь мэдэгдэх | maxRetryCount (✅) vs mrc (❌) |
| Төөрөгдөл үүсгэхгүй | Хуурмаг мэдээлэл агуулахгүй | accountList зөвхөн List бол → accounts |
| Ялгаатай нэр | Ижил төстэй нэр ашиглахгүй | getActiveAccount() vs getActiveAccountInfo() — юугаараа ялгаатай? |
| Дуудаж болохуйц | Амаар хэлж болохуйц нэр | genymdhms (❌) → generationTimestamp (✅) |
| Хайж болохуйц | Нэг үсэгтэй нэр хайхад хэцүү | e (❌) → event (✅) |
1.3.3 Java нэрлэлтийн конвенци
| Төрөл | Конвенци | Жишээ |
|---|---|---|
| Класс | PascalCase (Нэр үг) | StudentService, OrderProcessor |
| Метод | camelCase (Үйл үг) | calculateTotal(), findByName() |
| Хувьсагч | camelCase | studentName, totalAmount |
| Тогтмол | UPPER_SNAKE_CASE | MAX_RETRY_COUNT, DEFAULT_TIMEOUT |
| Package | бүгд жижиг | com.company.project.service |
| Interface | PascalCase | Serializable, PaymentService |
| Enum | PascalCase (нэр), UPPER (утга) | enum Color { RED, GREEN, BLUE } |
| Boolean | is/has/can + Тэмдэг нэр | isActive, hasPermission, canDelete |
// ❌ БУРУУ нэрлэлт
class data { ... } // Жижиг үсэг, тодорхойгүй
public void proc() { ... } // Товчилсон
boolean flag; // Юуны flag?
static final int num = 30; // Тогтмол нэрлэлт буруу
// ✅ ЗӨӨВ нэрлэлт
class StudentRegistration { ... } // PascalCase, тодорхой
public void processRegistration() { } // camelCase, үйл үг
boolean isEnrollmentOpen; // Boolean конвенци
static final int MAX_CLASS_SIZE = 30; // UPPER_SNAKE_CASE
1.3.4 Тохиромжтой нэрийн урт
// Хэт богино — ойлгомжгүй
int d;
String n;
void p() { }
// Хэт урт — уншихад хэцүү
int numberOfDaysSinceTheUserLastLoggedInToTheSystem;
void processAndValidateAndSaveStudentRegistrationFormData() { }
// Тохиромжтой — ойлгомжтой, товч
int daysSinceLastLogin;
String studentName;
void processRegistration() { }
💡 Зүйрлэл: Хүний нэр шиг — "Б" гэхэд хэн бэ мэдэхгүй, "Баатарын хүү Болдбаатарын ач Эрдэнэбаатар" гэхэд хэт урт. "Баатар" гэхэд яг тохиромжтой.
1.4 Функц / Метод дизайн
1.4.1 Функц жижиг байх ёстой
🔑 Robert C. Martin: "Функцийн эхний дүрэм — ЖИЖИГ байх. Хоёр дахь дүрэм — БҮҮР ЖИЖИГ байх."
// ❌ БУРУУ — 50+ мөр, олон зүйл хийж байна
public void processOrder(Order order) {
// Хэрэглэгч шалгах (15 мөр)
if (order.getCustomer() == null) { ... }
if (!order.getCustomer().isActive()) { ... }
// Нөөц шалгах (10 мөр)
for (Item item : order.getItems()) { ... }
// Үнэ тооцоолох (15 мөр)
double total = 0;
for (Item item : order.getItems()) { ... }
// Хөнгөлөлт (10 мөр)
if (order.getCustomer().isVIP()) { ... }
// Төлбөр (5 мөр)
paymentService.charge(total);
}
// ✅ ЗӨӨВ — Жижиг функцүүдэд хуваасан
public void processOrder(Order order) {
validateCustomer(order.getCustomer());
checkInventory(order.getItems());
double total = calculateTotal(order);
total = applyDiscount(order.getCustomer(), total);
processPayment(order.getCustomer(), total);
}
1.4.2 Нэг функц — Нэг зүйл (Do One Thing)
// ❌ БУРУУ — Олон зүйл хийж байна
public void emailClients(List<Client> clients) {
for (Client client : clients) {
if (client.isActive()) { // Шүүх
String email = client.getEmail(); // Өгөгдөл авах
if (email != null && !email.isEmpty()) { // Шалгах
sendEmail(email, "Hello!"); // Илгээх
}
}
}
}
// ✅ ЗӨӨВ — Тус тусдаа функцүүд
public void emailActiveClients(List<Client> clients) {
List<Client> activeClients = filterActiveClients(clients);
List<String> emails = extractValidEmails(activeClients);
sendBulkEmail(emails, "Hello!");
}
private List<Client> filterActiveClients(List<Client> clients) {
return clients.stream()
.filter(Client::isActive)
.collect(Collectors.toList());
}
private List<String> extractValidEmails(List<Client> clients) {
return clients.stream()
.map(Client::getEmail)
.filter(email -> email != null && !email.isEmpty())
.collect(Collectors.toList());
}
1.4.3 Функцийн параметрийн тоо
| Тоо | Нэр | Зөвлөмж |
|---|---|---|
| 0 | Niladic | ✅ Хамгийн сайн |
| 1 | Monadic | ✅ Сайн |
| 2 | Dyadic | ⚠️ Болгоомжтой |
| 3 | Triadic | ❌ Зайлсхий |
| 3+ | Polyadic | ❌ Объект ашигла |
// ❌ БУРУУ — 6 параметр
public void createStudent(String firstName, String lastName,
int age, String email,
String phone, double gpa) { ... }
// ✅ ЗӨӨВ — Объект ашиглах
public void createStudent(StudentDTO student) { ... }
class StudentDTO {
private String firstName;
private String lastName;
private int age;
private String email;
private String phone;
private double gpa;
}
1.4.4 Функцийн нэрлэлт
// ❌ БУРУУ — Юу хийдэг нь мэдэгдэхгүй
public void handle() { ... }
public Object get() { ... }
public void process() { ... }
public boolean check(Student s) { ... }
// ✅ ЗӨӨВ — Нэр нь зорилгоо тодорхой хэлж байна
public void handlePaymentTimeout() { ... }
public Student findStudentById(long id) { ... }
public void processMonthlyBilling() { ... }
public boolean isEligibleForScholarship(Student student) { ... }
1.4.5 Side Effect байхгүй байх
Side Effect = Функц нь нэрнээс мэдэгдэхгүй "нуугдмал" зүйл хийж байна.
// ❌ БУРУУ — checkPassword нь нууц "session initialize" хийж байна
public boolean checkPassword(String username, String password) {
User user = userRepository.findByName(username);
if (user != null && user.getPassword().equals(encrypt(password))) {
Session.initialize(); // ⚠️ Side Effect! Нэрнээс мэдэгдэхгүй
return true;
}
return false;
}
// ✅ ЗӨӨВ — Тусдаа функцүүд
public boolean checkPassword(String username, String password) {
User user = userRepository.findByName(username);
return user != null && user.getPassword().equals(encrypt(password));
}
public void loginUser(String username, String password) {
if (checkPassword(username, password)) {
Session.initialize(); // Тодорхой — login хийхэд session эхлэнэ
}
}
1.5 Тайлбар (Comments)
1.5.1 Сайн тайлбар vs Муу тайлбар
🔑 Robert C. Martin: "Тайлбар бичих шаардлагатай болсон бол — кодоо илүү сайн бичиж чадаагүй гэсэн дохио."
Сайн тайлбар:
// ✅ Хуулийн шаардлага тайлбарлах
// Хувийн мэдээлэл хамгаалах тухай хуулийн 15.3 заалтын дагуу
// 18 нас хүрээгүй хэрэглэгчийн мэдээллийг 90 хоногийн дараа устгана
public void deleteMinorUserData() { ... }
// ✅ Яагаад ийм шийдвэр гаргасныг тайлбарлах
// SimpleDateFormat нь thread-safe биш тул ThreadLocal ашиглаж байна
private static final ThreadLocal<SimpleDateFormat> formatter =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
// ✅ TODO тайлбар
// TODO: Кэш нэвтрүүлэх — одоогоор DB-с шууд уншиж байна
public Student findById(long id) { ... }
// ✅ Анхааруулга
// WARNING: Энэ тест 10 минут ажиллана
@Test
public void performanceTest() { ... }
Муу тайлбар:
// ❌ Код юу хийж байгааг давтах
// i-г нэгээр нэмэгдүүлэх
i++;
// ❌ Хуучирсан тайлбар (код өөрчлөгдсөн, тайлбар хэвээрээ)
// Хэрэглэгчийн нэрийг буцаана
public String getEmail() { return email; } // Нэр биш, имэйл!
// ❌ Шаардлагагүй тайлбар — код өөрөө ойлгомжтой
// Default constructor
public Student() { }
// ❌ Comment-оор "хаасан" хуучин код
// public void oldMethod() {
// // Хуучин логик...
// }
1.5.2 Код өөрөө тайлбарлагдах ёстой
// ❌ БУРУУ — Тайлбараар нөхсөн
// Хэрэглэгч нэвтрэх эрхтэй эсэхийг шалгах
// Нас 18-аас дээш, бүртгэл идэвхтэй, блоклогдоогүй байх
public boolean chk(User u) {
return u.getAge() >= 18 && u.isActive() && !u.isBlocked();
}
// ✅ ЗӨӨВ — Код өөрөө тайлбарлагдаж байна
public boolean isEligibleForAccess(User user) {
return user.isAdult() && user.isActive() && !user.isBlocked();
}
1.6 Формат (Formatting)
1.6.1 Босоо формат (Vertical Formatting)
// ✅ Холбоотой кодыг ойрхон, хоосон мөрөөр бүлэглэх
public class StudentService {
private final StudentRepository repository;
private final EmailService emailService;
public StudentService(StudentRepository repository, EmailService emailService) {
this.repository = repository;
this.emailService = emailService;
}
public Student findById(long id) {
return repository.findById(id)
.orElseThrow(() -> new StudentNotFoundException(id));
}
public Student createStudent(StudentDTO dto) {
Student student = mapToEntity(dto);
Student saved = repository.save(student);
emailService.sendWelcomeEmail(saved.getEmail());
return saved;
}
private Student mapToEntity(StudentDTO dto) {
// ...
}
}
Зарчим:
- Холбоотой код ойрхон байх (хувьсагч → ашигласан газар)
- Хоосон мөрөөр логик бүлгүүдийг тусгаарлах
- Нэг файлд 200-500 мөр (дээд тал нь)
- Import → Талбар → Constructor → Public метод → Private метод
1.6.2 Хэвтээ формат (Horizontal Formatting)
// ❌ БУРУУ — Нэг мөр хэт урт
public List<StudentDTO> findActiveStudentsWithGPAAboveThresholdAndEnrolledInCurrentSemester(double threshold) { ... }
// ✅ ЗӨӨВ — Мөр хуваах (80-120 тэмдэгт)
public List<StudentDTO> findActiveHighPerformers(double minGPA) {
return repository.findAll().stream()
.filter(Student::isActive)
.filter(s -> s.getGpa() >= minGPA)
.filter(s -> s.isEnrolledInCurrentSemester())
.map(this::toDTO)
.collect(Collectors.toList());
}
1.7 Алдаа зохицуулалт (Error Handling)
1.7.1 Exception ашиглах (Return Code биш)
// ❌ БУРУУ — Return code ашиглах
public int withdraw(double amount) {
if (amount <= 0) return -1; // Буруу дүн
if (amount > balance) return -2; // Хүрэлцэхгүй
balance -= amount;
return 0; // Амжилттай
}
// Дуудаж буй код:
int result = account.withdraw(100);
if (result == -1) { ... } // -1, -2 юу гэсэн утга вэ?
// ✅ ЗӨӨВ — Exception ашиглах
public void withdraw(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Дүн эерэг байх ёстой: " + amount);
}
if (amount > balance) {
throw new InsufficientFundsException(
"Үлдэгдэл хүрэлцэхгүй. Үлдэгдэл: " + balance + ", Хүсэлт: " + amount
);
}
balance -= amount;
}
1.7.2 Checked vs Unchecked Exception
| Төрөл | Тайлбар | Хэзээ ашиглах | Жишээ |
|---|---|---|---|
| Checked | Компайлер шалгадаг, заавал барих | Сэргээж болох алдаа | IOException, SQLException |
| Unchecked | Runtime-д гардаг, барих заавал биш | Програмын алдаа | NullPointerException, IllegalArgumentException |
1.7.3 Тодорхой Exception ашиглах
// ❌ БУРУУ — Ерөнхий Exception
try {
student = repository.findById(id);
} catch (Exception e) { // Бүх алдааг нэг дор барьж байна
log.error("Алдаа", e);
}
// ✅ ЗӨӨВ — Тодорхой Exception
try {
student = repository.findById(id);
} catch (StudentNotFoundException e) {
log.warn("Оюутан олдсонгүй: {}", id);
throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage());
} catch (DatabaseException e) {
log.error("Мэдээллийн сангийн алдаа: {}", e.getMessage());
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR);
}
1.7.4 Null буцаахгүй байх
// ❌ БУРУУ — null буцааж, NullPointerException-ийн эрсдэл
public Student findById(long id) {
return repository.findById(id); // null байж болно!
}
// Дуудсан газар:
Student s = service.findById(1);
s.getName(); // NullPointerException!
// ✅ ЗӨӨВ — Optional ашиглах
public Optional<Student> findById(long id) {
return repository.findById(id);
}
// Дуудсан газар:
Student s = service.findById(1)
.orElseThrow(() -> new StudentNotFoundException(id));
// Эсвэл:
service.findById(1).ifPresent(student -> {
System.out.println(student.getName());
});
1.7.5 Утга учиртай алдааны мессеж
// ❌ БУРУУ
throw new RuntimeException("Error");
throw new IllegalArgumentException("Invalid");
// ✅ ЗӨӨВ
throw new StudentNotFoundException("ID=" + id + " оюутан олдсонгүй");
throw new IllegalArgumentException(
"Нас 1-150 хооронд байх ёстой. Оруулсан: " + age
);
throw new InsufficientFundsException(
String.format("Үлдэгдэл хүрэлцэхгүй. Үлдэгдэл: %.2f₮, Хүсэлт: %.2f₮",
balance, amount)
);
1.8 Кодын стандарт (Coding Standards)
1.8.1 Кодын стандарт гэж юу вэ?
Баг/байгууллагын хэмжээнд хэрэглэх нэгдсэн дүрэм, конвенци — нэрлэлт, формат, бүтэц, алдаа зохицуулалт зэргийг тогтоосон.
💡 Зүйрлэл: Замын хөдөлгөөний дүрэм шиг — хүн бүр ижил дүрмээр жолоодвол осол бага. Код ч мөн адил — нэгдсэн стандартаар бичвэл алдаа бага, ойлголцох хялбар.
1.8.2 Java-ийн алдартай стандартууд
| Стандарт | Байгууллага | Онцлог |
|---|---|---|
| Google Java Style Guide | Маш дэлгэрэнгүй, өргөн хэрэглэгддэг | |
| Oracle Code Conventions | Oracle (Sun) | Java-ийн албан ёсны стандарт |
| Alibaba Java Coding Guidelines | Alibaba | Алдааны эрсдэлд анхаарсан |
1.8.3 Стандартын жишээ дүрмүүд
// ✅ Нэг мөрд нэг зарлалт
int width;
int height;
// ❌ БУРУУ
int width, height;
// ✅ Braces ашиглах (нэг мөр ч бай)
if (isActive) {
doSomething();
}
// ❌ БУРУУ — Braces-гүй бол ирээдүйд алдаа гарч болно
if (isActive)
doSomething();
// ✅ Magic number ашиглахгүй
private static final int MAX_LOGIN_ATTEMPTS = 5;
if (loginAttempts >= MAX_LOGIN_ATTEMPTS) { ... }
// ❌ БУРУУ
if (loginAttempts >= 5) { ... } // 5 юу вэ?
1.9 Статик анализ (Static Analysis)
Статик анализ гэж юу вэ?
Кодыг АЖИЛЛУУЛАХГҮЙГЭЭР автоматаар шалгаж, алдаа, code smell, аюулгүй байдлын сул тал зэргийг олох.
💡 Зүйрлэл: Эмчид үзүүлэхийн өмнө "эрүүл мэндийн оношилгоо" хийх шиг — кодыг ажиллуулахын өмнө статик анализ нь "оношилгоо" хийнэ.
Алдартай хэрэгслүүд:
| Хэрэгсэл | Зорилго | Тайлбар |
|---|---|---|
| SonarQube | Бүх талын анализ | Code smell, bug, аюулгүй байдал, давхардал, test coverage |
| PMD | Код чанар | Код загварын алдаа, шаардлагагүй код олох |
| CheckStyle | Формат/стиль | Google/Sun style guide-д нийцэж байгаа эсэх |
| SpotBugs | Bug олох | Нийтлэг алдааны загвар олох |
| IntelliJ Inspections | IDE шалгалт | IDE дотор real-time шалгалт |
| Lombok | Boilerplate бууруулах | Getter/Setter автомат үүсгэх |
SonarQube-ийн үндсэн хэмжигдэхүүнүүд:
| Хэмжигдэхүүн | Тайлбар | Сайн утга |
|---|---|---|
| Bugs | Алдааны тоо | 0 |
| Vulnerabilities | Аюулгүй байдлын сул тал | 0 |
| Code Smells | Кодын чанарын асуудал | Бага байх |
| Coverage | Тестийн хамралт | >80% |
| Duplications | Давхардсан кодын хувь | <3% |
| Technical Debt | Техникийн өрийг засах хугацаа | Бага байх |
1.10 Code Review
Code Review гэж юу вэ?
Code Review нь нэг хөгжүүлэгчийн бичсэн кодыг бусад хөгжүүлэгч шалгаж, санал болгож, сайжруулах процесс.
💡 Зүйрлэл: Эссэ бичсний дараа найзаараа уншуулж, алдаа олуулах шиг — Code Review нь кодын "эссэ шалгалт".
Code Review-ийн давуу тал:
| # | Давуу тал | Тайлбар |
|---|---|---|
| 1 | Алдаа олох | Тестэд баригдаагүй алдааг олно |
| 2 | Мэдлэг хуваалцах | Баг бүгд кодыг мэддэг болно |
| 3 | Стандарт баримтлах | Нэгдсэн стиль, чанар |
| 4 | Суралцах | Бие биенээсээ суралцана |
| 5 | Кодын эзэмшил | "Энэ зөвхөн миний код" биш, "МАНАЙ КОД" |
Code Review хийхдээ юуг шалгах вэ?
| Шалгах зүйл | Асуулт |
|---|---|
| Зөв ажиллагаа | Логик зөв үү? Edge case зохицуулсан уу? |
| Нэрлэлт | Нэрс утга учиртай юу? Конвенци баримталсан уу? |
| Бүтэц | Функц жижиг үү? SRP баримталсан уу? |
| Алдаа зохицуулалт | Exception зөв ашигласан уу? Null шалгасан уу? |
| Тест | Шинэ код тестлэгдсэн үү? Edge case тестэлсэн үү? |
| Аюулгүй байдал | SQL injection, XSS зэрэг эрсдэл байна уу? |
| Гүйцэтгэл | N+1 query, шаардлагагүй loop байна уу? |
| DRY | Давхардсан код байна уу? |
Сайн Code Review тайлбар:
// ❌ БУРУУ тайлбар:
"Энэ муу байна"
"Засаарай"
"Яагаад ингэж бичсэн бэ?"
// ✅ ЗӨӨВ тайлбар:
"Энд Optional ашиглавал NullPointerException-ийн эрсдэл буурна.
Жишээ: return Optional.ofNullable(result);"
"Энэ метод 2 зүйл хийж байна (шалгах + хадгалах).
validateStudent() ба saveStudent() гэж хуваах санал."
"nit: studentName → enrolledStudentName гэвэл илүү тодорхой болно."
"nit" = Nitpick (жижиг зүйл) — заавал засах шаардлагагүй, зөвхөн санал.
1.11 Кодын чанарын пирамид
╱╲
╱ ╲
╱ UI ╲ ← Хэрэглэгчийн туршлага
╱──────╲
╱ Тест ╲ ← Автомат тест
╱──────────╲
╱ Code Review╲ ← Багийн шалгалт
╱──────────────╲
╱ Статик анализ ╲ ← Автомат шалгалт
╱──────────────────╲
╱ Кодын стандарт ╲ ← Дүрэм, конвенци
╱──────────────────────╲
╱ Цэвэр код зарчмууд ╲ ← Clean Code
╱────────────────────────────╲
Доороос дээш: Цэвэр код → Стандарт → Статик анализ → Code Review → Тест → UI чанар
1.12 Нийтлэг алдаанууд ба засвар
1.12.1 God Class / God Method
// ❌ БУРУУ — "God Class" — бүхнийг мэддэг, бүхнийг хийдэг
class ApplicationManager {
void createUser() { ... }
void deleteUser() { ... }
void processPayment() { ... }
void generateReport() { ... }
void sendEmail() { ... }
void backupDatabase() { ... }
void handleError() { ... }
// ... 50+ метод
}
// ✅ ЗӨӨВ — Үүргээр хуваах (SRP)
class UserService { ... }
class PaymentService { ... }
class ReportService { ... }
class EmailService { ... }
class BackupService { ... }
1.12.2 Boolean параметр
// ❌ БУРУУ — Boolean параметр нь функцыг 2 зүйл хийхэд хүргэнэ
public void processOrder(Order order, boolean isExpress) {
if (isExpress) {
// Шуурхай боловсруулалт
} else {
// Энгийн боловсруулалт
}
}
// ✅ ЗӨӨВ — Тусдаа функцүүд
public void processStandardOrder(Order order) { ... }
public void processExpressOrder(Order order) { ... }
1.12.3 Гинжин if-else
// ❌ БУРУУ — Гинжин if-else
public double calculateShipping(String type) {
if (type.equals("standard")) {
return 5.0;
} else if (type.equals("express")) {
return 15.0;
} else if (type.equals("overnight")) {
return 25.0;
} else if (type.equals("international")) {
return 50.0;
}
return 0;
}
// ✅ ЗӨӨВ — Enum + Map ашиглах
enum ShippingType {
STANDARD(5.0), EXPRESS(15.0), OVERNIGHT(25.0), INTERNATIONAL(50.0);
private final double cost;
ShippingType(double cost) { this.cost = cost; }
public double getCost() { return cost; }
}
public double calculateShipping(ShippingType type) {
return type.getCost();
}
1.12.4 Hardcoded утга
// ❌ БУРУУ — Hardcoded
if (user.getRole().equals("admin")) { ... }
Thread.sleep(5000);
String url = "http://localhost:8080/api";
// ✅ ЗӨӨВ — Тогтмол / тохиргоо ашиглах
private static final String ADMIN_ROLE = "admin";
private static final long RETRY_DELAY_MS = 5000;
@Value("${api.base-url}")
private String apiBaseUrl;
if (user.getRole().equals(ADMIN_ROLE)) { ... }
Thread.sleep(RETRY_DELAY_MS);
ХЭСЭГ 2: ТҮЛХҮҮР ҮГ БА МЭРГЭЖЛИЙН НЭР ТОМЬЁО (Keywords & Glossary)
| # | Англи нэр томьёо | Монгол утга | Дэлгэрэнгүй тайлбар |
|---|---|---|---|
| 1 | Clean Code | Цэвэр код | Уншихад хялбар, засвар хийхэд тохиромжтой, бүтэц зохион байгуулалттай код. |
| 2 | Code Quality | Кодын чанар | Код зөв, найдвартай, уншигдахуйц, засварлаж болохуйц байх нэгдмэл ойлголт. |
| 3 | Readability | Уншигдах чанар | Бусад хөгжүүлэгч кодыг хялбар уншиж, ойлгож чадах эсэх. |
| 4 | Maintainability | Засварлах чанар | Кодонд өөрчлөлт хийхэд хэр хялбар байх. |
| 5 | Naming Convention | Нэрлэлтийн конвенци | Хувьсагч, метод, классын нэрлэлтийн нэгдсэн дүрэм. |
| 6 | camelCase | Тэмээний хэв | firstWordLower, дараагийнх UPPER: studentName. |
| 7 | PascalCase | Паскаль хэв | EveryWordCapitalized: StudentService. |
| 8 | UPPER_SNAKE_CASE | Дээд могойн хэв | Тогтмол (constant): MAX_RETRY_COUNT. |
| 9 | Side Effect | Гаж нөлөө | Функц нь нэрнээсээ гадуур нуугдмал зүйл хийх. |
| 10 | DRY | Өөрийгөө бүү давт | Don't Repeat Yourself — Ижил логик нэг газар л байх. |
| 11 | KISS | Энгийн байлга | Keep It Simple, Stupid — Хамгийн энгийн шийдлийг сонгох. |
| 12 | YAGNI | Танд хэрэг болохгүй | You Aren't Gonna Need It — Шаардлагагүй зүйл нэмэхгүй. |
| 13 | Magic Number | Шидэт тоо | Нэргүй тоон утга, тогтмолоор солих ёстой. |
| 14 | Boilerplate Code | Давтамжийн код | Олон газар давтагддаг загварчилсан код (getter/setter зэрэг). |
| 15 | Static Analysis | Статик анализ | Кодыг ажиллуулахгүйгээр автоматаар шалгах. |
| 16 | Code Review | Кодын шалгалт | Бусад хөгжүүлэгч кодыг шалгаж, санал болгох процесс. |
| 17 | SonarQube | СонарКьюб | Кодын чанарын платформ — bug, smell, coverage шалгана. |
| 18 | PMD | ПМД | Java кодын статик анализын хэрэгсэл. |
| 19 | CheckStyle | ЧекСтайл | Кодын формат, стилийн дүрэм шалгах хэрэгсэл. |
| 20 | SpotBugs | СпотБагс | Java кодын нийтлэг алдааг олох хэрэгсэл. |
| 21 | Technical Debt | Техникийн өр | Богино хугацааны шийдэл → Ирээдүйд нэмэлт ажил шаардах. |
| 22 | God Class | Бурхан класс | Бүх зүйлийг мэддэг, бүх зүйлийг хийдэг нэг том класс. |
| 23 | Code Smell | Кодын үнэр | Кодын чанарын асуудлыг илтгэх шинж тэмдэг. |
| 24 | Exception Handling | Алдаа зохицуулалт | Алдааг зохицуулах, мэдэгдэх, сэргээх механизм. |
| 25 | Checked Exception | Шалгагддаг алдаа | Компайлер шалгадаг, заавал барих ёстой алдаа. |
| 26 | Unchecked Exception | Шалгагддаггүй алдаа | Runtime-д гарах, барих заавал биш алдаа. |
| 27 | NullPointerException | Null заагчийн алдаа | null утга дээр метод дуудах үед гарах алдаа. |
| 28 | Optional | Заавал биш утга | null-ийн оронд ашигладаг, утга байж ч, байхгүй ч болно. |
| 29 | Coding Standard | Кодын стандарт | Баг/байгууллагын нэгдсэн кодын бичлэгийн дүрэм. |
| 30 | Linter | Линтер | Кодын стиль, формат автоматаар шалгах хэрэгсэл. |
| 31 | Code Coverage | Кодын хамралт | Тестүүд кодын хэдэн хувийг хамарч байгаа. |
| 32 | Cyclomatic Complexity | Цикломатик нарийн байдал | Кодын нөхцөл салаалтын нарийн байдлын хэмжигдэхүүн. |
| 33 | Self-Documenting Code | Өөрийгөө тайлбарладаг код | Нэрлэлт, бүтцээрээ тайлбаргүй ойлгогддог код. |
| 34 | Defensive Programming | Хамгаалалтын программчлал | Алдаа гарч болзошгүй бүх тохиолдлыг урьдчилж шалгах. |
| 35 | Fail Fast | Хурдан бүдрэх | Алдааг аль болох ЭРТ илрүүлж, тодорхой мэдэгдэх. |
| 36 | Guard Clause | Хамгаалалтын нөхцөл | Метод эхэнд буруу оролтыг шалгаж, эрт буцаах. |
| 37 | Single Responsibility | Нэг үүрэг | Нэг класс/метод зөвхөн нэг зүйлийг хариуцах. |
| 38 | Pair Programming | Хосоор программчлах | Хоёр хөгжүүлэгч нэг компьютер дээр хамтран код бичих. |
| 39 | Rubber Duck Debugging | Нугасан дебаг | Асуудлыг бусдад (эсвэл нугасанд) тайлбарлаж, шийдлийг олох арга. |
| 40 | Boy Scout Rule | Скаутын дүрэм | Кодыг олсноосоо илүү цэвэр орхи — жижиг сайжруулалт хий. |