Những việc bạn không bao giờ nên làm (Phần 1)
Người viết: Joel Spolsky Cuối cùng thì bản dùng thử public đầu tiên của Netscape 6.0 cũng đã được tung ra, trong khi chưa từng có bản 5.0 nào cả. Phiên bản lớn gần nhất của trình duyệt này, version 4.0, đã được xuất bản từ gần 3 năm trước. Ba năm là khoảng thời gian dài khủng khiếp ...
Người viết: Joel Spolsky
Cuối cùng thì bản dùng thử public đầu tiên của Netscape 6.0 cũng đã được tung ra, trong khi chưa từng có bản 5.0 nào cả. Phiên bản lớn gần nhất của trình duyệt này, version 4.0, đã được xuất bản từ gần 3 năm trước. Ba năm là khoảng thời gian dài khủng khiếp trong thế giới Internet. Trong quãng thời gian này, Netscape chỉ có thể ngồi nhìn thị phần của họ tụt giảm mạnh, một cách bất lực.
Tôi có chút thái quá khi chỉ trích họ về việc chờ đợi quá lâu giữa các kỳ xuất bản. Họ không cố tình làm như vậy, đúng không?
Có đấy. Cố tình đấy. Họ mắc phải một sai lầm chiến lược tồi tệ nhất mà một công ty phần mềm có thể đưa ra:
Họ quyết định code lại toàn bộ từ đầu.
Netscape không phải là công ty đầu tiên mắc phải sai lầm này. Borland cũng đã từng, đó là khi họ mua Arago và cố gắng biến nó thành dBase dành cho Windows, một dự án suy đồi kéo dài quá lâu, và để cho Microsoft Access “cướp miếng ăn” của họ trong lĩnh vực này. Sau đó, họ lại phạm sai lầm tương tự khi viết lại Quattro Pro từ đầu và làm người ta sững sờ về số tính năng ít ỏi mà nó cung cấp. Microsoft cũng suýt mắc phải lỗi đó, họ cố viết lại từ đầu Word cho Windows trong một dự án thất bại tên là Pyramid – dự án đã bị đóng cửa, quăng ra ngoài đường, dọn dẹp không còn chút tàn tích. Vẫn may cho Microsoft, họ chưa bao giờ dừng bảo trì bộ khung code cũ, họ vẫn có sản phẩm để deliver, vậy nên cho dự án kia “chỉ” gây ra một thảm họa tài chính thay vì một thảm họa chiến lược.
Chúng ta là những lập trình viên. Lập trình viên thì có bản năng của kiến trúc sư, và việc đầu tiên họ muốn làm khi được đưa tới một công trình là ủi phẳng chỗ đó để xây lên một cái gì đó thật đẹp. Chúng ta không thấy kích thích bởi những việc như: tu sửa căn nhà, cải tạo sân vườn, trồng thêm mấy chậu hoa.
Có một lý do làm cho các lập trình viên luôn luôn muốn đập bỏ source code cũ đi và làm lại từ đầu. Lý do đó là: họ nghĩ source code cũ là một đống tạp nham thối hoắc. Và đây là một đánh giá thú vị về việc đó: có lẽ họ đã sai. Nguyên nhân làm họ coi source code cũ như một đống rác rưởi là vì quy luật căn bản và thiết yếu của việc lập trình:
Đọc code thì khó hơn viết code
Đó là lý do vì sao việc tái sử dụng code lại khó như vậy. Nó cũng giải thích nguyên nhân mỗi người trong team bạn dùng một function khác nhau để tách chuỗi thành mảng chứa các chuỗi con. Họ viết function của riêng họ vì nó dễ hơn và tiện hơn việc tìm hiểu cách hoạt động của các function cũ.
Như là hệ quả tất nhiên của tâm lý trên, bạn có thể hỏi gần như mọi lập trình viên về phần code họ đang làm việc.
“Cái source code đấy hả? Nó là một đống bùng nhùng lộn xộn to oành”, họ sẽ kể như vậy.
“Tôi chỉ mong được quăng mẹ nó đi để code lại”.
“Đoạn code này đã làm tôi bị ung thư”.
Tại sao nó lại là một đống tạp nham bốc mùi?
“Mẹ kiếp,”, họ bảo, “nhìn cái function này đi. Nó dài tới 2 trang giấy! Chẳng có dòng nào liên quan đến nghiệp vụ này cả. Tôi không hiểu một nửa số dòng code gọi API này để làm quái gì nữa.”
Trước khi phần mềm xử lý bảng tính mới của Borland ra đời, Philippe Kahn, nhà sáng lập ưa hoa mĩ của Borland, đã rất huênh hoang trong các buổi họp báo về chuyện Quattro Pro sẽ tốt hơn nhiều so với Microsoft Excel, bởi vì nó được code lại từ đầu. Toàn bộ source code đều là mới! Như thể source code để lâu thì sẽ bị rỉ sét vậy.
Quan niệm code mới tốt hơn code cũ thì hiển nhiên là vô lý. Code cũ là cái đã được sử dụng. Nó đã được test. Nhiều bug đã được phát hiện và đã được fix. Không có vấn đề gì ở đấy cả. Source code đó không tự thâu tóm đống bug bằng việc chỉ nằm im đâu đó trong ổ cứng của bạn đâu nhé. Au contraire, baby! (Nhầm rồi cưng!) Phần mềm máy tính được xem như giống chiếc xe Dodge Dart cũ, sẽ rỉ sét khi nằm mãi trong garage hay sao? Hay là phần mềm giống như con teddy bear, trông sẽ thảm hại nếu không được làm toàn bộ từ những nguyên liệu mới?
Quay lại với cái function dài 2 trang giấy. Vâng, tôi biết, nó chỉ là một function đơn giản để hiển thị một window dialog, nhưng nó có mọc thêm tóc tai lông lá và không ai hiểu tại sao. Ừm, để tôi nói cho bạn lý do: mấy cái đó từ fix bug mà ra. Một trong số chúng để fix bug mà bạn Nancy gặp khi cố install chương trình trên máy tính không có Internet Explorer. Một chỗ khác thì fix bug xảy ra trong điều kiện máy thiếu memory. Chỗ khác thì fix bug về trường hợp file được chứa trong một cái đĩa mềm và người dùng cao hứng rút cái đĩa ra trong lúc đang chạy. Đoạn code gọi LoadLibrary trông xấu tệ hại nhưng nó giúp chương trình hoạt động trên version cũ của Windows 95.
Các bug kể trên đã sống nhiều tuần trời trước khi chúng được phát hiện. Lập trình viên có lẽ đã mất vài ngày tái hiện và fix bug. Nếu chúng giống hầu hết các bug thông thường khác, để fix được có lẽ chỉ cần 1-2 dòng code, hoặc thậm chí là sửa vài ký tự, nhưng rất nhiều công sức và thời gian đã phải bỏ ra để biết được vài ký tự cần sửa đó.
Khi bạn vứt bỏ code cũ để làm lại, bạn đang ném đi tất cả những hiểu biết trên. Tất cả những phần fix bug được tổng hợp lại. Hàng nhiều năm trời công sức lập trình.
Bạn đang ném đi uy thế đứng đầu trong lĩnh vực đã làm. Bạn đang tặng món quà trị giá 2 đến 3 năm cho các đối thủ cạnh tranh, và hãy tin tôi đi, đó là khoảng thời gian rất dài xét theo “năm phần mềm”.
Bạn đang tự đưa mình vào tình thế cực kỳ nguy hiểm khi mà bạn sẽ phải deliver một version code cũ trong vài năm, hoàn toàn không có khả năng đưa ra các thay đổi về chiến lược hoặc đáp ứng những tính năng mới mà thị trường đòi hỏi, bởi vì bạn không có source code để deliver. Bạn thậm chí có thể phải đóng cửa doanh nghiệp trong quãng thời gian đó.
Bạn đang lãng phí một khoản chi phí khó có thể chấp nhận, cho việc viết lại source code vốn đã có sẵn.
Có phương án thay thế nào không? Có vẻ họ ngầm hiểu rằng bộ khung code cũ của Netscape là thực sự tệ hại. Ừm, có thể đúng vậy, nhưng bạn biết điều gì khác về nó không? Nó vẫn hoạt động khá ổn trên một số lượng cực lớn các hệ thống máy tính đang vận hành ngoài kia.
Khi các lập trình viên nói bộ source của họ là đống tạp nham thối hoắc (họ vẫn nói vậy suốt), có 3 yếu tố sai lầm ở đấy:
Đầu tiên, có các vấn đề thuộc về kiến trúc phần mềm. Bộ source không được thiết kế đúng chuẩn. Phần code kết nối mạng tự bật ra một cái popup dialog từ giữa hư không; cái này nên được xử lý ở phần code giao diện mới phải. Những vấn đề kiểu này có thể được giải quyết gọn gàng trong một lần sửa, bằng cách cẩn thận di chuyển cách đoạn code, format lại source, cập nhật phần giao diện. Những việc này có thể được một dev thực hiện một cách cẩn thận và kiểm soát chặt chẽ những đoạn code đã thay đổi, để không làm các phần việc khác bị gián đoạn. Thậm chí các thay đổi tương đối lớn về mặt cấu trúc cũng có thể được thực hiện mà không cần xoá bỏ source code cũ. Hồi làm dự án Juno, có thời điểm chúng tôi trải qua vài tháng để thiết kế lại kiến trúc: chỉ di chuyển các thứ qua chỗ nọ chỗ kia, dọn dẹp gọn gàng, tạo các class base có ý nghĩa, và tạo các interface rõ ràng cho việc giao tiếp giữa các module. Nhưng chúng tôi đã làm rất cẩn trọng, với bộ khung code có sẵn, và không hề gây ra bug mới hay phải bỏ đi các phần code vốn đang hoạt động đúng.
Lý do thứ 2 mà lập trình viên nghĩ code cũ kém chất lượng, đó là về hiệu quả performance thấp. Phần code dựng hình của Netscape được đồn thổi là chạy chậm. Nhưng nó chỉ ảnh hưởng đến một phần nhỏ trong cả dự án, phần mà bạn có thể sửa để tối ưu hoá hoặc thậm chí viết lại. Bạn không cần phải viết lại cả bộ source làm gì cả. Khi thực hiện việc tối ưu hoá, 1% khối lượng source sẽ chiếm 99% hiệu quả performance.
Thứ 3, source code trông xấu đau xấu đớn. Trong một dự án tôi từng làm, thật sự đã có một kiểu dữ liệu được khai báo tên là FuckedString. Một dự án khác thì ban đầu dùng ký tự gạch dưới để khai báo biến class member, nhưng về sau lại dùng cái chuẩn hơn là “m_”. Vậy nên một nửa số function có tên bắt đầu bằng “_” và nửa còn lại bắt đầu bằng “m_”, trông rất xấu và thiếu nhất quán. Thực sự thì kiểu vấn đề này bạn có thể giải quyết bằng một macro trong Emacs chỉ trong 5 phút, không cần phải viết lại từ đầu đống function kia.
Một điều quan trọng là bạn phải nhớ rằng khi phát triển lại toàn bộ hệ thống từ đầu thì TUYỆT ĐỐI KHÔNG CÓ LÝ DO NÀO để tin chắc rằng bạn sẽ làm tốt hơn lần đầu tiên. Trước tiên thì team mới của bạn có lẽ không còn là team phát triển của version đầu, nên thật ra bạn sẽ không có “nhiều kinh nghiệm hơn” trước kia. Có lẽ bạn sẽ lại gặp phải những lỗi cũ một lần nữa, thêm vào đó là phát sinh những vấn đề mới mà version trước không có.
Câu thần chú cổ điển “đập đi làm lại” là rất nguy hiểm khi áp dụng vào các ứng dụng mang tính thương mại có quy mô lớn. Nếu bạn chỉ đang viết code thử nghiệm, có lẽ bạn sẽ muốn xé bỏ cái function viết tuần trước khi bạn nghĩ ra một thuật toán tốt hơn. Cái đó thì ok thôi. Có lẽ bạn sẽ muốn định dạng lại một class nào đó cho dễ sử dụng. Cũng ổn thôi. Nhưng bỏ đi toàn bộ chương trình cũ là một việc dại dột và nguy hiểm, và nếu Netscape thực sự có được bộ máy giám sát chuyên nghiệp giàu kinh nghiệm trong ngành công nghiệp phần mềm, có lẽ họ đã không tự bắn vào chân mình một phát đầy đau đớn như vậy.
Techtalk via Reddit Việt Nam