ЛЕКЦ 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Скаутын дүрэмКодыг олсноосоо илүү цэвэр орхи — жижиг сайжруулалт хий.


ХЭСЭГ 3: ЛАБОРАТОРИ БА ПРАКТИК ЗААВАР (Labs & Step-by-Step Guide)

3.1 Лабораторийн зорилго

Энэ лабораторид та цэвэр код бичих ур чадварыг бодит жишээнүүд дээр дадлагаар эзэмшинэ:

  1. Муу кодыг цэвэр код болгон сайжруулах
  2. Нэрлэлт, функц дизайн, алдаа зохицуулалтыг дадлагажуулах
  3. Кодын чанарын хэрэгсэл (CheckStyle) ашиглах
  4. Code Review хийх

Хэл: Java 17+ | IDE: Eclipse IDE


3.2 Лаб 1: Муу нэрлэлтийг засварлах

Даалгавар: Дараах кодын нэрлэлтийг цэвэр код зарчмаар сайжруулах

ӨМНӨ (Муу нэрлэлт):

public class Mgr {
    private List<int[]> lst = new ArrayList<>();

    public List<int[]> getThm() {
        List<int[]> r = new ArrayList<>();
        for (int[] x : lst) {
            if (x[0] == 4) {
                r.add(x);
            }
        }
        return r;
    }

    public double calc(List<Map<String, Object>> d) {
        double t = 0;
        int c = 0;
        for (Map<String, Object> m : d) {
            double v = (Double) m.get("v");
            t += v;
            c++;
        }
        return c > 0 ? t / c : 0;
    }

    public boolean chk(String s) {
        if (s == null) return false;
        if (s.length() < 8) return false;
        boolean h1 = false, h2 = false, h3 = false;
        for (char c : s.toCharArray()) {
            if (Character.isUpperCase(c)) h1 = true;
            if (Character.isLowerCase(c)) h2 = true;
            if (Character.isDigit(c)) h3 = true;
        }
        return h1 && h2 && h3;
    }
}

ДАРАА (Цэвэр нэрлэлт):

public class GameBoardManager {
    private List<int[]> cells = new ArrayList<>();

    public List<int[]> getFlaggedCells() {
        List<int[]> flaggedCells = new ArrayList<>();
        for (int[] cell : cells) {
            if (cell[STATUS_INDEX] == FLAGGED) {
                flaggedCells.add(cell);
            }
        }
        return flaggedCells;
    }

    public double calculateAverage(List<Map<String, Object>> dataPoints) {
        double totalValue = 0;
        int count = 0;
        for (Map<String, Object> dataPoint : dataPoints) {
            double value = (Double) dataPoint.get("value");
            totalValue += value;
            count++;
        }
        return count > 0 ? totalValue / count : 0;
    }

    public boolean isPasswordStrong(String password) {
        if (password == null) return false;
        if (password.length() < MIN_PASSWORD_LENGTH) return false;

        boolean hasUpperCase = false;
        boolean hasLowerCase = false;
        boolean hasDigit = false;

        for (char character : password.toCharArray()) {
            if (Character.isUpperCase(character)) hasUpperCase = true;
            if (Character.isLowerCase(character)) hasLowerCase = true;
            if (Character.isDigit(character)) hasDigit = true;
        }
        return hasUpperCase && hasLowerCase && hasDigit;
    }

    private static final int STATUS_INDEX = 0;
    private static final int FLAGGED = 4;
    private static final int MIN_PASSWORD_LENGTH = 8;
}

Сайжруулсан зүйлс:

#ӨмнөДарааАшигласан зарчим
1MgrGameBoardManagerУтга учиртай класс нэр
2lst, r, xcells, flaggedCells, cellУтга учиртай хувьсагч нэр
3getThm()getFlaggedCells()Метод зорилгоо илэрхийлэх
4calc()calculateAverage()Тодорхой метод нэр
5chk()isPasswordStrong()Boolean конвенци (is + тэмдэг нэр)
64, 8FLAGGED, MIN_PASSWORD_LENGTHMagic number → Тогтмол
7h1, h2, h3hasUpperCase, hasLowerCase, hasDigitBoolean хувьсагчийн нэрлэлт

3.3 Лаб 2: Функц дизайн — Нэг функц, нэг зүйл

Даалгавар: Дараах том функцыг жижиг, нэг зорилготой функцүүдэд хуваах

ӨМНӨ (Нэг том функц):

public class OrderProcessor {

    public String processOrder(String customerName, String email,
                               List<String> items, List<Double> prices,
                               String cardNumber, boolean isVIP) {
        // 1. Шалгах
        if (customerName == null || customerName.isEmpty()) {
            return "ERROR: Хэрэглэгчийн нэр хоосон";
        }
        if (email == null || !email.contains("@")) {
            return "ERROR: Имэйл буруу";
        }
        if (items.size() != prices.size()) {
            return "ERROR: Бүтээгдэхүүн ба үнэ тохирохгүй";
        }
        if (items.isEmpty()) {
            return "ERROR: Сагс хоосон";
        }

        // 2. Үнэ тооцоолох
        double total = 0;
        for (int i = 0; i < items.size(); i++) {
            total += prices.get(i);
        }

        // 3. Хөнгөлөлт
        double discount = 0;
        if (isVIP) {
            discount = total * 0.15;
        } else if (total > 100000) {
            discount = total * 0.05;
        }
        total = total - discount;

        // 4. Татвар
        double tax = total * 0.1;
        total = total + tax;

        // 5. Төлбөр
        if (cardNumber == null || cardNumber.length() != 16) {
            return "ERROR: Картын дугаар буруу";
        }
        System.out.println("Төлбөр боловсруулж байна: " + cardNumber);

        // 6. Баримт
        StringBuilder receipt = new StringBuilder();
        receipt.append("=== БАРИМТ ===\n");
        receipt.append("Хэрэглэгч: ").append(customerName).append("\n");
        for (int i = 0; i < items.size(); i++) {
            receipt.append(items.get(i)).append(": ")
                   .append(prices.get(i)).append("₮\n");
        }
        receipt.append("Хөнгөлөлт: -").append(discount).append("₮\n");
        receipt.append("Татвар: +").append(tax).append("₮\n");
        receipt.append("Нийт: ").append(total).append("₮\n");

        // 7. Имэйл илгээх
        System.out.println(email + " руу баримт илгээсэн");

        return receipt.toString();
    }
}

ДАРАА (Цэвэр функц дизайн):

public class OrderProcessor {

    private static final double VIP_DISCOUNT_RATE = 0.15;
    private static final double BULK_DISCOUNT_RATE = 0.05;
    private static final double BULK_THRESHOLD = 100_000;
    private static final double TAX_RATE = 0.10;
    private static final int CARD_NUMBER_LENGTH = 16;

    private final PaymentService paymentService;
    private final EmailService emailService;

    public OrderProcessor(PaymentService paymentService, EmailService emailService) {
        this.paymentService = paymentService;
        this.emailService = emailService;
    }

    public OrderResult processOrder(OrderRequest request) {
        validateOrder(request);
        OrderSummary summary = calculateOrderSummary(request);
        paymentService.charge(request.getCardNumber(), summary.getTotal());
        String receipt = generateReceipt(request, summary);
        emailService.sendReceipt(request.getEmail(), receipt);
        return new OrderResult(true, receipt);
    }

    private void validateOrder(OrderRequest request) {
        if (request.getCustomerName() == null || request.getCustomerName().isEmpty()) {
            throw new ValidationException("Хэрэглэгчийн нэр хоосон");
        }
        if (request.getEmail() == null || !request.getEmail().contains("@")) {
            throw new ValidationException("Имэйл буруу");
        }
        if (request.getItems().isEmpty()) {
            throw new ValidationException("Сагс хоосон");
        }
        if (request.getCardNumber() == null ||
            request.getCardNumber().length() != CARD_NUMBER_LENGTH) {
            throw new ValidationException("Картын дугаар буруу");
        }
    }

    private OrderSummary calculateOrderSummary(OrderRequest request) {
        double subtotal = calculateSubtotal(request.getItems());
        double discount = calculateDiscount(subtotal, request.isVIP());
        double taxableAmount = subtotal - discount;
        double tax = taxableAmount * TAX_RATE;
        double total = taxableAmount + tax;
        return new OrderSummary(subtotal, discount, tax, total);
    }

    private double calculateSubtotal(List<OrderItem> items) {
        return items.stream()
            .mapToDouble(OrderItem::getPrice)
            .sum();
    }

    private double calculateDiscount(double subtotal, boolean isVIP) {
        if (isVIP) return subtotal * VIP_DISCOUNT_RATE;
        if (subtotal > BULK_THRESHOLD) return subtotal * BULK_DISCOUNT_RATE;
        return 0;
    }

    private String generateReceipt(OrderRequest request, OrderSummary summary) {
        StringBuilder receipt = new StringBuilder();
        receipt.append("=== БАРИМТ ===\n");
        receipt.append("Хэрэглэгч: ").append(request.getCustomerName()).append("\n");
        for (OrderItem item : request.getItems()) {
            receipt.append(item.getName()).append(": ")
                   .append(String.format("%.0f₮", item.getPrice())).append("\n");
        }
        receipt.append(String.format("Хөнгөлөлт: -%.0f₮\n", summary.getDiscount()));
        receipt.append(String.format("Татвар: +%.0f₮\n", summary.getTax()));
        receipt.append(String.format("Нийт: %.0f₮\n", summary.getTotal()));
        return receipt.toString();
    }
}

Сайжруулсан зүйлс:

#ЗарчимТайлбар
1Нэг функц — Нэг зүйлprocessOrder → validate, calculate, pay, receipt, email
2Parameter Object6 параметр → OrderRequest объект
3Magic Number арилгасан0.15, 0.05, 100000 → Тогтмол
4Return code → Exception"ERROR:" string → ValidationException
5Dependency InjectionPaymentService, EmailService тусгаарлагдсан

3.4 Лаб 3: Алдаа зохицуулалт сайжруулах

Даалгавар: Null шалгалт, Exception зохицуулалтыг Clean Code зарчмаар сайжруулах

ӨМНӨ (Муу алдаа зохицуулалт):

public class StudentService {

    public String getStudentInfo(long id) {
        try {
            Student student = repository.findById(id);
            if (student == null) {
                return null;
            }
            String name = student.getName();
            if (name == null) {
                name = "Unknown";
            }
            Address addr = student.getAddress();
            String city = "";
            if (addr != null) {
                city = addr.getCity();
                if (city == null) {
                    city = "Unknown";
                }
            }
            return name + " - " + city;
        } catch (Exception e) {
            System.out.println("error");
            return null;
        }
    }

    public int divide(int a, int b) {
        return a / b;  // ArithmeticException if b == 0
    }
}

ДАРАА (Цэвэр алдаа зохицуулалт):

public class StudentService {

    private static final Logger log = LoggerFactory.getLogger(StudentService.class);

    public StudentInfo getStudentInfo(long id) {
        Student student = findStudentOrThrow(id);
        String name = student.getNameOrDefault("Нэргүй");
        String city = extractCity(student).orElse("Хотгүй");
        return new StudentInfo(name, city);
    }

    private Student findStudentOrThrow(long id) {
        return repository.findById(id)
            .orElseThrow(() -> {
                log.warn("Оюутан олдсонгүй: id={}", id);
                return new StudentNotFoundException("ID=" + id + " оюутан олдсонгүй");
            });
    }

    private Optional<String> extractCity(Student student) {
        return Optional.ofNullable(student.getAddress())
            .map(Address::getCity);
    }

    public int divideSafe(int dividend, int divisor) {
        if (divisor == 0) {
            throw new IllegalArgumentException(
                "Хуваагч 0 байж болохгүй. Хуваагдагч: " + dividend
            );
        }
        return dividend / divisor;
    }
}

Сайжруулсан зүйлс:

#ЗарчимТайлбар
1Optional ашиглахnull шалгалтыг Optional-оор солих
2Тодорхой ExceptionExceptionStudentNotFoundException
3Logger ашиглахSystem.out.println → Logger
4Guard ClausedivideSafe() — оролтыг эрт шалгах
5Утга учиртай мессеж"error" → "ID=1 оюутан олдсонгүй"

3.5 Лаб 4: Code Review дадлага

Даалгавар: Дараах кодыг Code Review хийж, асуудлуудыг олж, засварын санал бичих

Шалгах код:

public class u {
    String n;
    String e;
    int a;
    String p;

    public boolean l(String un, String pw) {
        if (un.equals(n) && pw.equals(p)) {
            System.out.println("ok");
            return true;
        } else {
            System.out.println("fail");
            return false;
        }
    }

    public void r(String n, String e, int a, String p) {
        this.n = n;
        this.e = e;
        this.a = a;
        this.p = p;
    }

    public String info() {
        return n + "," + e + "," + a;
    }
}

Code Review тайлбарууд:

#МөрАсуудалСанал
1class uМуу нэрлэлтclass User — PascalCase, тодорхой нэр
2String n, e, pНэргүй талбарname, email, password
3int aТодорхойгүйint age
4public талбаруудEncapsulation зөрчилprivate + getter/setter
5l() методМуу нэрlogin()
6r() методМуу нэрregister()
7pw.equals(p)Нууц үг шифрлэлтгүйХэзээ ч plain text нууц үг хадгалахгүй
8un.equals(n)NullPointerExceptionObjects.equals() эсвэл null шалгах
9System.out.printlnLogger ашиглахгүйlog.info() ашиглах
10Validation байхгүйОролт шалгаагүйEmail формат, нас зэрэг шалгах
11info() муу нэрТодорхойгүйgetFormattedInfo()
12"," hardcodedMagic stringТогтмол ашиглах

Засварласан код:

public class User {
    private String name;
    private String email;
    private int age;
    private String passwordHash;

    private static final Logger log = LoggerFactory.getLogger(User.class);

    public boolean login(String inputName, String inputPassword) {
        Objects.requireNonNull(inputName, "Нэр null байж болохгүй");
        Objects.requireNonNull(inputPassword, "Нууц үг null байж болохгүй");

        boolean isValid = inputName.equals(this.name)
            && PasswordEncoder.matches(inputPassword, this.passwordHash);

        if (isValid) {
            log.info("Амжилттай нэвтэрлэв: {}", inputName);
        } else {
            log.warn("Нэвтрэлт амжилтгүй: {}", inputName);
        }
        return isValid;
    }

    public void register(String name, String email, int age, String password) {
        validateRegistration(name, email, age, password);
        this.name = name;
        this.email = email;
        this.age = age;
        this.passwordHash = PasswordEncoder.encode(password);
        log.info("Шинэ хэрэглэгч бүртгэгдлээ: {}", name);
    }

    private void validateRegistration(String name, String email, int age, String password) {
        if (name == null || name.isBlank()) {
            throw new ValidationException("Нэр хоосон байж болохгүй");
        }
        if (email == null || !email.contains("@")) {
            throw new ValidationException("Имэйл буруу формат");
        }
        if (age < 1 || age > 150) {
            throw new ValidationException("Нас 1-150 хооронд байх ёстой");
        }
        if (password == null || password.length() < 8) {
            throw new ValidationException("Нууц үг 8+ тэмдэгттэй байх ёстой");
        }
    }

    public String getFormattedInfo() {
        return String.format("%s (%s, %d нас)", name, email, age);
    }

    // Getter методууд
    public String getName() { return name; }
    public String getEmail() { return email; }
    public int getAge() { return age; }
}


ХЭСЭГ 4: ШАЛГАЛТЫН АСУУЛТ (Knowledge Check — 100 тест)

Тест 1

"Цэвэр код" (Clean Code) гэж юу вэ?

  • A) Хурдан ажилладаг код
  • B) Бусад хөгжүүлэгч хялбараар уншиж, ойлгож, өөрчилж чаддаг код
  • C) Тайлбар маш их бүхий код
  • D) Нэг мөрөнд бичсэн код

Зөв хариулт: B

Тайлбар: Robert C. Martin-ий тодорхойлолтоор цэвэр код нь уншигдахуйц, ойлгомжтой, засварлахад хялбар байх ёстой. Зөвхөн хурдан биш — УНШИХАД хялбар.

Тест 2

Хөгжүүлэгч цагийнхаа хэдэн хувийг КОД УНШИХАД зарцуулдаг вэ?

  • A) ~10%
  • B) ~30%
  • C) ~50%
  • D) ~70%

Зөв хариулт: D

Тайлбар: Судалгаагаар хөгжүүлэгч цагийнхаа ~70%-ийг код уншихад, зөвхөн ~30%-ийг бичихэд зарцуулдаг. Тиймээс уншигдах чанар маш чухал.

Тест 3

DRY зарчим юу гэсэн утгатай вэ?

  • A) Do Repeat Yourself
  • B) Don't Repeat Yourself — Өөрийгөө бүү давт
  • C) Delete Repeated YAML
  • D) Debug Run Yesterday

Зөв хариулт: B

Тайлбар: DRY = Ижил логик нэг газар л байх. Давхардсан код → Нэг газар засвал, бусад газрыг мартана → Алдаа.

Тест 4

KISS зарчим юу гэсэн утгатай вэ?

  • A) Keep It Safe and Secure
  • B) Keep It Simple, Stupid — Энгийн байлга
  • C) Know It, Solve it, Ship it
  • D) Keep Iterating Software Solutions

Зөв хариулт: B

Тайлбар: KISS = Хамгийн энгийн шийдлийг сонгох. Нарийн төвөгтэй шийдэл ≠ Сайн шийдэл. Энгийн код = Ойлгомжтой + Алдаа бага.

Тест 5

YAGNI зарчим юу гэсэн утгатай вэ?

  • A) You Are Getting New Ideas
  • B) You Aren't Gonna Need It — Танд хэрэг болохгүй
  • C) Your Application Gets New Interfaces
  • D) Yet Another Great New Invention

Зөв хариулт: B

Тайлбар: YAGNI = Одоо хэрэггүй зүйлийг НЭМЭХГҮЙ. "Ирээдүйд хэрэг болно" гэж бодож шаардлагагүй функц нэмэх нь code bloat үүсгэнэ.

Тест 6

Дараах аль нь ЗӨӨВ нэрлэлт вэ?

  • A) int d;
  • B) int daysSinceLastLogin;
  • C) int x;
  • D) int temp;

Зөв хариулт: B

Тайлбар: daysSinceLastLogin нь юу хадгалж байгааг тодорхой хэлж байна. d, x, temp нь утга учирыг илэрхийлэхгүй.

Тест 7

Java-д класс нэрлэхэд ямар конвенци ашигладаг вэ?

  • A) camelCase
  • B) PascalCase
  • C) UPPER_SNAKE_CASE
  • D) kebab-case

Зөв хариулт: B

Тайлбар: Java класс = PascalCase (UpperCamelCase). Жишээ: StudentService, OrderProcessor. Нэр үг ашиглана.

Тест 8

Java-д тогтмол (constant) нэрлэхэд ямар конвенци ашигладаг вэ?

  • A) camelCase
  • B) PascalCase
  • C) UPPER_SNAKE_CASE
  • D) lowercase

Зөв хариулт: C

Тайлбар: Java constant = UPPER_SNAKE_CASE. Жишээ: MAX_RETRY_COUNT, DEFAULT_TIMEOUT. static final хувьсагчид ашиглана.

Тест 9

Boolean хувьсагчийн зөв нэрлэлт аль нь вэ?

  • A) boolean flag;
  • B) boolean isActive;
  • C) boolean status;
  • D) boolean value;

Зөв хариулт: B

Тайлбар: Boolean хувьсагч нь is/has/can + тэмдэг нэр: isActive, hasPermission, canDelete. flag, status нь тодорхойгүй.

Тест 10

"Magic Number" гэж юу вэ?

  • A) Тоон хувьсагч
  • B) Кодонд нэргүй шууд бичигдсэн тоон утга — юу гэсэн утга нь мэдэгдэхгүй
  • C) Тогтмол хувьсагч
  • D) Enum утга

Зөв хариулт: B

Тайлбар: if (age >= 18) — 18 юу вэ? Magic number! if (age >= LEGAL_AGE) — тодорхой. Тогтмолоор солих ёстой.

Тест 11

Функцийн эхний дүрэм юу вэ (Robert C. Martin-ий зарчмаар)?

  • A) Хурдан ажиллах
  • B) ЖИЖИГ байх
  • C) Олон параметртэй байх
  • D) Тайлбар ихтэй байх

Зөв хариулт: B

Тайлбар: "Функцийн эхний дүрэм — ЖИЖИГ байх. Хоёр дахь дүрэм — БҮҮР ЖИЖИГ байх." Нэг функц нэг зүйл хийх.

Тест 12

Функцийн параметрийн хамгийн сайн тоо хэд вэ?

  • A) 5
  • B) 0 (niladic)
  • C) 3
  • D) 10

Зөв хариулт: B

Тайлбар: 0 параметр хамгийн сайн, 1-2 зүгээр, 3+ нь олон → Объект (Parameter Object) ашиглах.

Тест 13

"Side Effect" гэж юу вэ?

  • A) Функцийн буцаах утга
  • B) Функц нь нэрнээсээ гадуур нуугдмал зүйл хийх
  • C) Функцийн параметр
  • D) Exception шидэх

Зөв хариулт: B

Тайлбар: checkPassword() функц дотор Session.initialize() хийх = Side Effect. Нэрнээс мэдэгдэхгүй, нуугдмал зүйл. Тусдаа функц болгох ёстой.

Тест 14

Дараах аль тайлбар нь ЗӨӨВ вэ?

  • A) // i-г нэгээр нэмэх (i++ мөрний дээр)
  • B) // Хувийн мэдээлэл хамгаалах хуулийн 15.3 заалтын дагуу
  • C) // Default constructor
  • D) // Хэрэглэгчийн нэрийг буцаана (getEmail() дээр)

Зөв хариулт: B

Тайлбар: Хуулийн шаардлага тайлбарлах = Сайн тайлбар. Код юу хийж байгааг давтах, хуучирсан тайлбар, шаардлагагүй тайлбар = Муу тайлбар.

Тест 15

"Код өөрөө тайлбарлагдах ёстой" (Self-Documenting Code) гэж юу гэсэн утгатай вэ?

  • A) Тайлбар хэзээ ч бичэхгүй
  • B) Нэрлэлт, бүтцээрээ тайлбаргүйгээр ойлгогддог код бичих
  • C) Бүх мөрд тайлбар бичих
  • D) README файл бичих

Зөв хариулт: B

Тайлбар: Сайн нэрлэлт + цэвэр бүтэц = тайлбар шаардлагагүй. isEligibleForAccess(user) нь chk(u)-аас ХАВЬГҮЙ ойлгомжтой.

Тест 16

Нэг мөрийн урт хэдэн тэмдэгтээс хэтрэхгүй байх ёстой вэ?

  • A) 50
  • B) 80-120
  • C) 200
  • D) Хязгааргүй

Зөв хариулт: B

Тайлбар: Ихэнх стандарт 80-120 тэмдэгт зөвлөдөг. Хэт урт мөр = Хажуу тийш scroll хийх → Уншихад хэцүү.

Тест 17

Exception ашиглах нь return code (эрроор код)-аас яагаад дээр вэ?

  • A) Хурдан
  • B) Алдааны утга тодорхой, заавал зохицуулах, тусдаа flow
  • C) Бичихэд богино
  • D) Санах ой бага зарцуулна

Зөв хариулт: B

Тайлбар: Return code (-1, -2) — юу гэсэн утга вэ? Exception = Тодорхой нэр (InsufficientFundsException), заавал зохицуулах, callstack мэдээлэл.

Тест 18

Checked Exception ба Unchecked Exception-ийн ялгаа юу вэ?

  • A) Ялгаагүй
  • B) Checked-ийг компайлер шалгаж, заавал барих шаарддаг. Unchecked нь Runtime-д гардаг
  • C) Unchecked-ийг заавал барих
  • D) Checked нь хурдан

Зөв хариулт: B

Тайлбар: Checked = IOException, заавал try-catch. Unchecked = NullPointerException, RuntimeException удамшил, барих заавал биш.

Тест 19

Optional юу хийдэг вэ?

  • A) Код хурдасгадаг
  • B) null-ийн оронд ашиглаж, NullPointerException-ийн эрсдэлийг бууруулдаг
  • C) Exception шиддэг
  • D) Тайлбар нэмдэг

Зөв хариулт: B

Тайлбар: Optional<Student> = Утга байж ч, байхгүй ч болно. .orElseThrow(), .ifPresent() зэргээр аюулгүй null шалгалт хийнэ.

Тест 20

God Class гэж юу вэ?

  • A) Хамгийн сайн класс
  • B) Бүхнийг мэддэг, бүхнийг хийдэг нэг том класс — SRP зөрчилдсөн
  • C) Abstract класс
  • D) Interface

Зөв хариулт: B

Тайлбар: God Class = ApplicationManager дотор user, payment, email, report, backup бүгдийг хийдэг. SRP зөрчил → Үүргээр хуваах ёстой.

Тест 21

SonarQube юу хийдэг вэ?

  • A) Код бичих
  • B) Кодын чанарын бүх талын статик анализ — bug, smell, coverage, давхардал шалгах
  • C) Тест ажиллуулах
  • D) Deploy хийх

Зөв хариулт: B

Тайлбар: SonarQube = Кодын чанарын платформ. Bug, Code Smell, Vulnerability, Coverage, Duplication зэргийг автоматаар шалгана. Dashboard-аар харуулна.

Тест 22

Code Review-ийн гол зорилго юу вэ?

  • A) Зөвхөн алдаа олох
  • B) Алдаа олох, мэдлэг хуваалцах, кодын чанар сайжруулах, нэгдмэл стиль
  • C) Код устгах
  • D) Зөвхөн формат шалгах

Зөв хариулт: B

Тайлбар: Code Review = Олон зорилготой: Алдаа + Мэдлэг хуваалцах + Чанар + Стиль. Баг бүхэлдээ суралцана.

Тест 23

"nit" гэж Code Review-д юу гэсэн утгатай вэ?

  • A) Заавал засах ёстой алдаа
  • B) Жижиг зүйл (nitpick) — заавал засах шаардлагагүй, зөвхөн санал
  • C) Том алдаа
  • D) Аюулгүй байдлын асуудал

Зөв хариулт: B

Тайлбар: "nit: studentName → enrolledStudentName гэвэл илүү тодорхой" — Жижиг санал, заавал биш. Reviewer нь ялгааг ойлгуулахад ашиглана.

Тест 24

"Boy Scout Rule" гэж юу вэ?

  • A) Код бүгдийг устгах
  • B) Кодыг олсноосоо илүү цэвэр орхих — жижиг сайжруулалт хий
  • C) Код хэзээ ч өөрчлөхгүй
  • D) Зөвхөн шинэ код бичих

Зөв хариулт: B

Тайлбар: Boy Scout Rule = "Хотыг олсноосоо цэвэрхэн орхи." Муу нэр олвол засах, magic number олвол тогтмол болгох. Жижиг, тогтмол сайжруулалт.

Тест 25

Дараах кодын асуудал юу вэ?

public void processOrder(Order order, boolean isExpress) {
    if (isExpress) { /* шуурхай */ }
    else { /* энгийн */ }
}
  • A) Асуудалгүй
  • B) Boolean параметр — функцыг 2 зүйл хийхэд хүргэж байна
  • C) Нэрлэлт буруу
  • D) Return утга байхгүй

Зөв хариулт: B

Тайлбар: Boolean параметр = Функц 2 зүйл хийж байна → processStandardOrder(), processExpressOrder() гэж хуваах.

Тест 26

Дараах аль нь "Fail Fast" зарчим вэ?

  • A) Алдааг нуух
  • B) Оролтыг метод эхэнд шалгаж, буруу бол шууд Exception шидэх
  • C) Алдааг дуусгалд л шалгах
  • D) Алдааг үл тоомсорлох

Зөв хариулт: B

Тайлбар: Fail Fast = Guard Clause. Метод эхэнд if (input == null) throw new ... → Алдаа ЭРТ илэрнэ, дебаг хялбар.

Тест 27

Guard Clause гэж юу вэ?

  • A) Try-catch блок
  • B) Метод эхэнд буруу оролтыг шалгаж, эрт буцаах/Exception шидэх
  • C) Finally блок
  • D) Бүх мөрд null шалгах

Зөв хариулт: B

Тайлбар: Guard Clause = Метод эхэнд оролтыг шалгаж, буруу бол цааш явахгүй. Nested if бууруулна, код уншигдах чанар сайжирна.

Тест 28

Дараах кодын аль нь зөв вэ?

// A:
if (loginAttempts >= 5) { lockAccount(); }
// B:
if (loginAttempts >= MAX_LOGIN_ATTEMPTS) { lockAccount(); }
  • A) A зөв
  • B) B зөв — тогтмол ашигласан, magic number арилгасан
  • C) Хоёулаа зөв
  • D) Хоёулаа буруу

Зөв хариулт: B

Тайлбар: 5 = Magic number (юу гэсэн утга вэ?). MAX_LOGIN_ATTEMPTS = Утга тодорхой, нэг газар солиход хангалттай.

Тест 29

Cyclomatic Complexity гэж юу вэ?

  • A) Кодын мөрийн тоо
  • B) Кодын нөхцөл салаалтын (if, switch, loop) нарийн байдлын хэмжигдэхүүн
  • C) Кодын хурд
  • D) Кодын хэмжээ

Зөв хариулт: B

Тайлбар: Cyclomatic Complexity = if, switch, for, while зэрэг нөхцөл бүр +1. Өндөр CC = Тестлэхэд хэцүү, алдаа ихтэй. 10-аас бага байх зөвлөмжтэй.

Тест 30

Статик анализ гэж юу вэ?

  • A) Кодыг ажиллуулж тестлэх
  • B) Кодыг АЖИЛЛУУЛАХГҮЙГЭЭР автоматаар шалгах
  • C) Гараар код уншиж шалгах
  • D) Deploy хийх

Зөв хариулт: B

Тайлбар: Статик анализ = Код ажиллуулахгүйгээр алдаа, code smell, аюулгүй байдлын сул талыг олно. SonarQube, PMD, CheckStyle зэрэг хэрэгсэл.

Тест 31

Дараах аль нь .gitignore-д БИЧИХГҮЙ?

  • A) .class файлууд
  • B) .idea/ хавтас
  • C) Student.java — Эх код
  • D) .env файл

Зөв хариулт: C

Тайлбар: Эх код (.java) нь Git-д ЗААВАЛ байх ёстой. .class (compiled), .idea/ (IDE), .env (нууц) → .gitignore-д.

Тест 32

"Technical Debt" гэж юу вэ?

  • A) Мөнгөний өр
  • B) Богино хугацааны хялбар шийдэл → Ирээдүйд нэмэлт засвар, ажил шаардах
  • C) Кодын хэмжээ
  • D) Тестийн тоо

Зөв хариулт: B

Тайлбар: Technical Debt = "Одоо хурдан хийе, дараа засна" → "Дараа" хэзээ ч ирэхгүй → Код улам муудна. Тогтмол засах нь чухал.

Тест 33

CheckStyle хэрэгсэл юу шалгадаг вэ?

  • A) Кодын хурд
  • B) Кодын формат, стиль — нэрлэлтийн конвенци, мөрийн урт, braces зэрэг
  • C) Кодын логик алдаа
  • D) Кодын аюулгүй байдал

Зөв хариулт: B

Тайлбар: CheckStyle = Google/Sun Java Style Guide-д нийцэж байгаа эсэхийг шалгана: нэрлэлт, indentation, мөрийн урт, braces, import дараалал.

Тест 34

Дараах аль нь ЗӨӨВ алдааны мессеж вэ?

  • A) throw new RuntimeException("Error");
  • B) throw new RuntimeException("Invalid");
  • C) throw new StudentNotFoundException("ID=5 оюутан олдсонгүй");
  • D) throw new RuntimeException("");

Зөв хариулт: C

Тайлбар: Утга учиртай, тодорхой мессеж → Дебаг хялбар. "Error", "Invalid" → Юуны алдаа, хаана, яагаад мэдэхгүй.

Тест 35

"Defensive Programming" гэж юу вэ?

  • A) Зөвхөн тест бичих
  • B) Алдаа гарч болзошгүй бүх тохиолдлыг урьдчилж шалгах, хамгаалах
  • C) Код нуух
  • D) Зөвхөн try-catch ашиглах

Зөв хариулт: B

Тайлбар: Defensive Programming = Оролтыг шалгах, null шалгах, хязгаар шалгах — "Юу ч буруу байж болно" гэж бодож код бичих. Бат бөх код.

Тест 36

Дараах кодын хамгийн том асуудал юу вэ?

public void handle() { ... }
public Object get() { ... }
public boolean check(Student s) { ... }
  • A) Асуудалгүй
  • B) Метод нэрс тодорхойгүй — юу хийдэг нь мэдэгдэхгүй
  • C) Return утга буруу
  • D) Параметр олон

Зөв хариулт: B

Тайлбар: handle() юу handle хийх вэ? get() юу авах вэ? check() юу шалгах вэ? → handlePaymentTimeout(), findStudentById(), isEligibleForScholarship().

Тест 37

Нэг файлд хэдэн мөр код байх нь тохиромжтой вэ?

  • A) 10-50
  • B) 200-500
  • C) 1000-5000
  • D) Хязгааргүй

Зөв хариулт: B

Тайлбар: Нэг файлд 200-500 мөр тохиромжтой. Хэт богино = Хэт олон файл. Хэт урт = God Class шинж. Clean Code = Тохиромжтой хэмжээ.

Тест 38

Дараах кодын асуудал юу вэ?

if (isActive)
    doSomething();
  • A) Асуудалгүй
  • B) Braces ({}) байхгүй — ирээдүйд мөр нэмэхэд алдаа гарч болно
  • C) Нэрлэлт буруу
  • D) Return утга байхгүй

Зөв хариулт: B

Тайлбар: Braces-гүй бол дараа нь мөр нэмэхэд if-ийн гадна бичигдэж, logical алдаа гарна. ЯМАГТ { } ашиглах.

Тест 39

Кодын чанарын пирамидын хамгийн доод (суурь) давхарга юу вэ?

  • A) Тест
  • B) UI чанар
  • C) Цэвэр код зарчмууд
  • D) Статик анализ

Зөв хариулт: C

Тайлбар: Суурь → Дээш: Цэвэр код → Стандарт → Статик анализ → Code Review → Тест → UI. Суурь бат бол дээрх давхаргууд сайн.

Тест 40

PMD хэрэгсэл юу хийдэг вэ?

  • A) Код форматлах
  • B) Кодын загварын алдаа, шаардлагагүй код, нарийн байдлын асуудал олох
  • C) Тест ажиллуулах
  • D) Deploy хийх

Зөв хариулт: B

Тайлбар: PMD = Java кодын статик анализ. Unused variable, empty catch, unnecessary code зэргийг олно. Кодын чанарын "эрт анхааруулга".

Тест 41

SpotBugs хэрэгсэл юу хийдэг вэ?

  • A) Формат шалгах
  • B) Java байткод анализаар нийтлэг bug загвар олох
  • C) Тест бичих
  • D) Код компайлдах

Зөв хариулт: B

Тайлбар: SpotBugs (FindBugs-ийн залгамжлагч) = Compiled байткодыг шалгаж, null dereference, infinite loop, resource leak зэрэг нийтлэг bug олно.

Тест 42

Code Coverage 80% гэдэг юу гэсэн утгатай вэ?

  • A) 80% функц бичигдсэн
  • B) Тестүүд кодын 80%-ийг ажиллуулж шалгасан
  • C) 80% алдаа олдсон
  • D) 80% хөгжүүлэгч тест бичсэн

Зөв хариулт: B

Тайлбар: Code Coverage = Тестүүд кодын ямар хувийг "ажиллуулж" шалгасан. 80%+ нь ерөнхий зөвлөмж. 100% нь бодит бус зорилт.

Тест 43

"Pair Programming" гэж юу вэ?

  • A) Хоёр хөгжүүлэгч тус тусдаа ажиллах
  • B) Хоёр хөгжүүлэгч нэг компьютер дээр хамтран код бичих — нэг нь бичих, нөгөө нь шалгах
  • C) Хоёр тест бичих
  • D) Хоёр branch ашиглах

Зөв хариулт: B

Тайлбар: Pair Programming = Driver (бичих) + Navigator (шалгах, чиглүүлэх). Алдаа бага, мэдлэг хуваалцах, кодын чанар сайн.

Тест 44

"Rubber Duck Debugging" гэж юу вэ?

  • A) Нугас хэлбэрийн хэрэгсэл ашиглах
  • B) Асуудлыг бусдад (эсвэл нугасанд) тайлбарлахад шийдэл олдох
  • C) Кодыг устгах
  • D) Тест ажиллуулах

Зөв хариулт: B

Тайлбар: Асуудлыг тайлбарлах явцад тархи зөв бодол дагуулж, шийдлийг ӨӨРӨӨ олдог. Бусад хүнд (эсвэл нугасанд) тайлбарлах = Маш үр дүнтэй дебаг арга.

Тест 45

Дараах аль нь encapsulation зөрчил вэ?

  • A) private String name;
  • B) public String name; (getter/setter-гүй шууд хандалт)
  • C) protected String name;
  • D) Бүгд зөрчил

Зөв хариулт: B

Тайлбар: public талбар = Гаднаас шууд хандаж, өөрчилж болно → Хяналтгүй. private + getter/setter = Encapsulation. Validation нэмэх боломжтой.

Тест 46

Дараах кодын асуудал юу вэ?

catch (Exception e) {
    // do nothing
}
  • A) Асуудалгүй
  • B) Алдааг "залгидаг" — асуудал нуугдаж, дебаг хэцүүдэнэ
  • C) Хурдан ажилладаг
  • D) Зөв арга

Зөв хариулт: B

Тайлбар: Хоосон catch = Алдааг "залгих" → Асуудал нуугдана, хожим арай том асуудал болж гарна. НААД зах нь log бичих, эсвэл дахин шидэх.

Тест 47

Дараах аль нь Parameter Object загвар вэ?

  • A) void create(String a, String b, int c, String d, double e)
  • B) void create(StudentDTO dto) — олон параметрийг нэг объектод нэгтгэх
  • C) void create()
  • D) void create(int id)

Зөв хариулт: B

Тайлбар: 3+ параметр → Parameter Object (DTO) ашиглах. StudentDTO дотор бүх талбар → Код уншигдах чанар сайжирна, хялбар өргөтгөнө.

Тест 48

Дараах аль нь SonarQube-ийн "Code Smell" шинж вэ?

  • A) Compile error
  • B) Хэт урт метод, давхардсан код, хэт нарийн нөхцөл
  • C) Runtime error
  • D) Syntax error

Зөв хариулт: B

Тайлбар: Code Smell = Compile/Runtime error биш, гэхдээ чанарын асуудал. Хэт урт метод, давхардал, magic number, God class зэрэг. "Үнэртэй" код.

Тест 49

Objects.requireNonNull(param, "message") юу хийдэг вэ?

  • A) Объект үүсгэх
  • B) param null бол NullPointerException шидэх — тодорхой мессежтэй
  • C) Файл нээх
  • D) Тест ажиллуулах

Зөв хариулт: B

Тайлбар: Objects.requireNonNull() = null шалгалтын стандарт арга. null бол мессежтэй NullPointerException шидэнэ. Guard clause-ийн нэг хэлбэр.

Тест 50

Дараах аль нь Dependency Injection (DI) зарчим вэ?

  • A) new PaymentService() метод дотор үүсгэх
  • B) PaymentService-ийг constructor-оор дамжуулах
  • C) Static метод ашиглах
  • D) Global хувьсагч ашиглах

Зөв хариулт: B

Тайлбар: DI = Хамааралтай объектыг ГАДНААС дамжуулах (constructor injection). new хийхгүй → Тестлэхэд хялбар, mock ашиглаж болно.

Тест 51

Дараах кодын гол асуудал юу вэ?

String url = "http://localhost:8080/api";
Thread.sleep(5000);
  • A) Асуудалгүй
  • B) Hardcoded утгууд — тогтмол/тохиргоо ашиглах ёстой
  • C) Нэрлэлт буруу
  • D) Exception байхгүй

Зөв хариулт: B

Тайлбар: URL, timeout зэрэг = Тохиргоо (configuration). Hardcode хийвэл орчин бүрт солих хэрэгтэй. Тогтмол, property файл, @Value ашиглах.

Тест 52

"Readability" ба "Performance" хоорондоо зөрчилдвөл ямар шийдвэр гаргах вэ?

  • A) Үргэлж Performance
  • B) ИХЭНХ тохиолдолд Readability-г сонгож, performance асуудал БАТАЛГААЖСАН үед оновчлох
  • C) Үргэлж Readability
  • D) Хоёуланг нь үл тоомсорлох

Зөв хариулт: B

Тайлбар: "Premature optimization is the root of all evil" (Knuth). Эхлээд уншигдахуйц, зөв код бич → Profiler-аар bottleneck олж, ЗӨвхөн тэндээ optimize хий.

Тест 53

Дараах if-else бүтцийг юугаар солих вэ?

if (type.equals("A")) return 10;
else if (type.equals("B")) return 20;
else if (type.equals("C")) return 30;
  • A) Солихгүй
  • B) Enum, Map, эсвэл Strategy Pattern ашиглах
  • C) Switch ашиглах
  • D) Бүгдийг устгах

Зөв хариулт: B

Тайлбар: Гинжин if-else = Open/Closed зөрчил. Enum + Map эсвэл Strategy Pattern → Шинэ төрөл нэмэхэд if-else нэмэхгүй.

Тест 54

Import дарааллын зөв дүрэм аль нь вэ?

  • A) Дарааллаар биш
  • B) java.* → javax.* → third-party → project — бүлэглэж, хоосон мөрөөр тусгаарлах
  • C) Бүгдийг * wildcard ашиглах
  • D) Нэг мөрд бүгдийг бичих

Зөв хариулт: B

Тайлбар: Import бүлэглэх + хоосон мөрөөр тусгаарлах = Уншигдах чанар. Wildcard * зайлсхий → Тодорхой класс import хийх.

Тест 55

"Single Responsibility Principle" (SRP) гэж юу вэ?

  • A) Нэг файлд нэг класс
  • B) Нэг класс/метод зөвхөн нэг үүрэг хариуцах, нэг шалтгаанаар л өөрчлөгдөх
  • C) Нэг хувьсагч нэг утга
  • D) Нэг тест нэг assert

Зөв хариулт: B

Тайлбар: SRP = "Нэг класс зөвхөн НЭГ шалтгаанаар өөрчлөгдөх ёстой." UserService нь зөвхөн user-тай холбоотой логик → Email, Payment тусдаа.

Тест 56

Лог (logging) бичихэд System.out.println ашиглах нь яагаад БУРУУ вэ?

  • A) Зөв, ашиглаж болно
  • B) Лог түвшин (level) байхгүй, файлд бичихгүй, формат байхгүй
  • C) Хурдан
  • D) Автомат

Зөв хариулт: B

Тайлбар: System.out.println = Лог түвшин (DEBUG, INFO, WARN, ERROR) байхгүй, файлд бичихгүй, production-д удирдах боломжгүй. → SLF4J/Logback ашиглах.

Тест 57

Дараах кодын аль нь илүү сайн вэ?

// A:
List<Student> result = new ArrayList<>();
for (Student s : students) {
    if (s.getGpa() >= 3.5) result.add(s);
}
// B:
List<Student> result = students.stream()
    .filter(s -> s.getGpa() >= 3.5)
    .collect(Collectors.toList());
  • A) A илүү сайн
  • B) B илүү сайн — Stream API нь зорилгоо илүү тодорхой илэрхийлж байна
  • C) Хоёулаа ижил
  • D) Хоёулаа буруу

Зөв хариулт: B

Тайлбар: Stream API = Declarative (юу хийхийг хэлэх), for loop = Imperative (яаж хийхийг хэлэх). Stream нь зорилгыг илүү тодорхой, товч илэрхийлнэ.

Тест 58

String.format() ашиглах нь string concatenation (+)-аас яагаад дээр вэ?

  • A) Хурдан
  • B) Уншигдах чанар сайн, формат тодорхой, олон хэлний дэмжлэг
  • C) Ялгаагүй
  • D) Compile error гарахгүй

Зөв хариулт: B

Тайлбар: String.format("Нэр: %s, Нас: %d", name, age) vs "Нэр: " + name + ", Нас: " + age. Format = Илүү уншигдахуйц, ялангуяа олон хувьсагчтай.

Тест 59

Enum ашиглах нь String тогтмолоос яагаад дээр вэ?

  • A) Ялгаагүй
  • B) Type-safe, IDE autocomplete, бүх боломжит утгыг нэг дор, typo алдаа compile-д баригдана
  • C) Бичихэд богино
  • D) Хурдан

Зөв хариулт: B

Тайлбар: String role = "admim" → Typo, runtime-д алдаа. Role.ADMIN → Compile-д шалгагдана, autocomplete, бүх утгыг switch-ээр handle хийж болно.

Тест 60

Дараах аль нь "code smell" БИШ вэ?

  • A) God Class
  • B) Magic Number
  • C) Утга учиртай нэрлэлт бүхий жижиг метод
  • D) Гинжин if-else

Зөв хариулт: C

Тайлбар: Утга учиртай нэрлэлт + жижиг метод = Clean Code зарчим. God Class, Magic Number, гинжин if-else = Code smell (кодын чанарын асуудал).

Тест 61

SonarQube-д "Vulnerability" гэж юу вэ?

  • A) Кодын стиль асуудал
  • B) Аюулгүй байдлын сул тал — SQL injection, XSS зэрэг эрсдэл
  • C) Кодын формат
  • D) Тестийн хамралт

Зөв хариулт: B

Тайлбар: Vulnerability = Аюулгүй байдлын асуудал. SQL injection, XSS, hardcoded password, insecure random зэрэг. Хакер ашиглаж болох сул тал.

Тест 62

Дараах кодын гол асуудал юу вэ?

// public void oldMethod() {
//     // хуучин логик
//     // маш олон мөр
// }
  • A) Асуудалгүй
  • B) Comment-оор хаасан хуучин код — Git түүхэнд хадгалагдана, устгах ёстой
  • C) Сайн арга
  • D) Нөөц код

Зөв хариулт: B

Тайлбар: Comment-оор хаасан код = "Код оршуулга". Git-ийн түүхэнд хуучин код хадгалагдана → Шаардлагагүй, устгах. Boy Scout Rule.

Тест 63

Тогтмолд (constant) ямар утга хадгалах ЗӨӨВ вэ?

  • A) Бүх зүйл
  • B) Олон газар давтагддаг, бизнес утга бүхий тоо/string
  • C) Хувьсагч бүрийг тогтмол болгох
  • D) Зөвхөн тоо

Зөв хариулт: B

Тайлбар: MAX_LOGIN_ATTEMPTS = 5, TAX_RATE = 0.1, ADMIN_ROLE = "admin" — Олон газар давтагддаг + утга учиртай. 0, 1, "" зэрэг ерөнхий утгыг заавал тогтмол болгохгүй.

Тест 64

"Premature Optimization" гэж юу вэ?

  • A) Зөв оновчлол
  • B) Performance асуудал БАТАЛГААЖААГҮЙ байхад хэт эрт, шаардлагагүй оновчлол хийх
  • C) Тест хийх
  • D) Code review

Зөв хариулт: B

Тайлбар: "Premature optimization is the root of all evil" — Donald Knuth. Эхлээд зөв, цэвэр код бич → Profiler-аар bottleneck ол → ЗӨВХӨН тэндээ optimize хий.

Тест 65

Дараах аль нь нэрлэлтийн "Хуурмаг мэдээлэл" (Disinformation) вэ?

  • A) List<Account> accountList; — Бодитоор List байвал зөв
  • B) List<Account> accountList; — Бодитоор Set байвал ХУУРМАГ
  • C) int age;
  • D) String name;

Зөв хариулт: B

Тайлбар: accountList гэж нэрлээд Set төрөл бол = Хуурмаг мэдээлэл. Уншигч List гэж бодно → Алдаа. accounts гэж нэрлэх нь зөв.

Тест 66

Файл нэрлэхэд аль зарчим зөв вэ?

  • A) file1.java, file2.java
  • B) Нэг файлд нэг public class, файлын нэр = классын нэр
  • C) Бүгд Main.java
  • D) Дугаарлах

Зөв хариулт: B

Тайлбар: Java стандарт: Нэг файл = Нэг public class. StudentService.java файлд public class StudentService. Олж хайхад хялбар.

Тест 67

Кодын "Complexity vs Readability" харьцааг хэрхэн шийдвэрлэх вэ?

  • A) Үргэлж readability
  • B) Эхлээд уншигдахуйц бич, зөвхөн БАТАЛГААЖСАН шаардлагаар complexity нэм
  • C) Үргэлж complexity
  • D) Хоёуланг нь үл тоомсорлох

Зөв хариулт: B

Тайлбар: Уншигдах чанар = Анхдагч зорилт. Performance/complexity зөвхөн profiler-аар баталгаажсан bottleneck-д → Тайлбартай optimize хийх.

Тест 68

try-with-resources юу хийдэг вэ?

  • A) Тест ажиллуулах
  • B) AutoCloseable нөөцийг (file, connection) автоматаар хаах — resource leak-ээс хамгаалах
  • C) Exception шидэх
  • D) Loop ажиллуулах

Зөв хариулт: B

Тайлбар: try (var reader = new FileReader(file)) { ... } — try блок дуусахад автоматаар close() дуудна. Finally-д гараар хаах шаардлагагүй.

Тест 69

Дараах аль нь null буцаахын оронд ашиглах ЗӨӨВ арга вэ?

  • A) null буцаах
  • B) Optional, хоосон collection, эсвэл Exception шидэх
  • C) -1 буцаах
  • D) "" (хоосон string) буцаах

Зөв хариулт: B

Тайлбар: null буцаавал дуудсан газар NullPointerException гарч болно. Optional = Утга байж ч болно, байхгүй ч болно. Хоосон List = null-аас аюулгүй. Exception = Тодорхой алдаа.

Тест 70

Дараах кодын аль нь илүү сайн вэ?

// A: return a > b ? a : b;
// B: return Math.max(a, b);
  • A) A
  • B) B — Стандарт сангийн метод ашиглах нь илүү ойлгомжтой
  • C) Хоёулаа ижил
  • D) Хоёулаа буруу

Зөв хариулт: B

Тайлбар: Math.max() = Зорилго тодорхой, бэлэн тестлэгдсэн, бусад хөгжүүлэгч шууд ойлгоно. "Дугуйг дахин зохиохгүй" зарчим.

Тест 71

Accessor метод (getter/setter) хэзээ шаардлагагүй вэ?

  • A) Хэзээ ч шаардлагатай
  • B) Дотоод (private) хэрэглээнд зориулсан immutable объектод setter шаардлагагүй
  • C) Бүх тохиолдолд шаардлагагүй
  • D) Public класст

Зөв хариулт: B

Тайлбар: Immutable объект = Үүсгэсний дараа өөрчлөгдөхгүй → setter шаардлагагүй. DTO, Value Object зэрэгт getter-ийг л хадгалж болно.

Тест 72

Builder Pattern хэзээ ашиглах вэ?

  • A) Нэг параметртэй үед
  • B) Олон параметр бүхий объект үүсгэхэд — constructor параметр олон болохоос сэргийлж
  • C) Хэзээ ч ашиглахгүй
  • D) Зөвхөн тест бичихэд

Зөв хариулт: B

Тайлбар: Student.builder().name("Бат").age(20).gpa(3.5).build() — Уншигдахуйц, параметр олон ч тодорхой. Telescope constructor-ийн оронд.

Тест 73

"Law of Demeter" (LoD) гэж юу вэ?

  • A) Хурд тооцоолох дүрэм
  • B) Объект зөвхөн шууд хамааралтай объекттой харилцах — гинжин дуудалт хийхгүй
  • C) Нэрлэлтийн дүрэм
  • D) Тестийн дүрэм

Зөв хариулт: B

Тайлбар: LoD = "Зөвхөн найзтайгаа ярь, найзын найзтай ярихгүй." a.getB().getC().doSomething() = Зөрчил. a.doSomethingViaB() = Зөв.

Тест 74

Дараах аль нь "Early Return" загвар вэ?

// A:
if (input != null) {
    if (input.isValid()) {
        // logic (олон мөр)
    }
}
// B:
if (input == null) return;
if (!input.isValid()) return;
// logic (олон мөр)
  • A) A
  • B) B — Буруу нөхцлийг эрт шалгаж буцаах → nested if бууруулна
  • C) Хоёулаа ижил
  • D) Хоёулаа буруу

Зөв хариулт: B

Тайлбар: Early Return = Guard Clause. Буруу нөхцлийг эрт шалгаж буцаах → Nested if (arrow code) бууруулж, гол логикийг тодорхой харуулна.

Тест 75

Immutable объект (өөрчлөгдөшгүй) ямар давуу талтай вэ?

  • A) Давуу талгүй
  • B) Thread-safe, side effect-гүй, debug хялбар, cache-д тохиромжтой
  • C) Зөвхөн хурдан
  • D) Зөвхөн жижиг

Зөв хариулт: B

Тайлбар: Immutable = Үүсгэсний дараа утга өөрчлөгдөхгүй → Thread-safe (lock шаардлагагүй), side effect-гүй, debug хялбар. String, LocalDate = Immutable.

Тест 76

Дараах аль нь equals() override хийхэд ЗААВАЛ хийх зүйл вэ?

  • A) toString() override
  • B) hashCode() ЗААВАЛ override — equals/hashCode гэрээ
  • C) clone() override
  • D) compareTo() override

Зөв хариулт: B

Тайлбар: Java гэрээ: equals() override хийвэл hashCode() ЗААВАЛ override. Хийхгүй бол HashMap, HashSet зэрэгт буруу ажиллана.

Тест 77

Дараах аль нь "Liskov Substitution Principle" (LSP) зөрчил вэ?

  • A) ArrayList-ийг List-ийн оронд ашиглах
  • B) Square класс Rectangle-аас удамшиж, setWidth хийхэд height ч өөрчлөгдөх
  • C) Interface implement хийх
  • D) Abstract class extend хийх

Зөв хариулт: B

Тайлбар: LSP = Удамшсан класс нь эцэг классын оронд ямар ч тохиолдолд ажиллах ёстой. Square.setWidth() нь Rectangle-ийн "width-ийг л өөрчлөх" гэрээг зөрчиж байна.

Тест 78

Code Review-д хэдэн мөр өөрчлөлт шалгахад ХАМГИЙН ҮР ДҮНТЭЙ вэ?

  • A) 1000+ мөр
  • B) 200-400 мөр
  • C) 1-10 мөр
  • D) 5000+ мөр

Зөв хариулт: B

Тайлбар: 200-400 мөр = Reviewer анхаарлаа хадгалж чадна. 1000+ мөр = "Бүгд зүгээр харагдаж байна" → Алдаа алдагдана. Жижиг PR = Чанартай review.

Тест 79

"Composition over Inheritance" зарчим юу гэсэн утгатай вэ?

  • A) Удамшил ашиглахгүй
  • B) Удамшлын оронд объектуудын нийлмэл бүтэц (composition) ашиглахыг зөвлөх
  • C) Зөвхөн interface ашиглах
  • D) Зөвхөн abstract class ашиглах

Зөв хариулт: B

Тайлбар: Удамшил = Хатуу холбоос, нэг эцгийн өөрчлөлт бүх хүүхдэд нөлөөлнө. Composition = has-a харилцаа, уян хатан, солих хялбар. is-a бат итгэлтэй бол л удамшил.

Тест 80

var keyword (Java 10+) хэзээ ашиглах нь зөв вэ?

  • A) Хэзээ ч ашиглахгүй
  • B) Баруун талд төрөл тодорхой байх үед — var list = new ArrayList<String>();
  • C) Бүх газар ашиглах
  • D) Зөвхөн тест бичихэд

Зөв хариулт: B

Тайлбар: var = Баруун талд төрөл тодорхой бол уншигдах чанарт сайн. var result = service.findById(id) — result юу вэ мэдэгдэхгүй бол Student result = ... илүү тодорхой.

Тест 81

"Cognitive Complexity" гэж юу вэ?

  • A) Кодын мөрийн тоо
  • B) Хүний тархинд кодыг ойлгоход хэр хүнд байдгийн хэмжигдэхүүн
  • C) Кодын хурд
  • D) Тестийн тоо

Зөв хариулт: B

Тайлбар: Cognitive Complexity = SonarQube-ийн хэмжигдэхүүн. Cyclomatic-аас ялгаатай нь: nested if, break/continue зэрэг "ойлгоход хэцүү" бүтцэд илүү өндөр оноо.

Тест 82

Дараах аль нь "Interface Segregation Principle" (ISP) зөрчил вэ?

  • A) Жижиг, тодорхой interface
  • B) Нэг том interface-д олон холбоогүй метод — зарим класс хэрэггүй метод implement хийх шаардлагатай
  • C) Олон жижиг interface
  • D) Abstract class

Зөв хариулт: B

Тайлбар: ISP = "Хэрэглэгч өөрт хэрэггүй interface-д хамаарах ёсгүй." Том interface-ийг жижиг, тодорхой interface болгон хуваах.

Тест 83

"Semantic Versioning" (v1.2.3) дахь MINOR дугаар хэзээ нэмэгдэх вэ?

  • A) Алдаа засахад
  • B) Шинэ функц нэмэхэд (хуучинтай нийцтэй)
  • C) Breaking change хийхэд
  • D) Код refactor хийхэд

Зөв хариулт: B

Тайлбар: MAJOR = Breaking change. MINOR = Шинэ функц (backward compatible). PATCH = Алдаа засвар. v1.2.3 → v1.3.0 = Шинэ функц нэмэгдсэн.

Тест 84

Lombok сангийн @Data annotation юу хийдэг вэ?

  • A) Мэдээллийн сан үүсгэх
  • B) Getter, Setter, toString, equals, hashCode автоматаар үүсгэх — boilerplate бууруулах
  • C) Тест ажиллуулах
  • D) Файл нээх

Зөв хариулт: B

Тайлбар: @Data = Getter + Setter + toString + equals + hashCode. Boilerplate код бууруулна. Compile-д автоматаар үүсгэнэ. Код товч, цэвэр.

Тест 85

Дараах аль нь "Open/Closed Principle" (OCP) зарчим вэ?

  • A) Код хаалттай байх
  • B) Өргөтгөхөд НЭЭЛТТЭЙ, засварлахад ХААЛТТАЙ — шинэ функц нэмэхдээ байгаа кодыг өөрчлөхгүй
  • C) Файл нээх, хаах
  • D) Зөвхөн public метод

Зөв хариулт: B

Тайлбар: OCP = Шинэ функц нэмэхдээ interface/abstract class + шинэ implementation. Байгаа if-else-д шинэ нөхцөл нэмэхгүй → Strategy, Factory pattern.

Тест 86

Дараах аль нь "Тест хялбар бичиж болох" кодын шинж вэ?

  • A) Static метод олонтой
  • B) Constructor Injection, жижиг метод, нэг үүрэг
  • C) Global хувьсагч олонтой
  • D) God Class

Зөв хариулт: B

Тайлбар: Тестлэхэд хялбар код = DI (mock ашиглаж болно) + жижиг метод (тусдаа тестлэж болно) + SRP. Static, global, God Class = Тестлэхэд хэцүү.

Тест 87

"Dead Code" гэж юу вэ?

  • A) Runtime error
  • B) Хэзээ ч ажиллахгүй, хүрч чадахгүй код — устгах ёстой
  • C) Production код
  • D) Тест код

Зөв хариулт: B

Тайлбар: Dead Code = Хэзээ ч дуудагдахгүй метод, хүрч чадахгүй if branch, unused import/variable. IDE анхааруулдаг → Устгах. Код цэвэрхэн.

Тест 88

final keyword хувьсагч дээр ашиглахын давуу тал юу вэ?

  • A) Давуу талгүй
  • B) Утга дахин оноогдохгүй гэдгийг баталгаажуулж, кодын зорилгыг тодорхой болгох
  • C) Хурдасгах
  • D) Санах ой хэмнэх

Зөв хариулт: B

Тайлбар: final String name = "Бат" — Энэ утга ХЭЗЭЭ Ч өөрчлөгдөхгүй. Код уншигчид тодорхой мэдээлэл → Итгэлтэй бодох. Immutability-ийн нэг хэсэг.

Тест 89

Дараах аль нь "Cohesion" (нягтралт) өндөр классын шинж вэ?

  • A) Олон холбоогүй метод
  • B) Классын бүх метод ижил зорилгод чиглэсэн, талбаруудыг хамтдаа ашигладаг
  • C) Static метод олонтой
  • D) 1000+ мөр

Зөв хариулт: B

Тайлбар: Өндөр Cohesion = Классын бүх гишүүд нэг зорилгод чиглэсэн. StudentService-ийн бүх метод оюутантай холбоотой. Бага Cohesion = God Class.

Тест 90

"Coupling" (холбоос) бага байх нь яагаад сайн вэ?

  • A) Ялгаагүй
  • B) Нэг класс өөрчлөхөд бусад класст нөлөөлөхгүй, тестлэхэд хялбар, дахин ашиглахуйц
  • C) Зөвхөн хурдан
  • D) Зөвхөн жижиг

Зөв хариулт: B

Тайлбар: Бага Coupling = Классууд бие биенээсээ бага хамааралтай → Нэгийг өөрчлөхөд нөгөө нь эвдэрэхгүй. Interface + DI = Coupling бууруулах.

Тест 91

Дараах аль нь switch expression (Java 14+) ашиглалт вэ?

// A: switch (day) { case MONDAY: return "Даваа"; ... }
// B: String name = switch (day) { case MONDAY -> "Даваа"; ... };
  • A) A
  • B) B — Arrow syntax, утга буцааж хувьсагчид оноох
  • C) Хоёулаа ижил
  • D) Хоёулаа буруу

Зөв хариулт: B

Тайлбар: Java 14+ switch expression = -> arrow syntax, break шаардлагагүй, утга буцааж хувьсагчид оноох боломжтой. Товч, аюулгүй (exhaustive шалгалт).

Тест 92

"Principle of Least Astonishment" гэж юу вэ?

  • A) Код аль болох нарийн байх
  • B) Код уншигчийг ГАЙХШРУУЛАХГҮЙ — нэрнээсээ ойлгогддог, хүлээгдсэн зүйлийг хийх
  • C) Код хурдан байх
  • D) Код жижиг байх

Зөв хариулт: B

Тайлбар: checkPassword() дотор session эхлүүлбэл = Гайхшруулна (Side Effect). Функц нэрнээс хүлээгдсэн зүйлийг л хийх. Гайхшруулалгүй = Аюулгүй.

Тест 93

Record (Java 16+) юу хийдэг вэ?

  • A) Файл бичих
  • B) Immutable data класс автоматаар үүсгэх — constructor, getter, equals, hashCode, toString
  • C) Тест бичих
  • D) Exception шидэх

Зөв хариулт: B

Тайлбар: record Student(String name, int age) {} — Автоматаар constructor, getter, equals, hashCode, toString үүсгэнэ. DTO, Value Object-д тохиромжтой.

Тест 94

Дараах аль нь sealed class (Java 17+) ашиглалт вэ?

  • A) Бүх классыг хязгаарлах
  • B) Зөвхөн зөвшөөрөгдсөн классууд л удамших боломжтой — domain model-д хяналт
  • C) Файл хааах
  • D) Thread хааах

Зөв хариулт: B

Тайлбар: sealed class Shape permits Circle, Rectangle, Triangle {} — Зөвхөн эдгээр 3 класс л удамших боломжтой. Pattern matching-д маш тохиромжтой.

Тест 95

Дараах аль нь logging-ийн ЗӨӨВ түвшин вэ?

  • A) Бүгд ERROR
  • B) DEBUG → хөгжүүлэлтийн дэлгэрэнгүй, INFO → ерөнхий, WARN → анхааруулга, ERROR → алдаа
  • C) Бүгд INFO
  • D) Бүгд DEBUG

Зөв хариулт: B

Тайлбар: DEBUG = Хөгжүүлэлтийн дэлгэрэнгүй (production-д унтраах). INFO = Ерөнхий мэдээлэл. WARN = Анхааруулга. ERROR = Алдаа. Зөв түвшин = Зөв мэдээлэл.

Тест 96

"Extract Method" refactoring юу хийдэг вэ?

  • A) Метод устгах
  • B) Кодын хэсгийг тусдаа метод болгон салгах — уншигдах чанар, дахин ашиглалт сайжруулах
  • C) Файл нэмэх
  • D) Тест бичих

Зөв хариулт: B

Тайлбар: Том метод дотроос логик бүлгийг тусдаа метод болгон салгах → Утга учиртай нэр → Код уншигдахуйц, дахин ашиглахуйц.

Тест 97

Дараах аль нь "Temporal Coupling" (цаг хугацааны холбоос) вэ?

  • A) Хурд хэмжих
  • B) Методуудыг тодорхой дарааллаар дуудах ШААРДЛАГА — init() дуудахгүйгээр process() ажиллахгүй
  • C) Threading
  • D) Timeout

Зөв хариулт: B

Тайлбар: init()process()cleanup() дарааллаар дуудах шаардлагатай = Temporal Coupling. Нэг метод болгох эсвэл Template Method Pattern ашиглах.

Тест 98

"Separation of Concerns" (SoC) зарчим юу вэ?

  • A) Бүгдийг нэг газар бичих
  • B) Өөр өөр үүрэг/зорилгыг тусдаа модуль/давхаргад хуваах
  • C) Зөвхөн тест бичих
  • D) Зөвхөн нэг хэл ашиглах

Зөв хариулт: B

Тайлбар: SoC = Controller (хүсэлт удирдах) ≠ Service (бизнес логик) ≠ Repository (мэдээллийн сан). Тус тусын үүрэг → Засвар хялбар, тест хялбар.

Тест 99

Дараах аль нь "Testability" сайн кодын шинж БИШ вэ?

  • A) Constructor Injection
  • B) Жижиг метод
  • C) Нэг метод дотор new keyword олонтой ашиглах
  • D) Interface ашиглах

Зөв хариулт: C

Тайлбар: new keyword олонтой = Тестлэхэд mock-оор солиж чадахгүй. DI (Constructor Injection) + Interface = Mock хялбар → Тестлэхэд хялбар.

Тест 100

Кодын чанар яагаад програм хангамжийн бүтээлтэд хамгийн чухал зүйлсийн нэг вэ?

  • A) Зөвхөн мэргэжлийн шаардлага
  • B) Уншигдахуйц, засварлахуйц, найдвартай код = Бүтээмж өндөр, алдаа бага, баг хамтран ажиллаж чадна, техникийн өр бага
  • C) Зөвхөн code review-д хэрэгтэй
  • D) Зөвхөн том компаниудад

Зөв хариулт: B

Тайлбар: Кодын чанар = Бүтээлтийн суурь. Цэвэр код → Уншихад хялбар (70% цагийг хэмнэнэ) → Засварлахад хурдан → Алдаа бага → Баг хамтран ажиллана → Техникийн өр бага → Бүтээмж ӨНДӨР.


📚 Ашигласан эх сурвалжууд:

  • Robert C. Martin — Clean Code: A Handbook of Agile Software Craftsmanship (2008)
  • Robert C. Martin — The Clean Coder (2011)
  • Martin Fowler — Refactoring: Improving the Design of Existing Code (2nd Edition, 2018)
  • Joshua Bloch — Effective Java (3rd Edition, 2018)
  • Google Java Style Guide — google.github.io/styleguide/javaguide.html
  • SonarQube Documentation — docs.sonarqube.org
  • Oracle Java Code Conventions
  • IEEE SWEBOK — Software Quality