# Debug ngoài hiện trường: một ca giả định về tàu tự hành lệch hướng khi vào bến

> Ngoài biển, lỗi chỉ xuất hiện một lần và đường truyền thì chậm. Vì vậy việc đầu tiên là ghi lại đủ dữ liệu để sau này tái hiện được lỗi trên máy ở văn phòng, còn sửa thì để sau.

Bản gốc: https://fdetimes.net/vi/bach-khoa/debug-hien-truong-he-thong-tu-hanh/

Thử hình dung: một con tàu không người lái chạy đúng hải trình suốt buổi sáng ngoài khơi. Đến chiều, lúc vào bến, nó bắt đầu lệch hướng, tự chỉnh lại, rồi lại lệch. Bạn mang log về văn phòng chạy lại thì mọi thứ đều đúng.

Xử lý kiểu lỗi này nằm ngay trong mô tả công việc của FDE làm hệ thống tự hành. Saronic, công ty làm tàu mặt nước tự hành, mô tả FDE của họ là người tích hợp, triển khai và cải tiến hệ thống tự hành trong môi trường thực tế.

Theo mô tả công việc, FDE phải xử lý cùng lúc sự cố phần mềm, phần cứng và mạng trong quá trình triển khai. Họ cũng dành từ 50% thời gian trở lên để đi công tác trong nước và quốc tế.

Có thể bạn sẽ không bao giờ phải lên tàu. Nhưng gần như FDE nào cũng từng gặp lỗi chỉ xảy ra ở chỗ khách hàng: không gắn được debugger, mạng chậm, và không ai tái hiện lại đúng khoảnh khắc đó cho bạn xem. Biển là phiên bản khắc nghiệt nhất của bài toán này, nên cũng là nơi học nó rõ nhất.

## Ngoài hiện trường, cái khó là tái hiện được lỗi

Một khoảnh khắc ngoài biển chỉ xảy ra một lần. Sóng, gió, tàu bè xung quanh và tín hiệu vệ tinh lúc đó sẽ không bao giờ lặp lại y hệt. Nếu sửa vội tại chỗ mà không ghi lại gì, bạn không chứng minh được bản sửa đúng, và khi lỗi quay lại bạn cũng không nhận ra nó.

Ở Saronic, vị trí lập kế hoạch thử nghiệm trên biển theo dõi lỗi bằng một quy trình có cấu trúc, ghi lại bước tái hiện, mức độ nghiêm trọng và hành động khắc phục cho từng lỗi. Nguyên tắc nên rút ra cho chính bạn: chưa tái hiện được thì chưa có gì chắc chắn để đem đi sửa.

Muốn tái hiện được thì phải có dữ liệu. Saronic cho biết đợt thử nghiệm độ bền của tàu Corsair tạo ra khoảng 500 giờ video từ nhiều camera, tổng cộng khoảng 17 TB.

Công ty nói sẽ dùng bộ dữ liệu này để phát triển model, chạy replay và regression testing. Đợt thử được thiết kế để chạy liên tục nhằm đánh giá độ tin cậy và sức bền, tức là để lộ ra những lỗi mà các bài test ngắn bỏ sót.

## Đường truyền chậm buộc bạn chọn gửi gì về

Một nghiên cứu về tàu tự hành chỉ ra rằng khi ra biển, tàu bị giới hạn bởi đường truyền vệ tinh băng thông thấp. Không ai stream được 17 TB qua đường truyền như vậy. Vì thế bạn cần tách hai việc: ghi đầy đủ ngay trên máy của tàu, và chỉ gửi về bờ đủ thông tin để người trên bờ biết có chuyện.

Dưới đây là bản phác đơn giản cho ý tưởng đó. Ngưỡng, thời gian cooldown và tên trường chỉ là ví dụ:

```python
import collections, json, time

def send_over_satlink(msg):
    """Stub: thay bằng client vệ tinh thật, có hàng đợi và giới hạn kích thước."""
    payload = json.dumps(msg).encode()
    assert len(payload) < 512, "bản tóm tắt phải nhỏ"
    print("SATLINK", payload)

class FieldRecorder:
    """Ghi đầy đủ trên máy tại chỗ, chỉ gửi tóm tắt qua đường truyền chậm."""
    def __init__(self, window_s=120, rate_hz=50, cooldown_s=60):
        self.buf = collections.deque(maxlen=window_s * rate_hz)
        self.cooldown_s = cooldown_s
        self.last_snap = {}  # reason -> thời điểm chụp gần nhất

    def record(self, s):  # s: dict gồm t, heading_err_deg, gps_fix, link_ok, sw_version
        self.buf.append(s)
        if abs(s["heading_err_deg"]) > 5:
            self.maybe_snapshot("heading_error")

    def maybe_snapshot(self, reason):
        now = time.monotonic()
        if now - self.last_snap.get(reason, float("-inf")) < self.cooldown_s:
            return  # vẫn là đợt lệch hướng cũ, không chụp thêm
        self.last_snap[reason] = now
        path = f"/data/snap_{int(time.time())}_{reason}.jsonl"
        with open(path, "w") as f:
            for s in self.buf:
                f.write(json.dumps(s) + "\n")
        # Chỉ vài trăm byte đi qua vệ tinh, file đầy đủ ở lại trên tàu
        send_over_satlink({"reason": reason, "file": path, "n": len(self.buf)})
```

Điểm mấu chốt là bộ đệm vòng (ring buffer): khi phát hiện bất thường, bạn có sẵn dữ liệu hai phút trước đó, tức phần dẫn tới lỗi. Cooldown cũng quan trọng không kém. Nếu thiếu nó, một lần lệch hướng kéo dài vài phút sẽ sinh ra hàng nghìn snapshot, làm đầy ổ đĩa và nghẽn đường truyền vệ tinh.

Ngoài ra, hãy ghi trạng thái của cả ba tầng vào cùng một bản ghi: phiên bản phần mềm, trạng thái GPS và trạng thái đường truyền. Có vậy, lúc khoanh vùng lỗi bạn mới có bằng chứng trong tay.

## Ví dụ: lỗi lệch hướng khi vào bến

Quay lại con tàu ở đầu bài. Đây là tình huống minh họa để luyện cách làm, không phải một sự cố Saronic đã công bố. Trên giấy có ba nhóm giả thuyết: logic điều hướng xử lý sai một tình huống chỉ gặp gần bờ, một cảm biến cho số liệu khác đi trong môi trường bến cảng, hoặc mất kết nối khiến hệ thống chuyển chế độ.

Với tầng định vị, giả thuyết này có cơ sở. Nghiên cứu về tàu tự hành cảnh báo rằng khi GPS mất tín hiệu, bị gây nhiễu (jamming) hoặc bị giả mạo (spoofing), một con tàu không có thủy thủ có thể rơi vào tình huống nguy hiểm. Vì thế trường `gps_fix` trong bản ghi rất quan trọng.

Phép thử quyết định là replay. Bạn đưa đúng snapshot đã ghi vào stack điều hướng trên máy ở văn phòng. Nếu tàu ảo cũng lệch hướng y như ngoài biển, lỗi nằm trong logic, và bạn đã có một test case để sửa.

Nếu replay ra kết quả hoàn hảo thì có hai khả năng. Khả năng đầu là dữ liệu bạn đưa vào khác thứ hệ thống thật sự nhận được ngoài biển, nên hãy nghi timing, phần cứng hoặc mạng.

Khả năng còn lại là stack không tất định: thứ tự luồng, độ trễ xử lý hay một bước ngẫu nhiên có thể khiến cùng một đầu vào cho ra kết quả khác nhau.

Vì vậy, hãy chạy replay nhiều lần, cố định seed và dùng đồng hồ mô phỏng. Nếu kết quả dao động giữa các lần chạy, hãy sửa tính tất định của stack trước rồi mới kết luận về phần cứng.

Kết quả được ghi vào phiếu lỗi như sau:

| Trường | Cách ghi cho lỗi lệch hướng |
|---|---|
| Hiện tượng | Sai lệch hướng vượt ngưỡng, lặp lại nhiều lần khi tiến vào bến |
| Điều kiện | Thời điểm, vị trí, trạng thái GPS, trạng thái đường truyền, phiên bản phần mềm |
| Bước tái hiện | Replay một snapshot cụ thể, ghi số lần chạy và số lần ra lỗi |
| Mức độ | Có ảnh hưởng tới an toàn vận hành không |
| Tầng nghi ngờ | Phần mềm, phần cứng hay mạng, kèm bằng chứng từ replay |
| Hành động khắc phục | Bản sửa, cùng một regression test dựng từ chính snapshot này |

Dòng cuối là chỗ nhiều người bỏ qua. Snapshot gây ra lỗi nên trở thành một test vĩnh viễn, để đợt thử nghiệm sau không phải đi tìm lại lỗi cũ ngoài biển.

## Chủ động gây lỗi trước khi môi trường thật gây ra

Cách tốt nhất để không bị bất ngờ ngoài biển là tự gây lỗi trong một đợt thử có kiểm soát. Năm 2013, trong một đợt thử ngoài biển, người ta cố ý gây nhiễu GPS và một hệ thống nguyên mẫu đã tự động chuyển sang eLoran.

Bài thử đó nhắm vào hệ thống định vị chứ không phải một con tàu tự hành, nhưng cách làm thì áp dụng được nguyên vẹn.

Một đợt trình diễn khả năng tự hành gần đây có cả bài phản ứng khẩn cấp với sự cố máy móc giả lập, trong khi con tàu được giám sát từ xa trên bờ.

Những bài thử như vậy chỉ có giá trị khi tiêu chí được đặt từ trước. Saronic tổ chức thử nghiệm quanh các ma trận thử nghiệm (test matrix), trong đó mỗi yêu cầu gắn với một tiêu chí đạt hay không đạt khách quan.

"Fallback chạy ổn" chỉ là một cảm nhận. Còn "mất GPS thì chuyển sang hệ dự phòng mà không vượt sai lệch cho phép" mới là tiêu chí kiểm tra được.

Rồi còn chuyện an toàn. Ở Saronic, người chỉ huy thử nghiệm tại hiện trường điều hành việc chạy thử theo thời gian thực và chịu trách nhiệm về an toàn của bài thử. Muốn gây lỗi có chủ đích, bạn phải thống nhất trước với người đó, không ai được tự ý ngắt một hệ thống đang chạy.

## Những sai lầm hay gặp

Sai lầm phổ biến nhất là chỉ debug ở tầng mình quen. Kỹ sư phần mềm lao vào đọc code trong khi bằng chứng đang chỉ về phía ăng-ten hoặc đường truyền. Mô tả công việc FDE gộp phần mềm, phần cứng và mạng vào chung một dòng cũng vì lẽ đó.

Sai lầm thứ hai là cố gửi mọi thứ về qua đường truyền chậm, làm nghẽn đúng lúc cần nó nhất. Thứ ba là sửa ngay tại chỗ mà không lưu snapshot, nên không bao giờ chứng minh được bản sửa đúng. Thứ tư là thử nghiệm khi chưa có tiêu chí đạt hay không đạt, để rồi sau đó cãi nhau xem kết quả có tốt không.

## Rút ngắn vòng lặp giữa hiện trường và code

Người lập kế hoạch thử nghiệm ở Saronic làm việc hằng ngày với đội phần mềm, đội vận hành tàu và các nhà cung cấp để nhanh chóng xử lý dứt điểm từng vấn đề. Phiếu lỗi tốt giúp vòng lặp này chạy: người ở văn phòng nhận được snapshot và bước tái hiện, nên không cần ra hiện trường mới hiểu chuyện gì đã xảy ra.

Về nghề nghiệp, khi đọc tin tuyển FDE, hãy để ý những cụm như "software, hardware, and networking" hay "real-world environments": đó là dấu hiệu công việc đòi hỏi debug ngoài hiện trường. Trong CV, đừng chỉ viết "xử lý sự cố production".

Hãy kể một lỗi cụ thể: bạn đã ghi dữ liệu thế nào, tái hiện ra sao, khoanh vùng ở tầng nào và biến nó thành regression test gì. Khi phỏng vấn, một câu chuyện như vậy thuyết phục hơn nhiều so với một danh sách công cụ.

Biển không cho bạn lần thử thứ hai. Kỹ sư giỏi là người mang được khoảnh khắc lỗi duy nhất đó về văn phòng và chạy lại bao nhiêu lần cũng được.

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

- Chọn một lỗi production cũ của bạn và viết lại thành phiếu lỗi có đủ sáu trường: hiện tượng, điều kiện, bước tái hiện, mức độ, tầng nghi ngờ, hành động khắc phục.
- Thêm một ring buffer có cooldown vào một service bạn phụ trách: khi gặp bất thường, service tự lưu 2 phút dữ liệu gần nhất ra file và chỉ gửi về một thông báo ngắn.
- Cố ý ngắt mạng hoặc tắt một dependency trên staging, rồi đối chiếu cách hệ thống fallback với tiêu chí đạt/không đạt bạn đã đặt từ trước.

## Nguồn

- [Senior Forward Deployed Engineer (Saronic Technologies)](https://jobs.8vc.com/companies/saronic-technologies-2/jobs/59439558-senior-forward-deployed-engineer)

- [Autonomous Sea Trials Test Planner (Saronic Technologies)](https://jobs.generalcatalyst.com/companies/saronic-technologies-2/jobs/81666065-autonomous-sea-trials-test-planner)

- [Saronic runs endurance trials on Corsair ASV for Navy program](https://www.workboat.com/saronic-runs-endurance-trials-on-corsair-asv-for-navy-program)

- [VR Teleoperation to support a GPS-free Positioning System in a Marine Environment](https://www.transnav.eu/html,1061.html)

- [Successful trial of automatic GPS backup](https://thedigitalship.com/news/electronics-navigation/successful-trial-of-automatic-gps-backup)

- [368-ton ex-US Navy vessel shows off advanced autonomy in high-stakes sea trials](https://interestingengineering.com/military/368-ton-ex-us-navy-vessel-tests-autonomy)
