Lập trình web: 10 antipattern nên tránh
Thiết kế cấu trúc website và ứng dụng, hoặc thiết lập workflow hiệu quả thường khiến ta vướn vào nhiều vấn đề nan giải. Ta không cần phải tìm giải pháp từ con số 0, vì ta có thể “tái sử dụng” nhiều giải pháp cấp cấu trúc tương tự như code cấp độ siêu vi . Design ...
Thiết kế cấu trúc website và ứng dụng, hoặc thiết lập workflow hiệu quả thường khiến ta vướn vào nhiều vấn đề nan giải. Ta không cần phải tìm giải pháp từ con số 0, vì ta có thể “tái sử dụng” nhiều giải pháp cấp cấu trúc tương tự như code cấp độ siêu vi.
Design patterns cũng là giải pháp “tái sử dụng” được cho một vài trường hợp, và có thể tối ưu code rất tốt.
Design patterns là công cụ hỗ trợ lập trình tuyệt vời với nhiều công thức đã được kiểm chứng. Tuy vậy, design pattern cũng có hiệu quả tiêu cực. Lúc này, ta gọi chúng là antipattern.
Antipattern là gì?
Thuật ngữ “antipattern” được giới thiệu lần đầu trong cuốn sách mang tên AntiPatterns 1998. Nó dùng để chỉ các giải pháp được tái sử dụng, ban đầu trong có vẻ rất hiệu quả, nhưng dần dần lại hại nhiều hơn lợi.
Quá trình này có nhiều nguyên nhân, như: sử dụng pattern không đúng bối cảnh, thời gian,… hoặc cả mô hình (paradigm) ngay từ đầu đã không được tốt.
Antipattern cũng thường được gọi là pattern thất bại. Thật may, ta hoàn toàn có thể nhận biết và tránh chúng.
Trong bài này tôi sẽ điểm qua 10 antipattern thường thấy trong lập trình web. (chú ý rằng những antipattern trong bài viết này không hoàn toàn giống với những antipattern trong cuốn sách trên.)
1. Premature optimization
Một nhân tố quan trọng trong tối ưu code là “thời gian chuẩn”. Nếu chúng ta để ý đến chi tiết và tối ưu chúng quá sớm trước khi biết rõ cần làm gì, ta có thể dễ dàng phạm phải antipattern “Tối ưu “non””.
Theo câu nói nổi tiếng của Donald Knuth “tối ưu sớm là gốc rễ mọi tội ác”, có hơi thái quá, nhưng có vậy mới thể hiện được các vấn đề nghiêm trọng trong tương lai của antipattern này.
Nếu ta tối ưu trước khi thiết lập cấu trúc hiệu quả, ta có thể làm code khó đọc hơn, debug và bảo trì khó khăn hơn, và thêm nhiều code dư thừa.
Để tránh tối ưu non, bạn có thể theo nguyên tắc lập trình YAGNI (You Aren’t Gonna Need It), theo đó “cần khi nào thì thêm khi đó”, chứ không phải theo kiểu “chắc là sau này sẽ cần”.
2. Reinventing the Wheel
Antipattern “reinventing the wheel” (tạm dịch “xây lại từ đầu”) xảy ra khi ta muốn tự mình làm tất tần tật mọi thứ và viết code từ đầu đến cuối, mà không tham khảo những phương pháp, API hay thư viện đã có.
Reinventing the wheel không chỉ lãng phí thời gian; mà các giải pháp tùy chọn, đặc biệt là các functionality cơ bản, thường không tốt như các functionality chuẩn đã được nhiều người dùng và lập trình viên thử nghiệm.
3. Dependency Hell
Ngược với “xây lại từ đầu”, ta có “địa ngục dựa dẫm”.
Nếu, thay vì cặm cuội code từ đầu đến cuối, ta lại dùng quá nhiều thư viện của nhiều bên thứ ba thì sao? Sẽ có lúc ta muốn cập nhật, và những thư viện này sẽ không tương thích với nhau.
Ta có thể giải quyết địa ngục dựa dẫm bằng cách sử dụng package manager cho phép ta cập nhật các thư viện độc lập thông minh. Nếu ta vấp phải quá nhiều vấn đề, refactoring có thể là ý hay.
4. Spaghetti Code
“Code mì ý” chắc hẳn là antipattern nổi tiếng nhất. cụm từ miêu tả ứng dụng khó debug hoặc điều chỉnh do thiếu cấu trúc đúng đắn.
Kết quả của thiết kế phần mềm hời hợt là một đống code ná ná nhau chồng chất thành một tô spaghetti, rối như tơ vò. code mì ý vô cùng khó đọc, và ta không cách nào hiểu được quy luật hoạt động chính xác của “mớ” code này.
5. Programming by Permutation
“Lập trình hoán vị” hoặc “lập trình tai nạn” xảy ra khi lần lượt thử nghiệm nhiều giải pháp cho các điều chỉnh nhỏ lẻ, và cuối cùng áp dụng cái đầu tiên.
Lập trình hoán vị sẽ tạo nhiều lỗi mới cho code. Hơn nữa, ta khó có thể nhận biết các lỗi này ngay. Trong hầu hết tình huống, đoán biết giải pháp cho mọi vấn đề là nhiệm vụ bất khả thi.
6. Copy and Paste Programming
“Lập trình chép dán” xảy ra khi ta không tuân theo nguyên tắc lập trình Don’t Repeat Yourself (DRY), và thay vì tìm giải pháp chung, ta lại đi nhập “vụn” code hết chỗ này đến chỗ khác, rồi còn cố chỉnh đi chỉnh lại cho phù hợp.
Vì những đoạn code này chỉ khác nhau ở một vài điểm nhỏ, kết quả là code của chúng ta sẽ lặp lại liên tục.
Ta không những thấy antipattern này ở ma mới, mà vẫn có ở những lập trình viên kỳ cựu, bởi nhiều người thường dùng code viết và tỗi ưu sẵn cho nhiều nhiệm vụ cụ thể, từ đó vô tình gây lặp lại.
7. Cargo-Cult Programming
Cái tên “lập trình cargo-cult” bắt nguồn từ một hiện tượng dân tộc học mang tên “cargo cult”. Cargo cults khởi nguồn tại khu vực Nam Thái Bình Dương sau thế chiến II, sự tiếp xúc giữa dân bản địa với nền văn minh mới khiến họ nghĩ rằng sản phẩm công nghiệp như Coca-Cola, TV, tủ lạnh trong những thùng hàng được chuyển lên đảo là kết quả của thế lực siêu nhiên; và nếu họ thực hiện “nghi thức màu nhiệm” như nền văn hóa phương Tây, những thùng hàng như vậy sẽ lại đến.
Antipattern này cũng tương tự. Ta cứ dùng những framework, thư viện, phương pháp, pattern thiết kế,… cơ lợi cho ta, mà không hiểu tại sao ta phải dùng tới chúng, hay cơ chế hoạt động của những công nghệ này ra sao.
Nhiều khi, lập trình viên cứ nhắm mắt thấy cái gì đang “hip” thì đưa vào mà không có mục đích cụ thể. Antipattern này không chỉ bơm ứng dụng của ta “căng phồng”, mà còn gây ra nhiều lỗi không đáng có.
8. Lava Flow
Ta nói đến antipattern “dòng dung nham” khi ta làm việc với code có nhiều phần dư thừa, chất lượng kém, đồng thời tích nguyên với cả chương trình, nhưng ta lại chả hiểu vai trò và ảnh hưởng của nó là gì. Vì vậy, việc loại bỏ code này mang lại nhiều rủi ro.
Hiện tượng này thường thấy ở legacy code, hoặc khi code này do người khác viết (thiếu tài liệu chính xác), hoặc khi project chuyển từ giai đoạn phát triển sang production quá nhanh.
Cái tên của antipattern này thể hiện sự tương đồng với dung nham núi lửa, ban đầu thì nhanh và êm nhẹ khó phòng ngừa, sau thì đặc quánh và khó chuyển dời.
Về mặt lý thuyết, ta có thể loại bỏ dòng dung nham khi đã kiểm tra và refactor kỹ lưỡng, nhưng trong thực tế, việc áp dụng sẽ rất khó, gần như bất khả thi. Dòng dung nham thường có chi phí thực hiện rất cao, vẫn tốt hơn nếu ngay từ đâu ta có workflow và cấu trúc vững chắc.
9. Hard Coding
“Lập trình dính cứng” là antipattern được nhắc đến rất nhiều trong các cuốn sách lập trình web. Lập trình cứng xảy ra khi ta lưu trữ cấu hình hoặc dữ liệu đầu vào (như đường dẫn file hoặc tên máy chủ từ xa) trong mã nguồn, chứ không phải một file, database, user input,… từ bên ngoài.
Và vấn đề ở đây là phương pháp này chỉ hoạt động chính xác trong một mội trường nhất định. Khi điều kiện thay đổi, ta phải thực hiện điều chỉnh lên mã nguồn, thường là ở nhiều chỗ phân tán.
10. Soft Coding
Nếu “cố quá” tránh lập trình cứng, ta có thể dễ dàng phạm phải một antipattern ngược lại, mang tên “lập trình mềm”.
Với lập trình mềm, ta đưa dữ liệu cần có trong mã nguồn ra các tài nguyên bên ngoài, ví dụ như khi ta lưu trữ business logic trong database. Lý do là vì ta lo lắng business rule sẽ thay đổi trong tương lai, và lúc đó phải viết lại code.
Trong những trường hợp cực đoan, chương trình quá mềm sẽ trở nên quá trừu tượng và rối rằm, không cách nào nắm bắt được (đặc biệt là với các thành viên khác trong team), và cực kỳ khó bảo dưỡng, debug.
Tecktalk via hongkiat