ОНОЛ 04

Кодын Дахин Засварлалт

ЛЕКЦ 04: КОДЫН ДАХИН ЗАСВАРЛАЛТ (Refactoring)

Хичээлийн зорилго: Кодын дахин засварлалт (refactoring)-ийн суурь ойлголт, code smell таних, нийтлэг refactoring техникүүд, Java дээр бодит жишээнүүдтэйгээр эзэмшүүлэх.

Хамрах хүрээ: Refactoring тодорхойлолт, Code Smell-ийн төрлүүд, нийтлэг refactoring техникүүд, Martin Fowler-ийн каталог, SOLID-тэй холбоос, IDE refactoring хэрэгслүүд.



ХЭСЭГ 1: ОНОЛЫН СУУРЬ (Theory & Foundations)

1.1 Refactoring гэж юу вэ?

Refactoring гэдэг нь кодын гадаад зан төлөвийг өөрчлөхгүйгээр дотоод бүтцийг сайжруулах процесс.

🔑 Martin Fowler-ийн тодорхойлолт: "Refactoring нь програм хангамжийн дотоод бүтцийг өөрчлөх арга бөгөөд гадаад зан төлөвийг хадгалсан нөхцөлд кодыг илүү ойлгомжтой, засвар хялбар болгоно."

Зүйрлэл:

💡 Байшинг гаднаас нь харахад ИЖИЛ харагддаг, гэхдээ дотоод цахилгааны утас, сантехникийг шинэчилсэн шиг — refactoring нь кодын "дотоод засвар".

Refactoring юу БИШ вэ?

RefactoringRefactoring БИШ
Кодын бүтцийг сайжруулахШинэ функц нэмэх
Уншихад хялбар болгохАлдаа засах (bug fix)
Засвар хялбар болгохГүйцэтгэлийг сайжруулах (optimization)
Давхардлыг арилгахБүтэн дахин бичих (rewrite)

⚠️ Чухал: Refactoring хийхдээ гадаад зан төлөв ӨӨРЧЛӨГДӨХГҮЙ. Өөрөөр хэлбэл, refactoring-ийн өмнө ба дараа тестүүд ИЖИЛ ҮР ДҮНТЭЙ дамжих ёстой.


1.2 Refactoring яагаад чухал вэ?

Кодын "ялзрал" (Code Decay):

Цаг хугацаа өнгөрөхтүтэй код ялзардаг — шинэ функц нэмэх, алдаа засах, хөгжүүлэгчид солигдох бүрд кодын бүтэц муудаж эхэлдэг.

💡 Зүйрлэл: Гэрийн цэвэрлэгээ хийхгүй бол бохир овоорч, юм олоход хэцүү болдог. Код ч мөн адил — байнгын "цэвэрлэгээ" хэрэгтэй.

Refactoring-ийн давуу талууд:

#Давуу талТайлбар
1Код ойлгомжтой болноШинэ хөгжүүлэгч хурдан ойлгоно
2Алдаа олоход хялбарЦэвэр кодонд алдаа нуугдах боломж бага
3Шинэ функц нэмэхэд хурданЦэвэр бүтцэнд шинэ зүйл оруулахад хялбар
4Засвар хялбарНэг газар өөрчилж, олон газар нөлөөлөхгүй
5Багийн бүтээмж нэмэгдэнэХүн бүр ойлгож, хамтран ажиллаж чадна
6Техникийн өрийг бууруулнаИрээдүйд засвар хийх зардал буурна

Техникийн өр (Technical Debt):

💡 Зүйрлэл: Банкны зээл шиг — одоо хурдан, бохир код бичвэл (зээл авбал), ирээдүйд ХҮҮТЭЙГЭЭР буцааж засах хэрэгтэй (өр төлөх). Refactoring нь тэр "өрийг" буцааж төлөх процесс.

Техникийн өрийн хуримтлал:
                        │
                        │     ╱ Өр ихсэх (refactoring хийхгүй)
    Засвар хийх         │    ╱
    зардал              │   ╱
                        │  ╱
                        │ ╱
                        │╱───── Refactoring хийх → Зардал тогтвортой
                        │
                        └──────────────────── Цаг хугацаа →

1.3 Code Smell гэж юу вэ?

Code Smell ("Кодын үнэр") гэдэг нь кодонд асуудал байж болзошгүйг илтгэдэг шинж тэмдэг. Алдаа биш, гэхдээ кодын чанар МУУДАЖ байгаагийн дохио.

💡 Зүйрлэл: Хоолны хадгалах хугацаа дуусаагүй ч МУУХАЙ ҮНЭРТЭЖ байвал — асуудалтай байж магадгүй. Code Smell нь кодын "муухай үнэр".

1.3.1 Bloaters (Хэт томорсон код)

Код, метод, класс хэт том болсон, удирдахад хэцүү.

а) Long Method (Урт метод)

// ❌ БУРУУ — 80+ мөр, олон зүйл хийж байна
public void processOrder(Order order) {
    // Хэрэглэгч шалгах (20 мөр)
    if (order.getCustomer() == null) { ... }
    if (!order.getCustomer().isActive()) { ... }
    // Бүтээгдэхүүн нөөц шалгах (15 мөр)
    for (Item item : order.getItems()) { ... }
    // Үнэ тооцоолох (20 мөр)
    double total = 0;
    for (Item item : order.getItems()) { total += ...; }
    // Хөнгөлөлт тооцоолох (15 мөр)
    if (order.getCustomer().isVIP()) { ... }
    // Төлбөр боловсруулах (10 мөр)
    paymentService.charge(order.getCustomer(), total);
    // Баримт илгээх (10 мөр)
    emailService.sendReceipt(order.getCustomer(), total);
}
// ✅ ЗӨӨВ — Жижиг методуудад хуваасан (Extract Method)
public void processOrder(Order order) {
    validateCustomer(order.getCustomer());
    checkInventory(order.getItems());
    double total = calculateTotal(order);
    double discountedTotal = applyDiscount(order.getCustomer(), total);
    processPayment(order.getCustomer(), discountedTotal);
    sendReceipt(order.getCustomer(), discountedTotal);
}

private void validateCustomer(Customer customer) { ... }
private void checkInventory(List<Item> items) { ... }
private double calculateTotal(Order order) { ... }
private double applyDiscount(Customer customer, double total) { ... }
private void processPayment(Customer customer, double amount) { ... }
private void sendReceipt(Customer customer, double amount) { ... }

б) Large Class (Том класс)

Нэг класс хэт олон үүрэг (responsibility) хариуцаж байна → Single Responsibility Principle зөрчиж байна.

// ❌ БУРУУ — UserManager бүх зүйл хийж байна
class UserManager {
    public void createUser() { ... }
    public void deleteUser() { ... }
    public void sendEmail() { ... }         // Имэйл илгээх → өөр үүрэг
    public void generateReport() { ... }     // Тайлан гаргах → өөр үүрэг
    public void backupDatabase() { ... }     // Нөөцлөлт → өөр үүрэг
}

// ✅ ЗӨӨВ — Үүргийг тусгаарласан (Extract Class)
class UserService {
    public void createUser() { ... }
    public void deleteUser() { ... }
}
class EmailService {
    public void sendEmail() { ... }
}
class ReportService {
    public void generateReport() { ... }
}
class BackupService {
    public void backupDatabase() { ... }
}

в) Primitive Obsession (Анхдагч төрлийн хэт хэрэглээ)

String, int зэрэг энгийн төрлийг хэт их ашиглаж, утга бүхий объект үүсгэхгүй байх.

// ❌ БУРУУ — Утасны дугаар, имэйл гэх мэт String-ээр
public void createUser(String name, String phone, String email,
                       String street, String city, String zipCode) { ... }

// ✅ ЗӨӨВ — Утга бүхий объект (Value Object)
public void createUser(String name, PhoneNumber phone, Email email,
                       Address address) { ... }

class PhoneNumber {
    private String value;
    public PhoneNumber(String value) {
        if (!value.matches("\\d{8}")) throw new IllegalArgumentException("Буруу дугаар");
        this.value = value;
    }
}

class Address {
    private String street;
    private String city;
    private String zipCode;
}

г) Long Parameter List (Олон параметр)

Метод хэт олон параметр авч байна.

// ❌ БУРУУ — 7 параметр
public void createEvent(String name, String desc, Date start, Date end,
                        String location, int maxPeople, double price) { ... }

// ✅ ЗӨӨВ — Parameter Object ашиглах
public void createEvent(EventConfig config) { ... }

class EventConfig {
    private String name;
    private String description;
    private Date startDate;
    private Date endDate;
    private String location;
    private int maxCapacity;
    private double price;
    // Builder pattern ашиглаж болно
}

1.3.2 Object-Orientation Abusers (ООП-ийн буруу хэрэглээ)

а) Switch Statements (Switch давтамж)

Ижил switch/if-else олон газар давтагдаж байна.

// ❌ БУРУУ — switch олон газар давтагдана
public double calculatePay(Employee emp) {
    switch (emp.getType()) {
        case ENGINEER: return emp.getSalary();
        case MANAGER: return emp.getSalary() + emp.getBonus();
        case INTERN: return emp.getSalary() * 0.5;
    }
    return 0;
}

public String getTitle(Employee emp) {
    switch (emp.getType()) {
        case ENGINEER: return "Инженер";
        case MANAGER: return "Менежер";
        case INTERN: return "Дадлагажигч";
    }
    return "";
}

// ✅ ЗӨӨВ — Polymorphism ашиглах (Replace Conditional with Polymorphism)
abstract class Employee {
    abstract double calculatePay();
    abstract String getTitle();
}

class Engineer extends Employee {
    double calculatePay() { return getSalary(); }
    String getTitle() { return "Инженер"; }
}

class Manager extends Employee {
    double calculatePay() { return getSalary() + getBonus(); }
    String getTitle() { return "Менежер"; }
}

б) Refused Bequest (Татгалзсан өв)

Дэд класс нь эх классын ихэнх метод/шинж чанарыг ашигладаггүй.

💡 Зүйрлэл: Аав нь тариачин, хүү нь программист — аавынхаа бүх тариалангийн багаж хэрэгслийг "өвлөж" авсан ч ашигладаггүй.

1.3.3 Change Preventers (Өөрчлөлтөд саад)

Нэг газар өөрчлөлт хийхэд олон газарт нөлөөлдөг.

а) Divergent Change (Салангид өөрчлөлт)

Нэг класст олон өөр шалтгаанаар өөрчлөлт хийх шаардлагатай.

б) Shotgun Surgery (Сум шиг тархалт)

Нэг өөрчлөлт хийхэд олон класст засвар хийх шаардлагатай.

💡 Зүйрлэл: Цахилгааны утас солиход бүх өрөөнд нэвтрэх шаардлагатай бол — бүтэц муу байна.

1.3.4 Dispensables (Шаардлагагүй зүйлс)

а) Dead Code (Үхсэн код)

Хэзээ ч ажиллахгүй, дуудагдахгүй код.

// ❌ БУРУУ — Хэзээ ч дуудагдахгүй метод
public void oldMethod() {
    // Энэ метод хаанаас ч дуудагдахгүй
}

// if (false) { ... }  — Хэзээ ч ажиллахгүй

б) Duplicate Code (Давхардсан код)

Ижил эсвэл маш төстэй код олон газар давтагдаж байна.

// ❌ БУРУУ — Ижил код 2 газар
public double calculateStudentDiscount(double price) {
    double tax = price * 0.1;
    double discount = price * 0.2;
    return price + tax - discount;
}

public double calculateTeacherDiscount(double price) {
    double tax = price * 0.1;
    double discount = price * 0.15;
    return price + tax - discount;
}

// ✅ ЗӨӨВ — Нийтлэг метод гаргах (Extract Method)
public double calculatePrice(double price, double discountRate) {
    double tax = price * 0.1;
    double discount = price * discountRate;
    return price + tax - discount;
}

public double calculateStudentDiscount(double price) {
    return calculatePrice(price, 0.2);
}

public double calculateTeacherDiscount(double price) {
    return calculatePrice(price, 0.15);
}

в) Speculative Generality (Шаардлагагүй ерөнхийлөлт)

Ирээдүйд хэрэгтэй БАЙЖ МАГАДГҮЙ гэж бодож шаардлагагүй абстракци үүсгэсэн.

💡 Зүйрлэл: "Ирээдүйд хэрэг болно" гэж 50 ширхэг цүнх авсан ч хэзээ ч ашиглаагүй.

г) Comments (Хэт олон тайлбар)

Код ОЙЛГОМЖТОЙ биш учраас тайлбараар нөхсөн.

// ❌ БУРУУ — Код муу, тайлбараар нөхсөн
// Хэрэглэгчийн насыг шалгах, 18-аас дээш бол true буцаах
// Хэрэв нас нь null бол false буцаах
public boolean chk(Integer a) {
    if (a == null) return false;
    return a >= 18;
}

// ✅ ЗӨӨВ — Код өөрөө тайлбарлагдаж байна
public boolean isAdult(Integer age) {
    if (age == null) return false;
    return age >= 18;
}

1.3.5 Couplers (Хэт нягт холбоос)

а) Feature Envy (Бусдын шинж чанарт шунах)

Метод нь өөрийн классын өгөгдлөөс илүү ӨӨӨР классын өгөгдлийг ашигладаг.

// ❌ БУРУУ — OrderPrinter нь Order-ийн бүх зүйлийг мэдэж байна
class OrderPrinter {
    public String format(Order order) {
        return order.getCustomerName() + ": " +
               order.getItems().size() + " бүтээгдэхүүн, " +
               order.getTotal() + "₮, " +
               order.getDiscount() + "₮ хөнгөлөлт";
    }
}

// ✅ ЗӨӨВ — Order класст format метод нэмэх (Move Method)
class Order {
    public String format() {
        return customerName + ": " + items.size() + " бүтээгдэхүүн, " +
               total + "₮, " + discount + "₮ хөнгөлөлт";
    }
}

б) Message Chains (Мессежийн гинж)

// ❌ БУРУУ — Гинж маягаар олон объектоор дамжих
String city = order.getCustomer().getAddress().getCity().getName();

// ✅ ЗӨӨВ — Delegate метод (Hide Delegate)
String city = order.getCustomerCity();  // Order дотор getCustomerCity() метод

1.4 Нийтлэг Refactoring Техникүүд

1.4.1 Extract Method (Метод гаргах)

Хэзээ: Урт метод, давхардсан код, тайлбар бичих шаардлагатай код блок.

// ӨМНӨ:
public void printReport(List<Student> students) {
    // Толгой хэвлэх
    System.out.println("=== Оюутны тайлан ===");
    System.out.println("Огноо: " + LocalDate.now());
    System.out.println("---");

    // Оюутнуудын мэдээлэл хэвлэх
    for (Student s : students) {
        System.out.println(s.getName() + " - " + s.getGPA());
    }

    // Хөл хэвлэх
    System.out.println("---");
    System.out.println("Нийт: " + students.size() + " оюутан");
}

// ДАРАА:
public void printReport(List<Student> students) {
    printHeader();
    printStudentDetails(students);
    printFooter(students.size());
}

private void printHeader() {
    System.out.println("=== Оюутны тайлан ===");
    System.out.println("Огноо: " + LocalDate.now());
    System.out.println("---");
}

private void printStudentDetails(List<Student> students) {
    for (Student s : students) {
        System.out.println(s.getName() + " - " + s.getGPA());
    }
}

private void printFooter(int count) {
    System.out.println("---");
    System.out.println("Нийт: " + count + " оюутан");
}

1.4.2 Rename (Нэр өөрчлөх)

Хэзээ: Хувьсагч, метод, классын нэр утга учиргүй.

// ӨМНӨ:
int d;                          // Юу гэсэн утга вэ?
public void proc(List<String> l) { ... }
class Mgr { ... }

// ДАРАА:
int daysSinceCreation;          // Тодорхой!
public void processNames(List<String> names) { ... }
class UserManager { ... }

1.4.3 Replace Magic Number with Named Constant (Шидэт тоог нэрлэсэн тогтмолоор солих)

// ӨМНӨ:
if (age >= 18) { ... }          // 18 юу гэсэн утга вэ?
double tax = price * 0.1;       // 0.1 юу вэ?
if (students.size() > 30) { ... }  // 30 яагаад?

// ДАРАА:
private static final int LEGAL_AGE = 18;
private static final double TAX_RATE = 0.1;
private static final int MAX_CLASS_SIZE = 30;

if (age >= LEGAL_AGE) { ... }
double tax = price * TAX_RATE;
if (students.size() > MAX_CLASS_SIZE) { ... }

1.4.4 Extract Class (Класс гаргах)

Хэзээ: Нэг класс хэт олон үүрэг хариуцаж байна.

// ӨМНӨ:
class Student {
    String name;
    String street;
    String city;
    String zipCode;
    String phone;
    String email;
}

// ДАРАА:
class Student {
    String name;
    Address address;
    ContactInfo contact;
}

class Address {
    String street;
    String city;
    String zipCode;
}

class ContactInfo {
    String phone;
    String email;
}

1.4.5 Replace Conditional with Polymorphism (Нөхцөлийг полиморфизмаар солих)

// ӨМНӨ:
class Shape {
    String type;

    double area() {
        if (type.equals("circle")) {
            return Math.PI * radius * radius;
        } else if (type.equals("rectangle")) {
            return width * height;
        } else if (type.equals("triangle")) {
            return 0.5 * base * height;
        }
        return 0;
    }
}

// ДАРАА:
interface Shape {
    double area();
}

class Circle implements Shape {
    private double radius;
    public double area() { return Math.PI * radius * radius; }
}

class Rectangle implements Shape {
    private double width, height;
    public double area() { return width * height; }
}

class Triangle implements Shape {
    private double base, height;
    public double area() { return 0.5 * base * height; }
}

1.4.6 Introduce Parameter Object (Параметрийн объект оруулах)

// ӨМНӨ:
public List<Event> findEvents(Date startDate, Date endDate,
                               String location, int minCapacity) { ... }

// ДАРАА:
public List<Event> findEvents(EventSearchCriteria criteria) { ... }

class EventSearchCriteria {
    private Date startDate;
    private Date endDate;
    private String location;
    private int minCapacity;
}

1.4.7 Move Method / Move Field (Метод/Талбар зөөх)

// ӨМНӨ: Order дахь метод Customer-ийн өгөгдлийг илүү ашиглаж байна
class Order {
    double getDiscountedPrice() {
        if (customer.getMemberYears() > 5 && customer.isPremium()) {
            return price * 0.8;
        }
        return price;
    }
}

// ДАРАА: Метод Customer руу зөөгдсөн
class Customer {
    double getDiscountRate() {
        if (memberYears > 5 && isPremium) return 0.8;
        return 1.0;
    }
}

class Order {
    double getDiscountedPrice() {
        return price * customer.getDiscountRate();
    }
}

1.4.8 Replace Temp with Query (Түр хувьсагчийг query-гээр солих)

// ӨМНӨ:
double basePrice = quantity * itemPrice;
if (basePrice > 1000) {
    return basePrice * 0.95;
}

// ДАРАА:
if (getBasePrice() > 1000) {
    return getBasePrice() * 0.95;
}

private double getBasePrice() {
    return quantity * itemPrice;
}

1.5 Refactoring хэзээ хийх вэ?

"Гурвын дүрэм" (Rule of Three):

"Ижил зүйлийг 3 дахь удаа давтахад refactor хий." — Don Roberts

  1. Анх удаа — Зүгээр хий
  2. 2 дахь удаа — Давтагдаж байна гэдгийг анзаар, гэхдээ зүгээр хий
  3. 3 дахь удаа — Refactor хий!

Refactoring хийх цагууд:

ЦагТайлбар
Шинэ функц нэмэхийн өмнөШинэ зүйл нэмэхэд хялбар болгох
Алдаа засахадАлдааг олоход хэцүү байсан бол — код ойлгомжтой биш
Код шалгалтын үед (Code Review)Баг бусад хөгжүүлэгчийн кодыг шалгахад
Техникийн өр хуримтлагдсан үедSprint backlog-д refactoring task нэмэх

Refactoring-ийн алхамууд:

1. 🧪 Тест бэлтгэх — Одоо байгаа зан төлөвийг тестлэх
2. 📝 Code Smell олох — Ямар асуудал байна?
3. 🔧 Жижиг алхмаар засах — Нэг удаад нэг refactoring
4. 🧪 Тест ажиллуулах — Зан төлөв өөрчлөгдөөгүй гэдгийг шалгах
5. 🔄 Давтах — Дараагийн smell руу шилжих

⚠️ Чухал: Refactoring-ийн ХАМГИЙН ЧУХАЛ алхам нь тест. Тестгүйгээр refactoring хийх нь нүдээ аниад газар хөдлөлтийн бүсэд барилга барьсантай адил.


1.6 Refactoring ба SOLID зарчмууд

SOLID зарчимRefactoring холбоос
S — Single ResponsibilityExtract Class, Extract Method → Нэг үүрэг
O — Open/ClosedReplace Conditional with Polymorphism → Шинэ төрөл нэмэхэд хаалттай
L — Liskov SubstitutionRefused Bequest засах → Зөв удамшил
I — Interface SegregationExtract Interface → Жижиг, тусгай интерфейс
D — Dependency InversionIntroduce Parameter → Абстрак хамаарал

1.7 IDE Refactoring хэрэгслүүд

Орчин үеийн IDE-нүүд refactoring-ийг автоматаар хийх хэрэгслүүдтэй.

Eclipse IDE-ийн refactoring товчлолууд:

ҮйлдэлWindows/LinuxMac
RenameAlt+Shift+RCmd+Option+R
Extract MethodAlt+Shift+MCmd+Option+M
Extract VariableAlt+Shift+LCmd+Option+L
Extract ConstantCtrl+1 → Extract ConstantCmd+1 → Extract Constant
InlineAlt+Shift+ICmd+Option+I
MoveAlt+Shift+VCmd+Option+V
Refactor MenuAlt+Shift+TCmd+Option+T

💡 Зөвлөгөө: IDE-ийн refactoring хэрэгсэл ашиглах нь гараар өөрчлөх дүрмаас найдвартай — IDE нь бүх reference-ийг автоматаар шинэчилдэг.


1.8 Refactoring-ийн жишээ: Бүтэн код

Өмнө (Refactoring хийхийн ӨМНӨ):

class OrderProcessor {
    public double proc(String ct, List<String[]> items, String dc) {
        double t = 0;

        // items = [name, price, qty]
        for (String[] i : items) {
            double p = Double.parseDouble(i[1]);
            int q = Integer.parseInt(i[2]);
            t += p * q;
        }

        // tax
        if (ct.equals("MN")) {
            t = t + t * 0.1;
        } else if (ct.equals("US")) {
            t = t + t * 0.08;
        }

        // discount
        if (dc != null) {
            if (dc.equals("VIP")) {
                t = t * 0.9;
            } else if (dc.equals("STUDENT")) {
                t = t * 0.8;
            }
        }

        if (t > 100000) {
            t = t * 0.95;
        }

        return t;
    }
}

Дараа (Refactoring хийсний ДАРАА):

class OrderProcessor {
    private static final double BULK_DISCOUNT_THRESHOLD = 100_000;
    private static final double BULK_DISCOUNT_RATE = 0.95;

    public double calculateTotal(String countryCode, List<OrderItem> items,
                                  DiscountType discountType) {
        double subtotal = calculateSubtotal(items);
        double totalWithTax = applyTax(subtotal, countryCode);
        double totalWithDiscount = applyMemberDiscount(totalWithTax, discountType);
        return applyBulkDiscount(totalWithDiscount);
    }

    private double calculateSubtotal(List<OrderItem> items) {
        return items.stream()
                    .mapToDouble(item -> item.getPrice() * item.getQuantity())
                    .sum();
    }

    private double applyTax(double amount, String countryCode) {
        double taxRate = TaxCalculator.getTaxRate(countryCode);
        return amount * (1 + taxRate);
    }

    private double applyMemberDiscount(double amount, DiscountType discountType) {
        if (discountType == null) return amount;
        return amount * discountType.getRate();
    }

    private double applyBulkDiscount(double amount) {
        if (amount > BULK_DISCOUNT_THRESHOLD) {
            return amount * BULK_DISCOUNT_RATE;
        }
        return amount;
    }
}

class OrderItem {
    private String name;
    private double price;
    private int quantity;
    // getters
}

enum DiscountType {
    VIP(0.9),
    STUDENT(0.8);

    private final double rate;
    DiscountType(double rate) { this.rate = rate; }
    public double getRate() { return rate; }
}

class TaxCalculator {
    private static final Map<String, Double> TAX_RATES = Map.of(
        "MN", 0.1,
        "US", 0.08
    );

    public static double getTaxRate(String countryCode) {
        return TAX_RATES.getOrDefault(countryCode, 0.0);
    }
}

Хийсэн refactoring-ууд:

#RefactoringТайлбар
1RenameproccalculateTotal, tsubtotal, ctcountryCode
2Extract MethodcalculateSubtotal(), applyTax(), applyMemberDiscount(), applyBulkDiscount()
3Replace Magic Number100000BULK_DISCOUNT_THRESHOLD, 0.95BULK_DISCOUNT_RATE
4Introduce Parameter ObjectString[]OrderItem класс
5Replace Conditional with Polymorphismif/else discount → DiscountType enum
6Extract ClassТатварын логик → TaxCalculator класс


ХЭСЭГ 2: ТҮЛХҮҮР ҮГ БА МЭРГЭЖЛИЙН НЭР ТОМЬЁО (Keywords & Glossary)

#Англи нэр томьёоМонгол утгаДэлгэрэнгүй тайлбар
1RefactoringДахин засварлалтГадаад зан төлөвийг өөрчлөхгүйгээр кодын дотоод бүтцийг сайжруулах.
2Code SmellКодын үнэрКодонд асуудал байж болзошгүйг илтгэдэг шинж тэмдэг. Алдаа биш, дохио.
3Technical DebtТехникийн өрХурдан гэхдээ бохир код бичсэнээс үүдсэн ирээдүйн засвар зардал.
4Extract MethodМетод гаргахКод блокийг тусдаа методод гаргах. Урт методыг хуваах.
5Extract ClassКласс гаргахНэг классын нэмэлт үүргийг тусдаа класст гаргах.
6RenameНэр өөрчлөхХувьсагч, метод, классын нэрийг утга учиртай болгох.
7Inline MethodМетод оруулахХэт энгийн методын биеийг дуудагч кодонд оруулах. Extract Method-ийн эсрэг.
8Move MethodМетод зөөхМетодыг илүү тохиромжтой класс руу зөөх.
9Replace Magic NumberШидэт тоо солихУтга учиргүй тоог нэрлэсэн тогтмолоор солих. 18LEGAL_AGE
10Long MethodУрт методХэт урт метод — олон зүйл хийж, ойлгоход хэцүү.
11Large ClassТом классХэт олон үүрэг хариуцсан класс (SRP зөрчил).
12Duplicate CodeДавхардсан кодИжил эсвэл маш төстэй код олон газар давтагдах.
13Dead CodeҮхсэн кодХэзээ ч ажиллахгүй, дуудагдахгүй код.
14Primitive ObsessionАнхдагч төрлийн хэрэглээString, int-ийг хэт их ашиглаж, утга бүхий объект үүсгэхгүй байх.
15Long Parameter ListОлон параметрМетод хэт олон параметр авч байна.
16Feature EnvyБусдын шинж чанарт шунахМетод өөрийнхөөсөө илүү бусад классын өгөгдлийг ашиглаж байна.
17Message ChainsМессежийн гинжa.getB().getC().getD() — олон объектоор дамжин дуудах.
18Switch StatementsSwitch давтамжИжил switch/if-else олон газар давтагдах.
19Refused BequestТатгалзсан өвДэд класс эх классын ихэнх зүйлийг ашигладаггүй.
20Shotgun SurgeryСум шиг тархалтНэг өөрчлөлт хийхэд олон класст засвар шаардлагатай.
21Divergent ChangeСалангид өөрчлөлтНэг класст олон өөр шалтгаанаар өөрчлөлт хийх.
22Speculative GeneralityШаардлагагүй ерөнхийлөлтИрээдүйд хэрэг болно гэж шаардлагагүй абстракци үүсгэсэн.
23Parameter ObjectПараметрийн объектОлон параметрийг нэг объектод цуглуулах.
24Value ObjectУтга объектУтга бүхий жижиг объект. PhoneNumber, Email, Address зэрэг.
25Replace Conditional with PolymorphismНөхцөлийг полиморфизмаар солихswitch/if-else-ийг удамшил, полиморфизмаар солих.
26Replace Temp with QueryТүр хувьсагчийг query-гээр солихТүр хувьсагчийн оронд метод дуудлага ашиглах.
27Introduce ParameterПараметр нэмэхМетод дотор хатуу утга (hardcode) байгааг параметрээр дамжуулах.
28Hide DelegateДелегат нуухMessage chain-ийг delegate метод ашиглан богиносгох.
29Self-Documenting CodeӨөрийгөө тайлбарлагч кодНэр, бүтцээрээ тайлбаргүйгээр ойлгогддог код.
30Rule of ThreeГурвын дүрэм3 дахь удаа давтагдвал refactor хий.
31Boy Scout RuleХөвгүүд скаутын дүрэмКодыг олсноосоо илүү цэвэр орхи.
32Code DecayКодын ялзралЦаг хугацаа өнгөрөхтүтэй кодын бүтэц муудах.
33Code ReviewКодын шалгалтБусад хөгжүүлэгчийн кодыг шалгаж сайжруулах.
34Inline VariableХувьсагч оруулахШаардлагагүй түр хувьсагчийг арилгаж шууд утга ашиглах.
35Extract InterfaceИнтерфейс гаргахКлассаас интерфейс тусгаарлах (ISP зарчим).
36Pull Up MethodМетод дээш зөөхДэд классуудын нийтлэг методыг эх класс руу зөөх.
37Push Down MethodМетод доош зөөхЭх классын тусгай методыг зөвхөн хэрэглэдэг дэд класс руу зөөх.
38Encapsulate FieldТалбар нуухpublic талбарыг private болгож, getter/setter нэмэх.
39Compose MethodМетод найруулахМетод дотор ижил абстракцийн түвшний алхмуудыг бүлэглэх.
40Martin FowlerМартин Фаулер"Refactoring" номны зохиогч. Refactoring-ийн каталог бүтээсэн.