Technical Debt (Nợ kỹ thuật) – có thể là một khái niệm còn mới lạ với nhiều người, đặc biệt đối với những lập trình viên mới vào nghề. Tuy vậy, theo thời gian, dù bạn là lập trình viên ở giai đoạn nào, cũng sẽ ít nhất một vài lần phải đối mặt với Nợ kỹ thuật. Hãy cùng Sutunam tìm hiểu về khái niệm này và bạn sẽ rút ra được những lưu ý hữu ích cho công việc của chính mình. 😉
1. Nợ kỹ thuật có nguồn gốc, ý nghĩa như thế nào?
Tên gọi này được khởi xướng bởi Ward Cunningham. Ông là một lập trình viên người Mỹ, cha đẻ của Wiki thời đầu, người tiên phong phát triển các design patterns, và cũng là một trong những người sáng lập ra nguyên tắc Agile trong phát triển phần mềm. Ông nhận định, nợ kỹ thuật có những điểm tương đồng của một khoản nợ tài chính, nhưng tồn tại trong quá trình phát triển phần mềm.
Đối với khoản nợ tài chính, hãy tưởng tượng bạn đang sở hữu một tấm thẻ tín dụng. Bạn được quyền mượn khoản tiền để tiêu dùng thoải mái, và sau 30 – 45 ngày mới cần hoàn trả lại. Đến hạn thanh toán, bạn có 2 lựa chọn:
- Bạn sẽ trả hoàn toàn khoản mình đã mượn chuẩn xác và đúng hạn.
- Bạn có thể trả một khoản tối thiểu và chấp nhận bị tính phí lãi từ Ngân hàng cho phần còn lại.
Đối với lựa chọn thứ hai, hiển nhiên rằng, thời gian bạn thanh toán toàn bộ càng lâu, phí lãi suất bạn phải trả sau đó càng nhiều. Đó cũng là lúc bạn rơi vào vòng xoáy nợ và lãi.
Sự tồn tại của technical debt trong ngành lập trình
Áp dụng trường hợp trên vào quy trình phát triển phần mềm, chúng ta cũng có 2 sự lựa chọn:
- Kiên trì: Code chuẩn chỉnh, thiết kế tỉ mỉ ngay từ đầu, cố gắng cải tiến và giảm những rủi ro ngầm trong tương lai.
- Cách thức đơn giản: Code rối hay tạo ra những dòng code tạm thời nhưng bàn giao nhanh và hoàn thiện mọi thứ trong một thời gian ngắn. Khi đó, phần code tạm thời có thể xử lý về sau.
Thực tế vì nhiều lý do mà chúng ta sẽ chọn hướng giải quyết đơn giản. Điều đó đang xảy ra hàng ngày ở nhiều công ty, vậy nên Ward Cunningham muốn nhấn mạnh:
“Việc đẩy đi những đoạn code chỉ để chạy, giống như đang tiến gần đến một khoản nợ. Một khoản nợ kỹ thuật nhỏ tồn tại, tất nhiên không ảnh hưởng tới tiến độ phát triển phần mềm, miễn sao nó được cải thiện và viết lại kịp thời. Chi phí cho khoản nợ kỹ thuật từ những phần code khác nhau gây nên vẫn có thể khoan nhượng được. Nhưng, ngay khi bạn quên không viết lại code chuẩn, mối nguy sẽ tìm đến. Bởi vì, mỗi phút của việc code ẩu đều đang bị tính lãi ngầm. Toàn bộ công việc của đội ngũ dự án có thể bị đình trệ dưới gánh nặng nợ nần của cả một quy trình chưa hợp nhất, chưa chuẩn chỉnh,…”
Nợ kỹ thuật có nhiều nguyên do: tiêu chuẩn về code của lập trình viên quá dễ dãi, thiếu quy trình làm việc của đội ngũ quản lý và cũng là áp lực kinh doanh, thời gian từ khách hàng, v.v…
Kết luận là, nợ kỹ thuật sẽ tồn tại khi chúng ta ưu tiên thời gian bàn giao dự án hơn chất lượng code. Nó có thể được phát hiện thấy ở bất cứ giai đoạn nào của phát triển phần mềm. Vì mỗi khi chúng ta làm tất cả mọi thứ ở mức tối thiểu, vừa đủ mà không nhằm tốt hơn, chúng ta sẽ không tạo ra thêm lợi ích, mà chỉ tạo ra một khoản nợ. Và không sớm thì muộn, chúng ta sẽ phải đối mặt với khoản nợ ở một mức độ nguy hại hơn.
2. Có nên lo ngại về nợ kỹ thuật?
Khác với khoản nợ tài chính, nợ kỹ thuật rất hiếm được để mắt tới, bởi vậy chúng ta dễ dàng lãng quên sau một thời gian. Nó chỉ thực sự trở thành vấn đề lớn khi có một người khác tiếp quản phần code của bạn. Họ phát hiện những dấu hiệu của nợ kỹ thuật (code lộn xộn, không theo hình thức nhất định nào cả,…) và có thể dẫn tới sự bất mãn.
Thế nên, việc lo ngại về tình trạng này là cần thiết, vì những hậu quả nghiêm trọng cho cả khía cạnh kinh doanh lẫn nhân sự của doanh nghiệp.
Ảnh hưởng kinh doanh
- Thời hạn hoàn thiện không chính xác
Chúng ta nghĩ rằng nợ kỹ thuật giúp đẩy nhanh tiến độ bàn giao dự án, nhưng thực tế nó lại đang làm mọi thứ chậm lại vào giai đoạn cuối trước khi hoàn thành. Chúng ta có thể bắt kịp tiến độ của những phân đoạn nhỏ (phát triển một trang đơn hay một tính năng). Nhưng cuối cùng sẽ liên tục gặp phải lỗi, và là ác mộng khi tiến vào giai đoạn kiểm thử chất lượng.
Không chỉ vậy, cả đội ngũ còn đối mặt với việc lãng phí nhiều thời gian sửa chữa, tối ưu hóa hơn so với dự kiến. Đó là lý do tại sao thời hạn hoàn thiện trở nên mơ hồ, khiến ta không thể đánh giá hay cam kết thời gian chính xác cho khách hàng.
- Chất lượng kém
Doanh nghiệp không thể đảm bảo gì cho khách hàng của mình, với một hệ thống code bất ổn. Càng tạo ra nhiều khoản nợ trong suốt quá trình làm dự án, chất lượng sản phẩm cuối cùng sẽ càng tệ. Lỗi sẽ xuất hiện từ những đoạn code rối và từ rủi ro bảo mật. Cứ như thế, chúng ta lại mất hàng giờ để gỡ rối và xử lý các khoản nợ cũ, thay vì làm việc để tạo ra giá trị mới.
- Rủi ro cao trong tương lai
Không có doanh nghiệp nào đứng yên, đồng nghĩa với việc mọi sản phẩm chúng ta tạo ra luôn cần được cải tiến, có thêm những cập nhật mới trong tương lai. Vậy nên, việc áp dụng những mẹo làm tắt trong code, giải pháp tạm thời ở một vài trường hợp nhất định, sẽ chỉ càng gia tăng rủi ro. Bổ sung tính năng mới trên một nền tảng base yếu kém, sẽ chỉ là khiến nỗi đau thêm dài.
Ảnh hưởng về con người
Technical Debt là yếu tố tiếp tay gây giảm động lực và thất vọng cho chính đội ngũ lập trình viên. Thông thường, lập trình viên thực sự dành nhiều thời gian hơn để “đọc” code và tìm hiểu nó, thay vì “viết” code.
Hãy thành thật rằng ai cũng thích những thứ sạch, đẹp, rõ ràng, vậy ai sẽ sống giữa mớ lộn xộn và những đoạn code “rác” mỗi ngày? Đôi khi, chúng ta cảm thấy vẫn chấp nhận được một số khoản nợ kỹ thuật nhỏ, cho đến khi nó xảy ra quá thường xuyên.
Và ta bắt đầu rơi vào một vòng lặp nhàm chán:
Làm việc không thể tập trung khi liên tục gặp phải những khoản nợ -> Giảm hứng thú với công việc -> Không muốn cố gắng cải tiến dự án nữa -> Bỏ qua sự chỉn chu vốn có của bản thân và tạo ra thêm nhiều bản nợ kỹ thuật khác.
Bên cạnh đó, trong môi trường làm việc còn có thể tồn tại tư duy “ai là người chịu trách nhiệm” khi nói đến technical debt. Vấn đề trở nên nghiêm trọng hơn khi nó gây ra bất đồng, tổn thương, chia rẽ tinh thần đồng đội.
Do vậy, khoản nợ này không chỉ ảnh hưởng đến sản phẩm của khách hàng mà còn phản ánh chính đội ngũ chúng ta. Chi phí nhân lực trở nên khó khăn hơn để quản lý dài hạn trong một công ty công nghệ.
3. Chúng ta nên làm gì để tránh technical debt?
Một bước quan trọng để xử lý nợ kỹ thuật là viết code với tiêu chuẩn chất lượng. Chúng ta xem xét, điều tra và chịu trách nhiệm cải thiện chất lượng code với tư cách là đồng đội. Một số điểm dưới đây có thể hữu ích:
Phân tích gốc rễ nguyên nhân
Trước khi nói sâu hơn, chúng ta cần gạt ngay tâm thế “Lỗi để đấy. Lần sau kiểm tra cẩn thận hơn là được”, và đơn thuần chỉ sửa các biểu hiện bề mặt, thay vì tìm hiểu sâu để chữa lỗi dứt điểm.
Một trong những cách đơn giản nhất là: Áp dụng chiến lược “5 Tại sao?“, tức là chúng ta tiếp tục tự hỏi bản thân năm lần để điều tra nguyên nhân. Sau nhiều lần “tại sao”, đôi khi chúng ta có thể rất ngạc nhiên khi phát hiện ra câu trả lời thực tế.
Ví dụ như:
1. Tại sao người dùng phàn nàn về việc không thể sử dụng tính năng “Gửi mail”?
Bởi vì có lỗi trong phiên bản mới nhất.
2. Tại sao lại có lỗi trong phiên bản mới nhất đó?
Bởi vì chúng ta đã không kiểm tra đến trường hợp này.
3. Tại sao lại bỏ qua trường hợp này?
Bởi vì chúng ta chỉ kiểm tra kỹ các tính năng đã phát triển trong tháng cuối. Chúng ta không kiểm tra tổng thể dự án từ đầu.
4. Tại sao không kiểm tra tổng thể dự án?
Bởi vì “Gửi mail” là một tính năng đã hoàn thiện từ lâu và không nhất thiết để rà soát lại.
5. Tại sao chúng ta lại nghĩ nó không thiết thực khi rà soát?
Vì ứng dụng quá lớn để kiểm tra lại từng tính năng một, sẽ quá tốn thời gian
Từ đây, chúng ta nhìn thấy một bức tranh rộng hơn: vấn đề chính là thiếu quy trình kiểm thử tự động, cái mà sẽ ảnh hưởng đến tất cả những tính năng tiếp theo, không chỉ dừng lại ở “Gửi mail”.
Lên lịch cho việc cải tiến code
Đội ngũ dự án có trách nhiệm nhắc nhở lập trình viên lưu tâm đến vấn đề nợ kỹ thuật.
Đặc biệt, hãy cho cả nhóm có thời gian, tài nguyên để cải tiến hàng ngày. Việc dành ra mỗi ngày một khoảng thời gian để kiểm tra và tái cấu trúc code sẽ tốt hơn là đối phó với một núi hỗn độn của cả dự án vào giai đoạn cuối.
Đóng gói tính năng và luôn kiểm thử tự động
Trong lĩnh vực tài chính, rất nhiều ngân hàng giúp người dùng tránh được những khoản nợ bằng tính năng “Thanh toán tự động”. Vậy đối với nợ kỹ thuật, chúng ta cũng nên có những cách thức tương tự, là kiểm thử tự động và liên tục tích hợp. Việc làm này sẽ giúp các lập trình viên sớm phát hiện lỗi, cũng như loại bỏ được giai đoạn tích hợp lâu dài, căng thẳng. Tất nhiên điều này làm tăng thời gian phát triển dự án, nhưng xét cho cùng, triển khai Tích hợp liên tục (CI) hạn chế rủi ro và tạo cảm giác dễ chịu cho đội ngũ dự án, điều này tốt hơn rất nhiều so với nỗi đau do nợ kỹ thuật gây nên.
Trao đổi, chia sẻ
Hãy luôn ghi nhớ rằng chúng ta là một “Hội cùng thuyền” và giao tiếp chính là yếu tố thiết yếu để cùng nhau đưa chiếc thuyền đó vươn thật xa. “Hãy khoan dung với mọi sai lầm trong lần đầu tiên. Không mắc lại cùng sai lầm đó lần hai”. Đổ lỗi hay xoáy sâu sai lầm sẽ không giúp giải quyết được vấn đề gì. Thay vì thế, chúng ta cần chọn cách thấu hiểu, trao đổi, và hợp sức tìm cách thoát ra vòng xoáy tư duy code tạm bợ và technical debt.
Một dự án thành công hay thất bại, vốn dĩ là kết quả của cả nhóm!
Có kỷ luật
Cuối cùng, kỷ luật là quan trọng. Mọi thứ vận hành đúng hướng đều nhờ có kỷ luật làm nền móng. Chính đội ngũ Sutunam cũng đã và đang nghiêm túc với những quy tắc, tiêu chuẩn hoặc tái cấu trúc để cải thiện dự án. Dù cho chỉ đang bước từng bước mỗi ngày, điều đó vẫn tốt hơn là đứng yên. Mục tiêu tuyệt vời chỉ có thể đạt được khi chúng ta bắt đầu thực hiện thường xuyên và không bao giờ bỏ cuộc.
Đọc đến đây, chúng tôi tin rằng bạn nhận thức được việc tránh hố đen nợ kỹ thuật (technical debt) là cấp thiết và quan trọng. Tư duy đúng đắn là khi bạn luôn nghiêm khắc nhắc nhở bản thân về sự cẩn trọng trong công việc. Khi đó bạn không những góp phần cải thiện tình trạng của dự án cho đội ngũ mà còn trở thành một tấm gương để mọi người học hỏi theo.