kiến thức [Event tặng Title] - Architectural Styles là gì - Các Architectural Styles phổ biến

conmoedethuong

The Canadian
Các bài viết về IT của tôi:
Disclaimer: bài viết có sử dụng nhiều thuật ngữ tiếng anh. Các thím học CNTT, IT thì nên làm quen với các thuật ngữ tiếng anh vì tài liệu tiếng Việt cho ngành này rất ít hoặc rất cũ.

# Dẫn nhập​

Được sự bảo đảm của mod @Fire Of Heart , với hôm nay tôi mới present ở conference xong nên cũng rảnh, thế là tôi tiếp tục viết tiếp bài này. Kiến thức này tôi học được trong một course level graduate ở Canada.

Chắc hẳn các thím cũng biết kiến trúc monolith và kiến trúc microservice. Vậy còn các dạng kiến trúc nào khác? Dạng tổng quát của các kiến trúc này là gì? Các câu hỏi đó sẽ được trả lời trong bài viết hôm nay.

# Architectural Style là gì​

## Architectural design​

Trước tiên, để hiểu Architectural Style là gì, các thím phải biết architectural design.

Vào năm 1997, Monroe, Robert T., et al. trong bài báo "Architectural styles, design patterns, and objects." IEEE software 14.1 (1997): 43-52. đã đưa ra khái niệm Architectural Design như sau (khúc này khó dịch vl, nên tôi chỉ dịch thoát nghĩa thôi nhé):

Một architectural design phục vụ 2 mục đích:
  • Cung cấp 1 cái nhìn tổng quan, trừu tượng về hệ thống. Nó ẩn đi các implementation, và lôi ra ngoài những gì cơ bản nhất của hệ thống.
  • Cung cấp 1 cấu trúc cơ bản của hệ thống cho mọi người biết. Dựa vào cấu trúc này, các thím có thể thay thế, bổ sung, thêm thắt tính năng nhưng vẫn đảm bảo tính chất của hệ thống ban đầu.

## Architectural Style​

Các vozer là một loài động vật có tính học hỏi cao. Nên câu hỏi đặt ra là làm thế nào để tổng quát hóa các architectural design và dùng nó phát triển các hệ thống mới khác.

Các thím junior có thể chưa đụng tới phần này, nhưng các thím sen nho chắc là có gặp 1 vài lần sếp kêu dev cho tôi tính năng a b c from scratch, hoặc build luôn nguyên cái system mới. Các architectural design các thím biết thường là đã được customize để phù hợp với bussiness của 1 project đặc thù nào đó, nên hơi khó để apply nó vào 1 hệ thống khác, cho dù nó có cùng tính năng chính đi chăng nữa.

Các researcher từ năm 1997 đã có cùng câu hỏi với các thím, và thế là, Architectural Style ra đời.

## Architectural Style và Design Pattern​

Object Oriented Design gặp khó khăn trong việc:
  • Mô tả 1 nhóm các object interact với nhau như nào
  • Mô tả và đóng gói 1 nhóm các object với nhau để xài đi xài lại.
Để phần nào giải quyết các hạn chế này, design pattern ra đời.

Architectural Style cũng có thể coi là 1 dạng pattern. Tuy nhiên, trong khi design pattern giải quyết 1 bài toán cụ thể, architectural style lại cung cấp cho các thím 1 cái nền tảng, hoặc nói theo một cách khác, 1 dạng hướng dẫn, để các thím có thể thiết kế hệ thống của mình.

# Các dạng Architectural Style​

1. Structure
  • Component-based (*)
  • Monolithic application
  • Layered (*)
  • Pipes and filters (*)
2. Shared memory
  • Database-centric (*)
  • Blackboard
  • Rule-based
3. Messaging
  • Event-driven aka implicit invocation (*)
  • Publish-subscribe (*)
  • Asynchronous messaging
4. Adaptive System
  • Plug-ins (*)
  • Microkernel
  • Reflection
  • Domain specific languages
5. Distributed systems
  • Client-server (multitier architecture exhibits this style) (*)
  • Shared nothing architecture (*)
  • Space-based architecture
  • Object request broker
  • Peer-to-peer (*)
  • Representational state transfer (REST) (*)
  • Service-oriented (*)
  • Cloud computing patterns

Tôi sẽ giải thích những cái có dấu * nhé. Những cái còn lại các thím có thể tham khảo wiki: https://en.wikipedia.org/wiki/List_of_software_architecture_styles_and_patterns
 
Last edited:

# Các Architectural Style phổ biến​

## Component-based​

Dù cái tên hơi khó hiểu, nhưng đây là architectural style phổ biến nhất, đơn giản nhất. Các thím xài hằng ngày mà ko nhận ra.
Nguyên tắc cơ bản của nó là "Separation of Concern". Những thứ có chung 1 mục đích thì được nhét chung với nhau.
Ví dụ:

Component Checkout đòi component CardProcessing xử lý card của client
Code:
,--------------.
|CardProcessing|
`--------------'
        |      
        |      
   ,--------.  
   |Checkout|  
   `--------'

Việc tách thành các component khác nhau này giúp các thím dễ dàng thay đổi khi cần. Ví dụ như CardProcessing chẳng hạn, các thím có thể đổi nó từ chỉ process debit card thành 1 component có khả năng process credit, debit và ATM card mà ko cần phải đập đi xây lại cả hệ thống checkout.

Cái này cũng giúp ích trong việc tìm và debug, dễ test hơn, dễ chia task hơn, vân vân và mây mây.

## Layered architecture​

Ý như tên. Architectural style này mô tả cách sắp xếp hệ thống theo dạng từng lớp từng lớp. Các thím có thể tưởng tượng nó giống củ hành tây. Để đến được lớp trong cùng, các thím phải bóc từng lớp một.

Layered Architecture cũng vậy, các thím phải đi qua từng layer một để access vào layer thấp nhất. Mỗi layer chỉ giao tiếp với layer ngay kế nó mà thôi.

Một ví dụ điển hình cho architectural style này trong thực tế là cấu trúc 1 package TCP, gồm 7 layers:

Gdqz22g.png


Một ví dụ khác, nếu các thím có xài VPN hay proxy, thì cấu trúc trừu tượng của hệ thống VPN hay proxy cũng là 1 dạng layered architecture, trong đó máy của các thím nằm ở tầng thấp nhất. Còn các VPN/Proxy server nằm ở các tầng cao hơn. ISP khi đọc gói tin được truyền qua VPN/Proxy thì chỉ đọc được các layer trên cao, mà ko biết các thím có đang coi pỏn húp hay ko là vậy.

## Pipes and Filters​

Để hình dung 1 cách dễ hiểu cái architectural style này, các thím hãy tưởng tượng nó giống như mấy cái đường ống cấp nước nhà thím vậy.

Với tình hình nước máy ở VN dơ vl, nên các thím phải lắp máy lọc nước Kanguroo hàng đầu VN ở nhà phải ko? Cái mô tả của architectural style này nó y chang như vậy.

Ở mỗi một filter, nước (data) của các thím sẽ được xử lý (tính toán) để loại bỏ/thêm thắt cái gì đó, trước khi nó tiếp tục đi trong đường ống tới cái filter tiếp theo, và cuối cùng là tới consumer.

Woe5p6r.png


hình chôm của MS ở đây: https://docs.microsoft.com/en-us/azure/architecture/patterns/pipes-and-filters

Một ví dụ cho architectural styles này, nếu thím nào làm .net core, sẽ biết từ .net core, MS đã thay thế cơ chế handlers = middlewares. Các middleware này được thiết kế như các filter để xử lý requests/responses trước khi nó được đưa vào controller.

Thôi hôm nay tới đây thôi nhé.
 
Last edited:

## Database Centric​

Y như tên gọi, mọi thứ xoay chuyển xung quanh cục data. Tức là các thím phải:
  • Đưa các business logic vào store procedure
  • Lưu các config vào database luôn. Hạn chế tối đa code logic ở backend. Nếu có chỉ là đọc config -> implemnent theo config.
  • Chia cục data thành nhiều phần (sharding) để interact giữa các parallel process.
R15lzaJ.png


Tại sao lại có cái arhictectural style cực đoan này? Lý do là vì data thì ko đổi, nhưng application (hoặc software) sẽ bị thoái hóa theo thời gian.

Tôi năm nay 70 tuổi rồi, nhưng tôi chưa thấy ai tuân thủ nghiêm ngặt cái arhictectural style này cả. Đa phần sẽ customize cái architecture này, để 1 phần logic nằm trong database, và 1 phần logic khác nằm trong code backend. Thường những thứ ít thay đổi sẽ được nhét vào database. Còn những cái đổi liên tục theo yêu cầu của client sẽ được nhét vào backend code.

Vì vậy mới nói, architectural style chỉ là 1 bản instruction để các thím tự build system của mình cho phù hợp với business logic.

## Event-driven​

Again, cái tên nói lên tất cả. Architectural Style này mô tả một hệ thống tạo ra các event, và có các function để thực thi 1 operation nào đó khi nó bắt gặp event đó.

Event được định nghĩa là 1 sự thay đổi trạng thái của object. Tôi lấy ví dụ trên wiki luôn cho lẹ:

Ví dụ: khi khách hàng mua 1 con xe van fít, trạng thái của xe chuyển từ "đang ế" -> "đã lùa được gà", đông thời sẽ bắn ra event "CarStateChanged" chẳng hạn. Hệ thống software của showroom sẽ bắt cái event này, kiểu như "á à, mới lùa 1 con gà thành công", sau đó nó sẽ thực thi operation như cộng tiền vào doanh thu, xuất hóa đơn, hay chỉ đơn giản là thêm 1 record vào database gà.

Hầu hết các software đều implement cái achitectural style này, từ di chuyển chuột, tới click nút, hay request tới pỏn húp cũng là 1 dạng event.

Đọc tới đây chắc các thím cũng nhận ra. Chắc chả có software nào chỉ implement 1 architectural style cả, mà thường nó sẽ kết hợp nhiều architectural style khác nhau để implement bussiness logic.

Tôi cúng nói luôn, nghe thì đơn giản đấy, nhưng event-driven development trong thực tế khá phức tạp. Phải làm gì khi event bắn ra quá nhiều? 2 event cùng tới 1 lúc đòi change database thì sao? Các event có thể tạo thành 1 chuỗi event được ko? Rồi lỡ deadlock thì sao? Vân vân và mây mây.

eQZODOC.png


## Publish - Subscribe​

Only quạt hoạt động theo mô hình này. Một service sẽ publish 1 event, và rất nhiều vozer đôi mắt hau háu sẽ "hứng" cái event/data này về làm của riêng, rồi làm gì đó với nó thì service ko biết.

9tQvxjw.png

có hình cho nó dễ hình dung

Nói chứ hình đây

t3hsHu3.png


Nếu 1 subscriber tạch, hệ thống vẫn hoạt động bình thường, nhưng nếu publisher tạch, thì hệ thống đi tong. Cái này gọi là Single point of failure.

## Plugs-in​

Thôi còn nói gì với cái architectural style này nữa. Vozer nào mà ko cài ublock orgin vào GG Chrome/Edge/Firefox phải ko? Đây là ví dụ điển hình cho plugs-in.

Để implement được cái arhictectural styles này, Robert C. Martin, aka uncle Bob, chế ra 1 (bộ) quy tắc: Open-closed principle

software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

1 cách khác để implement architectural style này, là software sẽ expose các API, và các plugs-in sẽ dùng các API này để thêm thắt/thay đổi tính năng của software. Ví dụ như vscode. Nếu ko cài extension nào thì nó chỉ là 1 cái text editor. Nhưng vscode expose rất nhiều API, cho phép các dev thoải mái sáng tạo ra nhiều extension.

Tôi gõ post này trên vscode = ngôn ngữ markdown nè. Gõ xong commit git cũng = vscode luôn. Thesis của tôi cũng gõ trên vscode. Tôi luyện leetcode java cũng = vscode. Too good for a text editor eh?

Thôi hẹn các thím ngày mai nói về dạng Achitectural style cuối cùng nhé.
 
Last edited:

## Client-Server​

Tôi còn phải nói gì với cái architectural style này nữa đây hẻ các thím? Client-Server giờ đang được ứng dụng ở khắp mọi nơi, từ website pỏn húp tới app zalo share rau.

Một điểm đáng chú ý là Client-Server cũng apply quy tắc Separation of Concerns. Trong đó Server sẽ có nhiệm vụ lưu trữ, xử lý và truy vấn data. Client sẽ có nhiệm vụ request data, hiển thị và xử lý user input (click, tap, select, etc.).

Càng nhiều task được đẩy về server để xứ lý, thì workload của client càng nhẹ.

01JeaDS.png


Nếu lấy ví dụ về các website bình thường thì nó...bình thường quá, nên tôi lấy ví dụ về dịch vụ game streamming mới của Google nhé:
Google Stadia là một dịch vụ stream game, trong đó các server của Google sẽ xử lý đồ họa, user chỉ cần xài 1 cái chromebook cấu hình cùi bắp là có thể chơi được các tựa game AAA đồ họa đỉnh cao như Cyberpunk 2077.

FTTmwCa.jpeg


Nói tới đây chắc các thím cũng thấy vấn đề của mô hình này. Kết nối giữa client và server ko ổn định. Nếu client và server là 2 application trên cùng 1 computer, hoặc 1 data center thì ko có gì phải bàn. Nhưng nếu server nằm ở US, còn client nằm ở VN ngày cá mập cắn, thì còn gì nữa đâu mà khóc với sầu.

## Share nothing architecture​

Cái architectural style này hơi thú vị. Nó mô tả 1 hệ thống có nhiều node, mà mỗi node đều có thể thỏa mãn yêu cầu của client. Chữ "nothing" ở đây mang ý nghĩa về CPU, storage, memory, etc. Lý tưởng nhất là các node nằm ở các computer khác nhau.

Nhưng bạn ơi, như vậy để làm gì?

Architectural Style này mang lại 1 số lợi ích:
  • Loại bỏ single point of failure
  • Hệ thống có thể scale up dễ dàng = cách thêm node
  • Chịu được high request, tăng throughput của toàn system
Nhưng nó cũng sinh ra 1 vài vấn đề
  • Làm thế nào để sync data giữa các node
  • Chọn node nào để xử lý request?
Một ví dụ về share nothing ít ai ngờ tới là cấu trúc đa nhân của CPU. Giờ còn có con CPU nào single core nữa phải ko các thím. Bét thì cũng phải 2 core 4 luồng. Mỗi core đều có thể xử lý tác vụ y như những core còn lại. Hoặc như RAM chạy dual channel, 2 cây 8 GB lại nhanh hơn 1 cây 16 GB.

F4VNB9h.png


Một ví dụ khác của Share Nothing:

Công nghệ Dual-Stream mới ra lò của Nikon trên các dòng máy ảnh ko gương lật cao cấp:

5749796_Cong_nghe_dual_stream_nikon_z9.jpeg


Bằng việc chia đôi luồng xử lý data vào memory card và data vào màn hình live view, khi chụp liên tục sẽ khắc phục được hiện tượng màn hình live view bị chớp đen trên các dòng máy ảnh ko gương lật của các hãng khác.

Như vậy các thím có thể thấy, dù các Architectural Styles đã rất cũ, rất cơ bản, nhưng nó vẫn được ứng dụng cực kỳ nhiều nơi để giải quyết các bài toán vô cùng nhức nách.

Trong hình trên các thím cũng có thể thấy Pipes and Filters architecture

## Peer-to-peer​

Torrent hoạt động dựa trên architectural style này.

Trong mô hình này, bất kỳ computer nào trong network cũng sẽ xử lý 1 phần request. Mỗi node cống hiến 1 phần resource của mình cho network. Resource đó có thể là CPU, có thể là storage, cũng có thể là network bandwidth. Mỗi node vừa là consumer, vừa là supplier của các resource này.

Ai cũng biết torrent, thế các thím có biết project SETI@Home ko? SETI at Home cho phép các thím sử dụng máy tính của mình, contribute vào 1 mạng lưới các máy tính xử lý một lượng khổng lồ data của telescope, radio signals để tìm kiếm trí thông minh nhân tạo ngoài trái đất. Project này đã dừng vào năm 2020, đánh dấu 20 năm hoạt động của project này. Năm 2000, đã có 2.6 triệu người tham gia, xử lý 25 nghìn tỷ phép tính / 1 giây (hay 25 tượng / giây).

GWejZgi.png

Một ví dụ khác, git source control cũng hoạt động theo mô hình P2P. Mỗi PC trong network của git đều có thể restore full source code đã bị xóa trên PC khác. Tuy nhiên, git thường được host trên 1 PC. Các PC khác sẽ fetch hoặc push lên pc này.

dojocat.jpg


## Representational state transfer​

Tôi ko chắc đây có phải là Architectural Style hay ko, nhưng thôi wiki nó list thì tôi cũng nói vậy.

REST là một kiến trúc dành riêng cho web. REST đưa ra một loạt các ràng buộc như sau:
  • Xài client-server architecture: như giải thích ở trên
  • Ko có state: Server ko lưu trữ state của client. Mọi request tới server đều là stateless. Tức là mọi request đều có thể xử lý độc lập mà ko phụ thuộc vào request trước nó. Cái này khá quan trọng. Vì tính chất Stateless này mà backend REST có thể scale up/down rất dễ dàng.
  • Cache được: Vì stateless, nên các response tương ứng với 1 request nào đó đều có thể được cache. Có thể cache ở client side, có thể cache để server side.
  • Xếp theo từng layer: Client sẽ ko biết nó đang truy cập tới server nào, hay chỉ đang connect tới 1 cái load balancer thôi.

Giờ người người REST, nhà nhà REST, cả con mòe trên hình cũng vậy.

## Service Oriented Architecture (SOA)​

Microservice là 1 dạng của SOA. Nói chung thì SOA mô tả 1 hệ thống mà các services được tách ra độc lập với nhau. Service này có thể consume, cũng như provide cho service khác, hoặc provide cho client. Các services kết nối thông qua network, dùng 1 dạng communication protocol (ví dụ như REST chẳng hạn)

SOA có 1 số extension/variants như:
  • Event-driven Architectures
  • API
  • Microservices

Vậy là tôi đã giới thiệu xong các architectural styles phổ biến. Các thím có thể tự tin mang các kiến thức này đi chém gió được rồi. Chúc các thím may mắn.
 
Last edited:
Hay, đặt gạch hóng tiếp mấy phần tiếp theo :D

Component based và Layered thì thím nào làm full-stack chắc rõ rồi, còn cái pipes and filters thì có vẻ ngoài dân Nodejs và Golang có middleware thì ít khi gặp. Tôi có làm qua 1 dự án tính điểm cho tài xe lái xe hơi để bán bảo hiểm, và tất nhiên không phải ở Việt Nam, output của service này là input của service khác, nó đi theo 1 chuỗi như vậy và tính ra điểm cuối cùng, chắc là cái này rồi :sneaky:
 
Hay, đặt gạch hóng tiếp mấy phần tiếp theo :D

Component based và Layered thì thím nào làm full-stack chắc rõ rồi, còn cái pipes and filters thì có vẻ ngoài dân Nodejs và Golang có middleware thì ít khi gặp. Tôi có làm qua 1 dự án tính điểm cho tài xe lái xe hơi để bán bảo hiểm, và tất nhiên không phải ở Việt Nam, output của service này là input của service khác, nó đi theo 1 chuỗi như vậy và tính ra điểm cuối cùng, chắc là cái này rồi :sneaky:
cái pipes này e thấy middleware các fw h đều dùng chứ đâu p chỉ mỗi node hay go
 
sắp hết 1 nửa thời gian event, cũng dc 8-9 bài khá chất lượng. Hy vọng tới hết tháng 12 sẽ dc thêm nhiều bài nữa, còn có động lực sang năm làm tiếp :)
 
Tôi có làm qua Spring của Java thì thấy nó hay xài AOP thôi, cũng 1 dạng vậy, còn system style cho nó thành pipes and filters thì nó lại là chuyện khác rồi thím ạ.
J2EE servlet filter thì chuẩn cmnl, còn AOP đâu có phải dạng này fen
 
Tôi có làm qua Spring của Java thì thấy nó hay xài AOP thôi, cũng 1 dạng vậy, còn system style cho nó thành pipes and filters thì nó lại là chuyện khác rồi thím ạ.
AOP ko phải pipes and filters nha. Nó là dạng component-based architecture. Khác là khác chỗ nó lôi cổ những "concern" mà component nào cũng có thành 1 component riêng.

Ví dụ như logging. Component nào cũng đòi log data, vậy là các thím có thể tách logging ra thành 1 component riêng. Sau đó = cách nào đó nhét functionality của logging component này vào các component khác (ví dụ như Dependency Injection chả hạn)
 
AOP ko phải pipes and filters nha. Nó là dạng component-based architecture. Khác là khác chỗ nó lôi cổ những "concern" mà component nào cũng có thành 1 component riêng.

Ví dụ như logging. Component nào cũng đòi log data, vậy là các thím có thể tách logging ra thành 1 component riêng. Sau đó = cách nào đó nhét functionality của logging component này vào các component khác (ví dụ như Dependency Injection chả hạn)
Thanks thím, cảm ơn đã thông não
 
Back
Top