# Đọc codebase Java, Go hay Node.js của khách khi bạn chỉ quen Python

> Trước buổi review tích hợp, bạn chưa cần học thêm ngôn ngữ mới. Bạn cần biết mở ba file nào trước, rồi lần theo một request cho tới tận database.

Bản gốc: https://fdetimes.net/vi/bach-khoa/doc-code-backend-java-go-nodejs-cua-khach/

Ngày thứ hai ở chỗ khách, bạn được cấp quyền vào repo. Đội bạn quen Python, nhưng service đơn hàng mà agent của bạn phải gọi lại viết bằng Go. Cổng thanh toán chạy Java, còn lớp API cho app mobile là Node.js. Chiều nay đã có lịch review tích hợp.

Với FDE, đây là chuyện bình thường. Khách sẽ không viết lại hệ thống cho hợp với bạn.

Tin tốt là bạn không cần thành thạo cú pháp trước buổi chiều. Thứ bạn cần là một tấm bản đồ: mở file nào trước, bỏ qua những gì, và làm sao để trả lời được câu hỏi duy nhất khách quan tâm: dữ liệu của họ đi qua đâu.

## Backend viết bằng ngôn ngữ nào cũng chạy cùng một mạch

Ở mọi backend, server nhận request, xử lý, có khi truy vấn database hoặc gọi một dịch vụ bên thứ ba, rồi trả response. API là cây cầu nối frontend với backend. Vì thế, khi gặp một codebase lạ, route hoặc handler API là chỗ tốt nhất để bắt đầu.

Cú pháp có thể khác nhau, nhưng mạch này thì ở đâu cũng giống. Vậy nên hãy đọc bằng ba câu hỏi, lần lượt từng câu. Dự án phụ thuộc vào những gì? Đó là việc của manifest. Chương trình bắt đầu chạy từ đâu? Đó là entry point. Một request cụ thể đi qua những chỗ nào? Đó là handler, rồi tới database hoặc dịch vụ ngoài.

Người mới hay mắc một lỗi: mở thư mục rồi đọc từ file đầu tiên theo thứ tự chữ cái. Làm vậy, bạn sẽ chìm trong code tiện ích trước khi kịp biết hệ thống làm gì.

## Ba ngôn ngữ cất những thứ đó ở ba chỗ khác nhau

Bảng dưới đây đặt mỗi ngôn ngữ cạnh thứ tương ứng mà bạn đã quen bên Python:

| Câu hỏi | Python | Go | Node.js | Java (Maven) |
|---|---|---|---|---|
| Phụ thuộc vào gì? | requirements.txt, pyproject.toml | go.mod | package.json | pom.xml ở thư mục gốc |
| Entry point ở đâu? | file chạy chính | hàm main trong package main | trường "main", hoặc "exports" nếu có | tìm hàm main trong src/main/java |
| Code chính và test nằm đâu? | tùy dự án | trong các thư mục package | tùy dự án | src/main/java và src/test/java |
| Một package là gì? | một file .py là một module | cả một thư mục | một thư mục có package.json | một nhánh trong cây package |

Với Node còn một chuyện bảng không chứa hết: file .js được hiểu là CommonJS hay ES module tùy trường "type" trong package.json gần nhất. Dòng cuối của bảng và chi tiết này là chỗ phản xạ Python dẫn bạn đi sai nhiều nhất.

## Ví dụ: lần theo một đơn hàng qua service Go

Thử hình dung repo `order-service` của khách. Bước đầu tiên là mở go.mod. Theo tài liệu của Go, file này định nghĩa module và theo dõi các module cung cấp package mà code dùng tới. Chỉ cần đọc danh sách dependency, bạn đã đoán được họ dùng thư viện gì cho HTTP và cho database.

Bước hai là tìm điểm khởi động. Trong Go, hàm `main` sẽ chạy khi bạn chạy package `main`, nên chỉ cần tìm đúng hai thứ đó:

```bash
cat go.mod
grep -rln "package main" --include=*.go .
grep -rn "func main()" --include=*.go .
```

Từ hàm `main`, bạn sẽ thấy chỗ server được khởi tạo và các route được đăng ký. Giả sử bạn thấy `POST /orders` trỏ tới hàm `CreateOrder` trong thư mục `api`. Mở hàm đó ra, bạn gặp lệnh gọi `store.SaveOrder(...)`.

Đến đây, phản xạ Python sẽ bảo bạn đi tìm file `store.go`. Đừng làm thế. Package trong Go gồm tất cả các file trong cùng một thư mục, nên `SaveOrder` có thể nằm ở bất kỳ file nào trong thư mục `store`. Hãy grep `func SaveOrder` trong thư mục đó thay vì đoán tên file.

Kết quả của buổi sáng nên là một bản trace dài năm dòng. `POST /orders` đi vào `CreateOrder` (thư mục api), rồi tới `SaveOrder` (thư mục store), ghi vào bảng orders, sau đó gọi dịch vụ thanh toán. Mang bản này vào buổi review, bạn đã có thể hỏi những câu cụ thể: lệnh gọi thanh toán có retry không, agent nên gọi vào tầng nào.

**Điểm mấu chốt:** Đừng cố hiểu cả repo. Hãy lần theo một request từ đầu đến cuối, rồi ghi lại đường nó đi.

## Với Node, lỗi import đầu tiên thường nằm ở package.json

Giờ tới lớp API mobile, thử hình dung là repo `mobile-gateway`. Bạn viết một script nhỏ để thử hàm kiểm tra token, import thẳng file `src/auth/token.js` của package. Script báo lỗi, và phản xạ đầu tiên là nghĩ code của khách hỏng.

Hãy mở package.json trước. Giả sử trong đó có trường "exports" chỉ khai báo đường dẫn gốc trỏ về `./src/index.js`. Theo tài liệu Node.js, khi có "exports", trường này được ưu tiên hơn "main" và mọi subpath không khai báo đều bị che, nên `src/auth/token.js` không import từ bên ngoài được.

Code không hỏng; bạn chỉ đang gõ vào cửa mà khách đã khóa.

Cũng trong package.json đó, giả sử có `"type": "module"`. Nếu package.json gần nhất không có trường này hoặc ghi "commonjs", mọi file .js đều bị coi là CommonJS. Ở đây thì ngược lại, nên các file dùng `import` chứ không dùng `require`, và script thử nghiệm của bạn phải viết theo cùng kiểu.

Từ `src/index.js`, bạn lần ra route `GET /orders/:id`, handler của nó gọi sang `order-service` mà bạn vừa đọc buổi sáng. Bản trace ghi: "exports" chỉ mở `src/index.js`, route `GET /orders/:id` vào handler, handler gọi `order-service`. Ba dòng, và giờ bạn biết agent nên gọi qua API công khai chứ không chọc vào file nội bộ.

## Với Java, để test dẫn đường qua cổng thanh toán

Cổng thanh toán Java dễ định vị hơn nhờ quy ước của Maven. Ở thư mục gốc có pom.xml, và chỉ có hai thư mục con chính là src và target. Code ứng dụng nằm trong src/main/java, test nằm trong src/test/java, và bên dưới mỗi nơi là cây package.

Với một hệ thống Java lớn, nên đọc test trước. Thử hình dung bạn tìm thấy một lớp test cho dịch vụ thanh toán trong src/test/java, với một ca kiểm tra đơn có số tiền âm và một ca kiểm tra lần gọi cổng ngân hàng thất bại.

Chỉ hai ca test đó đã cho bạn biết hệ thống được kỳ vọng xử lý đầu vào sai và lỗi bên ngoài ra sao.

Tiếp theo, đi theo cùng nhánh package sang src/main/java để mở lớp đang được test, rồi lần ngược lên controller nhận request từ `order-service`. Bản trace ghi: controller nhận yêu cầu thanh toán, chuyển cho dịch vụ thanh toán, dịch vụ gọi cổng ngân hàng, lỗi được xử lý theo đúng ca test kia.

Cách này thường nhanh hơn việc dò qua từng tầng class từ trên xuống.

## Những lỗi biến một buổi sáng thành ba ngày

Lỗi phổ biến nhất là tin rằng phải học xong ngôn ngữ rồi mới được đọc. Bạn chỉ cần đọc hiểu đủ để lần theo một request. Viết code thành thạo bằng Go hay Java là chuyện của tuần sau, nếu dự án thật sự cần.

Lỗi thứ hai là mang đơn vị module của Python sang mọi nơi. Bạn sẽ đi tìm một file trong Go trong khi đáng ra phải tìm cả thư mục. Bạn sẽ bỏ qua "type" và "exports" của Node, rồi kết luận rằng code của khách bị hỏng.

Lỗi thứ ba là đọc mà không ghi lại. Không có bản trace thì sang ngày hôm sau bạn lại phải lần từ đầu. Người của khách cũng không có gì để xác nhận hay sửa giúp bạn.

## Biến kỹ năng này thành bằng chứng khi đi xin việc

Nếu bạn là developer Python ở Việt Nam muốn chuyển sang FDE, khi đọc JD hãy để ý những cụm như "tích hợp với hệ thống sẵn có của khách". Cụm đó có nghĩa là bạn sẽ phải đọc code mà mình không viết, bằng những ngôn ngữ mình không chọn.

Trên CV, đừng viết "biết Go, Java, Node.js". Hãy mô tả một lần bạn đọc service viết bằng ngôn ngữ lạ, lần theo luồng dữ liệu và tích hợp thành công. Bản trace năm dòng chính là thứ đáng mang theo vào vòng phỏng vấn.

Khách sẽ không đánh giá bạn qua việc viết Go có chuẩn hay không. Họ đánh giá bạn qua việc ngay buổi chiều đầu tiên, bạn đã chỉ được dữ liệu của họ đi qua đâu.

**Thử ngay tuần này:**

- Chọn một repo Go mã nguồn mở có HTTP server. Trong 60 phút, viết một bản trace cho một endpoint, từ dòng module trong go.mod tới lệnh gọi database.
- Mở package.json của ba dự án Node trên GitHub. Ghi lại từng dự án có trường "type", "main" hay "exports" không, rồi đoán xem file .js của nó là CommonJS hay ES module.
- Lấy một dự án Spring Boot dùng Maven. Đọc một file test trong src/test/java trước khi đọc code chính, rồi kiểm tra xem test đã giúp bạn hiểu hành vi của hệ thống được bao nhiêu.

## Nguồn

- [What is backend? A comprehensive intro to server-side development](https://alokai.com/blog/what-is-backend)

- [Tutorial: Get started with Go](https://go.dev/doc/tutorial/getting-started)

- [Node.js API: Modules: Packages](https://nodejs.org/docs/latest/api/packages.html)

- [Introduction to the Standard Directory Layout – Apache Maven](https://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html)
