Mã có mùi trong quá trình phát triển XOOPS
Tổng quan
Phần tiêu đề “Tổng quan”Mùi mã là dấu hiệu cho thấy các vấn đề tiềm ẩn trong mã. Chúng không nhất thiết có nghĩa là mã bị hỏng, nhưng chúng gợi ý các lĩnh vực có thể được hưởng lợi từ việc tái cấu trúc.
Mùi mã thông thường
Phần tiêu đề “Mùi mã thông thường”flowchart TD A[Code Smell Detected] --> B{Type?} B --> C[Bloaters] B --> D[Object-Orientation Abusers] B --> E[Change Preventers] B --> F[Dispensables] B --> G[Couplers]
C --> C1[Long Method] C --> C2[Large Class] C --> C3[Long Parameter List]
D --> D1[Switch Statements] D --> D2[Temporary Field]
E --> E1[Divergent Change] E --> E2[Shotgun Surgery]
F --> F1[Dead Code] F --> F2[Duplicate Code]
G --> G1[Feature Envy] G --> G2[Inappropriate Intimacy]Kẻ phồng rộp
Phần tiêu đề “Kẻ phồng rộp”Phương pháp dài
Phần tiêu đề “Phương pháp dài”// Smell: Method does too muchfunction processArticleSubmission($data) { // 100+ lines of validation, saving, notification, etc.}
// Solution: Extract into focused methodsfunction processArticleSubmission(array $data): Article{ $this->validateInput($data); $article = $this->createArticle($data); $this->saveArticle($article); $this->notifySubscribers($article); return $article;}Lớp lớn (Đối tượng thần)
Phần tiêu đề “Lớp lớn (Đối tượng thần)”// Smell: Class does everythingclass ArticleManager { public function create() { ... } public function delete() { ... } public function sendEmail() { ... } public function generatePDF() { ... } public function exportToExcel() { ... } public function validateUser() { ... } public function checkPermissions() { ... } // ... 50 more methods}
// Solution: Split into focused classesclass ArticleService { ... }class ArticleExporter { ... }class ArticleNotifier { ... }class PermissionChecker { ... }Danh sách tham số dài
Phần tiêu đề “Danh sách tham số dài”// Smell: Too many parametersfunction createArticle($title, $content, $author, $category, $tags, $status, $publishDate, $featured, $image) { ... }
// Solution: Use parameter objectclass CreateArticleCommand { public string $title; public string $content; public int $authorId; public int $categoryId; public array $tags; public string $status; public ?DateTime $publishDate; public bool $featured; public ?string $image;}
function createArticle(CreateArticleCommand $command): Article { ... }Kẻ lạm dụng hướng đối tượng
Phần tiêu đề “Kẻ lạm dụng hướng đối tượng”Câu lệnh chuyển đổi
Phần tiêu đề “Câu lệnh chuyển đổi”// Smell: Type checking with switchfunction getDiscount($userType) { switch ($userType) { case 'regular': return 0; case 'premium': return 10; case 'vip': return 20; default: return 0; }}
// Solution: Use polymorphisminterface UserType { public function getDiscount(): int;}
class RegularUser implements UserType { public function getDiscount(): int { return 0; }}
class PremiumUser implements UserType { public function getDiscount(): int { return 10; }}
class VipUser implements UserType { public function getDiscount(): int { return 20; }}Trường tạm thời
Phần tiêu đề “Trường tạm thời”// Smell: Fields only used in certain situationsclass Article { private $tempCalculatedScore;
public function search($terms) { $this->tempCalculatedScore = $this->calculateScore($terms); // ... use score }}
// Solution: Pass as parameter or return valueclass Article { public function getSearchScore(array $terms): float { return $this->calculateScore($terms); }}Ngăn chặn thay đổi
Phần tiêu đề “Ngăn chặn thay đổi”Thay đổi khác biệt
Phần tiêu đề “Thay đổi khác biệt”// Smell: One class changed for many different reasonsclass Article { public function save() { ... } // Database change public function toJson() { ... } // API format change public function validate() { ... } // Business rule change public function render() { ... } // UI change}
// Solution: Separate responsibilitiesclass Article { ... } // Domain object onlyclass ArticleRepository { public function save() { ... } }class ArticleSerializer { public function toJson() { ... } }class ArticleValidator { public function validate() { ... } }Phẫu thuật bắn súng
Phần tiêu đề “Phẫu thuật bắn súng”// Smell: One change requires many file edits// Changing date format requires editing:// - ArticleController.php// - ArticleView.php// - ArticleAPI.php// - ArticleExport.php
// Solution: Centralizeclass DateFormatter { public function format(DateTime $date): string { return $date->format($this->config->get('date_format')); }}Vật dụng cần thiết
Phần tiêu đề “Vật dụng cần thiết”Mã chết
Phần tiêu đề “Mã chết”// Smell: Unreachable or unused codefunction processData($data) { if (true) { return $this->handleData($data); } // This never executes return $this->legacyHandler($data);}
// Old unused method still in codebasefunction oldMethod() { // Not called anywhere}
// Solution: Remove dead codefunction processData($data) { return $this->handleData($data);}Mã trùng lặp
Phần tiêu đề “Mã trùng lặp”// Smell: Same logic in multiple placesclass ArticleHandler { public function getActive() { $criteria = new CriteriaCompo(); $criteria->add(new Criteria('status', 'active')); return $this->getObjects($criteria); }}
class NewsHandler { public function getActive() { $criteria = new CriteriaCompo(); $criteria->add(new Criteria('status', 'active')); return $this->getObjects($criteria); }}
// Solution: Extract common behaviortrait ActiveRecordsTrait { public function getActive(): array { $criteria = new CriteriaCompo(); $criteria->add(new Criteria('status', 'active')); return $this->getObjects($criteria); }}Bộ ghép nối
Phần tiêu đề “Bộ ghép nối”Tính năng ghen tị
Phần tiêu đề “Tính năng ghen tị”// Smell: Method uses another object's data more than its ownclass Invoice { public function calculateTotal(Customer $customer) { $total = 0; foreach ($this->items as $item) { $total += $item->price; } // Uses customer data extensively if ($customer->isPremium()) { $total *= (1 - $customer->getDiscountRate()); } if ($customer->getCountry() === 'US') { $total *= 1.08; // Tax } return $total; }}
// Solution: Move behavior to the object with the dataclass Customer { public function applyDiscount(float $amount): float { return $this->isPremium() ? $amount * (1 - $this->discountRate) : $amount; }
public function applyTax(float $amount): float { return $this->country === 'US' ? $amount * 1.08 : $amount; }}Danh sách kiểm tra tái cấu trúc
Phần tiêu đề “Danh sách kiểm tra tái cấu trúc”Khi bạn phát hiện ra mùi mã:
- Nhận dạng - Mùi gì?
- Đánh giá - Tác động nghiêm trọng đến mức nào?
- Kế hoạch - Áp dụng kỹ thuật tái cấu trúc nào?
- Thử nghiệm - Đảm bảo tồn tại các thử nghiệm trước khi tái cấu trúc
- Refactor - Thực hiện các thay đổi nhỏ, tăng dần
- Xác minh - Chạy thử nghiệm sau mỗi thay đổi
Tài liệu liên quan
Phần tiêu đề “Tài liệu liên quan”- Nguyên tắc mã sạch
- Mã tổ chức
- Thử nghiệm các phương pháp hay nhất