ЛЕКЦ 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 юу БИШ вэ?
| Refactoring | Refactoring БИШ |
|---|---|
| Кодын бүтцийг сайжруулах | Шинэ функц нэмэх |
| Уншихад хялбар болгох | Алдаа засах (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
- Анх удаа — Зүгээр хий
- 2 дахь удаа — Давтагдаж байна гэдгийг анзаар, гэхдээ зүгээр хий
- 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 Responsibility | Extract Class, Extract Method → Нэг үүрэг |
| O — Open/Closed | Replace Conditional with Polymorphism → Шинэ төрөл нэмэхэд хаалттай |
| L — Liskov Substitution | Refused Bequest засах → Зөв удамшил |
| I — Interface Segregation | Extract Interface → Жижиг, тусгай интерфейс |
| D — Dependency Inversion | Introduce Parameter → Абстрак хамаарал |
1.7 IDE Refactoring хэрэгслүүд
Орчин үеийн IDE-нүүд refactoring-ийг автоматаар хийх хэрэгслүүдтэй.
Eclipse IDE-ийн refactoring товчлолууд:
| Үйлдэл | Windows/Linux | Mac |
|---|---|---|
| Rename | Alt+Shift+R | Cmd+Option+R |
| Extract Method | Alt+Shift+M | Cmd+Option+M |
| Extract Variable | Alt+Shift+L | Cmd+Option+L |
| Extract Constant | Ctrl+1 → Extract Constant | Cmd+1 → Extract Constant |
| Inline | Alt+Shift+I | Cmd+Option+I |
| Move | Alt+Shift+V | Cmd+Option+V |
| Refactor Menu | Alt+Shift+T | Cmd+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 | Тайлбар |
|---|---|---|
| 1 | Rename | proc → calculateTotal, t → subtotal, ct → countryCode |
| 2 | Extract Method | calculateSubtotal(), applyTax(), applyMemberDiscount(), applyBulkDiscount() |
| 3 | Replace Magic Number | 100000 → BULK_DISCOUNT_THRESHOLD, 0.95 → BULK_DISCOUNT_RATE |
| 4 | Introduce Parameter Object | String[] → OrderItem класс |
| 5 | Replace Conditional with Polymorphism | if/else discount → DiscountType enum |
| 6 | Extract Class | Татварын логик → TaxCalculator класс |
ХЭСЭГ 2: ТҮЛХҮҮР ҮГ БА МЭРГЭЖЛИЙН НЭР ТОМЬЁО (Keywords & Glossary)
| # | Англи нэр томьёо | Монгол утга | Дэлгэрэнгүй тайлбар |
|---|---|---|---|
| 1 | Refactoring | Дахин засварлалт | Гадаад зан төлөвийг өөрчлөхгүйгээр кодын дотоод бүтцийг сайжруулах. |
| 2 | Code Smell | Кодын үнэр | Кодонд асуудал байж болзошгүйг илтгэдэг шинж тэмдэг. Алдаа биш, дохио. |
| 3 | Technical Debt | Техникийн өр | Хурдан гэхдээ бохир код бичсэнээс үүдсэн ирээдүйн засвар зардал. |
| 4 | Extract Method | Метод гаргах | Код блокийг тусдаа методод гаргах. Урт методыг хуваах. |
| 5 | Extract Class | Класс гаргах | Нэг классын нэмэлт үүргийг тусдаа класст гаргах. |
| 6 | Rename | Нэр өөрчлөх | Хувьсагч, метод, классын нэрийг утга учиртай болгох. |
| 7 | Inline Method | Метод оруулах | Хэт энгийн методын биеийг дуудагч кодонд оруулах. Extract Method-ийн эсрэг. |
| 8 | Move Method | Метод зөөх | Методыг илүү тохиромжтой класс руу зөөх. |
| 9 | Replace Magic Number | Шидэт тоо солих | Утга учиргүй тоог нэрлэсэн тогтмолоор солих. 18 → LEGAL_AGE |
| 10 | Long Method | Урт метод | Хэт урт метод — олон зүйл хийж, ойлгоход хэцүү. |
| 11 | Large Class | Том класс | Хэт олон үүрэг хариуцсан класс (SRP зөрчил). |
| 12 | Duplicate Code | Давхардсан код | Ижил эсвэл маш төстэй код олон газар давтагдах. |
| 13 | Dead Code | Үхсэн код | Хэзээ ч ажиллахгүй, дуудагдахгүй код. |
| 14 | Primitive Obsession | Анхдагч төрлийн хэрэглээ | String, int-ийг хэт их ашиглаж, утга бүхий объект үүсгэхгүй байх. |
| 15 | Long Parameter List | Олон параметр | Метод хэт олон параметр авч байна. |
| 16 | Feature Envy | Бусдын шинж чанарт шунах | Метод өөрийнхөөсөө илүү бусад классын өгөгдлийг ашиглаж байна. |
| 17 | Message Chains | Мессежийн гинж | a.getB().getC().getD() — олон объектоор дамжин дуудах. |
| 18 | Switch Statements | Switch давтамж | Ижил switch/if-else олон газар давтагдах. |
| 19 | Refused Bequest | Татгалзсан өв | Дэд класс эх классын ихэнх зүйлийг ашигладаггүй. |
| 20 | Shotgun Surgery | Сум шиг тархалт | Нэг өөрчлөлт хийхэд олон класст засвар шаардлагатай. |
| 21 | Divergent Change | Салангид өөрчлөлт | Нэг класст олон өөр шалтгаанаар өөрчлөлт хийх. |
| 22 | Speculative Generality | Шаардлагагүй ерөнхийлөлт | Ирээдүйд хэрэг болно гэж шаардлагагүй абстракци үүсгэсэн. |
| 23 | Parameter Object | Параметрийн объект | Олон параметрийг нэг объектод цуглуулах. |
| 24 | Value Object | Утга объект | Утга бүхий жижиг объект. PhoneNumber, Email, Address зэрэг. |
| 25 | Replace Conditional with Polymorphism | Нөхцөлийг полиморфизмаар солих | switch/if-else-ийг удамшил, полиморфизмаар солих. |
| 26 | Replace Temp with Query | Түр хувьсагчийг query-гээр солих | Түр хувьсагчийн оронд метод дуудлага ашиглах. |
| 27 | Introduce Parameter | Параметр нэмэх | Метод дотор хатуу утга (hardcode) байгааг параметрээр дамжуулах. |
| 28 | Hide Delegate | Делегат нуух | Message chain-ийг delegate метод ашиглан богиносгох. |
| 29 | Self-Documenting Code | Өөрийгөө тайлбарлагч код | Нэр, бүтцээрээ тайлбаргүйгээр ойлгогддог код. |
| 30 | Rule of Three | Гурвын дүрэм | 3 дахь удаа давтагдвал refactor хий. |
| 31 | Boy Scout Rule | Хөвгүүд скаутын дүрэм | Кодыг олсноосоо илүү цэвэр орхи. |
| 32 | Code Decay | Кодын ялзрал | Цаг хугацаа өнгөрөхтүтэй кодын бүтэц муудах. |
| 33 | Code Review | Кодын шалгалт | Бусад хөгжүүлэгчийн кодыг шалгаж сайжруулах. |
| 34 | Inline Variable | Хувьсагч оруулах | Шаардлагагүй түр хувьсагчийг арилгаж шууд утга ашиглах. |
| 35 | Extract Interface | Интерфейс гаргах | Классаас интерфейс тусгаарлах (ISP зарчим). |
| 36 | Pull Up Method | Метод дээш зөөх | Дэд классуудын нийтлэг методыг эх класс руу зөөх. |
| 37 | Push Down Method | Метод доош зөөх | Эх классын тусгай методыг зөвхөн хэрэглэдэг дэд класс руу зөөх. |
| 38 | Encapsulate Field | Талбар нуух | public талбарыг private болгож, getter/setter нэмэх. |
| 39 | Compose Method | Метод найруулах | Метод дотор ижил абстракцийн түвшний алхмуудыг бүлэглэх. |
| 40 | Martin Fowler | Мартин Фаулер | "Refactoring" номны зохиогч. Refactoring-ийн каталог бүтээсэн. |