Kiến trúc tiến hóa và thiết kế nổi dần: Nghiên cứu điều tra kiến trúc và thiết
kế
Khám phá kiến trúc và thiết kế dễ bảo trì hơn
Neal Ford, Kiến trúc phần mềm, ThoughtWorks
Tóm tắt: Thiết kế và kiến trúc phần mềm phát sinh ra nhiều sức nóng tranh luận
nhưng không phát sinh nhiều ánh sáng. Để bắt đầu một cuộc trò chuyện mới về
những cách nghĩ khác đi về chúng, bài viết này khởi đầu loạt bài Kiến trúc tiến
hóa và thiết kế nổi dần. Kiến trúc tiến hóa và thiết kế nổi dần (Evolutionary
architecture and emergent design) là các kỹ thuật khéo léo để lùi các quyết định
quan trọng cho đến thời điểm hợp lý cuối cùng. Trong bài giới thiệu này, tác giả
Neal Ford của loạt bài viết sẽ định nghĩa kiến trúc và thiết kế rồi sau đó xác định
các mối quan tâm bao quát sẽ nảy sinh trong suốt cả loạt bài viết này.
Kiến trúc và thiết kế phần mềm đã chống lại mọi định nghĩa vững chắc trong một
thời gian dài do việc phát triển phần mềm, như một lĩnh vực chuyên môn, vẫn còn
chưa được nắm bắt đầy đủ tất cả những rắc rối và các mối liên quan của chúng.
Nhưng để tạo ra một cuộc đàm luận đúng mức về những chủ đề này, bạn phải bắt
đầu từ đâu đó. Loạt bài viết này quan tâm đến kiến trúc tiến hóa và thiết kế nổi
dần, do đó cần mở đầu cho loạt bài viết này bằng một loạt các định nghĩa, xem xét
cân nhắc và thiết lập nền tảng khác.
Về loạt bài viết này
Loạt bài này nhằm mục đích cung cấp một cách nhìn mới mẻ về các khái niệm
thường được bàn luận nhưng khó nắm bắt ý nghĩa, đó là thiết kế và kiến trúc phần
mềm. Thông qua các ví dụ cụ thể, Neal Ford sẽ mang lại cho bạn một nền móng
vững chắc về các biện pháp thực hành nhanh trong kiến trúc tiến hóa và thiết kế
nổi dần. Bằng cách lùi các quyết định kiến trúc và thiết kế quan trọng đến thời
điểm hợp lý cuối cùng, bạn có thể ngăn ngừa không để những phức tạp không cần
thiết hủy hoại các dự án phần mềm của bạn.
Định nghĩa kiến trúc
Kiến trúc trong phần mềm là một trong những khái niệm được nói đến nhiều nhất
nhưng lại được hiểu ít nhất mà các nhà phát triển phải đánh vật với nó. Tại các hội
nghị, các cuộc thảo luận và tụ họp của những người cùng chí hướng về kiến trúc
Kiến trúc doanh nghiệp
Kiến trúc doanh nghiệp bản thân nó quan tâm đến cách làm thế nào để doanh
nghiệp như là một tổng thể (thường có nghĩa là các ứng dụng đang chạy bên trong
một tổ chức lớn) sử dụng các ứng dụng. Một phép ẩn dụ hữu ích thường dùng về
mối quan hệ giữa kiến trúc doanh nghiệp và kiến trúc ứng dụng là ví kiến trúc
doanh nghiệp như việc quy hoạch thành phố và kiến trúc ứng dụng là xây dựng
các công trình kiến trúc. Các nhà quy hoạch thành phố phải suy nghĩ về việc cấp
nước, điện, thoát nước thải và các dịch vụ khác để cho phép thành phố hoạt động.
Bạn không thể có một tòa nhà tiêu thụ nhiều nước hơn lượng nước được chia sẻ
cho nó. Kiến trúc doanh nghiệp suy nghĩ về các vấn đề giống như thế nhưng cho
các ứng dụng: bạn không thể cho phép một ứng dụng tiêu thụ tất cả băng thông
của mạng thông tin và nếu các dịch vụ cơ sở hạ tầng bị sụp đổ, nước thải (ảo) lại
dâng lên.
Kiến trúc doanh nghiệp đã được chú ý rất nhiều trong vài năm gần đây nhờ có kiến
trúc hướng dịch vụ (SOA). SOA bản thân nó đã là một chủ đề lớn, do đó các bài
viết sắp tới của loạt bài này sẽ đề cập đến SOA như là một trường hợp riêng. Nó
cũng có những khía cạnh đáng quan tâm riêng bởi vì nó làm mờ đi đường biên
giới giữa kiến trúc doanh nghiệp và kiến trúc ứng dụng khi nó áp đặt các đặc trưng
kỹ thuật của cấu trúc ứng dụng.
Các đoạn trên đây đưa ra những định nghĩa hời hợt bên ngoài về các khái niệm
quan trọng này, nhưng chúng sẽ là bệ phóng xuất phát cho các định nghĩa khác
đáng chú ý hơn, nhiều sắc thái hơn về kiến trúc bao gồm cả một vài định nghĩa thu
hoạch được từ những định nghĩa khác.
Các định nghĩa hiện có
Nhiều người thông minh đã thử định nghĩa kiến trúc phần mềm, do đó tôi sẽ để họ
đưa ra một vài điều đáng suy nghĩ. Trong bài tham luận kinh điển của mình "Ai
cần một kiến trúc sư?" (xem Tài nguyên), Martin Fowler bàn luận về một số định
nghĩa. Ông trích dẫn định nghĩa đầu tiên từ một bài đăng tải trên danh sách thư
chung Lập trình đỉnh cao (Extreme Programming mailing list):
" RUP, cố thoát khỏi định nghĩa của IEEE, định nghĩa kiến trúc như là 'quan niệm
lẫn nhau. Ví dụ, hầu như tất cả các SOA phải thực hiện một sự thỏa hiệp giữa tính
linh hoạt và tốc độ. Hệ thống khách - chủ xưa cũ mà bạn hiện đang sử dụng hầu
như chắc chắn sẽ nhanh hơn các phiên bản thay thế nó mà dựa trên Web, dựa trên
máy portlet hay dựa vào dịch vụ. Trừ khi ứng dụng mới được các nhà phát triển rất
kém viết ra, các tầng bổ sung thêm cung cấp tính linh hoạt cũng có nghĩa là thời
gian đáp ứng cho những người dùng tăng lên, làm cho nó chậm hơn với người
dùng. Có lẽ kiến trúc sư là người sẽ phải nói với những người sử dụng, "Ôi, nhân
đây tôi muốn nói rằng, cái SOA mới mà chúng tôi vừa cài đặt sẽ làm việc tốt hơn
cho chúng tôi, nhưng bây giờ thì công việc của bạn sẽ mất nhiều thì giờ hơn đấy.
Xin lỗi nhé". Có lẽ đó là lý do tại sao các kiến trúc sư được trả tiền nhiều hơn các
nhà phát triển.
Còn lại định nghĩa kiến trúc yêu thích của tôi như sau:
"Điều khó có thể thay đổi sau này".
Định nghĩa này phù hợp nhất với ý tưởng về một kiến trúc tiến hóa. Một trong
những ý tưởng cốt lõi đằng sau kiến trúc tiến hóa là trì hoãn quyết định, càng
chậm càng tốt, nó cho phép bạn chọn những cách thay thế mà các trải nghiệm vừa
mới đây cho thấy là tốt hơn. Nhiều khối nền tảng của phong cách kiến trúc này
xuất hiện trong suốt loạt bài này và là động cơ thúc đẩy tạo ra loạt bài viết này.
Trước khi rời cuộc thảo luận về kiến trúc, sẽ là tắc trách nếu tôi không bàn về chức
danh "kiến trúc sư". Nó chọc tức các phòng nhân sự vì lẽ đã là một ngành công
nghiệp mà chúng ta lại có những chức danh công việc định nghĩa mơ hồ đến như
thế. Nhiều tổ chức muốn thăng cấp các nhà phát triển tốt nhất của họ — những
người đưa ra các quyết định quan trọng về những điều khó có thể thay đổi sau này
— nhưng không có thuật ngữ công nghiệp nào phù hợp hơn ngoài "kiến trúc sư".
Cũng không có bản mô tả công việc chung nào, do đó mỗi công ty tự định nghĩa
vai trò này có nghĩa là gì. Một số kiến trúc sư giống với ông Kiến trúc sư ở phần
cuối của bộ phim Ma trận thứ hai (mà Fowler xếp loại là Architectus Reloadus).
Các kiến trúc sư này đã viết những dòng mã cuối cùng khoảng một thập kỷ trước
và bây giờ họ đang thực hiện các quyết định quan trọng đối với công ty của bạn.
Công cụ phát triển phần mềm duy nhất mà họ sử dụng là Visio.
Các mối quan tâm về kiến trúc và thiết kế
Tiến hóa so với nổi dần
Lưu ý rằng loạt bài này được đặt tên là Kiến trúctiến hóa và thiết kế nổi dần. Tại
sao có sự phân biệt giữa tiến hóa và nổi dần? Kiến trúc nổi dần, như một trong
những đồng nghiệp của tôi nói với tôi, không phải là một ý tưởng nóng hổi lắm.
Nếu bạn chấp nhận tiền đề rằng kiến trúc là về những gì đó khó thay đổi sau này,
thì thật là khó cho phép một kiến trúc nổi dần lên. Kiến trúc quan tâm đến các yếu
tố cơ sở hạ tầng phải tồn tại trước khi bạn có thể bắt đầu ứng dụng. Tuy nhiên, chỉ
vì bạn không thể cho phép kiến trúc nổi dần lên không có nghĩa là nó không thể
tiến triển. Nếu bạn đã tạo ra một kiến trúc linh hoạt và đã chú ý không để tạo ra
các quyết định không thể thay đổi được, thì bạn có thể cho phép nó tiến triển theo
thời gian khi các mối quan tâm mới lại xuất hiện.
Bây giờ khi đã có các định nghĩa để làm việc về kiến trúc và thiết kế trong tay, tôi
muốn xoáy sâu vào toàn bộ các lĩnh vực quan tâm. Tất cả những chủ đề này giao
cắt với cả kiến trúc lẫn thiết kế ở cấp độ cơ bản, do đó việc trình bày trước cho
phép tôi nhắc lại chúng về sau trong loạt bài này. Trước tiên, tôi bàn luận về nợ kỹ
thuật (technical debt), sau đó là về độ phức tạp, và cuối cùng là về tính bao quát
tràn lan.
Món nợ chính và lãi phát sinh
Mỗi nhà phát triển đều ý thức được khái niệm nợ kỹ thuật, khi bạn thỏa hiệp trong
thiết kế của bạn vì một số sức ép bên ngoài, ví dụ như sức ép về lịch trình công
việc. Nợ kỹ thuật giống như nợ thẻ tín dụng: bạn không có đủ tiền vào lúc này, vì
vậy bạn vay nợ rồi trả lại trong tương lai. Tương tự, dự án của bạn hiện không có
đủ thời gian để làm một cái gì đó đúng cách, vì vậy bạn phải dùng tạm một giải
pháp vừa kịp có và hy vọng lúc nào đó trong tương lai sẽ quay lại và làm mới lại
nó. Thật không may, rất nhiều nhà quản lý có vẻ không hiểu về nợ kỹ thuật, phản
đối việc quay về xem xét lại công việc trong quá khứ.
Việc xây dựng phần mềm không giống như việc đào mương. Nếu bạn thỏa hiệp
thảo luận về các thuật ngữ này tỷ mỉ và cẩn thận trong cuốn sách Nhà lập trình
năng suất cao (The Productive Programmer) của tôi (xem Tài nguyên). Các thuật
ngữ này nói chung không phải là không có gì mới mẻ: chúng tồn tại trên một dải
phổ, giống như thiết kế. Một vài ví dụ sẽ giúp làm rõ sự khác biệt này.
Một trong những đồng nghiệp của tôi làm việc với một hệ thống bảng lương cho
một công ty có tổ chức công đoàn. Một trong những sự nhượng bộ mà công đoàn
đã đạt được dành cho một số trong các thành viên của họ là được thêm một ngày
nghỉ làm nữa vào đầu mùa săn bắn. (Này, họ chắc phải có những người đàm phán
tốt đấy chứ). Những công nhân đang nói đến ấy làm việc tại chỉ một nhà máy,
nhưng phụ cấp thêm cho một ngày nghỉ nữa là một phần hợp pháp của hệ thống
bảng lương cho toàn công ty. Việc thay đổi này làm tăng thêm khá nhiều tính phức
tạp của phần mềm, nhưng nó là độ phức tạp bản chất vì nó đã là một phần vấn đề
nghiệp vụ cần giải quyết.
Một ví dụ khác, đi xa hơn một chút trong phạm vi thiết kế, luôn luôn xuất hiện:
bảo mật ở mức các trường của các biểu mẫu nhập dữ liệu. Rất nhiều doanh nhân
nghĩ họ muốn có quyền kiểm soát các đặc tính bảo mật của mỗi trường với độ chi
tiết cao. Trong thực tế, họ hầu như luôn luôn ghét nó khi nó được thực thi bởi vì
nó tạo ra một gánh nặng cho những người sử dụng, những người cần phải định
nghĩa và duy trì tất cả các siêu dữ liệu này. Các doanh nhân ở một trong các dự án
của chúng tôi thực sự muốn có tính năng này, do đó chúng tôi thực thi một phần
của nó trên một trong các màn hình dành cho họ. Một khi họ lần đầu tiên tận mắt
nhìn thấy cần bao nhiêu nỗ lực để làm cho nó hoạt động, họ đã quyết định rằng, do
chỉ có quyền truy cập vào ứng dụng này từ một văn phòng có khóa, họ có thể đồng
ý với bảo mật có mức chi tiết thô hơn. Đây là một ví dụ hay về một quyết định
thiết kế xuất hiện ngay khi doanh nhân nhìn thấy thực tế những gì mà họ nghĩ rằng
họ muốn có.
Tại đầu mút bên kia của dải phổ theo hướng độ phức tạp ngẫu nhiên là các bài tập
đo độ sâu thuần túy giống như hai phiên bản đầu tiên của công nghệ Enterprise
JavaBeans (EJB) và các công cụ như BizTalk. Một vài dự án cần làm thêm công
việc mà các công cụ này đưa vào, nhưng chúng chẳng làm được bất kỳ điều gì
phép tôi trì hoãn quyết định đó?" Bạn sẽ ngạc nhiên về những điều mà bạn có thể
trì hoãn cho đến sau này nếu bạn chỉ cần áp dụng một số tài khéo léo cho quá trình
ra quyết định của bạn.
Sự khác biệt mà tôi đã nêu ở trên giữa kiến trúc mức khung công tác và kiến trúc
ứng dụng buộc chặt vào nguyên tắc về thời điểm hợp lý cuối cùng. Kiến trúc ứng
dụng có khuynh hướng trở thành một kiến trúc logic. Ví dụ, giả sử bạn biết rằng
bạn muốn phân tách các mối quan tâm về Mô hình-Khung nhìn-Trình bày. Rất
thông thường, bạn thực hiện bước nhảy ngay đến việc thực thi vật lý của kiến trúc
logic đó bằng cách chọn một khung công tác đáp ứng được một số hoặc tất cả các
yêu cầu. Hãy xem xem bạn có thể trì hoãn quyết định đó không vì một khi bạn đã
có thực thi vật lý triển khai rồi, nó khống chế các loại quyết định khác mà bạn phải
xem xét kỹ. Việc tạm để ra ngoài chưa xét một quyết định về khung công tác cho
đến khi còn có thể, sẽ để lại cho bạn những khả năng mở đối với các tùy chọn tốt
hơn, ít bị ô nhiễm bởi hoàn cảnh thực tế.
Tính bao quát tràn lan
Điều cuối cùng trong số các mối quan tâm bao trùm dành cho kiến trúc và thiết kế
là một cụm từ tôi đã tạo ra được gọi là tính bao quát tràn lan (rampant
genericness). Chúng ta hình như có một căn bệnh trong thế giới Java: bày ra quá
nhiều các giải pháp bằng cách cố gắng làm cho chúng càng bao quát chung càng
tốt. Động lực cho điều này là rõ ràng: Nếu chúng ta xây dựng sẵn nhiều tầng dành
cho việc mở rộng, chúng ta có thể xây dựng thêm bên trên chúng một cách dễ
dàng hơn về sau này. Tuy nhiên, đây là một bẫy nguy hiểm. Bởi vì tính bao quát
làm tăng thêm entropi, gây tổn hại đến khả năng làm tiến triển thiết kế theo những
cách đáng quan tâm ngay từ đầu trong dự án. Thêm quá nhiều tính linh hoạt làm
cho mọi thay đổi đối với cơ sở mã nguồn thành phức tạp hơn.
Tất nhiên, bạn không thể bỏ qua khả năng mở rộng. Phong trào ủng hộ thiết kế
nhanh nhẹn (agile) có một cụm từ thú vị tóm tắt quá trình quyết định việc thực thi
các đặc tính: YAGNI (Bạn sẽ không cần nó). Đây là một câu thần chú Ấn độ để cố
gắng tránh bày ra quá nhiều cho một đặc tính đơn giản. Chỉ cần thực thi chính xác
những gì bạn cần bây giờ và nếu sau này bạn cần thêm nhiều thứ khác thì bạn có