Chuyển đến nội dung chính (Skip to content)
Mục lục bài viết
Open Source Essentials

Open Source Essentials 056.1: Công cụ Phát triển

Open Source Essentials 056.1: Công cụ Phát triển

Phân biệt IDE, build, linter, debugger, các loại test và môi trường CI/CD; chạy lab Node để thấy cú pháp hợp lệ vẫn có thể sai hành vi rồi khôi phục.

Một thay đổi JavaScript chạy qua kiểm tra cú pháp nhưng trả sai mã ticket. Người viết tưởng rằng lệnh kiểm tra không báo lỗi nghĩa là chương trình đã đúng. Thực tế, mỗi công cụ chỉ trả lời một nhóm câu hỏi. Muốn chọn bước tiếp theo, cần biết mình đang kiểm tra cấu trúc mã, hành vi, tương tác hay điều kiện vận hành.

Bài 056.1, Công cụ phát triển, tham chiếu Open Source Essentials 050-100 trang in 248–266, biên soạn độc lập và đối chiếu ngày 23/10/2026. Bạn cần biết JavaScript modules và cách chạy lệnh cơ bản từ nhánh Web Development Essentials. Lab được kiểm chứng bằng Node.js 24.22.0, trong container Linux ARM64 không kết nối mạng, chạy bằng người dùng không phải root. Phiên bản tài liệu Node 24 hiện hành có thể mới hơn bản đã chạy lab.

Sau bài học, bạn có thể chọn loại công cụ phù hợp, phân biệt môi trường, giải thích các loại test và đọc kết quả thất bại mà không suy luận quá phạm vi. Bài tập chỉ tạo tệp trong thư mục riêng, không cài dependency, không mở cổng và không triển khai ứng dụng.

Chuỗi công cụ từ source tới chương trình

Trình soạn thảo xử lý văn bản mã nguồn; IDE tích hợp nhiều khả năng như điều hướng, phân tích, build và debug. Các tính năng cụ thể còn phụ thuộc extension, cấu hình và ngôn ngữ. Một giao diện hiện cảnh báo chưa chứng minh rằng mọi kiểm tra cần thiết đã được thực hiện.

Compiler có thể chuyển source sang mã máy hoặc một dạng trung gian. Linker kết hợp các phần cần thiết theo mô hình build. Runtime có thể thông dịch, thực thi bytecode hoặc biên dịch trong quá trình chạy. Không chia ngôn ngữ thành hai nhóm tuyệt đối rồi kết luận mọi trình thông dịch luôn chậm hơn.

Build tool giúp mô tả đầu vào, tùy chọn và thứ tự tạo đầu ra. Khi điều tra lỗi, cần biết artifact được build từ revision nào, dùng phiên bản công cụ và cấu hình nào. Một binary nằm trong thư mục dự án chưa chắc vừa được tạo từ source đang thấy.

Linter, kiểm tra cú pháp và debugger

Linter phân tích mã theo quy tắc, có thể tìm lỗi đáng ngờ hoặc vấn đề nhất quán. Nó khác formatter, vốn chủ yếu điều chỉnh cách trình bày. Kiểm tra cú pháp trả lời mã có được parser chấp nhận không; nó chưa chạy các đường đi của chương trình và chưa xác nhận kết quả đúng.

Debugger hỗ trợ dừng tại breakpoint, xem trạng thái và chạy từng bước. Một số công cụ còn hỗ trợ theo dõi thay đổi giá trị. Dữ liệu thấy được phụ thuộc ngôn ngữ, chế độ build và khả năng công cụ. Khi chụp log hoặc ảnh debug để nhờ hỗ trợ, loại bỏ thông tin riêng và bí mật không cần thiết.

Phân tích tĩnh xem mã mà không thực thi theo cách test động; phân tích động quan sát chương trình đang chạy. Cả hai đều có giới hạn. Không có cảnh báo từ một công cụ chưa đủ chứng minh phần mềm không có lỗi hoặc lỗ hổng.

Refactoring và mã được hỗ trợ tạo

Martin Fowler mô tả refactoring là thay cấu trúc bên trong mà giữ hành vi quan sát được. Nó có thể được làm từng bước nhỏ bằng tay hoặc với công cụ. Không đồng nhất refactoring với sinh mã bằng AI hoặc thêm tính năng mới.

Khi tách hàm hoặc đổi cấu trúc, các kiểm tra hành vi giúp nhận ra thay đổi ngoài ý muốn. Nếu đồng thời thay yêu cầu, cần mô tả riêng phần thay hành vi để reviewer hiểu. Một thao tác tự động trong IDE vẫn cần xem diff và chạy kiểm tra phù hợp.

Kỹ thuật đảo ngược nghiên cứu hành vi hoặc cấu trúc hệ thống; disassembler không khôi phục nguyên bản source cùng tên biến và chú thích. Quyền thực hiện tùy trường hợp cần được xác định trước. Lab này không phân tích phần mềm bên thứ ba hoặc hướng dẫn vượt cơ chế bảo vệ.

Chọn loại test theo câu hỏi

Loại kiểm tra Câu hỏi chính trong một dự án
Unit Một đơn vị hành vi phản ứng ra sao với đầu vào đã chọn?
Integration Các phần phối hợp có đúng hợp đồng không?
Acceptance Kết quả có đáp ứng tiêu chí nhu cầu đã thống nhất không?
Smoke Những hoạt động trọng yếu tối thiểu có chạy được không?
Regression Thay đổi có làm hỏng hành vi đã cần giữ không?
Performance Độ trễ, thông lượng hoặc tài nguyên ra sao trong tải và môi trường xác định?

Các nhãn có thể chồng lên nhau. Một unit test từng bắt lỗi cũng có thể được giữ làm regression test. Acceptance không chỉ dành cho giao diện, còn test integration không tự đồng nghĩa kiểm tra toàn bộ sản phẩm. Ghi đối tượng và phạm vi thay cho việc tranh luận chỉ về tên.

Kiểm tra bảo mật có thể kết hợp review và nhiều công cụ chuyên biệt trong phạm vi được phép. Fuzzing tạo hoặc biến đổi đầu vào theo chiến lược để tìm hành vi bất thường; không chỉ là gửi chuỗi rác bất kỳ. Bài nhập môn này không chạy fuzzing hoặc kiểm thử tải trên dịch vụ công cộng.

Công cụ cần được chọn theo câu hỏi, đầu vào và phạm vi kiểm chứng.
Hình 1. Công cụ cần được chọn theo câu hỏi, đầu vào và phạm vi kiểm chứng. Mở hình để xem chi tiết.

Dev, staging, production và CI/CD

Môi trường development phục vụ phát triển; staging dùng để đánh giá trước khi đưa thay đổi thật; production phục vụ công việc hoặc người dùng thật. Staging có ích khi đủ giống ở những yếu tố đang cần kiểm tra, nhưng không bảo đảm giống hoàn toàn. Dùng dữ liệu giả hoặc được xử lý phù hợp và giữ thông tin xác thực riêng theo môi trường.

CI đưa các thay đổi được tích hợp thường xuyên qua những kiểm tra tự động có phản hồi rõ. Có pipeline chưa đủ nếu lỗi bị bỏ qua hoặc kết quả không gắn với revision. DORA giải thích continuous delivery hướng tới khả năng cung cấp theo nhu cầu, khác với tự động deployment mọi thay đổi đạt điều kiện.

Một pipeline có thể có nhánh, công việc song song và bước phê duyệt. Cần biết bước nào chặn phát hành, artifact nào được chuyển tiếp và quyền của từng bước. Không gắn mọi credential production cho mọi job chỉ để tiện; lab hiện tại chưa tạo pipeline CI trên dịch vụ nào.

Lab: cú pháp đúng nhưng hành vi sai

Bước 1: tạo hàm nhỏ

Trong một thư mục học riêng, tạo ticket.mjs. Các lệnh sau chỉ dùng module tích hợp của Node; nếu máy chưa có Node, dùng môi trường lab đã chuẩn bị, không chạy lệnh cài từ nguồn lạ.

export function normalizeTicketId(value) {
  if (typeof value !== 'string') throw new TypeError('ID must be text');
  const id = value.trim().toUpperCase();
  if (!/^HD-[0-9]+$/.test(id)) throw new Error('Invalid ID');
  return id;
}

Hợp đồng DEMO nhận chuỗi, bỏ khoảng trắng đầu cuối, chuyển chữ hoa rồi yêu cầu dạng HD- kèm chữ số. Đây là quy tắc bài tập, không phải chuẩn mã ticket cho mọi hệ thống. Nó không kiểm tra ticket có tồn tại hoặc người gọi có quyền xem không.

Bước 2: viết kiểm tra hành vi

Tạo ticket.test.mjs cạnh tệp trên. Node có test runner tích hợp, nên ví dụ không cần framework tải thêm.

import test from 'node:test';
import assert from 'node:assert/strict';
import { normalizeTicketId } from './ticket.mjs';
test('normalizes spaces and case', () => {
  assert.equal(normalizeTicketId(' hd-7 '), 'HD-7');
});
test('rejects invalid inputs', () => {
  assert.throws(() => normalizeTicketId(7), TypeError);
  assert.throws(() => normalizeTicketId('bad'));
});

Test đầu xác nhận một kết quả có ích; test sau kiểm tra hai dạng đầu vào không hợp lệ. Các trường hợp được chọn chưa bao phủ mọi chuỗi, giới hạn độ dài hoặc yêu cầu bảo mật. Kết quả pass cần được đọc theo đúng hợp đồng này.

Bước 3: chạy hai loại kiểm tra

node --version
node --check ticket.mjs
node --test ticket.test.mjs

Trên môi trường đã nêu, kiểm tra cú pháp thành công và hai test pass. Nếu import không tìm được module, kiểm tra vị trí tệp, tên và phần mở rộng trước khi sửa hàm. Nếu test runner báo lỗi khác, giữ thông báo và phiên bản để xác định nguyên nhân.

Không dùng việc lệnh --check im lặng làm bằng chứng test đã chạy. Lệnh đầu kiểm tra phiên bản, lệnh thứ hai kiểm tra cú pháp, lệnh thứ ba mới chạy bài test. Ghi ba kết quả riêng giúp người khác đọc hồ sơ dễ hơn.

Bước 4: tạo regression có kiểm soát

Trong bản sao học tập, bỏ .toUpperCase() rồi chạy lại hai lệnh kiểm tra. Cú pháp vẫn hợp lệ nhưng test với ' hd-7 ' thất bại vì chuỗi sau trim còn chữ thường và không khớp mẫu. Test kiểm tra đầu vào sai vẫn pass.

Đây là lỗi chủ động tạo để học, không cần sửa test cho xanh. Khôi phục .toUpperCase() và chạy lại; hai test pass trở lại. Quy trình đã được chạy thực tế trên fixture ở môi trường trên, chưa kiểm thử giao diện, API, tải hoặc hệ thống production.

Fixture Node 24.22.0 cho thấy lỗi hành vi được test bắt dù kiểm tra cú pháp vẫn đạt.
Hình 2. Fixture Node 24.22.0 cho thấy lỗi hành vi được test bắt dù kiểm tra cú pháp vẫn đạt. Mở hình để xem chi tiết.

Đọc kết quả và tự kiểm tra

Khi test thất bại, đọc đầu vào, kết quả mong đợi và lỗi thực tế. Xác nhận test có phản ánh đúng yêu cầu trước khi sửa code. Nếu yêu cầu thay đổi, cần giải thích thay đổi hợp đồng và cập nhật bằng chứng; không sửa assertion chỉ để bỏ cảnh báo.

Nếu kiểm tra cú pháp pass nhưng test fail, hai công cụ có mâu thuẫn không? Không, chúng trả lời câu hỏi khác nhau. Hai test pass có chứng minh hàm an toàn cho production không? Chưa. Refactoring có phải thêm chức năng không? Mục tiêu của nó là giữ hành vi trong khi cải thiện cấu trúc.

Đội Help Desk không cần thành chuyên gia mọi công cụ để gửi báo cáo có ích. Phiên bản, bước tái hiện, kết quả và giới hạn đã biết giúp đội phát triển tìm đúng lớp vấn đề. Tránh gửi toàn bộ dữ liệu thật khi một fixture nhỏ có thể diễn đạt được lỗi.

Nguồn tham khảo

Khung mục tiêu: LPI Open Source Essentials 056.1. Node test runner, Refactoring và DORA được dẫn trực tiếp tại phần liên quan. Mã và test DEMO được biên soạn độc lập; kết quả chỉ áp dụng fixture đã mô tả.

Bài liên quan trong bộ LPI

Tìm hiểu thêm