Showing posts with label coding. Show all posts
Showing posts with label coding. Show all posts

Đi tìm đoạn code ngắn nhất nhưng lại... gây hại nhiều nhất

Đâu là đoạn code đúng ngữ pháp và ngắn nhất mà bạn có thể viết được? Đâu là đoạn code tạo ra ít thay đổi nhất với hệ thống, và đâu là đoạn code ngắn nhất nhưng lại gây ảnh hưởng nhiều nhất?


Tổng biên tập Motherboard, Derek Mead đã có lần đưa ra câu hỏi: Đoạn code có nghĩa và tạo ra ảnh hưởng rõ rệt nhất có thể viết được là gì?
Điều thú vị đầu tiên về câu hỏi này là sự mập mờ của nó: "đoạn code nhỏ" nghĩa là gì? Thế nào gọi là "có nghĩa" Chúng ta sẽ đo độ lớn/nhỏ của code bằng những thứ chúng ta có thể viết lên IDE hoặc màn hình command? Hay, liệu chúng ta nên đo độ lớn/nhỏ của code bằng tác động của chúng đến hệ thống?
Hãy kết hợp cả hai yếu tố và đi tìm câu trả lời cho 3 câu hỏi:
- Đoạn code ngắn nhất có thể viết được là gì?
- Đoạn code tạo ra ít thay đổi nhất với hệ thống mà bạn có thể viết ra là gì?
- Đâu là đoạn code ngắn nhất nhưng lại tạo ra thay đổi lớn nhất đối với hệ thống?
Đoạn code ngắn nhất
Đâu là đoạn code ngắn nhất nhưng vẫn đúng ngữ pháp của các ngôn ngữ?
Để trả lời câu hỏi này, bạn phải hiểu rằng các ngôn ngữ lập trình được chia làm 2 loại chính. Yêu cầu "ngắn nhất nhưng vẫn đúng ngữ pháp" có vẻ khá phù hợp với các ngôn ngữ biên dịch (interpreted language): trong các ngôn ngữ này, các phần mềm trung gian (interpreter) sẽ lần lượt dịch từng dòng code của lập trình viên thành mã máy khi thực thi dòng lệnh.
(Thực tế không phải là interpreter lúc nào cũng sẽ dịch từng dòng code nhưng dạng ngôn ngữ này có tính tuần tự rất rõ rệt).
//làm cái ảnh GIF như thế này, chắc khoảng 10 câu, lần lượt bay vào interpreter ra từng câu kết quả

Một dạng ngôn ngữ lập trình khác là ngôn ngữ lập trình biên dịch. Trong khi intepreter biến lần lượt từng dòng code của lập trình viên thành mã thực thi cho máy thì compiler lại mang "biên dịch" cùng lúc rất nhiều dòng code/file code thành một gói mã máy hoặc mã trung gian khổng lồ.

Bạn có thể hình dung ngôn ngữ dạng interpret giống như là cầm từng miếng logo để xây thành một tòa lâu đài, còn ngôn ngữ compiler thì giống như là mang một khối nhựa khổng lồ đổ khuôn trực tiếp thành tòa lâu đài mà bạn mong muốn.
Cả hai loại ngôn ngữ đều có điểm mạnh và điểm yếu riêng. Ngôn ngữ thông dịch thường dễ học và dễ sử dụng hơn do khả năng debug (theo dõi, bắt lỗi) vượt trội. Ngược lại, ngôn ngữ biên dịch có tốc độ thực thi ấn tượng hơn.
Nhưng như đã nói ở trên, ngôn ngữ thông dịch có trải nghiệm sử dụng rất dễ chịu. Thử lấy Python làm ví dụ: bạn thậm chí có thể nhập từng dòng lệnh vào interpreter của Python không khác gì nhập các dòng command vào CMD của Windows hay Bash trên Linux. Và dòng lệnh nhỏ nhất mà bạn có thể nhập vào interpreter của Python là một chữ số:

Điều mà interpreter của Python sẽ làm đơn giản là hiển thị lại con số này cho bạn mà không đưa ra bất kỳ cảnh báo hay bắt lỗi nào cả. Thậm chí, bạn còn có thể để trống câu lệnh và nhấn enter, nhưng đó không hẳn là một câu trả lời mà chúng ta mong đợi từ bài viết này.
Nếu muốn hiển thị một con số bằng ngôn ngữ compiler, bạn sẽ tốn nhiều công sức hơn. Bạn sẽ phải tạo ra một hàm để hệ điều hành có thể (tự động) "gọi" tới. Đây là hàm đơn giản nhất mà bạn có thể viết bằng C để hiển thị một ký tự và số lượng code cần ở đây tuy chưa đến 30 ký tự nhưng vẫn nhiều hơn đáng kể so với Python (chỉ một ký tự "0" duy nhất):

Ngôn ngữ tạo ra thay đổi nhỏ nhất với hệ thống
Dù rất ngắn nhưng đoạn mã mini viết bằng C hay ký tự "0" nhập vào interpreter của Python đều sẽ tạo ra những thay đổi khá lớn cho hệ thống. Ví dụ, để chạy được dòng code "0" trên Python bạn sẽ phải mở phần mềm interpreter có khả năng chiếm ít nhất là 10MB RAM. Như vậy, chúng ta đang sử dụng 10 triệu byte để hiển thị một byte, hoặc thậm chí là một bit dữ liệu.
Ngược lại, chương trình biên dịch từ đoạn mã C phía trên của chúng ta chỉ mất 28KB bộ nhớ. Rõ ràng là các ngôn ngữ compile dù rườm rà hơn nhưng vẫn có hiệu năng tốt hơn.
Tuy vậy, 28KB vẫn là 28.000 byte. Chúng ta có thể giảm con số này bằng cách chuyển sang ngôn ngữ C và sử dụng bộ thư viện stdio nhưng cuối cùng thì các ngôn ngữ lập trình vẫn sẽ luôn mất một lượng tài nguyên phần cứng tương đối lớn để giải quyết các tác vụ tương đối nhỏ. Đó là điều bắt buộc, bởi ngôn ngữ càng bậc cao (càng gần ngôn ngữ người) thì càng rườm rà, càng tốn nhiều tài nguyên xử lý.

Cách cuối cùng, tối ưu nhất để tạo ra một thay đổi có phạm vi nhỏ nhất tới hệ thống là ngôn ngữ Assembly. Đây là ngôn ngữ bậc thấp nhất, gần với ngôn ngữ máy nhất mà con người vẫn có thể hiểu được. Trong ngôn ngữ assembly, từng dòng lệnh do coder viết ra sẽ được phần mềm assembler dịch trực tiếp thành một lệnh đơn giản cho máy tính.
Trong ví dụ về số 0 của chúng ta, nếu bạn so sánh file assembly do các đoạn code Python hoặc C tạo ra với file assembly do coder trực tiếp viết để làm một tác vụ tương tự thì sự khác biệt sẽ là rất nhỏ. Nhưng hãy nhớ rằng ngôn ngữ assembly là một ngôn ngữ có bậc thấp nhấttrong tất cả các ngôn ngữ lập trình mà loài người có thể hiểu được. Việc hiển thị số 0 lên màn hình thực chất là một tác vụ lớn tương ứng với nhiều dòng lệnh trên assembly, giả dụ như khởi động màn hình, truyền số 0 từ mã nguồn lên bộ nhớ, truyền số 0 từ bộ nhớ lên màn hình v...v...
Vậy thay đổi nhỏ nhặt nhất mà chúng ta có thể tạo ra bằng assembly là gì? Có lẽ, đó là dòng lệnh sau đây:

Đây là câu lệnh được dùng để yêu cầu vi xử lý dịch chuyển một bit duy nhất trên thanh nhớ có tên eax. (Thậm chí, đây không phải là bộ nhớ RAM mà là bộ nhớ register trên CPU được dùng trực tiếp để tính toán.)
Mã nguồn thì ngắn nhưng hậu quả thì khổng lồ
Bạn hoàn toàn có thể tạo ra những dòng code rất ngắn nhưng lại có tác động cực kỳ lớn đến hệ thống. Ví dụ, hãy thử xét đến vòng lặp sau đây:

Có thể hiểu là chừng nào true còn có nghĩa là true thì các tác vụ bên trong { } vẫn sẽ được thực hiện. Dĩ nhiên là true vẫn có nghĩa là true và bạn thận chí còn không có cách nào để biến true thành false từ bên trong vòng lặp, nên vòng lặp này của chúng ta là vô hạn. Nếu chúng ta khai báo một biến số dù có nhỏ đến mấy (1 bit thôi chẳng hạn) bên trong dòng lặp và sau đó không giải phóng bit này thì chương trình vẫn sẽ gặm dần từng bit nhỏ của bộ nhớ đến lúc toàn bộ chiếc PC treo cứng.
Nếu bạn thích phá hoại máy móc thì các vòng lặp phức tạp hơn sẽ giúp bạn một cách dễ dàng nhất. Bạn có thể lồng các vòng lặp lại với nhau hoặc tạo ra một vòng lặp liên tục khởi tạo các biến số tốn chỗ (nhiều byte) chẳng hạn. Máy tính của bạn sẽ không mất quá nhiều thời gian để... treo cứng vì những vòng lặp dạng này.
Trong ví dụ này, chúng tôi sẽ liên tục khởi tạo các biến mới và thêm chúng vào một danh sách có tên arr. 4 dòng code nhỏ có đầy đủ khả năng làm cho máy treo:

Thêm một chút logic
Đoạn code như sau có thể khiến một chiếc PC chạy Core i7 có bộ nhớ 16GB treo cứng trong vòng vài giây:

Nếu tính độ dài thì đoạn code này có lẽ còn ngắn hơn cả bài kiểm tra triết học gần đây nhất của bạn, nhưng nếu nói về tác hại thì chắc chắn là cao hơn nhiều lần.
Ý nghĩa của đoạn code này là như sau: giả sử giá trị j đang ở mức 10000 thì chương trình sẽ lần mò từng con số từ 0 đến 10000 để tìm ra giá trị i = j (tức là bằng 10000). Cứ mỗi lần lần mò như vậy, chương trình này lại tạo thêm một biến số mới (để đưa vào danh sách arr của chúng ta). Khi i chạy từ 0 đến 10000, arr đã có thêm 10000 biến mới, chiếm giữ 10000 vị trí trong bộ nhớ của máy thực thi.
Trong trường hợp điều kiện i = j được thỏa mãn, j sẽ được tăng giá trị lên 1 và đạt 10001. Chương trình sẽ lại chạy vòng lặp một lần nữa cho i từ 0 đến 10001, cùng lúc tạo thêm 10001 biến "rác" cho bộ nhớ. Đến khi giá trị j đạt mức vừa đủ lớn, máy tính của bạn sẽ treo cứng dù đang sở hữu một (hoặc thậm chí là nhiều) nhân CPU có khả năng thực hiện vài triệu phép tính trong vòng một giây.
Bạn thấy đó, vài dòng code ngắn gọn có thể đánh sập chiếc máy tính vài chục triệu đồng của bạn.
Nhưng những dòng code dưới đây thì lại khác: bằng cách dịch chuyển vị trí của chỉ một dòng code duy nhất vào bên trong câu lệnh xét điều kiện, arr sẽ chỉ có thêm một biến số mới khi i đạt đến giá trị hiện tại của j. Điều đó có nghĩa rằng khi i = j = 10000, danh sách arr sẽ chỉ có thêm một biến số là 10000; khi i = j = 10001, arr chỉ có thêm 1 biến số là 10001 v...v... Hệ thống sẽ lâu bị treo hơn hoặc thậm chí là không treo trên các phần mềm thực thi được lập trình tốt.

Vẫn với logic tương tự nhưng thay vì lặp vô hạn thì chỉ (muốn) chạy đến lúc i = 2 thì dừng, nếu tôi chỉ quên một dòng lệnh duy nhất thì chương trình cũng chết. Lý do là bởi i chẳng bao giờ được tăng giá trị cả:

Hậu quả trong thực tế sẽ luôn tai hại
Thực tế, những gì chúng ta đang nghĩ đến ở đây chỉ là cho vui nhưng cũng đại diện cho các hoàn cảnh thực tế. Việc kiểm tra vòng lặp thực chất là khá đơn giản (người code tốt sẽ biết cách tránh "lồng" các vòng lặp với nhau), nhưng điều gì sẽ xảy ra nếu như trong mỗi vòng lặp chúng ta đều gọi đến một hàm tính năng (function) nào đó và bên trong hàm này chúng ta lại để lại một vài biến số "rác"?
Và điều gì xảy ra nếu chúng ta quên chỉ một câu lệnh để ngừng vòng lặp? Mỗi biến số có thể chỉ chiếm một vài byte nhưng mỗi giờ một hàm có thể được gọi hàng triệu lần mỗi giờ, bộ nhớ cứ thế tích tụ và sẽ có một lúc nào đó hệ thống phần cứng (hoặc chí ít là phần mềm server) của bạn treo cứng, bất kể là Xenon 8 nhân hay 4 chip chạy song song
Như vậy, chỉ với một câu hỏi nghe có vẻ khá đơn giản – đoạn code nhỏ nhất nhưng lại có thể gây tác hại lớn nhất là gì, chúng ta đã cùng khám phá ra 2 nguyên tắc thú vị: 1, ngôn ngữ càng dễ viết và ngắn gọn thì lại càng tiêu tốn hiệu năng phần cứng; 2, những đoạn code khá nhỏ cũng có thể gây ra hậu quả tai hại. Với các kỹ sư phần mềm chuyên nghiệp, việc phát hiện các lỗi vòng lặp hay quên giải phóng bộ nhớ do người khác để lại là chuyện rất dễ xảy ra. Do đó, khi lựa chọn ngôn ngữ và khi code thực sự (bất kể là với một ngôn ngữ nào), hãy tìm ra điểm cân bằng giữa mức độ rườm rà và mức độ dễ hiểu để "di sản" bạn để lại không khiến cho người khác... đau đầu.

Code lại từ đầu - Câu thần chú cổ điển “đập đi làm lại”

Kết quả hình ảnh cho Netscape
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

Kết quả hình ảnh cho Đọc 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.
Kết quả hình ảnh cho Java Code
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.

Kết quả hình ảnh cho Đọc code phức tạp
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.

Sự thật đắng lòng: Đôi khi cắm đầu ngồi code là cách ngu nhất để giải quyết vấn đề

Qua bài viết về button trị giá 300 triệu đô, mình thấy các bạn có vẻ hào hứng với những bài viết theo phong cách kể chuyện. Vì vậy, ở bài viết này, mình sẽ bắt đầu bằng cách kể một câu chuyện nho nhỏ về 1 chàng coder nghèo tên K (Gọi là Khoa Khoe Khoang hay Khải gì đó tuỳ bạn).
Tiếp xúc với máy tính từ năm 10 tuổi,  K vô cùng ngạc nhiên trước sức mạnh của cỗ máy vô tri vô giác ấy, và nuôi mơ ước trở thành một lập trình viên. Lên cấp 3, nhờ giỏi Toán, K được vào lớp chuyên Toán của trường. Với niềm đam mê lập trình, K nhanh chóng tiếp cận và thành thạo Pascal, C, giật được vài giải Olympic tin học.
Nhờ điểm cao, K đậu vào một trường đại học công khá danh tiếng. Vào trường, được học thêm Ngôn ngữ lập trình, về Cấu trúc dữ liệu và thuật toán, K càng ngày càng thích code hơn. K code ngày code đêm, cắm đầu vào luyện thuật toán cho thành guru, lúc rảnh rỗi K lại kiếm sách bài tập làm… cho đã thèm. K luôn nộp bài sớm hơn các bạn để thể hiện sự hơn người của mình. Do suốt ngày chỉ biết cắm mặt vào máy tính, K trải qua 4 năm đại học mà vẫn FA…
Tốt nghiệp ra trường, những tưởng một người lập trình tốt, giỏi technical (Như K tự nhận xét mình) sẽ kiếm được việc ngon, lương cao,dễ dàng thăng tiến. Vòng phỏng vấn diễn ra cũng khá suôn sẻ, K trả lời trơn tru một số câu hỏi về technical, nhưng lại ngập ngừng ở 1 số câu hỏi kiểu “Khi có xung đột với thành viên trong nhóm, em xử lý thế nào?” hoặc “Em đã có sản phầm cá nhân nào nổi bật chưa?”.
Đồng nghiệp của K có một thằng tên là H. K rất khinh thằng H này vì nó chỉ tốt nghiệp ĐH dân lập (FPT), đã thế trong giờ làm còn ít ngồi code mà toàn vào stackoverflow, pluralsight, webtretho, lâu lâu còn mở wordpress gõ gõ gì đó, hình như là blog. Thế rồi, vì vài chuyện nhỏ nhặt dưới đây, K dần dần chuyển từ khinh sang ghét và căm thù thằng H :
  • Chuyện thứ nhất: Công ty có một chương trình khá cũ chạy trên một con server cùi bắp. Gần đây, vì lưu lượng sử dụng nhiều, lâu lâu chương trình lại bị OutOfMemoriesException (tràn bộ nhớ). Tự tin với khả năng code của mình, K xin anh team leader source code của chương trình để ngồi optimize lại. Hì hục mất 2 tuần, K chỉ mới optimize được 30% chương trình cho tiết kiệm RAM. Thằng H nghe chuyện, nhanh nhảu đoảng liên hệ với anh team leader và bên IT, lắp thêm 2 thanh RAM 4GB vào con server cũ. Chỉ mất 5 phút, từ đấy chương trình chạy vo vo không còn OutOfMemories nữa.
  • Chuyện thứ hai: Team cần làm một phần mềm về phim ảnh, trích xuất dữ liệu từ Galaxy Cinema, Lotte, CGV. Với tinh thần hăng hái, ham học hỏi, K tự nghiên cứu về web parser để trích xuất thông tin từ các trang này. Do các trang này có dung Ajax, Paging phức tạp, K mất gần 2 tuần để viết và test việc parse dữ liệu từ Galaxy và Lotte. Công sức của K tiếp tục đổ sông đổ biển khi ngay hôm sau, thằng H nhanh nhảu nói với anh team leader: “Anh ơi, bên 123phim nó có API sẵn rồi, có cả Cinebox với 4,5 hãng nữa cơ. Phí chỉ có 50k/tháng thôi, mình liên hệ mua rồi integrate vào nha anh” và anh team leader gật đầu đồng ý.
  • Chuyện thứ ba: K thương thầm một em QC da trắng dáng cao tên ngực khủng tên M cùng công ty. Ngoài làm QC, em còn chuyên đăng hình khoe thân kiêm bán kem trộn làm trắng da trên facebook. Nghe tiếng K code giỏi, em thủ thỉ “Anh K làm cho em cái trang web bán hàng nha, làm đẹp đẹp em thưởng cho <3″. Vốn dại gái, lại tự tin rằng mình giỏi Java thần thánh, K bắt đầu vẽ database, dùng Spring Boot, Heroku để code một trang bán hàng hoành tráng.
  • Hôm sau lên công ty, đang định show giao diện cho em M xem thì K thấy em đang đứng bên cạnh thằng H, mắt long lanh đầy ngưỡng mộ “Anh H giỏi quá, làm web vừa đẹp lại vừa nhanh, em nhờ hôm qua mà giờ đã xong rồi”. Hóa ra thằng ku dùng PHP – thứ ngôn ngữ rẻ tiền, dung framework Magento và chôm đại cái theme có sẵn đâu đó để làm web cho ẻm một cách nhanh chóng. Hết giờ làm, bé M thưởng thằng H bằng cách đi ăn uống, xem phim rùi đi chỗ-mà-ai-cũng-biết-là-chỗ-nào-đấy :”>. Sau hôm đó, K nhìn thằng H bằng ánh mắt mang hình viên đạn.
  • Chuyện cuối cùng: Cay cú với thằng H, K quyết định viết một blog cá nhân để cạnh tranh với nó. Thấy thằng ku dùng wordpress cùi bắp, K quyết tự khẳng địng bản thân bằng cách code luôn một blog và publish mã nguồn lên github cho nó biết mặt. Code gần 3 tháng mà vẫn chưa xong, blog thì chưa viết được dòng nào, còn blog kia của thằng H đã được hơn 200 nghìn lượt xem.
Câu chuyện trên là hư cấu và không dựa trên bất cứ phần trăm sự thật nào (Bác nào thấy nhột thì cứ việc). Hãy khoan chửi em M là con bitch ngực to, hay ông team leader ngu chết mẹ không thấy đươc khả năng của K. Rõ ràng, cùng làm một việc, nhưng H lại hoàn thành một cách nhanh chóng và nhẹ nhàng hơn K. Lý do là vì K tiếp cận vấn đề theo cách của một coder, H lại tiếp cận vấn đề theo cách của một developer.
Với coder, code là thứ tối thượng có thể giải quyết mọi vấn đề. Họ thích tự học những ngôn ngữ/công nghệ mới. Họ là những người tập trung công sức để viết những dòng code thật tốt, chạy thật nhanh, optimize thật kĩ. Họ không thích tái sử dụng code của người khác, mà thích tự code để “học hỏi và phát triển”. Thế nhưng, một trong những sự thật đau lòng của ngành lập trình là đôi khi chả ai quan tâm đến code mình viết cả.
Khác với coder, developer thường tiếp cận vấn đề theo cách khác. Họ cũng có thể code và code giỏi, nhưng họ tập trung trước nhất vào vấn đề  cách giải quyết. Khi có yêu cầu từ khách hàng, họ sẽ phân tích, tìm cách giải quyết phù hợp nhất, ít tốn thời gian và công sức nhất, trước khi bắt tay vào code.
Như slogan “từ coder đến developer” của blog, mình viết để chia sẻ những kiến thức về technical và một vài thứ khác để giúp bạn tiến hóa từ coder lên developer. Giỏi technical sẽ giúp bạn làm một coder giỏi, nhưng chỉ technical không thôi là chưa đủ. Bạn cần phải nhét vào đầu tư duy lập trình, tư duy sản phẩm, tư duy phân tích thiết kế và vô số thứ khác để trở thành một developer đúng nghĩa. Để học được những điều này, hãy like fanpage và theo dõi những bài viết tiếp theo của blog nhé. Thân chào.
Chuyện bên lề, có 1 bạn khá dễ thương phỏng tác câu chuyện của mình theo 1 cách nhìn khác, cũng rất đáng đọc. Chắc cũngđồng cảm với bạn K nên trong truyện này bạn cho K 1 cái happy ending rất đẹp?
Câu chuyện hôm nay kể về một chàng coder H. Cậu đến với tin học hơi muộn, và khi nhận ra mình đam mê tin học thì đã muộn cho việc chuẩn bị thi vào các trường đại học danh tiếng về CNTT. H không giàu, nhưng cũng đủ khá giả để theo đuổi đam mê với đại học FPT.
Vào trường, cậu nhận thấy các trường đại học có vẻ danh tiếng kia dạy thật thiếu bài bản, toàn dạy những thứ lý thuyết, rất thiếu kỹ năng mềm, hay những thứ ứng dụng. Cậu học vừa đủ những môn CTDL, và tập trung hơn vào những môn “thực tế”, tự học lập trình ứng dụng và tham gia các hoạt động ngoại khóa.
Tốt nghiệp ra trường, nhờ vốn kỹ năng mềm cùng khả năng lập trình ứng dụng, cậu được nhận vào công ty. Nhưng khi phỏng vấn, cậu lại bị ngắc ngứ những câu cơ bản về cấu trúc dữ liệu, về nguyên lý lập trình.
Đồng nghiệp của H có một thằng tên K. H rất ghét thắng này vì nó tốt nghiệp đại học “danh tiếng”, lại còn khoe mấy cái giải thưởng tin học toàn mớ lý thuyết vô nghĩa. Hai đứa ngồi gần nhau, cậu lâu lâu ngó sang nó thấy nó cứ cắm cúi viết code, chả quan tâm gì đến thế sự cả. Còn cậu vừa phân bố thời gian để hoàn thành deadline, vẫn có thời gian để lên webtretho, viết blog, lâu lâu gặp bug thì chỉ cần lên stackoverflow là xong. Cậu không thích thằng K và sẽ cố gắng chứng tỏ mình hơn K. Và cậu đã làm được như vậy.
Chuyện thứ nhất – thứ hai – thứ ba – tương tự bài gốc
H rất hài lòng với những gì mình làm được. Còn K vẫn cứ ngồi đó cố gắng viết code hoàn chỉnh cho cái website bán hàng và blog, thật là rỗi việc.
  • Đến một ngày, cái phần mềm cũ rích chạy trên server cùi bắp lại dở chứng. Trưởng nhóm nhận thấy vấn đề diễn ra ngày càng thường xuyên hơn trước, tỉ lệ thuận với lượng dữ liệu đổ vào chương trình càng nhiều theo thời gian, và module gây ra chuyện đó còn được sử dụng ở nhiều chương trình khác nữa. Chẳng lẽ lại phải mua hẳn server mới và một loạt server khác nữa phòng tránh chuyện này? K nhanh nhảu chạy vào và xin tiếp tục dự án **tối ưu hóa code ** đã bị dừng lại trước đó. Trưởng nhóm đồng ý, và dù rất khó khăn nhưng 2 tuần sau K cũng đã hoàn thành. Và tất cả các chương trình sử dụng chung module đó đều chạy nhanh và ổn định hơn trước. K được anh trưởng nhóm hết sức khen ngợi và hứa hẹn sẽ tăng lương vào đợt tiếp theo.
  • 123phim đột ngột dừng hoạt động do kinh doanh thua lỗ. Các api chỉ còn truy cập được trong vòng 1 tháng. May mắn thay, nhờ có **crawler ** trước đây của K, nhóm đã nhanh chóng thay đổi và tích hợp trở lại vào phần mềm.
  • Em QC lắm chuyện đòi H thêm chức năng cho bán hàng, lần này là tích hợp với giaohangnhanh để ẻm đỡ mất công tìm người giao hàng, nhập đơn hàng bằng tay. Chết thật, H lâu lắm có đụng đến Magento đâu cơ chứ, lại chả có module nào trên mạng, mà cái theme cũng là hàng mua biết customize sao bây giờ. QC giận H và chạy sang nhờ K. K (dù rất ghét con nhỏ này) vui vẻ nhận lời vì K nắm rất rõ code của mình và việc chỉnh sửa không quá tốn thời gian lắm. Từ đó con nhỏ QC này suốt ngày bám lấy K mà quên H.
H tức giận vì K càng ngày càng được nhóm đề cao và cả em QC cũng đổ theo hắn nữa. Giờ H chỉ còn một blog. Chậc, 200k lượt xem, tên K kia đến bao giờ mời đạt được. Hắn chỉ có lèo tèo vài bài viết chán ngòm về kỹ thuật. Đến một hôm, K xin phép nghỉ việc. H mừng lắm, cuối cùng cái gai trong mắt cũng chịu đi.
Lại nói về K. Cái blog mà K chăm chút, viết blog dù ít nhưng chất lượng may mắn được một nhà tuyền dụng để mắt tới. Và công ty của nhà tuyển dụng này thuộc hàng top thế giới. K nhận được thư mời, dù rất đắn đo và lo lắng nhưng cậu quyết định thử sức. Bất ngờ thay, công ty nọ chỉ toàn hỏi những câu hỏi liên quan đến giải thuật, tư duy mà không hỏi bao nhiêu về công nghệ cả, và họ nói rằng họ rất ấn tượng với những giải thưởng tin học K đạt được. Tự tin với kiến thức nền tảng của mình, K trả lời xuất sắc hầu hết câu hỏi của nhà tuyển dụng. K nhanh chóng được đề nghị vào làm với một mức lương và môi trường làm việc mà mọi dev đều mơ ước.
Pham Huy Hoang
(Blog toidicodedao.com)

5 cách giúp các cuder ước lượng thời gian tốt hơn cho công việc

Chia nhỏ công việc:

Một trong những nguyên do khiến việc đánh giá trở nên khó khăn và thiếu chính xác chính là những công việc dài hạn. Lẽ đương nhiên, để đánh giá thời gian hoàn thành một công việc trong năm phút sẽ dễ dàng hơn so với một công việc tốn đến năm tháng.
Vậy làm sao để chúng ta giải quyết vấn đề này?
Thực ra, cách giải quyết rất đơn giản. Bạn chỉ cần chia công việc dài hạn thành những công việc ngắn hạn hơn và dễ đánh giá hơn.
Cube of rubik puzzle. Broken
Nhưng chẳng phải cách giải quyết này “đơn giản” quá hay sao? Nhiều người sẽ nghĩ vậy và đưa ra được hàng tấn lý do khiến họ không thể chia nhỏ công việc của mình, nhưng thực ra, mọi việc đều có thể được giải quyết một cách đơn giản nếu bạn đặt quyết tâm và bỏ công sức vào chúng.
Và đó cũng là cách để việc ước tính của bạn trở nên chính xác hơn!
Nếu bạn muốn ước lượng công việc một cách chính xác nhất, vậy thì đừng ngại bỏ thời gian và công sức mà chia nhỏ chúng ra. Lấy ví dụ như việc viết một blog post, hãy thử đánh giá sự khác biệt giữa việc ước lượng thời gian để:
  • Viết và đăng tải một bài blog post.
Hay:
  • Nghiên cứu về chủ đề muốn viết và tìm ý tưởng.
  • Viết dàn bài
  • Viết nháp lần đầu
  • Thêm hình ảnh và liên kết.
  • Lên kế hoạch đăng tải bài.
Rõ ràng việc đánh giá từng công việc nhỏ sẽ chính xác hơn so với cả một công việc lớn. Và một khi đã tách ra được những công việc nhỏ như trên, bạn hoàn toàn có thể đặt ra cho chúng một khung thời gian cụ thể và chính xác (điều này sẽ được nói cụ thể ở phía dưới).
Ồ, khoan! Có người sẽ nói rằng: “Ước lượng thời gian cho những công việc nhỏ có thể dễ dàng, nhưng một khi ghép chúng lại thành cả công việc lớn, sự tiên lượng của bạn vẫn có thể sai lệch đi vì nhiều lý do”. Đúng đấy, nhưng bạn hãy cứ nên chia nhỏ chúng ra đi, vì dù tổng thời gian chênh lệch của các công việc nhỏ có thể tương đương với cả công việc lớn, nhưng thời gian dao động của từng công việc nhỏ cũng dễ ước tính hơn cơ mà.

Dành thời gian để nghiên cứu.

Tại sao bạn lại ước lượng kém?
Vì bạn thậm chí còn chẳng biết mình đang ước lượng cái gì!
Bài viết trước đã đề cập đến sự ảnh hưởng của những “biến” chưa biết đến thời gian phát triển phần mềm của bạn, và bài viết này sẽ đề cập đến cách giải quyết chúng, đó là nghiên cứu.
Để giải quyết một vấn đề mà bạn không biết, thì bước đầu tiên là phải tìm hiểu về chúng.
Và bất cứ khi nào bạn phải ước lượng bất cứ thứ gì, thì việc đầu tiên bạn nên nghĩ đến là tìm hiểu về chúng và phát hiện ra những điều mà bạn không biết rằng bạn không biết.
Black-haired woman studying in the library
Black-haired woman studying in the library
Nhưng buồn cười là, đa số các developer chẳng mấy khi nghĩ đến điều này. Nếu như họ được giao cho một công việc có vẻ quen thuộc, thì họ sẽ căn cứ vào kinh nghiệm của mình để ước lượng và bỏ qua nguy cơ đến từ những vấn đề không biết. Còn nếu như họ gặp phải một công việc có vẻ lạ, thì hẳn họ nhìn đâu cũng sẽ thấy những vấn đề chưa biết, và sự ước lượng của họ sẽ bị kéo dài ra so với thời gian thực tế.
Bất cứ trường hợp nào cũng không phải kết quả mà một developer mong muốn, và trước nhất họ nên ước lượng xem mình sẽ tốn bao nhiêu thời gian để nghiên cứu về công việc được giao. Và thật lạ là các developer đều rất giỏi trong việc ước lượng xem mình phải tốn thời gian để nghiên cứu một công việc, trong khi họ lại cực kém trong việc ước lượng thời gian để hoàn thành công việc ấy.
Vậy nên hãy bỏ thời gian để nghiên cứu về công việc mà bạn được giao trước khi bắt tay thực hiện nó.
Nhưng mà, khách hàng và sếp lại không muốn tốn khoản thời gian ấy, vậy phải làm sao? Đơn giản thôi, hãy lên kế hoạch cho một công việc lớn trước khi nó bắt đầu. Bằng cách luôn tính trước mọi việc và dành thời gian nghiên cứu chúng, bạn sẽ hình thành thói quen ước lượng chính xác hơn hẳn.

Luôn theo dõi thời gian của bạn.

Thiếu cảm nhận chính xác về thời gian cũng là một vấn đề lớn khi bạn phải ước lượng công việc. Thông thường chúng ta sẽ ước lượng công việc dựa trên ký ức về những công việc tương tự, và ký ức ấy hoàn toàn có thể bị ảnh hưởng bởi tâm trạng, hứng thú hay đơn giản là cái sự đói.
Những ký ức này có thể khiến việc ước lượng của chúng ta bị sai lệch rất nhiều, vậy nên việc theo dõi thời gian là cực kỳ quan trọng. Một khi bạn đã hình thành được cho mình thói quen theo dõi thời gian, thì cảm nhận về thời gian của bạn cũng sẽ chính xác hơn nhiều. Và sẽ chẳng thực tế chút nào nếu bạn nghĩ rằng mình có thể ước lượng được thời gian để hoàn thành những việc bạn chưa từng làm, trong khi bạn còn chẳng thể đánh giá chính xác thời gian để hoàn thành những việc thường làm.
Vậy nên, hãy bắt đầu xây dựng cho mình thói quen theo dõi thời gian đi. Có rất nhiều công cụ có thể hỗ trợ cho bạn, ví dụ như:

Đặt khung thời gian

Một khi đã đặt khung thời gian cho từng công việc, bạn sẽ đảm bảo được thời gian hoàn thành công việc ấy đúng như mình muốn.
Thoughtful man working in office, analyzing some documents
Thoughtful man working in office, analyzing some documents
Và nếu bạn nghĩ rằng đa số công việc liên quan đến phát triển phần mềm không thể bị ép vào một khung thời gian cố định thì bạn đã nhầm. Khung thời gian có tác dụng thúc đẩy con người về mặt tinh thần, khiến họ có thêm ít nhất một lý do để hoàn thành công việc trong khoảng thời gian đã đặt ra. Đồng thời, nó cũng giúp bạn nhận định được việc nào là quan trọng và cần hoàn thành trước, cũng như những việc nhỏ nhặt có thể bỏ qua mà không làm ảnh hưởng đến kết quả chung. Tất nhiên, cũng có lúc bạn sẽ phải “vượt rào”, nhưng thường thì bạn sẽ hoàn thành được công việc trong khoảng thời gian mà mình đã đặt. Và đương nhiên, đây cũng là một thói quen mà bạn nên gây dựng cho mình nếu muốn ước lượng thời gian chính xác hơn.

Xem lại ước lượng của bạn.

Bí mật này: Bạn không nhất thiết phải ước lượng đúng ngay từ ban đầu, bởi bạn hoàn toàn có thể xem lại ước lượng của mình mỗi khi công việc tiến triển.
Đúng là các sếp thường muốn nhân viên của mình đưa ra những nhận định chính xác ngay từ đầu, nhưng bạn có thể báo cáo với sếp đánh giá “chuẩn” nhất lúc bấy giờ, và chỉnh lại nó dần dần cơ mà. Chẳng ở đâu mà người ta lại xem nhẹ việc cập nhật thông tin cả.
Hãy tận dụng bốn mẹo trên để đưa ra bản đánh giá sơ bộ hợp lý nhất, và rồi cập nhật chúng mỗi khi bạn có thể.
Đó là những cách mà tôi đã áp dụng để đánh giá công việc chuẩn xác hơn. Còn bạn thì sao?
Simpleprogrammer.com

The Ultimate XP Project

  (Bài chia sẻ của tác giả  Ryo Amano ) Trong  bài viết  số này, tôi muốn viết về dự án phát triển phần mềm có áp dụng nguyên tắc phát triển...