ОНОЛ 06

Кодын Чанар ба Цэвэр Код

ЛЕКЦ 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 зөв ашиглах
6DRYДавхардал байхгүй
7KISSЭнгийн байлга
8YAGNIШаардлагагүй зүйл нэмэхгүй

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()
ХувьсагчcamelCasestudentName, totalAmount
ТогтмолUPPER_SNAKE_CASEMAX_RETRY_COUNT, DEFAULT_TIMEOUT
Packageбүгд жижигcom.company.project.service
InterfacePascalCaseSerializable, PaymentService
EnumPascalCase (нэр), UPPER (утга)enum Color { RED, GREEN, BLUE }
Booleanis/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 Функцийн параметрийн тоо

ТооНэрЗөвлөмж
0Niladic✅ Хамгийн сайн
1Monadic✅ Сайн
2Dyadic⚠️ Болгоомжтой
3Triadic❌ Зайлсхий
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
UncheckedRuntime-д гардаг, барих заавал бишПрограмын алдаа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 GuideGoogleМаш дэлгэрэнгүй, өргөн хэрэглэгддэг
Oracle Code ConventionsOracle (Sun)Java-ийн албан ёсны стандарт
Alibaba Java Coding GuidelinesAlibabaАлдааны эрсдэлд анхаарсан

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-д нийцэж байгаа эсэх
SpotBugsBug олохНийтлэг алдааны загвар олох
IntelliJ InspectionsIDE шалгалтIDE дотор real-time шалгалт
LombokBoilerplate бууруулах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)

#Англи нэр томьёоМонгол утгаДэлгэрэнгүй тайлбар
1Clean CodeЦэвэр кодУншихад хялбар, засвар хийхэд тохиромжтой, бүтэц зохион байгуулалттай код.
2Code QualityКодын чанарКод зөв, найдвартай, уншигдахуйц, засварлаж болохуйц байх нэгдмэл ойлголт.
3ReadabilityУншигдах чанарБусад хөгжүүлэгч кодыг хялбар уншиж, ойлгож чадах эсэх.
4MaintainabilityЗасварлах чанарКодонд өөрчлөлт хийхэд хэр хялбар байх.
5Naming ConventionНэрлэлтийн конвенциХувьсагч, метод, классын нэрлэлтийн нэгдсэн дүрэм.
6camelCaseТэмээний хэвfirstWordLower, дараагийнх UPPER: studentName.
7PascalCaseПаскаль хэвEveryWordCapitalized: StudentService.
8UPPER_SNAKE_CASEДээд могойн хэвТогтмол (constant): MAX_RETRY_COUNT.
9Side EffectГаж нөлөөФункц нь нэрнээсээ гадуур нуугдмал зүйл хийх.
10DRYӨөрийгөө бүү давтDon't Repeat Yourself — Ижил логик нэг газар л байх.
11KISSЭнгийн байлгаKeep It Simple, Stupid — Хамгийн энгийн шийдлийг сонгох.
12YAGNIТанд хэрэг болохгүйYou Aren't Gonna Need It — Шаардлагагүй зүйл нэмэхгүй.
13Magic NumberШидэт тооНэргүй тоон утга, тогтмолоор солих ёстой.
14Boilerplate CodeДавтамжийн кодОлон газар давтагддаг загварчилсан код (getter/setter зэрэг).
15Static AnalysisСтатик анализКодыг ажиллуулахгүйгээр автоматаар шалгах.
16Code ReviewКодын шалгалтБусад хөгжүүлэгч кодыг шалгаж, санал болгох процесс.
17SonarQubeСонарКьюбКодын чанарын платформ — bug, smell, coverage шалгана.
18PMDПМДJava кодын статик анализын хэрэгсэл.
19CheckStyleЧекСтайлКодын формат, стилийн дүрэм шалгах хэрэгсэл.
20SpotBugsСпотБагсJava кодын нийтлэг алдааг олох хэрэгсэл.
21Technical DebtТехникийн өрБогино хугацааны шийдэл → Ирээдүйд нэмэлт ажил шаардах.
22God ClassБурхан классБүх зүйлийг мэддэг, бүх зүйлийг хийдэг нэг том класс.
23Code SmellКодын үнэрКодын чанарын асуудлыг илтгэх шинж тэмдэг.
24Exception HandlingАлдаа зохицуулалтАлдааг зохицуулах, мэдэгдэх, сэргээх механизм.
25Checked ExceptionШалгагддаг алдааКомпайлер шалгадаг, заавал барих ёстой алдаа.
26Unchecked ExceptionШалгагддаггүй алдааRuntime-д гарах, барих заавал биш алдаа.
27NullPointerExceptionNull заагчийн алдааnull утга дээр метод дуудах үед гарах алдаа.
28OptionalЗаавал биш утгаnull-ийн оронд ашигладаг, утга байж ч, байхгүй ч болно.
29Coding StandardКодын стандартБаг/байгууллагын нэгдсэн кодын бичлэгийн дүрэм.
30LinterЛинтерКодын стиль, формат автоматаар шалгах хэрэгсэл.
31Code CoverageКодын хамралтТестүүд кодын хэдэн хувийг хамарч байгаа.
32Cyclomatic ComplexityЦикломатик нарийн байдалКодын нөхцөл салаалтын нарийн байдлын хэмжигдэхүүн.
33Self-Documenting CodeӨөрийгөө тайлбарладаг кодНэрлэлт, бүтцээрээ тайлбаргүй ойлгогддог код.
34Defensive ProgrammingХамгаалалтын программчлалАлдаа гарч болзошгүй бүх тохиолдлыг урьдчилж шалгах.
35Fail FastХурдан бүдрэхАлдааг аль болох ЭРТ илрүүлж, тодорхой мэдэгдэх.
36Guard ClauseХамгаалалтын нөхцөлМетод эхэнд буруу оролтыг шалгаж, эрт буцаах.
37Single ResponsibilityНэг үүрэгНэг класс/метод зөвхөн нэг зүйлийг хариуцах.
38Pair ProgrammingХосоор программчлахХоёр хөгжүүлэгч нэг компьютер дээр хамтран код бичих.
39Rubber Duck DebuggingНугасан дебагАсуудлыг бусдад (эсвэл нугасанд) тайлбарлаж, шийдлийг олох арга.
40Boy Scout RuleСкаутын дүрэмКодыг олсноосоо илүү цэвэр орхи — жижиг сайжруулалт хий.