Coffee Talk: Anh CuongLM - Golang Contributor

<- Quay về trang chủ

Chào mừng các bạn đã quay trở lại với chuyên mục Coffee Talk, trong buổi trò chuyện hôm nay, xin giới thiệu đến các bạn một nhân vật không xa lạ với Cộng đồng Golang Việt Nam, đó là anh CuongLM, nhiều người biết đến anh với vai trò là một contributor cho ngôn ngữ lập trình Golang. Hôm nay anh Cường chia sẻ những kinh nghiệm của anh trong việc tham gia các dự án mã nguồn mở (OSS) nói chung và Golang nói riêng. Mình hy vọng những buổi Coffee Talk này sẽ là nguồn cảm hứng để các bạn lập trình viên trẻ trong nước có thể học hỏi và phát triển. Giới thiệu thế đủ rồi, chúng ta bắt đầu nào.


Huy: Xin chào anh Cường, rất cảm ơn anh đã nhận lời tham gia buổi nói chuyện hôm nay, anh có thể giới thiệu một chút về mình với các bạn độc giả được không?

Cường: Chào Huy, chào các bạn, mình là Cường, hiện đang sinh sống và làm việc tại Hà Nội, Việt Nam. Hiện tại mình đang làm Backend Engineer tại Windscribe, một công ty cung cấp các sản phẩm để bảo vệ privacy cho người dùng internet, trong đó nổi bật là sản phầm VPN. Mình có hơn 8 năm kinh nghiệm làm việc, chủ yếu về backend. Mình rất thích OSS và cũng tham gia nhiều các cộng đồng này, trước đây là U&L, hiện tại thì mình chủ yếu tham gia Go community. Sở thích của mình ngoài computer là cờ tướng, bóng rổ, motorbike.

Huy: Cơ duyên đến với open source của anh là như thế nào? Anh bắt đầu contribute cho Go từ bao giờ? Và tại sao lại là Go?

Cường: Cơ duyên đến với open source chắc phải kể từ hồi mới bắt đầu đi làm, lúc đó mình làm Linux System Administrator. Lúc đấy thì công ty cũng chủ yếu sử dùng các sản phẩm open source, nên việc quản trị và vận hành hệ thống hàng ngày đã luyện cho mình các thói quen như đọc log, đọc man, rồi khi gặp các vấn đề sâu hơn thì có thể “nhảy” vào source code của phần mềm đó mà đọc. Mình còn nhờ cái đầu tiên mình chọt vào source của nó - trong môi trường làm việc - là một plugin của Nagios viết bằng Perl. Cũng trong quá trình làm việc thì mình thấy các anh trong team hay tham gia vào serverfault.com - Q&A site cho network/system admin, nên mình cũng tham gia luôn. Ban đầu mục đích chỉ để hỏi những câu liên quan đến vấn đề đang gặp phải tại hệ thống của công ty. Dần dần thì mình nhận ra đây là một môi trường tốt cho việc học hỏi, nâng cao kiến thức của bản thân, nên mình biến nó thành một thói quen hàng ngày, tham gia hỏi/trả lời/bình luận, và thành một thành viên tích cực của cộng đồng U&L (Unix & Linux).

Mình bắt đầu contribute cho Go từ khoảng năm 2016, trước đấy cũng có sử dụng Go rồi, từ version 1.5 thì phải. Mình nhớ patch đầu tiên mà mình submit là cho thư viện os, liên quan đến việc xử lý sai tham số đặc biệt của shell “-”.

Tại sao lại là Go:

  • Lý do ban đầu là vì docker. Đợt cuối 2013, đầu 2014, docker đang hot, lúc đó mình không làm system admin nữa, mà chuyển sang làm dev. Mình không nhớ cụ thể, nhưng lúc đó gặp phải 1 vấn đề mà mình nhảy vào source của docker để đọc, lúc đó mình mới biết tới Go. Đọc code thấy rõ ràng, tường mình → Thích
  • Càng tìm hiểu về Go thì mình nhận ra 1 điều là Go thay đổi tư duy lập trình của mình. Trước đó mình nghĩ có Perl và Lisp, cũng là 2 ngôn ngữ tạo cho mình cách nhìn nhận, giải quyết vấn đề một cách khác biệt so với trước đây.
  • Ở trên là 2 lý do mình chọn học/sử dụng Go. Lý do mình contribute cho Go:
    • Muốn hiểu Go rõ hơn, do mình “work in Go” hàng ngày, nên việc hiểu cách Go hoạt động (compiler, runtime) sẽ giúp mình viết code Go tốt hơn, ví dụ biết lúc nào chọn readability hơn là performance và ngược lại, biết tránh các pitfails, edge case. Hiểu nôm na là “work on Go” sẽ giúp cho việc “work in Go” tốt hơn. Cái này mình nghĩ có thể thay thế “Go” trong câu trên bằng bất cứ phần mềm nào khác.
    • Chắc do thói quen từ lúc tham gia U&L, mình học được nhiều từ cộng đồng Go, nên muốn “làm gì đó” ngược lại cho nó. Mà việc thiết thực nhất là contribute, vì Go vẫn là một ngôn ngữ mới, còn nhiều vấn đề cần được cải tiến, giải quyết
    • Yêu thích! Lúc đầu mới thì không có cái này, nhưng hiện tại thì có. Hằng ngày ngoài thời gian cho công việc, chơi với con, chạy xe, chơi tennis, thì thời gian còn lại chủ yếu mình dành cho Go ^^

Huy: Quả nhiên kĩ năng đọc code là một kĩ năng rất quan trọng và không thể thiếu đối với developer, đặc biệt là với các project có code base lớn. Khi mới bắt đầu thì anh mất bao lâu để có thể hiểu và nắm được toàn bộ cấu trúc project của Go? Và tương tự với os package? mất bao lâu để anh submit được pull request đầu tiên? Anh có thể chia sẻ một chút về những kĩ thuật hay những cách anh dùng để tiếp cận với một project có code base lớn như Go hay Docker được không?

Cường: Trước khi mình submit Change List (trong Gerrit, mỗi Change tương đương với mỗi commit trong 1 Pull Request, và 1 Change List - CL - tương dương với 1 Pull Request), mình cũng đã theo dõi development process của Go một thời gian (bằng cách subscribe vào Go repo trên giao diện Gerrit, khi có CL mới được gửi thì mình sẽ nhận notify qua email), do đó mình cũng hiểu được một phần process. Mình nghĩ khoảng 1-2 tháng là có thể nắm được toàn bộ cấu trúc project của Go rồi: cách tổ chức package, cách thêm package mới, chỗ nào viết unit test, chỗ nào viết regression tests, chỗ nào viết docs,… Với các standard lib thì sẽ ít thời gian hơn, và phụ thuộc vào từng package nữa. Với package os thì mình nghĩ mất khoảng 1 tuần đọc code là ok, nhưng với package json thì sẽ mất thời gian hơn, vì nó dùng reflect ^^.

Nếu mình nhớ không nhầm, CL đầu tiên của mình mất khoảng 3-4 tuần, nhưng chủ yếu là do không có ai review ^^ Khi được review thì chủ yếu sửa về code style, sửa code style xong thì chỉ 1-2 ngày sau là được submit rồi. Một kinh nghiệm là khi mình contribute cho package nào thì nên follow coding convention của package đó. Với các public APIs thì reviewers sẽ rất “strict”, và buộc phải tuân theo “gofmt” style, ví dụ như CamelCase. Với các private APIs thì tùy vào từng owners của mỗi packages. Khi đã quen rồi, thì mỗi khi gửi CL mình đã biết được nên tag những ai để review, khi đó process sẽ nhanh hơn.

Khi tiếp cận với một project có code base lớn:

  • Theo dõi development process
  • Đọc toàn bộ các CLs (PRs) liên quan đến phần mà mình muốn tìm hiểu
  • Với 1 đoạn code mình muốn thay đổi, hoặc mình muốn hiểu, đọc toàn bộ git history liên quan đến nó:
    • Tại sao đoạn code đó tồn tại?
    • Tại sao nó lại được refactoring?
    • Tại sao nó lại bị xóa bỏ?

Dần dần, bạn sẽ hiểu code base hơn, và nắm được toàn bộ các ngữ cảnh (context) liên quan đến phần đó. Tất nhiên, mình sẽ có thể bị tình trạng lan man, và không biết đâu là chỗ để dừng, khi đó mình nên đặt câu hỏi cho các owner, maintainer, hoặc mailing list. Ví dụ gần đây mình có refactoring phần checkptr instrumentation từ compiler frontend vào compiler backend. Ở compiler frontend mình có thể truyền vào 1 slice, nhưng vào backend thì lại truyền vào 3 tham số. Khi hỏi ra mới biết là do func(*_type, slice, int)func(*_type, unsafe.Pointer, int, int, int) có cùng 1 calling convention, nên ở compiler backend, các bước register allocation / stack frame layout sẽ cho cùng 1 kết quả → it just works. Thêm 1 tính năng / Sửa một bug không khó, nhưng làm sao để khi mình thêm/sửa code, nó giúp cho code base đẹp hơn, dễ maintain hơn và “still open room for improvement” mới khó.

Huy: Còn việc bắt đầu contribute, thì trước khi submit PR, anh có trao đổi với những maintainer khác về hướng giải quyết vấn đề hoặc về những cái thay đối anh tính đưa vào không?

Cường: Ban đầu thì không, sau này thì có! Nghe có vẻ hơi ngược, nhưng ban đầu mình chưa hiểu rõ hết code base, cứ nghĩ fix được là fix, nên có issue là debug + submit fix liền. Sau này khi mình hiểu rõ hơn, có kinh nghiệm hơn thì với những cái mình đã hiểu rõ, nắm chắc, thì mình có thể submit CL luôn. Với các CL mà mình biết có thể ảnh hưởng đến các phần khác thì mình sẽ trao đổi trước với maintainer. Thật ra việc trao đổi hoàn toàn có thể thực hiện trên Gerrit, nhưng nó sẽ mất thời gian hơn là mình trao đổi trực tiếp. Mình thấy các maintainers của Go rất “nice”, nên các bạn nếu cần hỏi gì cứ email cho họ, thường họ sẽ trả lời vào đầu hoặc cuối ngày làm việc của họ. Càng tham gia contribute cho Go lâu, mình càng thấy việc trao đổi là quan trọng. Vì không ai có thể nắm rõ mọi phần của Go compiler (mình không nhớ chính xác, nhưng 1 Go maintainer từng nói “No one’s brain can fit all the Go compiler parts”), ngay cả với từng thành viên trong Go compiler team. Ví dụ như trong lúc mình đang trả lời những câu này, mình có fix 1 bug tại https://go-review.googlesource.com/c/go/+/364614, lý do người mà fix issue ban đầu không tham gia sâu vào quá trình phát triển generic trong Go, dẫn đến việc submit CL để fix generic issue đã break non-generic tests code. Hay trong đợt go1.17 release, mình và anh Matthew Dempsky cũng đã trao đổi rất nhiều khi refactoring lại compiler frontend để chuẩn bị cho việc thêm generic.

Huy: Về việc trao đổi với maintainer như thế, đã có khi nào xuất hiện xung đột giữa quan điểm của anh và maintainer chưa?

Cường: Cũng thỉnh thoảng xảy ra việc này. Tuy nhiên việc giải quyết xung đột cũng đơn giản, cả 2 sẽ cũng phân tích xem cái nào là giải pháp tốt nhất. Nếu không đi đến được thống nhất thì sẽ tham khảo ý kiến của người thứ 3. Cũng có nhiều khi mình không hoàn toàn ok với giải pháp của bác maintainer, nhưng dù sao thì “take it easy”. Thường thì maintainer sẽ có nhiều context hơn mình về một vấn đề nào đó trong Go, và có những lý do mà họ không thể chia sẻ được cho mình tại một thời điềm nào đó. Mình thấy cái này là điều không thể tránh khỏi, không chỉ với OSS mà ngay cả với chính trong công việc hàng ngày.

Huy: Có một tình huống em thường gặp phải khi có ý định contribute cho một project OSS, đó là mình muốn làm một feature hay fix một issue nào đó, và trước đó đã có người làm rồi, PR cũng đã tạo rồi, nhưng sau đó thì tác giả bặt vô âm tín. Anh đã bao giờ gặp tình huống như thế này chưa? Và giả sử anh là người đến sau, muốn take over chức năng đó thì anh sẽ làm gì?

Cường: Trường hợp này thì mình sẽ chủ động tạo CL mới dựa trên CL cũ, và credit cho tác giả của CL ban đầu. Ví dụ:

Huy: Từ lúc bắt đầu contribute cho Go đến giờ, chắc chắn là anh đã thu về không ít kiến thức và kinh nghiệm quý giá, ngoài những cái đó ra, thì còn có những benefit nào khác không anh nhỉ? Ví dụ về hiện vật hay về cơ hội về công việc hay networking với các maintainer khác thì sao nhỉ?

Cường: Cũng có đó. Ví dụ như năm nay mình nhận được quà từ Google Open Source, là một bộ kit đi picnic, và $250 cho giải thưởng Google Open Source Peer Bonus (cụ thể tại https://cuonglm.xyz/post/google_opensource_peer_bonus). Những cái này hoàn toàn do người làm việc ở Google tiến cử, cụ thể trường hợp của mình là do 2 bác trong Go team. Cái này Google Open Source họ có cơ chế cụ thể, mình cũng không rành lắm. Cơ hội networking thì rất nhiều. Với 2 job gần nhất của mình, mình đều được điểm cộng vì họ thấy profile của mình có đóng góp cho Go. Cụ thể thì 1 job ông CTO cũng là core contributor cho Go, nên khi mình apply ông nhận ra liền và việc interview cũng diễn ra thuận lợi hơn. Ở đây mình muốn làm rõ là không phải người interview bị “bias”, mà họ đã thấy được phong cách làm việc/lối tư duy/kỹ năng của mình …, nên mình sẽ có lợi thế hơn các ứng viên khác, và người interview sẽ biết được ngay là mình có phải người phù hợp với văn hóa công ty họ hay không. Với job hiện tại thì cũng tương tự, chỉ khác là CTO không phải core contributor của Go, nhưng cũng ấn tượng về profile của mình. Thật lòng thì khi trải qua rồi mình mới nhận ra những điều này, chứ ban đầu khi mình contribute cho Go, đó không phải là mục đích chính.

Huy: Giờ mình đổi chủ đề tí nhỉ? Hiện tại ngoài Go ra thì anh có quan tâm đến ngôn ngữ nào khác không, ví dụ Rust hay Swift?

Cường: Thật ra thì mình không quan tâm một ngôn ngữ cụ thể nào hết, mà mình quan tâm đến “Programming Language” nói chung. Ví dụ như type system, runtime … Mình vẫn follow dev mailling list của một số ngôn ngữ khác như bash, zsh, perl, python, emacs lisp. Rust thì mình chủ yểu dành thời gian rảnh để đọc source code. Mình nghĩ với các bạn đã thành thạo một ngôn ngữ cụ thể nào đó, thì việc học cú pháp của một ngôn ngữ mới là việc không khó. Các bạn nên tìm hiểu về “inner working” của ngôn ngữ thì sẽ tốt hơn.

Huy: Thế còn editor thì sao? Xem trên Github thì có vẻ như anh xài cả Emacs lẫn Vim, em không có tính khơi chuyện editor war đâu, nhưng hiện tại anh đang xài gì?

Cường: Tricky question! Hiện mình chủ yếu dùng Goland + Emacs key binding ^^ Với các tác vụ cần quick script hay prototype thì mình dùng vim. Nếu phải lựa chọn thì mình vẫn chọn Emacs. Mình chuyển qua Goland chủ yếu do trước đây có làm 1 project dùng go-qt, load project bằng Emacs treo máy luôn! Mình nghĩ ai quen gì dùng nấy thôi, không cần thiết phải editor war.

Huy: Rất cảm ơn những chia sẻ và kinh nghiệm hết sức bổ ích của anh, hy vọng câu chuyện của anh sẽ là nguồn cảm hứng để nhiều bạn trẻ đến với OSS. Anh có lời khuyên gì cho các bạn trước khi chúng ta kết thúc buổi trò chuyện này không?

Cường: Hmm, một câu hỏi khó đấy Mình chỉ mong các bạn khi muốn tiếp cận/đến với OSS thì nên kiên trì/khiêm tốn học hỏi. Đừng nên đặt quá nặng vấn đề “fame”, hay xem nhẹ phần này, phần kia trong một dự án OSS. Tất cả đóng góp đều rất đáng quý và trân trọng, kể cả các thảo luận. Mình nhớ khi tham dự GopherCon 2019 ở Sing, mình có gặp 1 bạn người Việt Nam đang làm cho 1 công ty ở Sing. Khi trao đổi thì thấy bạn cũng hứng thú và muốn contribute cho Go. Mình cũng chia sẻ các kinh nghiệm mình đã kể ở trên, rồi cũng hướng dẫn bạn khi bạn có các CLs đầu tiên. Tuy nhiên bẵng đi một thời gian thì không thấy bạn còn active nữa, các CLs cũng đều pending. Mình không biết lý do cụ thể, nhưng mình đoán có lẽ do các CLs của bạn bị maintainer yêu cầu sửa đổi nhiều, hoặc là lâu nhận được review nên bạn nản và từ bỏ. Mình thấy tiếc và mong các bạn trẻ sau này sẽ không lặp lại vết xe đổ đó.

Rất cảm ơn Huy đã setup buổi coffee talk này, để mình có thể chia sẽ các kinh nghiệm về Go nói riêng và OSS nói chung. Hi vọng các kinh nghiệm của mình sẽ giúp ích cho các bạn! Cảm ơn các bạn đã theo dõi và hẹn gặp lại trọng một OSS community nào đó 😎