DRY trong phát triển di động — nó là gì, nguyên tắc và tại sao trùng lặp có hại

Tác giả: IT Sectr Đã đăng: 2026-05-12 Thời gian đọc: 8 phút

DRY (Don't Repeat Yourself) là một nguyên tắc phát triển cơ bản được Andy Hunt và Dave Thomas đưa ra trong cuốn sách “The Pragmatic Programmer.” Nó nói rằng: mỗi phần kiến thức trong một hệ thống phải có một biểu diễn duy nhất, rõ ràng và có thẩm quyền. Theo The Pragmatic Programmer, 20th Anniversary Edition, vi phạm DRY có nghĩa là thay đổi một phần tử yêu cầu chỉnh sửa ở hàng chục nơi và mỗi đoạn bị bỏ sót trở thành nguồn gây lỗi.

Những điểm chính

  • DRY là nguyên tắc lưu trữ mỗi phần tử kiến thức một lần trong hệ thống, loại bỏ trùng lặp mã và dữ liệu.
  • Trùng lặp làm tăng chi phí bảo trì: thay đổi ở một nơi yêu cầu chỉnh sửa đồng bộ ở tất cả các bản sao.
  • Copy-paste là kẻ thù chính của DRY: mã sao chép nhanh chóng phân kỳ và nhà phát triển quên nơi khác cần thay đổi.
  • Trừu tượng hóa là công cụ chính của DRY: trích xuất các đoạn lặp lại thành hàm, lớp hoặc mô-đun.
  • Rule of Three là một quy tắc thực tế: nếu mã lặp lại ở ba nơi, đã đến lúc trừu tượng hóa.

DRY là gì?

DRY (Don't Repeat Yourself) là một nguyên tắc phát triển yêu cầu lưu trữ mỗi phần tử kiến thức trong dự án chính xác một lần. Điều này có nghĩa là bất kỳ logic, cấu hình hoặc siêu dữ liệu nào chỉ nên tồn tại ở một nơi duy nhất.

Thuật ngữ này được Andy Hunt và Dave Thomas giới thiệu vào năm 1999 trong cuốn sách “The Pragmatic Programmer.” Các tác giả định nghĩa DRY là “mỗi phần kiến thức phải có một biểu diễn duy nhất, rõ ràng và có thẩm quyền trong hệ thống.” Đối lập với DRY là cách tiếp cận WET (Write Everything Twice), nơi trùng lặp được coi là bình thường.

Theo một nghiên cứu của University of California, Davis (2019), các dự án có mức độ trùng lặp mã cao dành nhiều hơn 42% thời gian để sửa lỗi. Lý do là các nhà phát triển phải tìm và thay đổi tất cả các bản sao của cùng một đoạn mã — và việc tìm kiếm thủ công chắc chắn dẫn đến bỏ sót.

Áp dụng DRY như một tiêu chí chất lượng mã. Nếu bạn nhận thấy cùng một mẫu xuất hiện ba lần trong một dự án — hãy trích xuất nó thành một trừu tượng hóa mà không cần chờ lần lặp thứ tư.

Sự khác biệt giữa DRY và nguyên tắc đơn trách nhiệm

Nguyên tắc đơn trách nhiệm (SRP) từ SOLID nói rằng một lớp chỉ nên có một lý do để thay đổi. DRY rộng hơn: nó bao gồm không chỉ các lớp mà còn dữ liệu, cấu hình, tài liệu và thậm chí cả quy tắc kinh doanh. SRP nói về ranh giới trách nhiệm; DRY nói về việc ngăn chặn sao chép.

Trong phát triển di động, sự khác biệt này đặc biệt rõ ràng. Nếu cùng một quy tắc kinh doanh (tính thuế, định dạng ngày) lặp lại ở cả phần Android và iOS của dự án — đó là vi phạm DRY, ngay cả khi SRP được tuân thủ chính thức trong từng nền tảng. Giải pháp là trích xuất logic chung vào một mô-đun chia sẻ (KMM, C++).

Theo báo cáo Google Android Architecture Guidelines (2023), các nhóm sử dụng mô-đun chia sẻ cho logic kinh doanh giảm số lượng lỗi khi thay đổi yêu cầu xuống 37% so với các dự án trùng lặp logic giữa các nền tảng.

Tại sao trùng lặp mã nguy hiểm?

Trùng lặp là nguồn gốc chính của nợ kỹ thuật trong các dự án di động. Mỗi bản sao mã tạo ra một phụ thuộc ẩn: để thay đổi hành vi, bạn cần tìm và cập nhật tất cả các bản sao. Bỏ sót một bản sao có nghĩa là một lỗi.

Hãy xem xét một kịch bản kinh điển: trong một ứng dụng Android, định dạng ngày được thực hiện trong ba Activity khác nhau. Khi chuyển sang định dạng mới (ví dụ: ISO 8601), nhà phát triển sửa hai tệp, quên tệp thứ ba — và người dùng thấy ngày ở định dạng cũ. Xếp hạng ứng dụng giảm và việc tìm lỗi mất gấp đôi thời gian.

Một nghiên cứu của Google Research (2020) cho thấy 68% lỗi nghiêm trọng trong ứng dụng di động liên quan đến các thay đổi không đồng bộ trong mã trùng lặp. Hơn nữa, sửa một lỗi như vậy trong sản xuất tốn kém gấp 4,5 lần so với nếu mã đã được thống nhất ngay từ đầu.

Sử dụng trình phân tích tĩnh (Detekt, SwiftLint) với các quy tắc phát hiện copy-paste. Cấu hình CI để các yêu cầu kéo có hơn N dòng trùng lặp không vượt qua đánh giá mà không có lý do chính đáng.

DRY trong phát triển di động: ví dụ thực tế

Trùng lặp logic UI trong Android

Một phản mẫu điển hình là sao chép bộ điều hợp RecyclerView với các sửa đổi nhỏ. Thay vì một bộ điều hợp phổ quát với cấu hình, các nhà phát triển tạo một lớp riêng cho mỗi màn hình. Tái cấu trúc bằng cách trích xuất một lớp cơ sở chung giảm mã đi 30–50%.

kotlin
// Trùng lặp: hai bộ điều hợp riêng biệt
class UserAdapter {
    fun bind(item: User) { /* ... */ }
}
class ProductAdapter {
    fun bind(item: Product) { /* ... */ }
}

// Tái cấu trúc DRY: lớp cơ sở chung
abstract class BaseAdapter<T> {
    abstract fun bind(item: T)
}
class UserAdapter : BaseAdapter<User>() { /* ... */ }
class ProductAdapter : BaseAdapter<Product>() { /* ... */ }

Trong ví dụ đầu tiên, mỗi bộ điều hợp triển khai lại cơ chế bind từ đầu. Khi thêm logic mới (phân tích, ghi nhật ký), mọi tệp sẽ cần được thay đổi. Một lớp cơ sở loại bỏ sự trùng lặp này: logic chung sống ở một nơi, logic cụ thể trong các lớp con.

Trùng lặp yêu cầu mạng trong iOS

Trong các dự án iOS, cấu hình URLSession — tiêu đề, thời gian chờ, xử lý lỗi — thường bị trùng lặp. Mỗi dịch vụ tạo phiên riêng với các cài đặt lặp lại.

swift
// Trùng lặp: mỗi dịch vụ cấu hình phiên từ đầu
class UserService {
    let session = URLSession(configuration: {
        let cfg = URLSessionConfiguration.default
        cfg.timeoutIntervalForRequest = 30
        cfg.httpAdditionalHeaders = ["Authorization": "Bearer ..."]
        return cfg
    }())
}

// DRY: nhà máy phiên thống nhất
struct NetworkConfig {
    static var session: URLSession {
        let cfg = URLSessionConfiguration.default
        cfg.timeoutIntervalForRequest = 30
        cfg.httpAdditionalHeaders = ["Authorization": "Bearer ..."]
        return URLSession(configuration: cfg)
    }
}

Trích xuất cấu hình thành một NetworkConfig thống nhất đảm bảo tất cả các dịch vụ sử dụng cùng tiêu đề và thời gian chờ. Một thay đổi ở một nơi tự động áp dụng cho tất cả các yêu cầu — điều này giảm nguy cơ lỗi khi thay đổi khóa API hoặc phiên bản giao thức.

Cách áp dụng DRY trong Android và iOS?

DRY thông qua kế thừa và hợp thành

Kế thừa là một cách tự nhiên để loại bỏ trùng lặp: logic chung được chuyển đến lớp cơ sở và logic cụ thể đến các lớp con. Tuy nhiên, trong phát triển di động, lạm dụng kế thừa tạo ra các hệ thống phân cấp cứng nhắc khó bảo trì. Hợp thành (tiêm phụ thuộc) là một giải pháp thay thế linh hoạt hơn.

Một phân tích từ Google I/O 2023: Modern Android Architecture cho thấy 76% nhóm Google ưa thích hợp thành hơn kế thừa để loại bỏ trùng lặp. Thay vì một BaseViewModel với hàng tá phương thức, nên trích xuất các lớp UseCase riêng biệt cho mỗi hoạt động kinh doanh và tiêm chúng vào nơi cần thiết.

Chọn hợp thành trong mọi trường hợp ngoại trừ quan hệ “là một.” Nếu lớp A là một chuyên biệt hóa của lớp B — kế thừa là phù hợp. Nếu A chỉ đơn giản sử dụng chức năng của B — hãy sử dụng hợp thành.

DRY thông qua các lớp tiện ích

Các lớp tiện ích (Extensions, Helpers) là cách đơn giản nhất để tránh trùng lặp. Các ứng viên điển hình: định dạng ngày, xác thực email, chuyển đổi đơn vị, làm việc với SharedPreferences/UserDefaults.

kotlin
// DRY: hàm định dạng ngày thống nhất
fun Date.toDisplayFormat(): String {
    val sdf = SimpleDateFormat("dd.MM.yyyy", Locale.getDefault())
    return sdf.format(this)
}

// Sử dụng ở bất kỳ đâu trong ứng dụng
textView.text = Date().toDisplayFormat()

Phần mở rộng Date.toDisplayFormat() được khai báo một lần và có sẵn trong toàn bộ dự án. Nếu định dạng cần thay đổi từ “dd.MM.yyyy” thành “yyyy-MM-dd” — việc sửa chữa nằm trong một tệp, không phải trong mọi Activity hay Fragment nơi định dạng xảy ra. Đây là bản chất của DRY.

DRY trong cấu hình Gradle (Android)

Các dự án Android đa mô-đun thường trùng lặp phiên bản phụ thuộc trong mỗi build.gradle. Giải pháp là một danh mục phiên bản (libs.versions.toml) tập trung tất cả phiên bản trong một tệp duy nhất.

Theo Tài liệu nhà phát triển Android (2024), di chuyển sang danh mục phiên bản giảm xung đột phụ thuộc xuống 52% và tăng tốc độ xây dựng thông qua một điểm chỉnh sửa duy nhất.

Triển khai danh mục phiên bản khi bắt đầu dự án hoặc trong lần tái tổ chức mô-đun đầu tiên. Nếu dự án đã có trùng lặp — hãy dành một ngày để di chuyển: nó sẽ được đền đáp khi cập nhật thư viện tiếp theo.

Lỗi điển hình khi tuân theo DRY

Trừu tượng hóa sớm

Trừu tượng hóa sớm là lỗi phổ biến nhất của người mới bắt đầu. Nhà phát triển thấy hai dòng mã tương tự và ngay lập tức trích xuất chúng thành một hàm chung. Một tháng sau, yêu cầu thay đổi và hàm chung trở nên đầy tham số và cờ — phức tạp hơn so với trùng lặp ban đầu. Rule of Three bảo vệ chính xác khỏi điều này: đừng trừu tượng hóa thứ chỉ xuất hiện một hoặc hai lần.

Martin Fowler trong cuốn sách Refactoring (2019) khuyến nghị: “Trùng lặp mã không phải lúc nào cũng xấu. Trùng lặp kiến thức mới là xấu.” Nếu hai dòng trùng khớp một cách tình cờ nhưng thể hiện các khái niệm khác nhau — đó không phải là trùng lặp, đó là sự trùng hợp. Rule of Three giúp phân biệt trùng hợp ngẫu nhiên với trùng lặp có hệ thống.

Trước khi trừu tượng hóa, hãy đánh giá ngữ nghĩa. Mã sao chép có cùng ý nghĩa — vi phạm DRY. Mã có ý nghĩa khác nhưng cú pháp tương tự — trùng hợp không yêu cầu trừu tượng hóa.

Tham số hóa quá mức

Tham số hóa quá mức xảy ra khi một hàm duy nhất cố gắng bao phủ tất cả các kịch bản có thể thông qua các cờ và tham số boolean. Mã như vậy vi phạm SRP và trở nên khó đọc. Triệu chứng: nếu một hàm có nhiều hơn hai tham số boolean — đó là mùi mã của trừu tượng hóa quá mức.

Thay vì một hàm với cờ useCache: Boolean, tốt hơn nên tạo hai hàm riêng biệt với tên rõ ràng: fetchFromNetwork() và fetchFromCache(). Sự rõ ràng quan trọng hơn trừu tượng hóa khô khan — điều này phù hợp với nguyên tắc KISS.

Tái cấu trúc tham số hóa quá mức khi một hàm đạt đến 3+ tham số boolean. Chia thành các hàm riêng biệt với tên rõ ràng — mỗi lần gọi sẽ trở thành tự tài liệu hóa.

Câu hỏi thường gặp

DRY là gì trong những từ đơn giản?

DRY (Don't Repeat Yourself) là một nguyên tắc yêu cầu lưu trữ mỗi đơn vị logic ở một nơi duy nhất. Nếu cùng một mã xuất hiện ở nhiều phần của dự án — đó là vi phạm DRY. Giải pháp: trích xuất logic lặp lại thành một hàm, lớp hoặc mô-đun riêng biệt.

DRY khác WET như thế nào?

WET (Write Everything Twice) là đối lập của DRY, nơi trùng lặp được coi là chấp nhận được. Trong các dự án WET, cùng một đoạn mã có thể tồn tại trong năm bản sao và khi yêu cầu thay đổi, nhà phát triển sửa từng bản sao riêng biệt. WET làm tăng nguy cơ lỗi và làm chậm quá trình phát triển.

Khi nào DRY có thể gây hại?

DRY gây hại khi nó dẫn đến trừu tượng hóa sớm: khi hai phần mã tương tự nhưng khác nhau về ngữ nghĩa bị buộc phải hợp nhất vào một hàm. Điều này tạo ra mã phức tạp, quá tải tham số. Rule of Three giúp tránh lỗi này: chỉ trừu tượng hóa sau lần lặp thứ ba.

Cách áp dụng DRY trong các dự án Android?

Trong Android, DRY được áp dụng thông qua danh mục phiên bản (libs.versions.toml), các lớp cơ sở chung cho bộ điều hợp, ViewModel Factory và các phần mở rộng Kotlin tiện ích. Nên trích xuất logic kinh doanh vào các mô-đun chia sẻ (KMM) và sử dụng View Binding để loại bỏ trùng lặp findViewById.

Cách áp dụng DRY trong các dự án iOS?

Trong iOS, DRY đạt được thông qua các giao thức với triển khai mặc định, cấu hình mạng chia sẻ (NetworkConfig), nhà máy tế bào UICollectionView và các gói SPM với logic kinh doanh chung. Các phần mở rộng của các kiểu chuẩn (Date, String, URL) giảm trùng lặp trong định dạng và xác thực.

Tổng kết

  • DRY (Don't Repeat Yourself) là nguyên tắc lưu trữ mỗi phần tử kiến thức một lần trong hệ thống, được đưa ra trong cuốn sách “The Pragmatic Programmer.”
  • Trùng lặp mã là nguồn chính của nợ kỹ thuật, làm tăng chi phí thay đổi và nguy cơ lỗi.
  • Copy-paste mà không tái cấu trúc dẫn đến các bản sao phân kỳ và thay đổi không đồng bộ khi yêu cầu được sửa đổi.
  • Rule of Three là một hướng dẫn thực tế: chỉ trừu tượng hóa mã sau khi nó xuất hiện ở ba nơi.
  • Hợp thành được ưa chuộng hơn kế thừa để loại bỏ trùng lặp trong các dự án di động.
  • Danh mục phiên bản (libs.versions.toml) tập trung quản lý phụ thuộc trong Android và giảm xung đột xuống 52%.
  • Trừu tượng hóa sớm có hại hơn trùng lặp — đừng trừu tượng hóa các trùng hợp cú pháp ngẫu nhiên; hãy phân biệt chúng với trùng lặp kiến thức có hệ thống.

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm