Clean Architecture – Điều đơn giản với ý tưởng củ hành

Clean Architecture – Điều đơn giản với ý tưởng củ hành

July 18, 2021 2 By Nam Vu

Trong bài viết sự tiến hóa của kiến trúc phần mềm mình có đề cập đến loại kiến trúc này, bạn đọc có thể tìm đọc lại link ở cuối bài viết.Bài viết này mình sẽ đi sâu hơn một chút nhưng vẫn không phải dùng những thuật ngữ đao to búa lớn để diễn tả kiến trúc này, mà mình thông qua những ví dụ đơn giản nhất để bạn đọc có thể hiểu được một cách dễ dàng.

Bắt đầu nhé!

Bạn bắt đầu hình dung, một ứng dụng hay một website thường sẽ có 3 lớp thành phần chính đó là tầng giao diện, tầng xử lý nghiệp vụ business và tầng  cơ sở dữ liệu. Ba lớp ngày sẽ đi từ ngoài vào trong, thứ mà đập vào mắt bạn như bài viết này cũng không ngoại lệ, để có thể hiển thị được cho bạn đọc (client hay frontend) thì nó cần được xử lý bên phía trong hay còn được gọi với cái tên mĩ miều là backend, thế rồi chúng được lưu ở đâu đó như khi bạn lưu video hay ho trong ổ cứng của bạn. Bạn có thể bắt gặp ở đâu đó một mô hình thể hiện 3 tầng này chính là MVC (Model – View – Controller) hay MVP (Model – View – Presenter) hay MVVM (Model – View – ViewModel). Dù là mô hình nào thì nó cũng đều phân chia nhiệm vụ đảm nhận cho 3 tầng thành phần bên trên.

Nhưng có một vài lý do mà sự phát triển của mô hình 3 lớp này dần dần chuyển hóa thành mô hình cao cấp hơn. Trong bài viết kiến trúc phần mềm là để thay đổi, mình có đề cập một số nhu cầu tiến hóa của phần mềm và với kiến trúc mới này cũng không ngoại lệ.

Đầu tiên là Không phụ thuộc vào nền tảng (Independent of Frameworks). Bạn nghĩ sao khi bạn lưu một bộ phim hay trên ổ đĩa máy tính này nhưng bạn lại muốn xem chúng ở một máy tính khác, hoặc là bạn copy ra usb như ngày xưa chúng ta thường làm hoặc là bạn đưa chúng lên trên mây như hiện tại. Dù cách nào đi chăng nữa thì vấn đề bạn hướng tới là sự linh hoạt mà không phụ thuộc vào thiết bị cũng như cơ sở hạ tầng. Bạn dùng công nghệ nào, ngôn ngữ nào cho một trong 3 lớp thành phần điều này không còn quan trọng nữa.

Thứ 2 là kiểm thử dễ dàng (Testable). Phần mềm được phát triển thì phải được kiểm tra xem có lỗi hay không trước khi phát hành và việc chia tách từng lớp rõ ràng khiến việc kiểm thử dễ dàng hơn. Video trong usb của bạn không xem được, hoặc là do usb của bạn hỏng, hoặc là do máy tính bạn hỏng, hoặc là do màn hình bạn hỏng, dù cái gì hỏng đi chăng nữa thì bạn cũng dễ dàng kiểm tra các thành phần còn lại khi bạn mang qua liên kết với máy tính khác để kiểm tra một cách dễ dàng, khoanh vùng lỗi phát sinh cũng dễ dàng hơn.

Thứ 3 là không phụ thuộc vào giao diện (Independent of UI), thật may mắn khi từ khi máy tính ra đời, chúng ta không phải tiếp xúc ngay với những thế hệ đầu tiên màn hình đen xì và những dòng lệnh khô khan, thay vào đó là những màn hình windows với những click chuột, rồi dần dần nó không chỉ nằm chết tại máy của bạn nó có thể sử dụng ở bất cứ đâu thông qua giao diện web, hay giao diện mobile. Việc chia lớp thành phần View tách biệt với các thành phần còn lại giúp chúng ta có những trải nghiệm người dùng tốt hơn và dễ dàng thích ứng với mọi điều kiện thiết bị.

Thứ 4 đó là không phụ thuộc vào cơ sở dữ liệu (Independent of Database). Có thể bạn đã biết thì chúng ta có rất nhiều loại cơ sở dữ liệu được lưu trữ, cũng như nhiều loại ổ cứng hay usb hay đám mây cũng có nhiều loại như google cloud, icloud, onedrive… Vậy làm sao để ứng dụng của bạn không phụ thuộc vào chúng, mà chỉ cần tích hợp là chúng có thể chạy mượt mà. Việc tách lớp cơ sở dữ liệu riêng biệt giúp bạn làm được việc này.

Cuối cùng là không phụ thuộc vào bất kỳ bên thứ ba nào (Indenpendent of any External Agency). Bạn có nghĩ một trang thương mại điện tử có bao nhiêu hình thức thanh toán, có thể là vn-pay, có thể là momo, có thể là visa card. Dù là hình thức thanh toán nào cũng sẽ trở nên dễ dàng và có thể thay thế khi bạn làm việc trao đổi mọi thứ thông qua API (Application Programming Interface), một giao thức kết nối với các thư viện và ứng dụng khác.

Quay trở lại với kiến trúc Clean Architecture (mình xin phép không dịch vì không biết dịch sao nữa :D) mình chỉ lấy ví dụ nó như một củ hành có nhiều lớp, với các lớp đảm nhận nhiệm vụ với những tính chất được mô tả bên trên.

ntechdevelopers

Bạn có thể thấy với kiến trúc này là những vòng tròn đồng tâm thể hiện các lớp thành phần như một củ hành vậy. Vậy từng lớp của củ hành như thế nào thì chúng ta cùng đi tìm hiểu tiếp nào!

Với kiến trúc Clean Architecture thì 3 lớp thành phần chính vẫn được giữ nguyên nhưng chỉ tổ chức lại thể hiện từ lõi hành ra bên ngoài vỏ bao gồm: Entity (Lớp lõi làm việc với cơ sở dữ liệu), Usecase (Lớp xử lý nghiệp vụ kết nối trao đổi dữ liệu với lớp lõi và tương tác với lớp ngoài), Interface (Lớp vỏ liên kết và kết nối với thế giới bên ngoài sau khi xử lý nghiệp vụ và có được dữ liệu sau khi xử lý), Driver (Lớp thể hiện hay lưu trữ dữ liệu)Rồi chúng ta hãy cùng đi bóc hành từng lớp từ ngoài vào trong nhé!

ntechdevelopers

Frameworks and Drivers layer

Thứ mà đập thẳng vào mắt người dùng cũng như lớp mà tiếp xúc, trao đổi với các ứng dụng khác hay trao đổi với các cơ sở dự liệu chính là đây.  Vỏ hành chính là lớp giúp chúng ta tiếp xúc với mọi thứ, có thể nó là một yêu cầu từ người dùng (request) của một trang web nào đó, có thể là một public api giúp tích hợp với một bên thứ ba hoặc hệ thống bên ngoài, có thể là một thiết bị di động như Android Apps hay Iphone Apps, có thể là một công cụ phân tích đọc dữ liệu database nào đó.

Interface Adapters layer

Đúng như tên gọi đây chính là lớp chuyển đổi dữ liệu, khi nhận được một tín hiệu nào đó từ lớp vỏ bên ngoài, lớp này có nhiệm vụ chuyển đổi những yêu cầu đó vào lớp xử lý bên trong. Hãy tưởng tượng nó như một ổ cắm đa năng vậy, nó nhận đầu vào, phân loại chúng và gửi đi những đúng nơi, đúng chỗ, đúng người xử lý, sự điều phối này giúp hệ thống có thể dễ dàng tích hợp với nhiều nơi hơn mà lớp vỏ hỗ trợ. Nếu như lớp vỏ bên ngoài có rất nhiều nền tảng như desktop app, web app, mobile app, hệ thống bên thứ 3… thì sau khi qua lớp này, nó sẽ được quy chuẩn về một đầu vào duy nhất để hệ thống của bạn có thể xử lý chúng dễ dàng hơn. Đầu vào lúc này có thể là GraphQL, Restful, Soap, Scheduled Jobs, GUI, Odata… (kỹ thuật đặc thù một chút nhưng bạn có thể hiểu đơn giản nó là các giao thức truyền nhận dữ liệu khác nhau) chúng sẽ được xử lý thành một luồng dữ liệu mà lớp lõi bên trong có thể hiểu và xử lý được.

Use Case layer hay Application Logic layer

Sau khi đã được chuẩn hóa đầu vào và phân loại các vùng xử lý dữ liệu rồi thì vào đến lớp cận lõi này các nghiệp vụ đặc thù sẽ được xử lý tại đây, có thể nó là nghiệp vụ ngân hàng, có thể nó là nghiệp vụ thương mại điện tử, hay chỉ đơn giản là đếm số lượt upvote cho bài viết này. Việc xử lý nghiệp vụ ở lớp này khiến bạn dễ dàng phân loại xử lý nghiệp vụ của bạn hơn mà không phụ thuộc vào bất kỳ những yếu tố nào bên ngoài cũng như những lỗi không mong muốn từ cơ sở dữ liệu thô. Việc kiểm thử các chức năng nghiệp vụ tại lớp này cũng được dễ dàng hơn, tổ chức modular hay microservices cũng được phân chia dựa theo nghiệp vụ của lớp này.

Entities layer

Cuối cùng chính là lớp lõi domain entity, với lớp này chỉ đơn thuần là ảnh xạ (mapping) dữ liệu hay đơn giản là nhằm mục đích chứa dữ liệu thô, không phụ thuộc vào bất cứ thư viện, nền tảng, kỹ thuật, hay nghiệp vụ nào. Thô là thô, nó đảm bảo dữ liệu nguyên bản nhất để lớp cận lõi phía trên có thể có dữ liệu xử lý nghiệp vụ một cách chính xác. Đối với các công trình xanh dựng thì lớp này chính là các nguyên vật liệu xây dựng chưa qua bất kỳ công đoạn xử lý nào của một công trình như gạch đá, xi măng, sắt thép… Nó chỉ duy nhất thể hiện được là những dữ liệu nào liên quan đến nhau, phân nhóm dữ liệu, mối quan hệ cha con cũng như kiểu dữ liệu của chúng mà thôi.

Nếu bạn là người trong ngành và có căn bản một chút thì hình dưới đây sẽ giúp bạn nhận diện được những công nghệ nằm trong từng lớp nhé. Ở bài viết này mình sẽ không giải thích từng công nghệ trong hình này mà muốn mô tả một cách tổng quan hết về kiến trúc Clean Architecture.

ntechdevelopers

Vậy ưu điểm nhiều thế thì kiến trúc này có nhược điểm gì không?

Tất nhiên là có nhé!

Đầu tiên là nó phức tạp, chính vì sự trừu tượng hóa quá nhiều, muốn mọi thứ không phụ thuộc vào nhau mà nó không tuân theo bất cứ quy tắc nào. Chính điều này khiến các lập trình viên khó nắm bắt và đi theo một tiêu chuẩn có sẵn như những kiến trúc cổ điển.

Tiếp nữa là không có sự định hướng cụ thể, mọi thứ đều là gián tiếp. Do muốn đa dạng hóa các lớp thành phần kiến chúng làm việc với nhau một cách gián tiếp và nếu chúng ta không kiểm tra chặn chẽ đầu vào và đầu ra của từng lớp thành phần vô tình khiến chúng trở thành lỗ hổng lớn.

Cuối cùng là nặng nề, thái hành quá nhiều lớp sẽ dễ khiến chúng ta cay mắt, khi một ứng dụng nhỏ không có nhu cầu mở rộng mà tuân theo kiến trúc này sẽ khiến chúng ta thêm vất vả nhiều hơn vì phải xây dựng rất nhiều lớp thành phần mới có thể tạo nên một tính năng đơn giản. Câu hỏi đặt ra trong trường hợp này là có thật sự cần thiết không.

Trên đây là bài viết về kiến trúc Clean Architecture với những ví dụ giúp bạn có thể nắm được một cách tổng quan nhất về kiến trúc này. Để hiểu hơn về tác giả của kiến trúc cũng như những kiến trúc nhỏ bên trong để hình thành nên kiến trúc này như hiện tại bạn có thể đọc thêm tại đây

Còn đây là demo cho mô hình này của mình nhé! Hi vong có thể giúp bạn tham khảo một phần nào đó

#ntechdevelopers

Các bài viết khác liên quan đến kiến trúc phần mềm

  1. Sự tiến hóa của kiến trúc phần mềm và sự ra đời của kiến trúc Microservice
  2. Monolithic Architecture – Kiến trúc một khối truyền thống
  3. Client Server Architecture – Kiến trúc client-server
  4. Serverless Architecture – Kiến trúc không có máy chủ
  5. Service-oriented Architecture (SOA) – Kiến trúc hướng dịch vụ
  6. Microservices Architecture – Kiến trúc Microservices
  7. Lột tả bản chất của kiến trúc Microservice so với kiến trúc xây dựng
  8. Tại sao thiết kế phần mềm càng đa dụng lại càng phức tạp
  9. Kiến trúc phần cứng là để tồn tại lâu dài, kiến trúc phần mềm là để thay đổi