11/08/2018, 20:59

Thế giới của abstraction và khi abstraction bị rò rỉ

Abstraction là gì? Thế giới của chúng ta đang sống được xây dựng dựa trên các abstraction. Khi Honda bán một chiếc xe máy, họ sẽ bảo bạn rằng chỉ cần leo lên xe, khởi động và rồ ga thì xe sẽ chạy, bạn không cần phải biết nó sử dụng động cơ đốt trong hay đốt phông lông, hai thì hay bốn thì, ...

Abstraction là gì?

Thế giới của chúng ta đang sống được xây dựng dựa trên các abstraction.

Khi Honda bán một chiếc xe máy, họ sẽ bảo bạn rằng chỉ cần leo lên xe, khởi động và rồ ga thì xe sẽ chạy, bạn không cần phải biết nó sử dụng động cơ đốt trong hay đốt phông lông, hai thì hay bốn thì, dung tích xy-lanh 150cc hay 1500cc.

xe honda

Với Microsoft Internet Explorer, họ sẽ quảng cáo rằng bạn chỉ cần nhập đường dẫn và nhấn Enter, trang web sẽ được hiển thị mà không đòi hỏi bạn phải tìm hiểu về giao thức HTTP, bảo mật TLS hay dữ liệu được truyền qua cáp mạng như thế nào.

Với truy vấn SQL của MySQL, bạn chỉ cần gõ SELECT * FROM users WHERE username = 'john.cena' thì bạn sẽ có ngay thông tin của john.cena mà không cần phải biết cách họ cấu trúc dữ liệu, cách một plan được thực thi hay aggregate ra sao.

Khi thực hiện các phép tính toán trong máy tính như 35 + 69, nhờ abstraction bạn sẽ không cần phải biết các số nguyên được biểu diễn dưới phần cứng như thế nào, adder chip nó ra làm sao.

Nói cách khác, abstraction giúp developer giấu đi cách cài đặt phức tạp ở các tầng thấp hơn và cung cấp một interface (giao diện) đơn giản hơn cho người dùng ở tầng hiện tại.

Lợi ích của Abstraction

Lợi ích của abstraction cho cả hai phía, win-win:

  1. Người dùng chỉ cần biết thông tin ở tầng mình sẽ ứng dụng mà không cần phải biết sâu hơn về các tầng bên dưới.

  2. Developer / Nhà sản xuất có thể nâng cấp phần mềm / sản phẩm của mình mà không phải đào tạo lại người dùng, nếu sử dụng lại interface cũ.

Ví dụ là Honda có thể sản xuất ra nhiều chủng loại xe máy với đủ thứ dung tích xy lanh và động cơ nhưng không cần phải giáo dục lại cho người dùng cách sử dụng những chiếc xe đó như thế nào, vì interface của chúng (cách lái) là như nhau.

Leaky abstraction

Joel Spolsky trong bài viết về Leaky abstraction của anh ấy có viết là.

All non-trivial abstractions, to some degree, are leaky.

Mọi abstraction lớn nhỏ đều bị rò rỉ sự phức tạp của các tầng bên dưới ở một mức độ nào đó.

Chiếc Honda được thiết kế để chỉ cần leo lên, khởi động, rồ ga là sẽ chạy, nhưng qua thời gian thì bạn phát hiện là cần phải đổ dầu nhớt để nó chạy êm, chứ không phải dầu ăn, vì động cơ đốt trong cần phải bôi trơn để hoạt động tốt.

Trình duyệt web vốn được thiết kế để người dùng chỉ cần nhập đường dẫn, nhấn Enter là nó sẽ hiển thị trang web, nhưng một ngày bạn phát hiện là cùng một máy tính nhưng lướt Facebook ở công ty không được, vì ai đó ở công ty đã chặn facebook trong network của cục router.

alt text

Khi câu SQL SELECT * FROM users WHERE username='john.cena' được thực hiện, bỗng bạn phát hiện ra rằng câu query sẽ thực hiện nhanh hơn nếu cột username được đánh index, bởi với index MySQL sẽ không cần phải scan toàn bộ bảng để tìm kiếm john.cena.

Với thao tác tính toán hai số trong máy tính, sẽ có lúc bạn nhận ra là 0.1 * 0.2 không hẳn sẽ trả về 0.02, vì cách máy tính lưu trữ floating point.

Và cứ như thế, các abstraction, vốn được tạo ra để giấu đi sự phức tạp của các tầng bên dưới, nhưng bằng cách nào đó, những sự phức tạp này vẫn rò rỉ ra cho người dùng cuối.

Bài viết này có giúp tôi tăng lương không?

Chân thành mà nói thì không.

Nhưng nó có thể giúp bạn viết code tốt hơn bằng cách hạn chế abstraction bị rò rỉ.

Giả sử bạn đang viết module để lưu file lên cloud storage.

class CloudStorage {
  public static S3Object store(string content) {
    return S3.createObject(content);
  }

  public static String getS3OjectUrl(S3Object object) {
    return S3.getObjectUrl(object);
  } 
}

Với cách cài đặt abstraction này, developer đã vô tình để rò rỉ thông tin về storage engine là S3 với chính public API là getS3OjectUrl với kiểu trả về là S3Object. Điều này ảnh hưởng đến:

  1. Người dùng: phải tìm hiểu thông tin về S3Object, là tầng bên dưới của CloudStorage vốn cần phải được giấu đi với CloudStorage.
  2. Nhà phát triển: việc nâng cấp trở nên khó hơn, giả sử như nếu họ muốn thay S3 với một cloud storage khác, người dùng cũng phải thay đổi API theo.
  3. Người dùng của người dùng: nếu người dùng cũng là một nhà phát triển và lặp lại sai lầm này, họ sẽ lại rò rỉ abstraction cho một tầng cao hơn nữa.

Ta có thể sửa lại là.

class CloudStorage {
  public static CloudStorageObject store(string content) {
    S3Object s3Object = S3.createObject(content);
    return CloudStorageObject.build_from_s3_object(s3Object);
  }

  public static String getObjectUrl(CloudStorageObject object) {
    return object.generateUrl();
  } 
}

Với cách cài đặt như vậy thì ta đã hạn chế được rò rỉ abstraction của CloudStorage đi một chút, vì bây giờ người dùng sẽ thao tác với CloudStorageObject, và khi chúng ta cần nâng cấp thư viện hay thay đổi storage engine ở các tầng dưới, người dùng sẽ không bị ảnh hưởng quá nhiều nữa.

Xong! Giờ bạn có thể xin tăng lương thôi.

alt text

0