+2

BÀI 1: Giải Mã Tư Duy Trừu tượng hóa – Nghệ thuật "Giấu Sự Phức Tạp"

Khi nhìn vào một hệ thống lớn, lập trình viên giỏi và lập trình viên non tay thường nhìn thấy hai thế giới hoàn toàn khác nhau:

  • Người non tay: Nhìn thấy một mớ hỗn độn các dòng code, các câu lệnh SQL lằng nhằng, các thư viện bên thứ ba chằng chịt và cảm thấy ngợp.
  • Kỹ sư giỏi: Nhìn thấy các tầng (Layers), các ranh giới (Boundaries) và các hợp đồng giao tiếp (Contracts/Interfaces). Họ không quan tâm chi tiết bên trong chạy ra sao, họ chỉ quan tâm khối đó nhận vào cái gì và trả về cái gì.

Đó chính là cốt lõi của Trừu tượng hóa (Abstraction).

1. Trừu tượng hóa là gì trong Lập trình?

Hiểu một cách đơn giản nhất: Trừu tượng hóa là việc tách biệt giữa "Cái gì làm" (What)"Làm thế nào để làm" (How).

  • Mức chi tiết (How): Cách mà cơ sở dữ liệu xử lý câu lệnh, cách cỗ máy Elasticsearch phân tích cú pháp query DSL, hoặc cách một thư viện HTTP gửi gói tin đi.
  • Mức trừu tượng (What): Một cái tên hàm cực kỳ ngắn gọn như findWhere(), create(), hay sendEmail().

Ví dụ thực tế ngoài đời: Khi bạn lái ô tô, bạn chỉ cần đạp chân ga (Giao diện / Abstraction) để xe chạy nhanh hơn. Bạn không cần biết kim phun nhiên liệu hoạt động thế nào, hỗn hợp khí và nhiên liệu cháy ra sao trong buồng đốt (Chi tiết bên dưới). Chân ga chính là lớp trừu tượng tuyệt vời giúp não bạn không bị quá tải.

2. Tại sao chúng ta cực kỳ cần Tầng Trừu tượng (Abstraction Layer)?

Nếu không có các lớp trừu tượng, hệ thống của bạn sẽ nhanh chóng rơi vào thảm họa Spaghetti Code (Mã mì tôm) với các hệ lụy:

  • Tightly Coupled (Ghép nối chặt chẽ): Business logic của bạn dính chặt vào một công nghệ cụ thể. Ngày mai sếp bảo đổi từ MySQL sang PostgreSQL, hoặc đổi từ thư viện Elasticsearch này sang thư viện khác, bạn sẽ phải sửa code ở hàng trăm nơi.
  • Cognitive Load (Gánh nặng nhận thức): Lập trình viên phải ôm đồm quá nhiều thứ trong đầu cùng một lúc (vừa phải nghĩ logic nghiệp vụ, vừa phải nhớ cú pháp chi tiết của từng thư viện bên ngoài).
  • Khó viết Unit Test: Không thể viết test cho logic nghiệp vụ nếu nó bị phụ thuộc cứng vào database thật hoặc API bên thứ ba.

3. Phân biệt Trừu tượng hóa (Abstraction) và Đóng gói (Encapsulation)

Hai khái niệm này hay bị nhầm lẫn, hãy phân định chúng bằng một quy tắc vàng:

  • Đóng gói (Encapsulation): Là việc giấu đi trạng thái và dữ liệu bên trong của một đối tượng, không cho bên ngoài can thiệp trực tiếp (dùng private, protected). Mục đích là bảo vệ dữ liệu.
  • Trừu tượng hóa (Abstraction): Là việc giấu đi độ phức tạp của logic thực thi, chỉ phơi ra những gì cần thiết qua một giao diện chung. Mục đích là giảm độ phức tạp và định hình góc nhìn.

4. Ví dụ Thực chiến: Đập tan Code "Mì Tôm"

Hãy nhìn vào cách một lập trình viên viết code vi phạm nguyên tắc trừu tượng, và cách một kỹ sư tối ưu nó.

❌ Cách 1: Code bết bát (Không có Abstraction Layer)

Controller trực tiếp gọi thư viện bên ngoài:

public function search(Request $request){
    // Controller đang phải ôm đồm cả cú pháp chi tiết của Elasticsearch Client thuần
    $client = \Elastic\Elasticsearch\ClientBuilder::create()->build();
    
    $response = $client->search([
        'index' => 'production_products_v1',
        'body' => [
            'query' => [
                'match' => ['name' => $request->keyword]
            ]
        ]
    ]);

    return response()->json($response->asArray());
}

Hậu quả: Nếu ngày mai đổi cách gọi thư viện Elasticsearch, hoặc đổi tên index, bạn phải đi sửa ở mọi Controller. Controller đang bị "nhiễm độc" bởi chi tiết hạ tầng.

✅ Cách 2: Code chuẩn mực (Sử dụng Abstraction Layer - Repository & Builder)

Áp dụng tư duy mà chúng ta đã phân tích ở các bài toán trước:

  1. Định nghĩa một Contract (Interface):
interface EsRepositoryInterface {
    public function newEsBuilder(): EsBuilder;
    public function indexName(): string;
}
  1. Controller gọi cực kỳ gọn gàng (Chỉ quan tâm What, không quan tâm How):
public function search(Request $request, EsRepositoryInterface $productRepo){
    // Tầng trừu tượng che giấu toàn bộ sự phức tạp của Elasticsearch bên dưới
    $results = $productRepo->newEsBuilder()
        ->where('name', $request->keyword)
        ->get();

    return response()->json($results);
}

Nhìn vào đoạn code thứ hai, Controller trông cực kỳ sạch sẽ, dễ đọc, dễ viết test và hoàn toàn độc lập với việc tầng dưới đang dùng công nghệ gì.

Tổng kết

  • Trừu tượng hóa giúp bạn che giấu sự phức tạp và chỉ phơi ra các giao diện giao tiếp rõ ràng.
  • Một Abstraction Layer tốt giúp mã nguồn linh hoạt, dễ thay thế linh kiện (công nghệ) mà không làm sập hệ thống.

Bạn đã sẵn sàng để chuyển sang Bài 2 chưa? Trong bài tiếp theo, chúng ta sẽ mổ xẻ cách xây dựng các Interface và Contract sao cho chuẩn chỉnh nhất mà không bị lạm dụng (tránh việc tạo ra lớp trừu tượng rỗng tuếch).


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí