After a while, too tired and indisposed with parts of our commnunity, I try to figure out what I’m expecting myself and others to behave, what are the characteristics that this career requires. Then I found out this how-to document. We’ve seen too many how-to on the web: how to setup Apache with SSL, how to date a girl, how to build your own business … But this is a real how-to, in a programmer’s usual style, concised, practical, and shows a right attitude towards our job. I’ve made a Vietnamese translation of this document. Let taste our career as serious and gentle as it could be.
GIỚI THIỆU
Lập trình viên là một nghề khó khăn và cao quý. Phần khó nhất có lẽ là làm việc với các đồng nghiệp và khách hàng. Viết chương trình khéo là một kỹ năng lớn, nhưng chỉ là trò trẻ so với những thứ khác mà một lập trình viên phải làm để một hệ thống phần mềm thành công. Trong tài liệu này, tôi tóm tắt ngắn gọn những điều tôi ước có ai đó chỉ cho tôi lúc tôi 21 tuổi. Những điều viết ra đây chỉ mang tính chất cá nhân, và phần nào bảo thủ. Một số vấn đề khá chung nên có thể nghe nhàm chán. Nhưng tôi hy vọng chúng sẽ có ích.
Chào mừng đến với cộng đồng !
I. CHO NGƯỜI MỚI VÀO NGHỀ
I.1. CÁC KỸ NĂNG CÁ NHÂN
I.1.1 HỌC CÁCH DEBUG
Debug là nền móng của công việc lập trình. Nghĩa đầu tiên của động từ debug là sửa lỗi, nhưng nghĩa thực sự cần hiểu là: xem xét quá trình thực thi của một chương trình. Một lập trình viên không biết debug thì xem như bị mù trong nghề của mình vậy.
Những người có cái nhìn lý tưởng về nghề lập trình thường xem lập trình bao gồm thiết kế, phân tích, các lý thuyết về độ phức tạp, vân vân… Nhưng thực sự những điều đó không phảI là những nền móng của nghề này. Chúng ta không sống trong thế giới lý tưởng và ngay cả khi bạn cảm thấy mình là lý tưởng và hoàn hảo thì những điều xung quanh bạn cũng không phải vậy. Phần lớn các mã nguồn đều không hoàn hảo, và tài liệu của chúng càng như vậy. Thiếu cái nhìn vào bên trong quá trình thực thi của một đoạn mã đến lúc sẽ gây rắc rối cho bạn.
Nhiều gói phần mềm được mua từ các hãng thứ ba, và bạn không có cơ hội xem mã nguồn của chúng. Nhiều đoạn mã nguồn thực thi không đúng như tài liệu kỹ thuật của chúng. Nhiều khi bạn viết một đoạn code có lỗi mà vẫn không hiểu vì sao nó gây lỗi (điều này thường là vì bạn đã ngầm định một số điều kiện nào đó, nhưng thực tế những điều đó không xảy ra). Đôi khi đọc kỹ càng từng dòng code một sẽ tìm được lỗi, nhưng nhiều khi không thể phát hiện được chúng bằng cách này. Khi đó thì phải debug thôi.
Những cách debug thông thường:
- Dùng một công cụ debug
- In ra từng dòng một
- Log
Các công cụ debug rất tuyệt nếu chúng ổn định. Công cụ debug của một ngôn ngữ thường phát triển chậm hơn ngôn ngữ đó, nhiều khi bạn không thể tìm được một công cụ debug tốt. Hơn nữa, trong quá trình debug, các công cụ này có thể đã thay đổi quá trình thực thi của chương trình. Nên các công cụ sau là quan trọng hơn.
Nhiều người mới vào nghề thường sợ sửa code khi debug. Nhưng debug cũng như phẫu thuật vậy, bạn phải loay hoay trong đống code với nhiều thử nghiệm khác nhau. Nếu bạn sợ việc này thì tốt nhất hãy tìm sự giúp đỡ ở một người có nhiều kinh nghiệm hơn bạn.
I.1.2 DEBUG BẰNG CÁCH CHIA NHỎ KHÔNG GIAN BÀI TOÁN
Đầu tiên debug là một công việc thú vị. Nó giống như bạn đi thám hiểm, một không gian bạn nghĩ nó phải như thế này nhưng thực sự nó không giống như vậy. Debug đòi hỏi tính sáng tạo. Và nếu có chìa khóa nào cần biết để debug thì đó là dùng kỹ thuật chia để trị (devide to conquer).
Ví dụ như một đoạn code làm 10 công việc. Bạn viết xong, thế rồi nó crash, mà bạn không viết nó để nó crash. Thế là bạn phải debug, nhìn trên màn hình output, bạn thấy 7 việc đầu tiên vẫn bình thường, như vậy nghi ngờ của bạn là nó có thể crash ở việc #7, #8 hay #9. Như vậy không gian tìm kiếm đã thu hẹp lại. Và luôn có trong đầu một vùng để nghi ngờ như vậy sẽ giúp bạn tìm ra chỗ sai. Rất nhiều khi, một nhóm lập trình viên tập trung cho một lỗi được phát hiện, dưới sức ép của deadline đang đến gần, nhưng dưới sức ép đấy, không ai giữ được sự tập trung trong không gian tìm kiếm của mình, hoặc không biết cách chia xẻ không gian đấy với nhau.
Nó cũng giống như việc thiết kế thuật toán: nếu bạn biết cách chia nhỏ không gian tìm kiếm thì thực sự bạn sẽ không phải chia nhỏ nó quá nhiều lần. Và luôn giữ sự tập trung vào một miền không gian nào đó. Nhưng đâu là miền không gian bạn cần phải tập trung? Đây là vấn đề của kinh nghiệm và sự sáng tạo.
Với người mới vào nghề thì dường như lỗi có thể ở mọi nơi: bạn không có được cái nhìn về các phương diện (dimension) khác nhau của chương trình: các dòng mã, cấu trúc dữ liệu, quản lý bộ nhớ, tương tác với các thư viện bên ngoài… Với người có kinh nghiệm, chính những chiều khác nhau này tạo nên cái mô hình không hoàn hảo nhưng lại có ích để biết được chỗ sai có thể nằm ở đâu. Và nắm bắt được mô hình này sẽ giúp cho việc định hướng trong không gian tìm kiếm.
Không phải khi nào bạn cũng có thể thu hẹp được không gian tìm kiếm đến một dòng mã code nào đó, và nếu như thế thì bạn may mắn. Thường thì lỗi không nằm tại một dòng mã, hay một đoạn mã, mà có thể có tình huống như: “trong đồ thị đó (cấu trúc dữ liệu) có con trỏ nào trỏ sai không?”, và bạn cần viết một chương trình khác để kiểm tra điều này.
I.1.3 SỬA LỖI NHƯ THẾ NÀO
Khi bạn đã tìm ra lỗi, tiếp theo là việc sửa nó. Hãy làm theo cách nào đòi hỏi ít thay đổi nhất. Cũng có khi bạn phát hiện ra nhiều thứ khác cần cải tiến, nhưng hãy chỉ làm một việc tại một thời điểm thôi. Nhiều khi có nhiều lỗi trông giống như nhau, hãy định nghĩa từng lỗi riêng biệt và sửa từng cái một. Đôi khi bạn không rõ đoạn mã đó làm gì hay ý tác giả ban đầu như thế nào. Khi đó cần phải thử nghiệm và phán đoán để quyết định ý nghĩa của đoạn mã đó. Đây là một kỹ năng không phải của người mới vào nghề, và thường là khó hơn cả việc viết chúng lúc ban đầu. Nhưng thế giới thực là như vậy, bạn phải sửa nó vì bạn không thể tạo ra nó.
I.1.4 DÙNG LOG NHƯ THẾ NÀO
Log khác với việc in ra từng kết quả một tạm thời. Người mới vào nghề cần log vì kinh nghiệm của họ hạn chế. Kiến trúc sư hệ thống cần log vì hệ thống thực phức tạp. Tốt nhất là bạn có thể cấu hình mức độ ít nhiều thông tin trong log-file ngay khi chương trình đang chạy. Log có những lợi điểm sau:
- Log lưu thông tin về các lỗi khó lập lại (reproduce), nhất là những lỗi chỉ xuất hiện trong hệ thống thực mà không xuất hiện ở các hệ thống test.
- Log có thể cho các con số thống kê về hiện suất của hệ thống (thời gian thực thi các tác vụ…)
- Khi có thể cấu hình được, log cho phép bạn sửa những lỗi mới mà không phải sửa hay xem xét lại nhiều các đoạn code chỉ để đối phó với một dạng lỗi ấy.
Quá nhiều thông tin trong log-file sẽ gây rối việc tìm kiếm, quá ít sẽ không có điều bạn cần tìm. Vậy nên cần phải tạo log-file sao cho có thể cấu hình tính nhiều/ít thông tin này được. Mỗi record trong log-file thường có: vị trí trong mã nguồn, thread nào đang thực thi, thời gian thực thi, giá trị của các biến, lượng bộ nhớ còn trống… Những đoạn mã ghi ra log-file có thể ở khắp nơi, cần nhất là ở những chức năng quan trọng và các đoạn mã nguy hiểm (có khả năng gây nhiều lỗi). Mỗi đoạn mã ghi log-file cần được gán một mức độ quan trọng, và bạn điều chỉnh cái gì cần ghi ra bằng cách thay đổi mức độ quan trọng này. Log được thiết kế cho các vấn đề mà bạn lường trước, và luôn lường trước vấn đề hiệu suất của hệ thống.
I.1.5 HIỂU VẤN ĐỀ HIỆU SUẤT CỦA HỆ THỐNG NHƯ THẾ NÀO
Vấn đề hiệu suất của hệ thống cũng có cùng lý do như việc debug. Ngay cả khi bạn hiểu một đoạn code đủ rõ, thì không có nghĩa là nó sẽ chạy tốt, đôi khi nó gọi hàm từ một thư viện bên ngoài nào đó, mà bạn thì không kiểm soát được thư viện này. Thực tế thì vấn đề hiệu suất cũng không khác và không dễ hơn việc debug. Nếu hệ thống quá chậm, bạn cần xác định do đâu mà nó chậm, và do đó cần xây dựng một mô hình về vấn đề này. Có câu châm ngôn nổi tiếng là: 90% thời gian được chi trên 10% lượng mã nguồn. Theo kinh nghiệm của tôi, phần lớn thời gian chậm là chi vào các thao tác nhập xuất (I/O) theo cách này hay cách khác.
Có nhiều lý do khác ảnh hưởng đến hiệu suất hệ thống. Nhưng đầu tiên là hãy đo thời gian thực thi của các đoạn mã. Log lại điều này rất quan trọng vì đôi khi chúng cho ta biết tình huống mà các kỹ thuật profiling khác không phát hiện được. Đôi khi một hàm thực thi chậm hơn vài giây so với khi bạn đã sửa chúng, nhưng thực sự thì vẫn tốt hơn vì có thể các chi phí khác (bộ nhớ, băng thông, cơ sở dữ liệu…) sẽ đắt hơn khi đưa hệ thống vào chạy thực.
Các tài nguyên chia xẻ không được đồng bộ hóa đúng có thể dẫn đến deadlock, hay starvation. Nếu có thể hãy lường trước các vấn đề này từ lúc bắt đầu dự án.
I.1.6 SỬA VẤN ĐỀ HIỆU SUẤT HỆ THỐNG NHƯ THẾ NÀO
Chọn các giải pháp đơn giản và nhanh chóng dưới sức ép của thời gian là một việc làm khôn ngoan. Nhưng hiệu suất là một phần của sản phẩm, và do đó phải cân nhắc vấn đề này kỹ lưỡng. Chìa khóa là: biết các cổ chai (bottleneck) của hệ thống nằm ở đâu, hay chỗ nào tiêu thụ nhiều tài nguyên nhất. Việc tối ưu một hàm chạy nhanh hơn 1% thực sự chẳng có mấy ý nghĩa, và bạn chỉ nên làm điều này khi bạn nghĩ bạn có thể làm cho hệ thống chạy nhanh gấp đôi so với trước. Cân nhắc các chi phí testing và QA đối với những thay đổi này. Ngay cả khi bạn đã làm cho hệ thống chạy nhanh gấp đôi, hãy phân tích lại để tìm ra những bottleneck còn lại, để có thể làm cho hệ thống chạy nhanh thêm gấp đôi nữa.
Thường thì việc tìm các bottleneck sẽ giống như việc đếm bò bằng cách đếm số chân rồi chia cho 4 thay vì đơn giản hơn bạn có thể đếm số đầu. Ví dụ như: không làm chỉ mục cho một trường sử dụng rất nhiều lần trong cơ sở dữ liệu có thể làm cơ sở dữ liệu đó chạy chậm hơn 20 lần. Những cải tiến dạng này thường được gọi là low-hanging fruit, có thể dễ dàng hái chúng để có được lợi ích. Khi những quả ở thấp đã hết, bạn sẽ phải leo lên cao hơn. Bạn có thể cần cù làm những cải tiến nhỏ trên cao này, hoặc bạn có thể thiết kế lại toàn bộ hệ thống. Đây là cơ hội để chứng tỏ bạn là một lập trình viên thực thụ, nhưng chỉ làm thế khi đề nghị của bạn có thể làm cho tình huống 5 hay 10 lần tốt hơn.
I.1.7 TỐI ƯU CÁC VÒNG LẶP NHƯ THẾ NÀO
Đôi khi bạn gặp một vòng lặp tạo nên bottleneck của hệ thống. Trước khi tìm cách cải tiến vòng lặp cho nó nhanh hơn một chút, hãy cân nhắc xem có cần đến vòng lặp này không đã: có thuật toán nào khác không cần đến lặp, hay thực sự thông tin đã được tính toán đâu đó rồi? Nếu không làm được vậy thì việc tối ưu hóa vòng lặp cần đến hiểu biết về các chi phí của từng lệnh cụ thể, một số gợi ý:
- Tránh các phép tính dấu chấm động (floating point operation).
- Không cấp phát bộ nhớ một cách không cần thiết.
- Ghép các hằng số lại với nhau.
- Đem các thao tác I/O vào một bộ đệm (buffer)
- Tránh các phép chia
- Tránh ép kiểu
- Dùng con trỏ thay vì tính toán lại chỉ mục
Chi phí của những việc cụ thể này còn phụ thuộc hệ thống. Một số trình biên dịch và phần cứng làm những việc tối ưu này cho bạn. Nhưng dù sao mã hiệu quả vẫn tốt hơn.
I.1.8 XỬ LÝ CÁC THAO TÁC NHẬP XUẤT (I/O) NHƯ THẾ NÀO
Thường thì CPU nhanh hơn các thiết bị ngoại vi như đĩa, mạng, database… Nên việc tối ưu hệ thống thường không phải là việc tối ưu một vài vòng lặp, mà tối ưu các thao tác nhập xuất. Có hai kỹ thuật cơ bản:
- Caching: tránh các thao tác I/O không cần thiết bằng cách lưu các giá trị thường truy cập ở một nơi nào đó. Có điều nguy hiểm với việc caching là các bản lưu này đôi khi không được cập nhật với bản gốc.
- Representation: tìm cách biểu diễn data hiệu quả hơn. Nhưng cũng cần xem xét đến các yêu cầu khác: rõ ràng với người đọc, có thể dễ dàng chuyển đổi qua các dạng khác… Kinh nghiệm cho thấy việc biểu diễn có thể được tối ưu 2 hay 3 lần so với phiên bản biểu diễn đầu tiên. Kỹ thuật: biểu diễn nhị phân đi kèm với một từ điển các ký hiệu (để không phải mã hóa các ký hiệu quá dài), các thuật toán nén như mã hóa Huffman…
Một kỹ thuật thứ ba có thể được dùng: vị trí giải quyết vấn đề, nếu bạn cần một tính toán đơn giản trên một số data từ database (như một phép cộng), tốt hơn hãy nhờ đến database làm điều đó.
I.1.9 QUẢN LÝ BỘ NHỚ NHƯ THẾ NÀO
Bộ nhớ là tài nguyên quý giá không thể để cạn kiệt. Bạn có thể lơ vấn đề này một lúc, nhưng cuối cùng cũng phải nghĩ đến việc quản lý nó. Tùy vào hệ thống, có hệ thống bạn cần hủy bộ nhớ đã cấp phát một cách tường minh. Có hệ thống có thiết kế một “bộ phận thu nhặt rác” (garbage collector – GC), bộ phận này sẽ tự động giải phóng các phần bộ nhớ không cần đến mà không cần đến thao tác nào từ lập trình viên. Các GC rất có ích, dùng chúng bất cứ lúc nào có thể.
Tuy vậy, bạn có thễ vẫn để rác trong bộ nhớ. Một lỗi cổ điển như: dùng bảng băm và quên giải phóng các tham chiếu trong bảng băm đó, vùng nhớ vẫn còn tham chiếu đến mặc dù đã hết sử dụng. Vấn đề này gọi là rò rỉ bộ nhớ (memory leak). Bạn phải để ý vấn đề này từ sớm, một số hệ thống không cho thấy vấn đề bộ nhớ nào lúc test, nhưng sẽ nãy sinh vấn đề trong môi trường sử dụng thật.
Nếu bạn có thể định nghĩa một chặn trên (upper bound) cho các đối tượng (cùng kích thước) cần cấp phát, bạn nên cấp phát cả một vùng đệm (buffer) một lúc để lưu chúng. Nếu có thể, hãy cấp phát và giải phóng các đối tượng bên trong vùng đệm này theo kiểu xoay vòng (ring-buffer). Điều này thường nhanh hơn là cấp phát trong heap.
Đôi khi bạn cần phải giải phóng tường minh một đối tượng (để cấp phát lại chẳng hạn) và không thể nhờ đến GC. Hãy cẩn thận, hãy chắc chắn rằng tương ứng với một lệnh cấp phát là một lệnh giải phóng. Điều này thường rất khó, thường thì lập trình viên sử dụng một dạng GC đơn giản nào đó (như đếm tham chiếu – reference counting) để làm việc này.
I.1.10 ĐỐI PHÓ VỚI CÁC LỖI BẤT CHỢT NHƯ THẾ NÀO
Có những lỗi thực sự là ác mộng, chúng lúc nắng lúc mưa, ít xảy ra đến độ dường như không nắm bắt được, và không thể debug vì không biết chúng ở đâu. Dường như chúng chỉ xảy ra sau 8 giờ làm việc, khi bạn bắt đầu nghi ngờ chúng có tồn tại hay không. Điều làm cho chúng khó nhận ra là bạn không biết chúng xảy ra trong điều kiện nào: tìm cách ghi nhận tình huống xảy ra, hoặc cũng có thể lỗi chỉ xảy ra với một dạng đặc biệt nào đó của dữ liệu, ví dụ như “nó chỉ xảy ra khi có từ wyoming trong dữ liệu nhập vào”. Sau hết, nếu không phải là các nguyên nhân này, hãy nghĩ đến lỗi đồng bộ hóa tiến trình.
Nếu không thể lặp lại lỗi (reproduce), hãy tìm cách bẫy nó. Bố trí lại hệ thống log theo các hướng bạn phán đoán. Đôi khi điều này cũng không đem lại kết quả gì ngoài việc bạn biết cách cải tiến hệ thống log tốt hơn, và điều đó có thể giúp bạn bẫy được những lỗi này về sau.
Lỗi ngu ngốc nhất tôi từng gặp phải là trong một chương trình có nhiều tiến trình, tôi đã kiểm tra kỹ lưỡng việc đồng bộ hóa các tiến trình nhưng quên đồng bộ hóa GC. Hệ thống kết thúc tốt đẹp mọi tác vụ trước khi lỗi xảy ra, và điều ngu ngốc hơn nữa là tôi lúc đó đã bắt đầu nghi ngờ phần cứng có vấn đề trước khi biết được lỗi là do phần tôi.
I.1.11 HỌC CÁC KỸ NĂNG THIẾT KẾ NHƯ THẾ NÀO
Để học cách thiết kế, hãy quan sát các hành động của người làm điều đó. Sau đó xem xét các gói phần mềm viết tốt, và có thể đọc một vài cuốn sách mới nhất về vấn đề này. Sau đó thì hãy tự bạn làm, khởi đầu với các dự án nhỏ. Sau khi thành công hay thất bại, tìm cách hiểu xem bạn đã ly khai khỏi các ý tưởng sơ khởi như thế nào. Sau đó làm các dự án lớn hơn, với nhiều người thiết kế hơn. Thiết kế là kỹ năng đánh giá chỉ có được sau nhiều năm. Một lập trình viên có thể học các điều cơ sở chỉ sau vài tháng và cứ thế tiến bộ. Nhưng thiết kế thì khác, nó là vấn đề nghệ thuật hơn là khoa học, và những người viết sách về vấn đề này thường cố trình bày như chúng rất là khoa học, nhưng cũng đừng tin một cách giáo điều, võ đoán theo những sách đấy.
I.1.12 TIẾN HÀNH THỬ NGHIỆM NHƯ THẾ NÀO
Edsger Dijkstra đã hùng hồn giải thích rằng khoa học máy tính (CS) không phải là một khoa học thực nghiệm và không phụ thuộc vào các máy tính điện tử, ông ta nói những điều này vào những năm 1960:
Tội ác đã hoàn tất! Khoa học này đã được gọi bằng cái tên: Khoa học Máy tính, theo cùng một cách như bạn gọi Giải phẫu học là Khoa học Con dao, và điều đó khiến cho mọi người nghĩ rằng khoa học máy tính là về các máy móc cũng như các thiết bị ngoại vi của chúng. Do đó lập trình cũng không thuộc về khoa học thực nghiệm.
Nhưng phần lớn lập trình viên không có được cái xa xỉ mà Dijkstra nói đến. Chúng ta làm việc trong một lĩnh vực cũng giống như một số nhà vật lý học (thực hành) làm vậy. Nếu như trong vòng 30 năm nữa mà lập trình không còn cần đến thử nghiệm nào thì đó là một thành tựu lớn lao của Khoa học Máy tính. Những dạng thử nghiệm cần tiến hành bao gồm:
- Test các hệ thống với các ví dụ nhỏ để kiểm chứng nó có chạy đúng như tài liệu nói không, hay để hiểu các tác vụ của chúng khi không có tài liệu.
- Test các thay đổi để xem chúng có thực sự sửa được lỗi không.
- Đo hiệu suất của hệ thống dưới các điều kiện khác nhau vì không biết các đặc điểm về hiệu suất này.
- Kiểm tra tính toàn vẹn của dữ liệu.
- Thu thập số liệu thống kê để tìm giải pháp cho các vấn đề khó.
Tôi có hai lời khuyên cho việc này:
- Hãy làm cho các giả thiết của bạn rõ ràng, nếu có thể, viết chúng ra giấy.
- Bạn thường tiến hành các thí nghiệm dựa trên kết quả của thí nghiệm trước. Do đó hãy thiết kế các thí nghiệm (các bài test – ND) làm sao để nó có thể cung cấp nhiều thông tin nhất. Và cân bằng với yêu cầu đơn giản của thí nghiệm là một kinh nghiệm bạn chỉ có được với thời gian.
I.2. CÁC KỸ NĂNG NHÓM
I.2.1 TẠI SAO ƯỚC LƯỢNG QUAN TRỌNG
Một dự án phần mềm không chỉ bao gồm việc coding mà còn thiết kế, làm tài liệu, testing, và các công việc kinh doanh… Nếu không đoán trước được tiến độ phát triển, sẽ không thể có kế hoạch hiệu quả được.
Ước lượng tốt giúp dự đoán tốt. Những nhà quản lý thích điều đó, và họ cũng nên làm điều đó. Thực tế là, trên cả phương diện lý thuyết lẫn thực hành, không thể dự đoán chính xác thời gian cũng như chí phí để làm tất cả những công việc đó. Chúng ta được đòi hỏi làm những điều có thể làm được, do đó thật không hay khi thú nhận không thể làm được chúng. Có rất nhiều chuyện hiểu lầm trong việc ước lượng, ví như thường thì người ta, thật ngạc nhiên, có xu hướng hiểu câu sau một cách khôn ngoan:
Tôi ước lượng rằng, nếu tôi thật sự hiểu vấn đề, thì khoảng 50% chắc chắn là chúng ta sẽ xong việc đó trong vòng 5 tuần (nếu không ai quấy rầy chúng ta suốt thời gian đó).
Như sau:
Tôi hứa sẽ làm xong tất cả trong vòng 5 tuần kể từ bây giờ.
Những kiểu diễn dịch này đòi hỏi bạn phải thảo luận rõ ràng tất cả những ước lượng đó nghĩa là gì, với ông chủ cũng như với khách hàng, cứ như họ là những người ngu ngốc. Và lặp đi lặp lại điều đó cho dù họ có tỏ ra như thế nào.
I.2.2 ƯỚC LƯỢNG NHƯ THẾ NÀO
Ước lượng cần phải được thực tập, và nó cũng tốn nhiều công sức. Và nó tố nhiều công sức đến nỗi chúng ta cần ước lượng thời gian chúng ta cần để ước lượng thời gian làm công việc thực sự, nhất là khi bạn được yêu cầu làm một khối lượng công việc lớn. Nếu phải ước lượng một điều gì lớn, điều lương thiện nhất bạn cần làm là trì hoãn. Sẽ có nhiều lập trình viên khác thông cảm cho điều này. Dĩ nhiên sẽ có người không hài lòng vì điều đó, nhưng một ước lượng tức thì có thể sẽ không chính xác. Trong lúc trì hoãn, bạn có thể tìm cách làm hoặc phác thảo việc cần làm. Và nếu bầu không khí tại nơi làm việc cho phép, đây là cách tốt nhất để ước lượng, hơn nữa, nó cũng đóng góp vào tiến độ thực sự.
Nếu không thể trì hoãn, bạn cần trước nhất phát biểu ước đoán của mình thật rõ ràng. Viết lại phần ước đoán của mình ở cuối phần văn bản viết, và trong phần kế hoạch viết, chia nhỏ các công việc sao cho các công việc con chỉ cần tối đa 1 ngày để hoàn thành. Điều quan trọng nhất là không để sót điều gì, ví dụ như: phần viết tài liệu, phần testing, thời gian lên kế hoạch, thời gian tương tác với các nhóm khác, và cả thời gian nghĩ. Nếu mỗi ngày, bạn cảm thấy cần nhiều thời gian hơn vì phải làm việc với những kẻ ngu đần thì gộp cả thời gian đó vào trong kế hoạch. Những điều này cho phép ông chủ biết bạn ít nhất đang làm gì, vì thực sự bạn sẽ cần nhiều thời gian hơn. Tôi biết có những kỹ sư lập trình tốt, những người ngầm tính thêm một khoảng thời gian vào thời gian đã ước lượng. Nhưng tôi khuyên bạn không nên làm vậy, vì sự tin tưởng ở nơi bạn có thể bị giảm sút. Ví dụ một lập trình viên ước lượng 3 ngày cho một công việc anh ta có thể làm trong 1 ngày, và 2 ngày dư ra, anh ta có thể chỉ ngồi viết tài liệu hay làm việc khác. Nếu việc ấy bị phát hiện, sẽ có ý kiến cho rằng bạn lười nhác hay ước lượng quá. Tốt hơn là bạn cho phép Người ta nhìn rõ vào tiến trình bạn làm việc.
Thay vì như vậy, bạn có thể tính thêm một khoảng thời gian một cách công khai. Ví dụ như công việc mất một ngày, nhưng cũng có thể 10 ngày nếu cách tiếp cận không đúng, thì hãy ghi điều đó vào ước lượng của bạn, hay ít nhất tính trung bình trên các ước lượng khác của bạn. Bất kỳ yếu tố rủi ro nào cũng cần được xác định và đưa vào lịch làm việc. Nếu công ty có những khóa học bắt buộc thì cũng phải thêm thời gian đó vào. Dĩ nhiên vẫn sẽ còn lại những thứ không thể xác định, hay nghĩa là không thể được xác định bởi một cá nhân. Tạo thêm một mục cho điều này và làm cách nào đó để sếp của bạn biết, và làm sao cho sếp bạn phải biết, vì rất dễ sau đó ước lượng sẽ trở thành kế hoạch. Trong một nhóm, bạn cũng sẽ cần những người làm các công việc cụ thể có ước lượng của mình, và bạn cũng sẽ cần sự nhất trí của các nhóm khác. Mọi người rất khác nhau về kỹ năng, kinh nghiệm, mức độ sẵn sàng, tính tự tin… Tai họa đến khi một lập trình viên giỏi ước lượng theo khả năng của anh ta sau đó giao công việc cho một lập trình viên kém. Việc có được sự đồng ý của mỗi thành viên trong nhóm trên mỗi dòng của bản ước lượng sẽ giúp cả nhóm hiểu, đó cũng là cơ hội để có thể có được sự phân chia tốt nhất.
Nếu có những rủi ro chưa thể lượng giá, thì bạn phải gào lên làm sao cho giám đốc của bạn không ủy thác điều gì trong nhiệm vụ đó và sẽ không ngạc nhiên, bối rối khi nó xảy ra. May thay, thường trong những trường hợp đó, tất cả những gì có thể làm sẽ được làm để giảm thiểu rủi ro. Nếu bạn có thể thuyết phục công ty bạn dùng Extreme Programming, thì bạn sẽ chỉ cần ước lượng các việc tương đối bình thường, và sẽ có được hiệu suất tốt hơn.
I.2.3 TÌM THÔNG TIN NHƯ THẾ NÀO
Bản chất của vấn đề bạn cần biết xác định cách bạn sẽ tìm chúng. Nếu bạn cần thông tin về các đối tượng cụ thể, dễ xác định (như bản vá sau cùng của một sản phẩm), thì chỉ cần hỏi ai đó, tìm trên internet, hay gởi bài trong các diễn đàn thảo luận. Nếu bạn có được kiến thức chung về những thứ đã có chủ đề, thì hãy tìm nó ở thư viện. Nếu bạn cần biết cách làm một điều gì đó khó, thì thường cần đọc 2, 3 cuốn sách về chủ đề đó, những thứ dễ đã có trên internet. Nhưng bạn rất dễ tốn nhiều thời gian chỉ để tìm kiếm, và sắp xếp những thứ kiếm được, và tìm hiểu về nguồn gốc của chúng, hơn là thực sự nắm bắt những điểm quan trọng trong đó.
Nếu bạn cần thông tin về những thứ mà bạn không nghĩ sẽ có ai khác biết, đầu tiên vẫn cần tìm trên internet, ở thư viện, và nếu đều không có kết quả thì phải thăm dò vấn đề đó bằng những thí nghiệm. Nếu bạn cần những đánh giá chuyên môn, tốt nhất là bạn có được những chuyên gia.
Nếu bạn cần quyết định những chuyện cá nhân chỉ có bạn quyết định được, ví như có nên làm công ty riêng hay không, thì hãy viết một danh sách những điều nên, và không nên. Nếu điều này cũng không giúp gì, thì hãy xem xét việc tin vào chiêm tinh bói toán. Và nếu bạn đã hỏi ý kiến tất cả các thiên thần, đã suy xét tất cả hệ quả, những điều thuận lợi và khó khăn mà vẫn chưa quyết định được, thì hãy bảo đầu bạn câm mồm lại và nghe theo con tim bạn. Tất cả các dạng chiêm tinh bói toán đều có tác dụng xác định các ước mơ nửa thức nửa ngủ của bạn, vì mỗi ước ao đại diện cho một mẫu tình cờ và mơ hồ mà tiềm thức của bạn sẽ tự gán cho nó những ý nghĩa.
I.2.4 DÙNG NGƯỜI KHÁC NHƯ NGUỒN THÔNG TIN NHƯ THẾ NÀO
Hãy tôn trọng thời gian của người khác và tìm cách cân bằng nó với của bạn. Hỏi người khác một câu thì sẽ được nhiều hơn là một câu trả lời. Bạn sẽ biết về người khác theo một cách nào đó, và thường thì điều đó quan trọng hơn câu hỏi. Nhưng thường thì những giá trí này càng ít đi nếu bạn càng làm nhiều nó. Thời gian bạn cần nói chuyện với các đồng nghiệp tùy thuộc vào vai trò của họ (hơn là vị trí của họ). Bạn nên nói chuyện với những người cao hơn bạn, ít nhất là một lần một tháng. Quy luật rất đơn giản: mọi người có lợi khi nói chuyện với nhau, nhưng nói càng nhiều thì lợi càng ít, do đó cần phải cân đối với chi phí (là thời gian bạn trò chuyện). Nếu nói chuyện với ai đó có thể tiết kiệm thời gian của bạn thì bạn nên trò chuyện với người đó, trừ khi bạn nghĩ là thời gian của người đó quý giá hơn của bạn.
I.2.5 LÀM TÀI LIỆU NHƯ THẾ NÀO CHO KHÔN NGOAN
Cuộc đời quá ngắn để viết những thứ tào lao không ai đọc. Nên chỉ cần một it tài liệu tốt vẫn tốt hơn. Những người làm quản lý thường không hiểu điều này, vì những tài liệu tệ đã làm họ quá chán với những thứ lập trình viên viết ra. Nếu ai đó khăng khăng đòi bạn viết những thứ tài liệu tào lao, giả tạo, thì cứ nói Có và sau đó yên lặng tìm một công việc khác tốt hơn. Thực tế thì thật là lạnh lẽo: làm tài liệu, cũng như testing, hay coding thường cần nhiều thời gian hơn dự tính.
Để viết tài liệu tốt, dĩ nhiên đầu tiên là viết tốt. Nhưng nếu bạn viết kém thì có một quy luật vàng: làm cho người khác đúng như cách người ấy sẽ làm với bạn. Dành thời gian suy nghĩ về ai sẽ là người đọc, họ cần biết điều gì từ tài liệu, và bạn có thể diễn đạt điều đó như thế nào. Nếu bạn làm được như vậy, thì chắc chắn bạn đã hơn một người viết tài liệu trung bình, và dĩ nhiên là một lập trình viên tốt.
Những lập trình viên tốt nhất tôi được biết có một đức tính chung: viết giải thích ngay trong code và chỉ viết tài liệu những nơi mà cần thiết. Như vậy có hai cái lợi: một là ai cần hiểu hệ thống sẽ có cơ hội đọc code, hai là như vậy thì code và tài liệu sẽ không có chỗ mâu thuẫn nhau. Cùng lắm thì code rối hoặc sai cũng chẳng sao, nhưng tài liệu mà sai thì nhiều lần tệ hơn. Nhưng giải thích trong code là sao:
- Viết những mã mà biết chắc rằng có ai đó sẽ đọc nó.
- Dùng luật vàng đã nói trên.
- Chọn giải pháp dễ hiểu nhất, ngay cả khi bạn có một giải pháp nhanh hơn.
- Bỏ những cải tiến nhỏ làm rối code.
- Hãy nghĩ một chút về người đọc, và bỏ thêm thời gian làm những gì bạn viết dễ đọc hơn, và
- Đừng bao giờ dùng những tên hàm như: foo, bar hay doIt.
I.2.6 LÀM VIỆC VỚI CODE TỆ NHƯ THẾ NÀO
Bạn sẽ rất thường gặp code ai đó viết rất tệ. Đừng nghĩ nhiều về điều đó, vì đôi khi bạn cũng sẽ như vậy, họ có thể đã làm việc rất nhanh để kịp tiến độ. Dù sao để làm việc với những code không rõ ràng, bạn cũng phải hiểu chúng, và điều đó tốn thời gian. Bạn sẽ phải đọc code, và đây là lúc để làm tài liệu. Có thể chỉ là để làm cho chính bạn thôi, nhưng điều này sẽ giúp bạn hiểu các khía cạnh khác của vấn đề, và tài liệu viết được sẽ đến lúc có ích. Bạn cũng có thể nghĩ đến việc viết lại toàn bộ hay một phần code, nhưng cần cân nhắc khi nào điều này.
Điều quan trọng cần nhớ là abstraction và encapsulation, là hai công cụ tốt nhất của lập trình viên, và cũng là cách trị code tệ hại. Vì bạn không thể thiết kế lại một khối code lớn, nhưng bạn có thể gói chúng vào một lớp trừu tượng nào đó và như vậy bạn cũng có thể có được một thiết kế chút ít tốt hơn mà không phải làm việc lại với toàn bộ code, hơn nữa, có thể cô lập một số code thực sự tệ để thiết kế lại riêng sau.
I.2.7 DÙNG SOURCE CODE CONTROL – SCC NHƯ THẾ NÀO
Các hệ thống kiểm soát phiên bản code là không thể thiếu được, ngay cả khi bạn làm việc đơn độc: nó theo dõi tất cả các thay đổi, không có sửa chữa nào mất đi, những code debug và code “vất đi” vẫn có thể được viết thoải mái và không ảnh hưởng đến nhánh code chính thức. Có thể hình dung một hệ thống như thế này một quần thể có tiến hóa, có nhiều thay đổi nhỏ và liên tục. Một lỗi lầm liên quan đến kiểm soát code làm ảnh hưởng đến toàn nhóm là một điều cấm kỵ.
I.2.8 UNIT-TEST NHƯ THẾ NÀO
Unit test là một phần của việc coding. Cũng như một phần của việc thiết kế code là thiết kế công việc test. Bạn nên viết xuống một kế hoạch test, ngay cả khi chỉ có một dòng. Đôi khi unit-test rất đơn giản: “cái nút nhìn có đẹp không?”, đôi khi lại là phức tạp: “thuật toán so sánh mẫu có trả về những phép so sánh đúng không?”
Dùng assertion và test driver bất kỳ lúc nào có thể. Điều này không chỉ bắt các lỗi sớm, mà còn ngăn chặn các “lỗi bí ẩn” về sau. Các lập trình viên của Extreme Programming có những bài viết rất hay về unit-test.
I.2.9 HÃY NGHỈ KHI RỐI TRÍ
Khi bạn rối trí, tốt nhất hãy nghỉ một lát. Tôi thường trầm tư khoảng 15 phút khi rối trí và thường thì vấn đề được giải quyết sau đó. Nhưng toàn diện hơn cả là một giấc ngủ đủ. Hay bạn cũng có thể chuyển qua một công việc hay hoạt động khác.
I.2.10 HÃY BIẾT KHI NÀO NÊN VỀ NHÀ
Lập trình là một hoạt động, và là một văn hóa. Nhưng không may, văn hóa đó không tôn trọng sức khỏe tinh thần và thể xác lắm. Lập trình viên thường bị làm việc quá mức, 60 giờ một tuần là phổ biến. Đây là vấn đề nghiêm trọng của lập trình viên, người có trách nhiệm không chỉ với anh ta mà với cả nhóm. Bạn cần biết khi nào phải về nhà, và đôi khi cũng nên đề nghị người khác về nhà. 60 giờ một tuần là quá mức với tôi, và tôi chỉ có thể chịu được như vậy trong khoảng 1 tuần. Thực tế đáng buồn là lập trình viên thường bị đòi hỏi làm việc nhiều chỉ để trình diễn cho ai khác xem, như là giám đốc muốn chứng tỏ cho ủy viên hội đồng quản trị xem. Mà lập trình viên thì thường không giỏi nói Không. Có bốn cách chống lại điều này:
- Giao tiếp với mọi người trong công ty để không ai có thể lợi dụng một cơ hội như vậy.
- Học cách ước lượng và lập lịch có phòng bị rõ ràng và cho mọi người xem điều đó.
- Học cách nói Không, và cả nhóm nói Không, và
- Cứ về nếu bạn phải thế
Lập trình viên thương thích làm nhiều việc, nhưng có một sức ỳ tâm lý trong lúc khởi động lúc giải quyết một vấn đề, và lúc bị chìm sâu vào vấn đề đó. Đa số các lập trình viên cảm thấy họ cần có một khoảng thời gian dài, không ngắt quảng để khởi động và tập trung. Nhưng ai cũng phải ngủ, và còn nhiều việc khác. Mỗi người cần tìm cách thỏa mãn cả nhịp điệu sinh học và nhịp điệu làm việc của mình, và tạo được giai đoạn làm việc hiệu quả.
Khi tôi có con, tôi đã thử ở với con về đêm, vì nhịp điệu làm việc hiệu quả của tôi là một ngày rất dài, và ngủ tại ngay văn phòng, chiều hôm sau thì về nhà sớm với các con trước khi chúng đi ngủ. Thực tôi cũng không thoải mái khi phải như vậy, nhưng mà đó là cách thỏa hiệp tốt nhất của tôi. Bạn cần phải về nhà nếu bạn đang mang bệnh có thể lây. Về nhà ngay khi bạn có ý nghĩ tự sát. Bạn cũng nên về nhà khi thoáng có ý nghĩ phải giết ai đó trong đầu. Bạn cũng nên ép ai đó về nhà nếu người ấy có biểu hiện tâm thần không bình thường hơn là chỉ chán nản mệt mỏi. Nếu bạn có những ý nghĩ không tốt vì mệt mà thường bạn không có, bạn cũng nên nghỉ. Đừng dùng thuốc an thần và đừng nghiện cà phê.
I.2.11 LÀM VIỆC VỚI NHỮNG NGƯỜI KHÓ TÍNH NHƯ THẾ NÀO
Bạn có thể sẽ gặp những người khó tính, hoặc chính bạn cũng có thể là người khó tính. Nếu bạn là kiểu người có nhiều mâu thuẫn với đồng nghiệp hay các nhân vật có quyền lực, bạn phải tự vui với sự độc lập mà cá tính bạn mang lại, và tìm cách làm việc với nhiều người mà không phải hy sinh các nguyên tắc và suy nghĩ của mình.
Điều này có thể rất phiền toái với một số lập trình viên, những người ít kinh nghiệm với kiểu người khó tính, và cuộc sống của họ có những kiểu cách không hợp lắm với không gian công việc Những người khó tính thường là người quen với những ý kiến bất đồng và ít bị ảnh hưởng bởi áp lực xã hội hơn những người khác. Chìa khóa ở đây là tôn trọng họ đúng mức: nhiều hơn bạn muốn, nhưng không nhiều như họ muốn.
Lập trình viên làm việc theo nhóm, và khi có bất đồng, không nên để lâu. Người khó tính thường lại là những người rất thông minh và họ có những cách rất hiệu quả. Điều rất quan trọng là bạn lắng nghe những người này mà không có định kiến gì. Tìm cách trao đổi một cách trầm tĩnh và chân thành, đừng mắc vào những cớ gây mâu thuẫn lớn hơn. Sau khi đã tìm cách hiểu hãy quyết định.
Đừng nghe theo sức ép của những kẻ bắt nạt. Nếu bạn là team-leader, làm điều bạn nghĩ là tốt nhất. Đừng quyết định vì lý do cá nhân, và chuẩn bị để giải thích quyết định của mình. Nếu cùng nhóm với một người khó tính, đừng để leader phải quyết định mang tính chất cá nhân, và nếu không đi con đường của bạn được thì đi con đường kia một cách thành tâm.
Những người khó tính vẫn có thay đổi và cải thiện. Tôi đã thấy, nhưng điều đó hiếm. Ai cũng có những lúc lên, xuống tạm thời. Và điều khó khăn, nhất là leader phải làm là làm sao cho những người khó tính bận bịu. Họ thiên về các công việc họ yêu thích và phản ứng tiêu cực hơn những người khác.
II CHO TRÌNH ĐỘ TRUNG BÌNH
II.1. CÁC KỸ NĂNG CÁ NHÂN
II.1.1. LÀM SAO ĐỂ LUỐN CÓ THÁI ĐỘ TÍCH CỰC
Điều ngạc nhiên và kỳ diệu trong giới lập trình viên là họ luôn bị thúc đẩy bởi mong muốn tạo ra những sự vật đẹp, có ích, thuận tiện. Điều này khá phổ biến trong giới lập trình viên và do đó phân biệt họ với những người khác, trong những vai trò khác.
Điều này có những hệ quả quan trọng và thực tế. Nếu bắt lập trình viên làm việc gì không đẹp, không ích lợi, họ sẽ cảm thấy miễn cưỡng khi làm. Làm những việc xấu xí, ngu ngốc, nhàm chán thì có nhiều tiền, nhưng tôi tin rằng, cuối cùng làm những việc vui vẻ sẽ mang lại nhiều lợi ích cho công ty nhất. Có những điều rất riêng biệt cho các lập trình viên giỏi:
- Dùng ngôn ngữ tốt nhất cho công việc.
- Tìm cơ hội áp dụng các kỹ thuật, công nghệ mới.
- Tìm cách học hay dạy những điều mới, cho dù nhỏ.
- Cuối cùng, tự quan sát công việc của mình dưới các khía cạnh khác. Ví dụ như khi tôi fix bug, số các bug fix được chẳng bao giờ làm tôi vui, vì nó chẳng nghĩa lý gì so với số bug còn phải fix, và chẳng đóng góp gì mấy về phía công ty. Nhưng với một bug nào đó, sự hài lòng của khách hàng cũng là một phần thưởng.
II.1.2 LÀM SAO ĐỂ ĐƯỢC TIN TƯỞNG RỘNG RÃI
Đầu tiên phải có mặt. Nếu chẳng ai thấy bạn thì không ai tin bạn được. Có những phản hồi nhiều thông tin với người khác. Nhiều khi người khác sẽ làm phiền bạn với sự tin cậy này, và có những đòi hỏi vô lý, khi đó hãy giải thích cho họ hiểu bạn phải bỏ điều gì khi phải đáp ứng họ. Đừng giả vời biết những điều bạn không biết. Với những người không ở trong nhóm của bạn, đôi khi phải phân biệt rõ giữa không thể biết được ngay và dù sao cũng không có cách nào biết được.
II.1.3 CÂN BẰNG GIỮA KHÔNG GIAN VÀ THỜI GIAN NHƯ THẾ NÀO
Bạn có thể làm một lập trình viên giỏi mà không cần phải qua đại học. Nhưng một người có trình độ trung bình trong nghề này phải biết những kiến thức căn bản, như là lý thuyết độ phức tạp của tính toán chẳng hạn. Bạn không cần phải biết big O notation là gì, nhưng bạn cần phân biệt được tuyến tính với thời gian, n log n, và n bình phương khác nhau như thế nào. Bạn cũng vẫn có thể biết cách cân bằng giữa không gian và thời gian, nhưng cũng khó để giao tiếp với đồng nghiệp nếu như bạn không biết những điều trên.
Cải tiến việc cân bằng giữa không gian (bộ nhớ) và thời gian (thời gian chạy CPU) có thể thay đổi nhiều điều một cách ngoạn mục. Nhưng đầu tiên, cần phải xem có cần phải cải tiến không. Vì cải tiến một cái không phải là vấn đề thực sự chẳng làm nên điều khác biệt nào, ngoài việc tạo thêm một khối lượng test. Bộ nhớ máy tính càng ngày càng rẻ, và việc tiêu phí nó không dễ thấy như là thời gian của CPU, cho đến khi chi phí đụng trần, và tai họa xảy đến. Cần cân nhắc khi bạn bán không gian để mua thời gian (tốc độ).
II.1.4. STRESS TEST NHƯ THẾ NÀO
Stress test là thử nghiệm hệ thống với tải. Thực tế, rất nhiều khi hệ thống làm việc tốt với một tải nhất định, và chỉ bắt đầu có vấn đề với một tải trọng nào đó, tức hệ thống đụng trần (hit the wall). Và stress test thực sự là để tìm ra xem cái trần này là ở đâu, và tìm xem có cách nào dỡ trần lên cao hơn không.
Kế hoạch cho việc stress test cần phải được làm ở giai đoạn đầu của dự án, vì như vậy cũng là xác định chúng ta mong đợi đến chừng nào ở sản phẩm: 2 giây cho việc một yêu cầu một trang web có phải là một thất bại hay không hay là một thành công rực rỡ?. Kế đến, stress test cần được thực hiện trong một môi trường đủ gần với môi trường thực.
Khi tiến hành stress test, bắt đầu với tải nhẹ, và nâng dần tải trọng lên theo một số chiều nào đó, cho đến khi bạn đụng trần. Và nếu trần quá thấp thì bạn gặp phải vấn đề về hiệu suất hệ thống, nghĩa là thường thì có một bottleneck ở đâu đó. Sau đó thì bạn tìm cách nâng dần trần lên, nhưng nhớ rằng một hệ thống chịu được tải nặng không có nghĩa là hệ thống đó chạy tốt với tải nhẹ. Sau đó thì làm test trên các chiều khác nữa. Có nhiều kỹ thuật khác nhau, như các hệ thống log thường cho biết nhiều điều về thời gian dùng CPU, nhưng ít khi cho được cái nhìn đúng về tình trạng bộ nhớ. Trong các hệ thống hiện đại, nhiều phần mềm và nhiều máy tính có thể cùng tương tác, khi bạn đụng trần đâu đó thì các hệ thống khác cũng bị ảnh hưởng theo, do đó theo dõi tất cả các máy cũng sẽ rút được nhiều thông tin.
Cuối cùng, biết được trần ở đâu không có nghĩa là phải nâng trần lên, chỉ là để có cái nhìn mang tính dự đoán để giúp cho mặt kinh doanh của sản phẩm.
II.1.5 CÂN BẰNG GIỮA TRỪU TƯỢNG VÀ KHÚC CHIẾT NHƯ THẾ NÀO
Trừu tượng hóa là chìa khóa của lập trình. Nhưng bạn cần cân nhắc mức độ trừu tượng hóa, người mới vào nghề thường trừu tượng vấn đề nhiều hơn cần thiết. Dấu hiệu nhận biết điều này là tạo nhiều lớp không thực sự chứa đoạn mã nào và chỉ để phục vụ cho việc trừu tượng hóa một điều gì đó. Dĩ nhiên điều này là hấp dẫn, nhưng bạn cũng cần đến tính khúc chiết, ngắn gọn trong code.
Đôi khi, chúng ta thấy những lỗi lầm của những người nhiệt thành và lý tưởng: tại giai đoạn sơ khởi của dự án, nhiều lớp được định nghĩa cho thấy viễn cảnh có thể xử lý mọi tình huống có thể xảy ra. Sau đó thì phần thân của các hàm càng ngày càng dài, code càng ngày càng hỗn độn, và nhiều lớp trống không được viết tài liệu vì mọi người đều rất bận. Kết cục đó có thể tránh được nếu để dành công sức cho sự trừu tượng hóa này vào việc giữ mọi thứ ngắn gọn và đơn giản. Tôi đề nghị đọc Succinctness is Power của Paul Graham.
Có một số giáo điều với các kỹ thuật như che giấu thông tin (information hiding) hay lập trình hướng đối tượng (object oriented programming). Những kỹ thuật này giúp lập trình viên code những đoạn mã có tính trừu tượng cao và thích nghi với thay đổi. Nhưng, theo cá nhân tôi, bạn không nên viết quá nhiều code như thế.
II.1.6 HỌC CÁC KỸ NĂNG MỚI NHƯ THẾ NÀO
Học các kỹ năng mới, nhất là các kỹ năng không phải là kỹ thuật là điều thú vị nhất. Phần nhiều các công ty sẽ có chính sách tốt hơn nếu họ hiểu những lập trình viên muốn điều này như thế nào. Đọc sách, dự các khóa học cũng là một cách, nhưng thực sự bạn có thể kính trọng một lập trình viên nếu như anh ta chưa viết một chương trình nào không? Nhưng để học một kỹ năng, bạn phải tự đặt mình vào cái vị thế đáng thương nơi bạn có thể thực tập kỹ năng đó. Một cố vấn kinh nghiệm thường tốt hơn sách vở nhiều, nhưng điều đó cũng không thay thế được việc bạn tự học. Tìm cách bắt sếp cho bạn học các lớp chính thức nhiều hơn, nhưng cũng nên hiểu rằng điều đó cũng chẳng tốt hơn việc bạn từ mày mò là bao nhiêu. Vì thường là đòi có lớp học thì dễ hơn đòi được nghĩ xả hơi, còn lớp học thì nhiều khi là những bài giảng ngái ngủ để đợi đến giờ ăn.
Nếu bạn lãnh đạo người khác, hãy hiểu họ học như thế nào và khuyến khích bằng cách giao những việc đúng tầm và đúng kỹ năng. Nhớ rằng các kỹ năng quan trọng lại không phải là các kỹ năng kỹ thuật và để mọi người có cơ hội giao tiếp, và nâng cao tình bằng hữu và sự mạnh dạn trong công việc.
II.1.7. TẬP CÁCH GÕ BÀN PHÍM
Đây là kỹ năng trung cấp, vì viết code thường khó và thường bạn không đủ thời gian để gõ những gì bạn nghĩ. Và trong công việc, càng ngày bạn càng viết lách nhiều hơn (mà ít phải gõ code hơn). Giai thoại kể lại rằng khi Michael Tiemann ở MCC, người đứng ngoài cửa có thể nghe được tiếng vo ve của các phím bấm, nhanh đến nỗi chẳng phân biệt được các phím với nhau.
II.1.8. INTERGRATION TESTING NHƯ THẾ NÀO
Intergration testing (IntT) là khi bạn tích hợp tất cả các phần khác nhau của hệ thống đã được unit-test. IntT thường tốn kém, và bạn phải tính thời gian làm điều này trong lịch làm việc của bạn. Tốt nhất là làm sao không có giai đoạn IntT này vào cuối mỗi chu kỳ, bạn tích hợp dần dần mọi thứ và kiểm tra dần cho đến lúc hệ thống thành hình.
II.1.9 NGÔN NGỮ GIAO TIẾP
Có một số ngôn ngữ không phải là ngôn ngữ lập trình, nhưng là ngôn ngữ giao tiếp giữa các chương trình, đã được hình thành và dần chuẩn hóa như UML, XML, SQL… Bạn cần phải biết những ngôn ngữ này cũng như biết dùng chúng lúc cần.
UML rất đẹp ở chỗ nó vừa trực quan, lại vừa hình thức. XML là chuẩn để định nghĩa những chuẩn mới. Nó không phải là giải pháp cho vấn đề trao đổi dữ liệu như bạn nghĩ, dù là nó được nói đến như vậy. Nó chỉ là việc tự động hóa cho phần chán nhất của trao đổi dữ liệu: biến đổi toàn bộ cấu trúc của dữ liệu thành tuyến tính để gởi đi và ngược lại. XML có những phương pháp kiểm tra kiểu và kiểm tra tính chính xác, nhưng lần nữa, cũng chỉ là một phần của những cái bạn sẽ cần đến trong thực tế. SQL không thực sự là một ngôn ngữ lập trình, và là ngôn ngữ chung của các cơ sở dữ liệu quan hệ. Có thể bạn không làm việc liên quan đến cơ sở dữ liệu, nhưng cũng nên có hiểu biết cơ bản về cú pháp và ngữ nghĩa của SQL.
II.1.10 CÁC CÔNG CỤ HẠNG NẶNG
Theo đà phát triển, công nghệ phần mềm tiến từ chỗ không thể hiểu nỗi đến nghiên cứu, đến sản phẩm mới, đến các sản phẩm chuẩn hóa, đến các sản phẩm giá rẻ. Do đó các công cụ công nghệ phần mềm nặng ký thường đòi hỏi nhiều đầu tư để hiểu và sử dụng chúng. Các lập trình viên hạng trung cần biết sử dụng chúng khi cần thiết. Theo tôi, một số công cụ nặng ký cần có:
- Cơ sở dữ liệu quan hệ.
- Các máy tìm kiếm toàn văn (full-text search engine).
- Các thư viện toán học.
- OpenGL.
- Các bộ phân tích cú pháp XML (XML-parser).
- Các chương trình bảng tính.
II.1.10 PHÂN TÍCH DỮ LIỆU NHƯ THẾ NÀO
Phân tích dữ liệu nằm ở giai đoạn sớm của dự án, khi bạn phân tích các hoạt động kinh doanh và tìm ra các yêu cầu đối với phần mềm. Định nghĩa hình thức này có thể làm cho bạn, lập trình viên, nghĩ rằng cần phải tập trung vào coding và để công việc đó cho ai đó làm thiết kế. Nếu theo đúng các tiến trình làm phần mềm thì có thể là như vậy. Nhưng lập trình viên kinh nghiệm thường trở thành người thiết kế, và người thiết kế sắc bén thường trở thành người phân tích kinh doanh. Và họ được trao cái quyền thu thập yêu cầu dữ liệu và đặt các yêu cầu đó trên bàn cho bạn làm. Nhưng vì dữ liệu nằm ở trung tâm của hoạt động lập trình, người phân tích kinh doanh phân tích dữ liệu ở cấp cao, kế đến người thiết kế bóp nặn các phân tích đó sao cho khi nó đến bàn của bạn, bạn chỉ việc áp dụng những thuật toán thông minh nhất để giải quyết công viêc. Sự việc không hoàn toàn như vậy, vì dù ở công đoạn nào dữ liệu cũng là điều chính yếu cần quan tâm. Nếu bạn tìm hiểu xem tay phân tích kinh doanh làm gì để lấy yêu cầu từ khách hàng, bạn sẽ thấy họ vẽ những data flow diagram, định vị các nguồn thông tin, cũng như định hình các dòng thông tin lưu chuyển. Có được yêu cầu cần phải tích hợp luồng thông tin nào vào hệ thống, người thiết kế sẽ xây dựng các nguồn thông tin theo các thuật ngữ của cơ sở dữ liệu quan hệ, của các protocol trao đổi thông tin, của các định dạng file….để công việc có thể được giao xuống cho lập trình viên. Tuy nhiên quá trình chưa dừng ở đây, vì bạn, lập trình viên, sau quá trình tinh lọc dữ liệu này, cần phải phân tích dữ liệu để có thể làm điều đó theo cách tốt nhất. Cái dòng bên dưới công việc của bạn là gì nếu không phải là câu của Niklaus Wirth: Algorithms + Data Structures = Programs. Không có thuật toán nào tự đứng một mình, tự nó làm điều gì đó với chính nó. Do không có thuật toán nào chạy trong chân không nên bạn cần biết phân tích dữ liệu ai đó đã đem đến cho bạn để có thể viết code.
Ví dụ: tìm xem từ nào trong từ điển có nhiều hơn 3 anagram có nghĩa (tức là cũng có trong từ điển) (anagram: một cách đảo các chữ cái của từ đó). Nếu bạn làm bằng cách xem xét tất cả hoán vị có thể có thì dường như bạn đã chọn cách làm tệ nhất.
II.2 CÁC KỸ NĂNG NHÓM
II.2.1 QUẢN LÝ THỜI GIAN PHÁT TRIỂN NHƯ THẾ NÀO
Để quản lý thời gian phát triển, luôn duy trì một kế hoạch ngắn gọn và cập nhật. Kế hoạch là một tập các ước lượng, các lịch biểu, các cột mốc (milestone) đê đánh dấu tiến độ. Trong kế hoạch đó cần có tất cả những thứ bạn cần làm, các buổi họp, các buổi làm việc với QC, tài liệu, đặt mua thiết bị… Nếu là kế hoạch cho nhóm, thì cả nhóm phải đồng ý với kế hoạch đầu và trong mỗi lúc thực hiện.
Kế hoạch dự án là để giúp ra quyết định, chứ không phải để phô bày cách tổ chức. Kế hoạch phải cập nhật, để cùng với phán đoán của bạn, có thể dịch chuyển các tác vụ từ người này sang người khác. Nếu để lỡ một milestone, phải có hành động ngay, như là báo cho ông chủ biết. Vì ước lượng và lập lịch không bao giờ là hoàn hảo, và có thể tạo ra ảo tưởng bạn có thể bù những ngày đã lỡ trong những ngày còn lại.
II.2.2 QUẢN LÝ RỦI RO CỦA CÁC GÓI PHẦN MỀM DO HÃNG THỨ 3 VIẾT NHƯ THẾ NÀO
Có những rủi ro liên quan đến các phần mềm do một hãng thứ 3 viết:
Đừng đặt hy vọng vào các thứ chưa có, các phần mềm được hứa là sẽ có. Dĩ nhiên là không nên hoàn toàn hoài nghi về lời hứa của một công ty về một sản phẩm nào đó trong một hạn thời gian nào đó, nhưng khôn ngoan hơn là làm lơ như là chưa nghe lời hứa đó. Và đừng đưa nó vào các văn kiện viết.
Ngay cả khi các lời hứa có thể tin được, nó vẫn chứa rủi ro. Nếu bạn dùng phần mềm của một hãng thứ ba, nhớ là hãy đánh giá nó sớm, sớm hơn rất nhiều trước khi tích hợp. Hiểu được mức độ của các phần mềm do hãng thứ ba viết là một kiến trúc rất đặc biệt, và thường chỉ có chuyên gia mới có được. Và bạn tiết kiệm được rất nhiều thời gian nếu có những người như vậy. Tìm cách có một kế hoạch dự phòng trong trường hợp bất khả kháng.
II.2.3 QUẢN LÝ CÁC CỐ VẤN NHƯ THẾ NÀO
Dùng các cố vấn (consultant), nhưng đừng dựa hẳn vào họ. Họ là những người tuyệt vời và xứng đáng được kính trọng. Vì họ tham gia vào nhiều dự án, họ sẽ biết nhiều về các công nghệ đặc biệt, hay ngay cả các kỹ thuật lập trình nhiều hơn bạn. Cách tốt nhất sử dụng họ là nhờ họ như những gia sư: dạy học các bằng ví dụ. Hơn nữa, họ có thể dễ đến và dễ đi hơn. Họ thường được ít hơn nếu công ty làm việc tốt hơn. Một số thật giỏi, một số trung bình, số còn lại thì kém. Nhưng thường thị bạn chọn họ không kỹ như là chọn lập trình viên, nên thường bạn có nhiều người dỡ hơn. Nếu cố vấn đi viết code, thì bạn cần phải cân nhắc hơn, vì bạn không thể kết thúc dự án với một khối code lớn không có ai review.
II.2.4 GIAO TIẾP ĐÚNG MỨC NHƯ THẾ NẦO
Cân nhắc chi phí của các buổi họp. Chi phí của nó bằng thời gian nhân cho số người tham gia. Họp hành thì cần, nhưng ít hơn nghĩa là tốt hơn. Khuyến khích các giao tiếp ít hình thức, vì thường là có nhiều việc được làm hơn trong giờ ăn trưa hơn các giờ khác. Thật xấu hổ là nhiều công ty không nhận ra và hỗ trợ điều này.
II.2.5 TỎ THÁI ĐỘ BẤT ĐỒNG MỘT CÁCH LỊCH SỰ VÀ QUÊN NÓ ĐI NHƯ THẾ NÀO
Bất đồng là cơ hội để có được một quyết định tố, nhưng phải được xử lý không khéo. Nếu bạn cảm thấy mình đã diễn đạt tốt và được mọi người chú ý lắng nghe thì không có gì nhiều để nói. Nhưng nếu bạn không thể bênh vực cho quyết định mà bạn bất đồng, thì hãy cứ nói vậy. Điều này chứng tỏ bạn là người có suy nghĩ độc lập và có trách nhiệm. Trong một số trường hợp, bất đồng có thể đưa đến công việc được xử lý theo cách của các cá nhân, khi người ra quyết định cảm thấy bất an và cảm thấy đây là một thách thức với uy quyền của cá nhân mình, hãy nhớ rằng trong những trường hợp đó, họ phản ứng với phần có nguồn gốc bò sát trong não họ, bạn nên trình bày những lý lẽ của mình ở một nơi riêng. Nhưng cho dù quyết định có được đảo ngược hay không, ban không bao giờ được nói: Tôi đã nói với anh mà!.
II.3. CÁC KỸ ĐÁNH GIÁ
II.3.1 CÂN BẰNG THỜI GIAN VÀ CHẤT LƯỢNG NHƯ THẾ NÀO
Phát triển phần mềm đã luôn là cân bằng giữa việc làm gì và việc phải hoàn thành nó. Cái chính là bạn sẽ bị đòi hỏi hy sinh chất lượng cho thời gian theo cách làm tổn thương các kỹ sư cũng như các nhân viên kinh doanh. Nếu điều này xảy ra, hãy thông báo cho các thành viên của nhóm cái giá của việc giảm bớt chất lượng, vì dù sao bạn cũng hiểu điều này hơn là ông chủ. Hãy là rõ cái gì mất và cái gì được. Nếu nó ảnh hưởng đến phía QA, hãy làm rõ nó ra, nếu nó để lại nhiều bug về sau, cũng chỉ ra điều đó. Nếu như bạn được yêu cầu gói cái đống kém chất lượng này vào một component nào đó để chuẩn bị làm nó ở các phase sau, hãy giải thích điều đó với nhóm của bạn để họ có chuẩn bị.
NinjaProgrammer ở Slashdot có nói:
Nhớ rằng thiết kế tốt sẽ có tác dụng chống lại code kém. Nếu như các phần trừu tượng, giao diện (interface) tốt có nhiều trong code, thì việc viết lại mớ code đó sẽ ít khó khăn hơn. Nếu như khó viết code khó sửa thì hãy xem xem điều gì sai trong thiết kế.
II.3.2 QUẢN LÝ SỰ PHỤ THUỘC HỆ THỐNG NHƯ THẾ NÀO
Các hệ thống phần mềm hiện đại càng phụ thuộc nhiều vào các component không trực tiếp nằm trong vòng kiểm soát của bạn. Điều này tăng hiệu suất nhờ vào việc tái sử dụng. Tuy vậy các component cũng mang đến vài vấn đề:
- Sửa lỗi trong các component này thế nào?
- Component có làm bạn phụ thuộc vào hệ thống hay phần mềm khác không?
- Bạn làm gì nếu như component không làm việc?
Nên luôn cần phải gói các component này bằng một cách nào đó, cô lập nó và thay thế khi cần thiết. Hơn nữa việc gói này cũng khiến cho porting phần mềm (từ hệ thống này sang hệ thống khác) cũng dễ hơn.
Có được source code của các component làm rủi ro giảm đi khoảng 4 lần. Nếu bạn fix lỗi của các component này, nhớ đưa nó lại cho người sản xuất chúng, để họ tích hợp các fix vào các bản phát hành sau, nếu không bạn sẽ không vui vẻ gì khi phải hỗ trợ một phiên bản không chính thức.
II.3.3. QUYẾT ĐỊNH LÀM SAO NẾU PHẦN MỀM QUÁ TỆ
Dùng các gói phần mềm người khác viết là cách hay nhanh để tạo nên hệ thống, nhưng rủi ro cần phải cân nhắc. Bạn phải cân nhắc xem gói phần mềm đó đã đủ trưởng thành chưa (vì thường thì các gói phần mềm trưởng thành cùng với quá trình sử dụng):
- Gói đó có thực sự có được không?
- Bạn đã biết gì về gói đó?
- Bạn có phải là người dùng đầu tiên?
- Có lý do mạnh nào để tiếp tục không?
- Gói đó có được bảo trì không?
- Nếu những người đang bảo trì “bỏ chạy” thì nó có tiếp tục sống không?
- Có gói nào khác thay thế được chỉ tốt bằng nửa thế không?
- Công ty bạn có thực sự muốn nó không ?
- Nếu nó thực sự tốt, bạn có thể thuê người làm tiếp trên nó không?
Cân nhắc tất cả những tiêu chí này mới thấy giá trị lớn lao của các gói phần mềm mã nguồn mở được phát hành tốt trong vai trò giảm rủi ro cho các doanh nghiệp.
II.3.4 QUYẾT ĐINH MUA HAY LÀM NHƯ THẾ NÀO
Các doanh nghiệp thường luôn phải quyết định: mua hay làm. Những quyết định này thường đáng tiếc ở những điểm sau: nó thường bỏ lơ các gói mã nguồn mở (vì chúng không cần phải mua). Điều quan trọng hơn là một quyết định như vậy thường bỏ qua chi phí tích hợp, mà chi phí này không nhỏ:
- Những gì bạn cần có giống những thứ đã được thiết kế sẵn đó không?
- Bạn sẽ cần phần nào của cái bạn mua?
- Chi phí của việc tích hợp?
- Chi phí cho đánh giá việc tích hợp?
- Mua sẽ gia tăng hay giảm bớt chi phí bảo hành về lâu về dài?
- Nếu phải tự làm, điều đó có đặt bạn vào một vị trí kinh doanh bạn không muốn không?
Bạn phải nghĩ rất kỹ nếu như làm một cái gì đó rất lớn đủ để xây cả một doanh nghiệp khác. Những ý tưởng như vậy thường được đề nghị bởi những người giỏi và lạc quan, những người sẽ cống hiến rất nhiều cho nhóm của bạn. Nếu nó hấp dẫn, bạn cũng có thể thay đổi kế hoạch kinh doanh, nhưng đừng đầu tư lớn hơn cho cả doanh nghiệp của bạn mà không suy nghĩ tỉnh táo.
Sau đó bạn xây dựng hai kế hoạch, một tự làm và một mua và so sánh chi phí. Và những chi phí này phải tính trên thời gian dài.
II.3.5 LÀM SAO ĐỂ PHÁT TRIỂN MỘT CÁCH CHUYÊN NGHIỆP
Tưởng tượng bạn có trách nhiệm vượt quá thẩm quyền của bạn. Đóng cái vai bạn muốn làm. Biết ơn những đóng góp cho công ty cũng như cho cá nhân. Nếu bạn muốn thành leader, hãy tìm cách tập trung sự hưởng ứng. Nếu bạn muốn là manager, hãy có trách nhiệm với lịch biểu. Ngay cả khi đang làm việc với leader hay manager của mình, bạn vẫn có thể làm vậy, vì làm vậy giúp họ rảnh hơn. Lên kế hoạch học các kỹ năng: kỹ thuật cũng như xã hội.
II.3.6 TUYỂN DỤNG NHÂN VIÊN MỚI NHƯ THẾ NÀO
Tuyển dụng luôn không được quan tâm đúng mức. Thuê một người không thích hợp cũng giống như một hôn nhân có vấn đề.
Có nhiều kiểu phỏng vấn khác nhau. Một số có tính “giày vò”, giao cho ứng viên một khối lượng khổng lồ. Điều này cũng giúp cho việc phát hiện các điểm mạnh và yếu của ứng viên khi phải chịu sức ép. Ứng viên sẽ không thành thật với chính mình hơn là với người phỏng vấn, và các khả năng tự lừa dối mình thật đáng ngạc nhiên.
Bạn nên hỏi miệng các ứng viên các vấn đề kỹ thuật trong khoảng 2 giờ. Với thực hành, bạn sẽ biết cách tìm ra họ biết và không biết những gì, và chỉ ra cho họ thấy. Các ứng viên thường tôn trọng điều này. Tôi đã đôi lần nghe các ứng viên nói rằng chất lượng của các kỳ sát hạch là một trong những động lực cho việc chọn công ty làm việc của họ. Những người tốt muốn được thuê vì khả năng, chứ không phải vì nơi họ làm việc sau cùng, hay vì một đặc tính không quan trọng nào khác. Bạn cũng cần đánh giá khả năng học hỏi của ứng viên, và điều này quan trọng hơn chúng ta tưởng.
Phỏng vấn cũng là một quá trình bạn: bạn bán công ty hay dự án cho ứng viên. Tuy nhiên, khi nói chuyện với lập trình viên, cũng đừng cố tô bóng sự thật, nói về những thứ không tốt trước, sau đó về các thứ tốt hơn.
II.3.7. KHI NÀO DÙNG CÁC KỸ THUẬT TIN HỌC TINH VI
Có một phần của khoa học máy tính gồm cả thuật toán, cấu trúc dữ liệu, toán… những lập trình viên biết nhưng ít dùng. Thực tế, những thứ này quá phức tạp và không cần thiết lắm. Ví dụ như không ích lợi gì trong việc cải tiến một thuật toán nếu như phần lớn thời gian là gọi cơ sở dữ liệu một cách không hiệu quả. Phần đáng thương của lập trình là làm cho các hệ thống nói chuyện được với nhau và dùng các cấu trúc dữ liệu đơn giản để xây dựng các giao diện đẹp.
Khi nào thì công nghệ cao là công nghệ thích hợp? Khi nào thì bạn nên cày một cuốn sách để tìm một thuật toán không có gì đặc biệt? Đôi khi làm điều này cũng có ích nhưng cũng với đánh giá cẩn thận.
Ba cân nhắc quan trọng nhất đối với các kỹ thuật khoa học máy tính có tiềm năng là:
- Nó có được gói cẩn thận để ít gây rủi ro cho các hệ thống khác, và chi phí toàn bộ cho bảo trì có thấp không?
- Lợi ích có đáng chú ý không?
- Bạn có thể kiểm tra và đánh giá nó đúng được không?
Nếu như một sửa đổi thuật toán có thể làm hiệu suất toàn hệ thống tăng gấp đôi (hay giảm chi phí phần cứng đi một nữa) thì đúng là tội ác nếu không cân nhắc nó. Chìa khóa khi biện hộ cho sự thay đổi là: rủi ro thật sự ít, công nghệ này đã được nghiên cứu kỹ, chỉ còn rủi ro khi tích hợp.
II.3.8 NÓI CHUYỆN VỚI NHỮNG NHÂN VIÊN KHÔNG KỸ THUẬT NHƯ THẾ NÀO
Kỹ sư, lập trình viên thường được liệt vào một loại người, một loại văn hóa khác với những người khác. Điều này có nghĩa là những người khác thì khác chúng ta. Khi phải trao đổi với những nhân viên không kỹ thuật, hãy luôn nhớ rằng: tìm cách hiểu họ.
Những nhân viên không kỹ thuật cũng thông minh, nhưng không có chung nền tảng kỹ thuật với chúng ta. Chúng ta làm ra sản phẩm, họ bán, đếm, quản lý sản phẩm… họ cũng không giỏi làm việc nhóm như chúng ta (điều này hiển nhiên không có ngoại lệ). Kỹ năng xã hội của họ tệ lắm cũng bằng chúng ta, nhưng công việc của họ không đòi hỏi họ phải thực tập cách hành xử thân mật, cách ăn nói chính xác, cách chia nhỏ sự việc như chúng ta. Những người này thường dễ bằng lòng hơn, cũng như chúng ta, họ có thể nói Có mà không thực sự hàm ý vậy.
Những người không kỹ thuật vẫn có thể hiểu các vấn đề kỹ thuật, nhưng họ không có cái mà với chúng ta cũng là một điều khó: đánh giá kỹ thuật. Họ vẫn có thể kỹ thuật vận hành như thế nào, nhưng lại không thể hiểu tại sao làm theo cách này lại mất 3 tháng trong khi cách kia lại mất 3 ngày (lập trình viên cũng có những huyền thoại kiểu như vậy thôi), và đây cũng là một cách để tìm tiếng nói chung với họ.
Khi nói chuyện với người trong nhóm, bạn thường dùng một vài kiểu viết tắt có liên quan đến kinh nghiệm làm việc của bạn. Cần phải có chút nỗ lực để không dùng các dạng này với người không hiểu chúng, nhất là khi có thành viên khác của nhóm bạn ở đó. Với nhóm bạn, những điều ngầm định và mục đích cơ bản không cần phải nhắc lại nhiều, phần lớn thời gian dành cho các chi tiết. Với người ngoài nhóm, câu chuyện phải ngược lại. Họ thường không hiểu những gì bạn không bỏ qua, và làm cho hai bên nghĩ rằng mình hiểu nhau, nhưng thực ra sự không thông hiểu lại càng lớn. Bạn sẽ phải nghĩ rằng bạn sẽ không giao tiếp tốt và tìm hiểu tại sao như vậy. Tìm cách bắt họ tóm tắt những gì bạn nói để chắc rằng họ hiểu.
Tôi thích làm việc với những thành viên không kỹ thuật. Bạn thường có được lợi thế vì bạn biết nhiều ví dụ và ngôn ngữ của bạn rõ ràng. Bạn được đào tạo để tìm trật tự trong hỗn loạn, và họ thích điều đó ở chúng ta. Vì chúng ta hiểu biết các lý luận kỹ thuật, chúng ta cũng sẽ dễ hiểu các khoản liên quan đến kinh doanh, và chúng ta thường tìm được giải pháp cho vấn đề. Những nhân viên không kỹ thuật thường đề xuất các giải pháp họ nghĩ là sẽ dễ hơn cho chúng ta, nhưng thực tế, những giải pháp sau cùng thường chỉ được tìm thấy bằng cách tổng hợp các cái nhìn ngoài cuộc với các đánh giá kỹ thuật. Cá nhân tôi thích Extreme Programming vì nó đã đề cập đến sự không hiệu quả này; kết nối các lượng giá với các ý tưởng sẽ dễ dàng tìm được các kết hợp tốt nhất giữa chi phí và lợi ích hơn.
III CHO TRÌNH ĐỘ CAO CẤP
III.1. ĐÁNH GIÁ KỸ THUẬT VÀ CÔNG NGHỆ
III.1.1 BIẾN ĐIỀU KHÔNG THỂ THÀNH ĐIỀU KHÓ
Việc của chúng ta là làm những điều khó và thăm dò những điều không thể. Từ quan điểm của hầu hết lập trình viên, một điều là không thể khi nó không thể có được từ hệ thống hiện tại hay nó không thể đánh giá được một cách chính xác. Nếu theo định nghĩa này thì tất cả những việc nghiên cứu là không thể.
Sự phân biệt không khôi hài như ta nghĩ, vì thực sự đôi khi bạn đã được đòi hỏi phải làm điều không thể (từ quan điểm khoa học hay từ quan điểm công nghệ phần mềm). Thực sự thì đó chỉ là việc giúp tìm ra một giải pháp cho một vấn đề thực sự khó và hoàn tất phần quan trọng của giải pháp đó. Và một giải pháp được gọi đơn thuần chỉ là khó khi nó có thể được lập lịch một cách tự tin và các rủi ro được hiểu rõ.
Một yêu cầu như thế này thì rất khó có thể thỏa mãn: xây dựng một hệ thống tính toán được kiểu tóc và màu tóc hấp dẫn nhất cho một người. Nhưng vấn đề có thể trở thành đơn thuần chỉ là khó nếu nó có thể được phát biểu sinh động hơn: xây dựng một hệ thống tính được các kiểu tóc và màu tóc hấp dẫn cho một người, cho phép họ xem trước và thay đổi, để sau một hồi thay đổi, họ thấy kiểu ban đầu rất đạt và do đó chúng ta có thể kiếm tiền từ đó. Bạn không thể thành công nếu bạn không có các định nghĩa sinh động về chữ thành công.
III.1.2 DÙNG CÁC NGÔN NGỮ NHÚNG NHƯ THẾ NÀO
Nhúng một ngôn ngữ vào hệ thống là công việc gợi tình và sáng tạo nhất bạn có thể làm. Nó làm cho hệ thống trở nên rất mạnh. Ví dụ như các text-editor tốt nhất đều có các ngôn ngữ nhúng. Nó có thể được sử dụng để người dùng có thể sử dụng sản phẩm với nhiều tính năng hơn. Dĩ nhiên là chức năng này cần phải được xem là tùy chọn, để người đã quen dùng và không ai khác phải dùng đến nó. Tôi và nhiều lập trình viên khác đã rơi vào cái bẫy này nhiều lần. Đã có nhiều ngôn ngữ nhúng và bạn cần cân nhắc kỹ khi tạo ra một cái mới.
Câu hỏi thực sự cần cân nhắc là: điều này ủng hộ hay chống lại văn hóa của người sử dụng? Nếu người dùng hoàn toàn không phải là lập trình viên, liệu điều đó sẽ có ích gì không? Nếu người dùng là lập trình viên, tốt hơn chăng nếu bạn xài một tập các hàm API? Lập trình viên thường không muốn học các ngôn ngữ ít người dùng, nhưng nếu ngôn ngữ đó “khớp” vào trong môi trường của họ thì họ chẳng phải tốn nhiều thời gian để học nó.
III.1.3. CHỌN NGÔN NGỮ
Một lập trình viên đơn độc thích chọn ngôn ngữ phù hợp nhất cho công việc. Số còn lại không có ý thức nhiều về ngôn ngữ họ sẽ dùng. Thường thì việc quyết định điều này sẽ do các ông chủ chẳng mấy am hiểu kỹ thuật, và không đủ can đảm ủng hộ các công cụ không quy ước, mặc dù họ biết rằng các công cụ ít được chấp nhận nhất thường là những thứ tốt nhất. Dĩ nhiên sẽ là một lợi điểm lớn nếu như một nhóm có lựa chọn của riêng mình, bỏ ngoài tai tiếng nói của một cá nhân, vì ông chủ thường muốn thuê các lập trình viên dễ kiếm, và do đó phải là một ngôn ngữ phổ biến.
Nhưng điều gì cũng có nhiều mặt, ngay khi ngôn ngữ chính được chọn, các công cụ và chương trình khác vẫn nên được viết bằng một ngôn ngữ khác. Và nếu ngôn ngữ đó sẽ được nhúng, sự quyết định sẽ phụ thuộc vào văn hóa của cộng đồng lập trình. Việc học ngôn ngữ mới đối với người mới khởi đầu thường là đáng sợ, nhưng với người đã có kinh nghiệm, nó cũng như việc làm quen một thư viện mới. Thường thì người ta nghĩ một hệ thống lớn viết bằng 3, 4 ngôn ngữ thật là hỗn độn, nhưng theo ý tôi, thường thì các hệ thống đó mạnh hơn các hệ thống đơn ngữ.
III.2. THỎA HIỆP MỘT CÁCH KHÔN NGOAN
III.2.1 CHỐNG LẠI ÁP LỰC CÔNG VIỆC NHƯ THẾ NÀO
Áp lực công việc nếu hiểu theo nghĩa bình thường thì đó là một dấu hiệu tốt, nó thể hiện khả năng và sức khỏe của hệ thống của bạn. Nhưng một khi áp lực đó được lập lịch thì điều đó có nghĩa là bạn buộc phải giao hàng sớm hơn bạn có thể, và điều đó thường không tốt, nhưng lại phổ biến. Áp lực được lập lịch thường có vài lý do: những lập trình viên không cảm thấy yêu thích công việc của mình, cũng có thể là từ khách hàng, họ nghĩ đòi hỏi sản phẩm sớm hơn sẽ khiến chúng ta làm việc chăm hơn. Điều này có thể là đúng, nhưng hiệu quả thực sự lại nhỏ, và thiệt hại lại lớn. Khách hàng thường không biết nội bộ của công việc như thế nào, do đó họ càng đặt thêm nhiều áp lực lên chúng ta. Điểm chính để chống lại áp lực được lập lịch là hiểu nó như một áp lực kinh doanh thông thường, giám sát quan hệ giữa các nguồn lực ta có và sản phẩm, Ước tính chi tiết, hào hiệp về tất cả nhân lực chúng ta có. Và điều này cho phép có những quyết định quản lý tốt về các khả năng cân bằng, co giãn.
Điều then chốt bên trong việc ước lượng này là: sức lao động là thứ chất lỏng hầu như không nén được. Hiểu theo cách khác, một lập trình viên sẽ không nói Không nhưng có thể nói: Khi nào ông sẽ từ bỏ thứ ông muốn?. Đánh giá rõ ràng, chính xác cũng là cách để được các lập trình viên kính trọng, và đây cũng là cách những người chuyên nghiệp hành xử. Thiết lập một lịch trình không tưởng rõ ràng sẽ gây đau đớn cho mọi người. Extreme Programming đã nói rõ về điều này, và tôi nghĩ ai cũng có thể dùng nó.
III.2.2 HIỂU NGƯỜI DÙNG NHƯ THẾ NÀO
Trách nhiệm của bạn là hiểu những người dùng, và giúp ông chủ của bạn cũng hiểu như vậy. Vì người dùng không liên quan mật thiết đến quá trình sản xuất, họ sẽ cư xử khác so với bạn:
- Người dùng thường tuyên bố ngắn gọn
- Người dùng có công việc riêng, họ thường nghĩ về các cải tiến nhỏ trong sản phẩm, chứ không phải các cải tiến lớn.
- Người dùng thường không có được cái nhìn về chính cộng đồng người dùng của họ.
Nhiệm vụ của bạn là đem lại thứ họ muốn, chứ không phải là thứ họ nói họ muốn. Tốt hơn, hãy đề nghị và kiểm chứng họ đồng ý về đề nghị của bạn trước khi bắt đầu. Bạn phải coi chừng tính kiêu ngạo cũng như tính khiêm tốn giả tạo khi muốn biết khách hàng cần gì. Lập trình viên được đào tạo để thiết kế và code. Nghiên cứu viên thị trường được đào tạo đế biết người khác muốn gì. Hai kiểu người này, hay hai trạng thái này trong cùng một con người phải làm việc hòa hợp với nhau để tạo ra được viễn cảnh tốt nhất. Và bạn hãy kiểm tra các suy nghĩ, ý kiến của bạn càng nhiều càng tốt.
III.2.3 LÀM SAO ĐỂ THĂNG TIẾN
Muốn thăng tiến đến một vị trí, hãy hành xử như là bạn đang ở trong vị trí đó. Muốn thăng tiến đến một chức danh, tìm hiểu xem người khác chờ đợi điều gì từ chức danh đó và làm chúng. Để được tăng lương, hãy thương lượng với đầy đủ thông tin. Nếu bạn cảm thấy bạn bị bỏ qua quyền được thăng tiến, hãy nói chuyện với ông chủ về điều đó, hỏi rõ ràng bạn cần phải làm gì để được như vậy và hãy làm chúng. Nghe có vẻ nhàm chán, nhưng thường thì những điều bạn thấy cần phải làm lại khác với ý kiến của ông chủ bạn. Và điều này cũng giúp chốt ông chủ của bạn lại ở một vài điểm. Hầu hết các lập trình viên đều có cái nhìn phóng đại về khả năng của mình. Dù sao, không phải ai cũng ở trong top-ten. Nhưng tôi đã thấy nhiều người không được đánh giá đúng mức, nhưng thường thì mọi người xung quanh tương đối vừa phải, bạn không thể được đánh giá đúng nếu như không làm cho ai thấy rõ ràng điều đó trong công việc. Đôi khi do nguyên nhân thói quen cá nhân, một số người sẽ không được để ý đến nhiều…
III.3. PHỤC VỤ NHÓM CỦA BẠN
III.3.1 PHÁT TRIỂN TÀI NĂNG NHƯ THẾ NÀO
Nietschze đã cường điệu khi nói: Cái gì không huỷ diệt tôi sẽ làm tôi mạnh hơn. Trách nhiệm lớn nhất của bạn là với nhóm của bạn. Bạn phải hiểu rõ mọi người. Và tìm cách mở rộng công việc hơn là làm họ quá tải với chúng. Nói chuyện với mọi người về sức ép công việc, và cách nó đang ép họ. Nếu lập trình viên cảm thấy mình chịu được một dạng sức ép, họ sẽ cảm thấy có động lực từ đó. Bạn cũng nên tìm hiểu về động cơ làm việc của những người khác, cái gì làm cho họ thấy công việc thú vị. Nhiều khi bạn cũng không thể thỏa mãn được họ, nhưng ít ra bạn cũng biết được họ mong muốn điều gì.
Bạn cũng nên cho phép người khác (và cả chính bạn) thất bại đôi lần, và chuẩn bị có một số thất bại trong kế hoạch. Nếu không có thất bại nào, bạn sẽ không có được cảm giác phiêu lưu, hay là bạn đang không cố gắng đúng mức. Nếu ai đó cố tình không làm việc ở mức đúng với họ, hãy kiên nhẫn tìm cách làm cho họ hoạt bát hơn. Nhưng khi kiên nhẫn cạn hết thì hãy cứ sa thải. Bạn không thể tiếp tục giữ anh ta vì như vậy không công bằng với các thành viên khác.
Với những thành viên giỏi, hãy công khai tán dương họ trước mọi người, và giữ những lời phê bình ở chỗ riêng tư. Người giỏi thường làm những việc khó hơn, và điều này là tự nhiên, chẳng ai để ý gì đến điều đó nếu ai cũng làm việc chăm chỉ. Một thực tế ít khi nhìn thấy là 1 lập trình viên giỏi thường tốt hơn cả 10 lập trình viên kém. Nên có tình huống là, bạn sẽ đi nhanh hơn nếu bỏ những người yếu hơn ở lại phía sau. Nhưng thường thì như vậy chỉ mang lại các lợi ích ngắn hạn, về lâu về dài, cộng đồng cần những dạng ích lợi khác: sự đào tạo những người kém hơn, sự phổ biến tri thức trong mọi người, và khả năng đứng vững khi những người giỏi ra đi.
III.3.2. CHỌN NHỮNG THỨ ĐỂ LÀM NHƯ THẾ NÀO
Bạn cân bằng nhu cầu cá nhân với nhu cầu của nhóm khi chọn các phương diện của dự án để tham gia. Bạn nên làm những gì bạn giỏi nhất, nhưng cũng nên học các kỹ năng mới. Kỹ năng lãnh đạo và giao tiếp quan trọng hơn kỹ năng kỹ thuật. Nếu bạn rất giỏi, hãy nhận phần khó và rủi ro nhất của công việc, và làm nó sớm nhất có thể.
3.3 LÀM SAO ĐỂ CÓ ĐƯỢC NHIỀU NHẤT TỪ NHÓM CỦA BẠN
Xây dựng tinh thần đồng đội và giữ cho mọi người có liên quan với nhau. Để xây dựng tinh thần đồng đội, những thứ như áp quần, logo, đồng phục cũng hay, nhưng không bằng những kính trọng cá nhân. Tinh thần này có được khi mọi người quyết định hy sinh vì tập thể và nghĩ rằng những hy sinh đó cũng là vì lợi ích của họ. Là leader, bạn không thể đòi hỏi điều này nhiều hơn bạn có thể cung cấp chúng. Chìa khóa của việc lãnh đạo là tạo sự đồng tâm nhất trí giữa mọi người.
III.3.4 LÀM SAO ĐỂ MỖ XẺ VẤN ĐỀ
Nhiều giám đốc nghĩ rằng lên kế hoạch và không cần để ý đến những người sẽ làm chúng. Điều này là không thể vì khả năng và năng suất của mọi người khác nhau.
Cũng như một nhạc trưởng cần cân nhắc các loại gỗ làm ra các nhạc cụ trong giàn nhạc, leader thường không thể tách rời các thành viên ra khỏi các công việc đã được chia. Đây cũng là lý do không nên phá vỡ các nhóm đang có hiệu suất cao.
Cũng có một nguy cơ tiềm tàng là mọi người sẽ chán những việc họ thường làm mà không được học các kỹ năng khác và cải thiện các điểm yếu của họ. Dù sao, chuyên môn hóa vẫn tốt nếu không bị lạm dụng.
III.3.5. XỬ LÝ CÁC CÔNG VIỆC NHÀM CHÁN THẾ NÀO
Nhiều khi không thể tránh được các công việc nhàm chán, vì nó quan trọng với sự thành công của dự án. Những công việc này có thể làm tổn thương những người làm chúng. Hãy tìm cách bắt máy tính làm giùm, hay giúp các thành viên khác làm nó. Làm một chương trình làm những công việc nhàm chán trong một tuần hay tự làm việc đó cũng trong một tuần, dĩ nhiên cách làm tự động hóa sẽ tốt hơn. Nếu không thể khác được thì cũng phải làm thôi, nhưng đừng để những người phải làm việc đó một mình, ít nhất hãy giao việc đó cho một nhóm hai người.
III.3.6 TÌM TÀI TRỢ CHO DỰ ÁN NHƯ THẾ NÀO
Tạo ra một viễn cảnh và minh họa giá trị của viễn cảnh đó với cả tổ chức. Cho phép người khác có phần trong viễn cảnh đó. Tìm ra các nhà tài trợ chính riêng rẽ, làm một mô hình để minh họa các ý tưởng. Mô hình, hình mẫu luôn tốt hơn, nhất là trong ngành phần mềm.
III.3.7 PHÁT TRIỂN MỘT HỆ THỐNG NHƯ THẾ NÀO
Hạt giống chứa những ý tưởng từ những người đã trưởng thành nhưng chưa được thực hiện. Hạt giống phát triển thành phôi, và lớn lên. Và cuối cùng thì đơm hoa kết trái. Về sau thì cây chết và xác nó dùng để nuôi những sinh vật khác. Phần mềm cũng vậy. Một cây cầu thì không thể như vậy, chúng ta có một chiếc cầu chưa hoàn tất, chứ không có một chiếc cầu “trẻ em”, vì cầu đơn giản hơn phần mềm nhiều.
Bạn nên nghĩ về phần mềm như một sinh vật phát triển, nó cho phép chúng ta có những bước tiến dài trước khi thấy được hình ảnh sau cùng. Phải có được phản hồi từ phía người dùng về phần mềm. Phát triển và tỉa bớt các cành yếu. Lập trình viên là những người phát triển một sản phẩm hoàn chỉnh, nhưng lập trình viên giỏi phải phát triển được con đường phát triển cho đến hệ thống sau cùng.
Những cách tiếp cận thường có dạng xoắn ốc, và nhớ đặt những milestone trên đó. Và trên đường phát triển, không chỉ phát triển hệ thống mà phát triển nhóm và con người.
Rob Hafernik đã gửi cho tôi những ghi chú này, và tôi không thể làm tốt hơn là trích dẫn lại ở đây:
Đó không phải chỉ là hệ thống, mà là thuật toán, giao diện người dùng, mô hình dữ liệu, vân vân… Điều sống còn là bạn làm việc trên toàn hệ thống để biết được nó đạt những mục tiêu trung gian. Không gì tệ hơn việc xây dựng tất cả mọi thứ để cuối cùng biết rằng nó không làm việc (như thất bại gần đây ở Voter News System). Vì điều đó là do một quy luật tự nhiên: không hệ thống phức tạp nào được xây từ đầu, nó chỉ có thể tiến hóa từ hệ thống đơn giản lên hệ thống phức tạp qua những bước có chủ ý.
III.3.8 GIAO TIẾP TỐT NHƯ THẾ NÀO
Giao tiếp tốt rất khó, nó là một kỹ năng thuộc về chính nó. Càng khó hơn, vì người mà bạn giao tiếp ai cũng có thiếu sót. Thường họ không cố hiểu bạn, họ diễn đạt nghèo nàn. Họ thường làm việc quá nhiều, hay quá chán công việc, và thường chú trọng vào việc của họ hơn những điều bạn đề cập. Bạn càng viết, nghe, nói giỏi, bạn càng dễ tìm hiểu xem vấn đề nằm ở đâu và làm sao để giải quyết chúng.
Lập trình viên là một sinh vật có xã hội và sống phụ thuộc vào giao tiếp với cộng nhóm mình. Lập trình viên giỏi là những sinh vật xã hội chỉ bằng lòng với việc giao tiếp nhiều hơn ra ngoài nhóm của mình. Và ông chủ (nếu không phải là lập trình viên) cần lập trình viên vì họ là một phần của chiếc cầu nối giữa các ý tưởng và thực thể trong quần thể.
Tôi không hẳn đã giao tiếp tốt, nhưng tôi thường làm các cách sau: chuẩn bị các ý tưởng, nói cho người khác nghe, giao cho họ một văn bản viết, cho họ xem demo, và lặp đi lặp lại như vậy. Và không nên thất vọng khi các ý tưởng của bạn chưa được chấp nhận.
III.3.9 NÓI VỚI NGƯỜI KHÁC NHỮNG ĐIỀU HỌ KHÔNG MUỐN NGHE THẾ NÀO
Nhiều khi bạn phải nói với một người những điều sẽ làm họ khó chịu. Nhớ rằng bạn làm vậy có lý do, ngay cả khi không thể làm được gì khác thì hãy cố nói với họ sớm. Cách thông báo tốt nhất là kèm theo luôn một giải pháp. Cách thứ nhì là nhờ họ giúp với chính vấn đề đó. Và có nguy cơ là người ta sẽ không tin bạn, và bạn cần hậu thuẫn cho sự quyết đoán của mình.
Một trong những điều khó chịu nhất bạn thường nói là: kế hoạch phải trễ một thời gian. Ai có lương tâm cũng ghét những câu này, vậy nên hãy nói nó sớm. Không gì tệ hơn tiếp tục trì hoãn khi đã trễ. Bạn cũng có thể tìm cách nói điều đó với sự hậu thuẫn của một nhóm.
III.3.10 LÀM VIỆC VỚI CÁC “CHUYỆN HOANG ĐƯỜNG” CỦA VIỆC QUẢN LÝ
“Chuyện hoang đường” hàm nghĩa không có thật, nhưng nó có những ý nghĩa sâu xa hơn. Nó có nghĩa như là những câu chuyện của lòng tin, những câu chuyện giải thích quan hệ giữa con người và vũ trụ. Những giám đốc thường quên họ đã học những gì khi còn là lập trình viên, và tin vào những chuyện hoang đường ấy dễ dàng. Bạn cần phải nhận ra những điều đó:
- Nhiều tài liệu hơn là tốt hơn (họ muốn có tài liệu, nhưng họ không muốn bạn mất thời gian để làm chúng).
- Có thể coi mọi lập trình viên như nhau (thật sự các lập trình viên rất khác nhau).
- Có thể thêm tài nguyên vào một dự án trễ để tăng tốc (chi phí giao tiếp với những người mới nhiều khi nhiều hơn là những người đó có thể giúp).
- Có thể ước lượng chi phí phát triển phần mềm chính xác (điều này ngay cả về mặt lý thuyết cũng không làm được).
- Có thể ước lượng hiệu suất của lập trình viên bằng một số lượng giá đơn giản, như số dòng code (nếu như ngắn gọn là sức mạnh, thì có lẽ càng ít code càng tốt).
Nếu có cơ hội, hãy tìm cách giải thích những điều này, nhưng đừng thất vọng nếu không thành công, và đừng chiến đấu một cách ngoan cố. Những huyền thoại này chỉ cũng cố ý kiến của các giám đốc là mình phải cố kiểm soát mọi việc. Sự thật là người ta đã ủng hộ nếu nó tốt và chống lại nếu nó xấu.
III.3.11 ĐƯƠNG ĐẦU VỚI TÌNH TRẠNG HỖN LOẠN TỔ CHỨC NHƯ THẾ NÀO
Có những lúc công ty sẽ có vấn đề: ngừng sản xuất, công ty bị mua lại… Những điều này không làm ai yên tâm, nhưng có lẽ ít tác động đến lập trình viên hơn, vì tính cách lập trình viên thiên về khả năng hơn là vị trí. Nếu bạn không phải là lập trình viên, xin dừng ở đây.
Các kỹ sư có năng lực sáng tạo, và chống đỡ. Những người không phải là kỹ thuật có thể ra lệnh cho người khác xung quanh, nhưng họ chẳng làm gì được nếu không có các kỹ sư. Và đây là nền móng để tạm thời chống đỡ các tình trạng hỗn loạn trong tổ chức. Nếu bạn lâm vào tình trạng đó, tốt nhất làm lơ và tiếp tục công việc như chẳng có gì xảy ra. Rất thường thấy một kẻ xả stress nào đó không có năng lực sẽ tìm cách bảo bạn làm những điều ngu ngốc, tốt nhất là hãy cười và chẳng làm gì hết cho đến khi hắn đi khỏi, và tiếp tục làm những gì bạn nghĩ là tốt nhất lúc đó. Đây là điều tốt nhất có thể làm cho bạn, và cho cả dự án và công ty.