12/08/2018, 12:15

Cấu trúc dữ liệu là trái tim của hệ Thống

Mở đầu Bạn nên chọn việc tạo ra cấu trúc dữ liệu phức tạp hơn là logic xử lý phức tạp. Thực tế cho thấy rằng cấu trúc dữ liệu phức tạp sẽ loại bỏ nhu cầu có logic xử lý phức tạp. Điều này sẽ đem lại một hệ thống nhanh hơn và có ít code để maintain hơn. Cấu trúc dữ liệu là ngôn ngữ chung mà ...

Hear of data

Mở đầu

Bạn nên chọn việc tạo ra cấu trúc dữ liệu phức tạp hơn là logic xử lý phức tạp. Thực tế cho thấy rằng cấu trúc dữ liệu phức tạp sẽ loại bỏ nhu cầu có logic xử lý phức tạp. Điều này sẽ đem lại một hệ thống nhanh hơn và có ít code để maintain hơn.

Cấu trúc dữ liệu là ngôn ngữ chung mà các lập trình viên có thể thảo luận mà không bị bó buộc vào một ngôn ngữ hay framework nhất định.

Hé lộ mục đích hệ thống

Chỉ cần nhìn vào cấu trúc dữ liệu, bạn có thể mường tượng ra vai trò của nó trong hệ thống.

Ví dụ 1

[125.25, "Love is in the air"]

Cái gì vậy nhỉ? Mục đích của cái chuỗi này là gì? Rất khó nói và người ngoài chỉ có thể đưa ra các giả định mà thôi. Nếu chuỗi này được gán vào một argument của method, thì method đó sẽ phải sử dụng giá trị của chuỗi trên ở nhiều nơi và đây không phải là một cách hay để đóng gói dữ liệu này, nhất là khi dữ liệu này đại diện cho một phần quan trọng của hệ thống

Ví dụ 2

{
  frequency: 125.25,
  channel_name: "Love is in the air"
}

Dữ liệu này cung cấp cho chúng ta những từ khoá chúng ta có thể tham khảo. Bạn có thể nói rằng dữ liệu này có giá trị cao trong hệ thống.

Ví dụ 3

channel = Struct.new(:frequency, :channel_name) do
  def mirror_frequency
    frequency + 10.2
  end
end

Cấu trúc dữ liệu này thể hiện nhiều ý nghĩa. Lưu ý rằng frequency bên trong miror_frequency không thông qua các object khác để làm điều nó cần làm, nó làm việc trực tiếp trên dữ liệu. Việc này sẽ loại bỏ gánh nặng khi code của các ứng dụng khác phải làm việc với gói dữ liệu này.

Rút ngắn khoảng cách với dữ liệu

Law of Dementer(LoD)

Hay còn gọi là principle of least knowledge - biết càng ít càng tốt Có thể hiểu như sau:

Đối tượng A có thể gọi một hàm của đối tượng B, như đối tượng A không nên 'chạm sâu' vào đối tượng B để có thể, lại truy cập được một đối tượng khác, là C, để yêu cầu C thực hiện yêu cầu. Làm như vậy tức là A đang yêu cầu biết được cấu trúc bên trong của B. Thay vào đó interface của B cần được thay đổi nếu cần thiết để có thể thực hiện trực tiếp yêu cầu của A. Nếu nguyên tắc trên được áp dụng thì chỉ có B mới biết cấu trúc bên trong của chính nó.

Vi phạm nguyên tắc LoD

Các hàm được sử dụng theo dạng chuỗi chính là dấu hiệu cho thấy nguyên tắc LoD đang bị vi phạm và hệ thống của bạn đang không gần với cấu trúc dữ liệu.

Ví dụ

receipt.customer.address.city

so với

customer.city

Rule of Representation

Dựa vào nguyên tắc này của UNIX, bạn nên đóng gói thông tin vào dữ liệu và logic hệ thống có thể đơn giản, có khi là ngu ngốc nhưng mà lại nhanh chóng. Dữ liệu dễ truy cứu hơn là những logic mang tính thủ tục. Bắt đầu ứng dụng của bạn mà không quan tâm tới cấu trúc dữ liệu, thêm vào những dòng code sẽ chỉ dẫn đến một thiết kế 'béo phì' mà thôi. Hãy bắt đầu với cấu trúc dữ liệu trước và bạn sẽ không phải viết những dòng code không cần thiết.

Giải quyết vấn đề ngay từ nguồn

Không nên thêm code vào hệ thống để giải quyết vấn đề mà có thể sửa ngay từ nguồn (dữ liệu). Điều này có vẻ hiển nhiên nhưng vẫn thường hay xảy ra.

Ví dụ: Chúng ta tạo hàm available? trong employee để cho việc xử lý không cần phải làm bên ngoài của đối tượng

class Employee
  ...

  def available?
    !on_vacation? && in_working_hour?
  end
end

assign_job if employee.available?

Đối nghịch với:

assign_job if !employee.on_vacation? && employee.in_working_hour?

Độ phức tạp chu trình

Hãy coi việc thiết kế cấu trúc dữ liệu là việc giảm độ phức tạp chu trình của ứng dụng

Ví dụ

Chúng ta muốn phân loại message được gửi đến dựa vào type và tạo ra email với tiêu đề - subject tương ứng. Điều đầu tiên loé lên trong đầu là logic điều kiện. Phải không?

subject = case message.type
  when "resign"
    "Resignation Letter"
  when "notice"
    "Notice"
  when "salary"
    "Payslip"
  else
    "No title"
  end

Điều làm làm đóng như những gì chúng ta muốn nhưng cũng là một ví dụ cho việc tạo ra logic không cần thiết mà có thể xử lý được bằng cấu trúc dữ liệu. Hãy viết một hash mà trong đó có xử lý mặc định cho những key không được định nghĩa.

message_subjects = Hash.new("No title").merge(
  "resign" => "Resignation Letter",
  "notice" => "Notice",
  "salary" => "Playslip"
)

subject = message_subjects[message.type]

Với những type không được định nghĩa sẽ trả về giá trị mặc định là No title. Vậy là chúng ta đã bỏ được logic điều kiện và thay vào đó là một cơ chế pattern matching cung cấp bởi cấu trúc dữ liệu.

Bất kỳ khi nào bạn thấy logic điều kiện, hãy xem xét xem nó có thể thay thế bởi một cấu trúc dữ liệu thông minh không.

Lời kết

Thiết kế cấu trúc dữ liệu từ ban đầu sẽ đem lại nhiều ảnh hưởng tích cực, bao gồm việc có ít đi đoạn mã phức tạp Ngay khi bạn taọ ra được nền móng cho cấu trúc dữ liệu, mã ứng dụng sẽ kết dính lại với nhau dễ hơn. Bạn hãy bắt đầu nghĩ đến quan hệ giữa các cấu trúc dữ liệu với nhau chứ không phải là từng bước một để đi từ A cho đến B.

0