Tại sao nên có một hệ thống xây dựng?

Báo cáo sự cố Xem nguồn

Trang này thảo luận về hệ thống xây dựng là gì, chức năng của hệ thống xây dựng, lý do bạn nên sử dụng hệ thống xây dựng, cũng như lý do vì sao trình biên dịch và tập lệnh bản dựng không phải là lựa chọn tốt nhất khi tổ chức của bạn bắt đầu mở rộng quy mô. API này dành cho các nhà phát triển không có nhiều kinh nghiệm về hệ thống xây dựng.

Hệ thống xây dựng là gì?

Về cơ bản, tất cả các hệ thống xây dựng đều có mục đích đơn giản: chúng chuyển đổi mã nguồn do các kỹ sư viết thành các tệp nhị phân có thể thực thi mà máy có thể đọc được. Hệ thống xây dựng không chỉ dành cho mã do con người tạo; chúng còn cho phép máy móc tự động tạo bản dựng, cho dù là để kiểm thử hay phát hành chính thức. Trong một tổ chức có hàng nghìn kỹ sư, thông thường thì hầu hết các bản dựng đều được kích hoạt tự động thay vì do kỹ sư trực tiếp kích hoạt.

Tôi không thể chỉ sử dụng một trình biên dịch phải không?

Nhu cầu xây dựng một hệ thống xây dựng có thể không rõ ràng ngay lập tức. Hầu hết các kỹ sư đều không sử dụng hệ thống xây dựng trong quá trình học lập trình: hầu hết bắt đầu bằng cách gọi các công cụ như gcc hoặc javac ngay từ dòng lệnh hoặc công cụ tương đương trong môi trường phát triển tích hợp (IDE). Miễn là tất cả mã nguồn đều nằm trong cùng một thư mục, thì bạn sẽ dùng được một lệnh như sau:

javac *.java

Thao tác này sẽ hướng dẫn trình biên dịch Java lấy mọi tệp nguồn Java trong thư mục hiện tại rồi chuyển tệp đó thành tệp lớp nhị phân. Trong trường hợp đơn giản nhất, đây là tất cả những gì bạn cần.

Tuy nhiên, ngay khi mã mở rộng, các chức năng sẽ bắt đầu. javac đủ thông minh để tìm mã cần nhập trong các thư mục con của thư mục hiện tại. Tuy nhiên, công cụ này không có cách nào để tìm mã được lưu trữ trong các phần khác của hệ thống tệp (có thể là thư viện được một số dự án dùng chung). Nó cũng chỉ biết cách tạo mã Java. Hệ thống lớn thường liên quan đến nhiều phần được viết bằng nhiều ngôn ngữ lập trình với mạng lưới các phần phụ thuộc giữa các phần đó, tức là không có trình biên dịch nào cho một ngôn ngữ đơn lẻ có thể xây dựng được toàn bộ hệ thống.

Khi bạn xử lý mã từ nhiều ngôn ngữ hoặc nhiều đơn vị biên dịch, mã tạo bản dựng không còn là quy trình một bước nữa. Bây giờ, bạn phải đánh giá những phần phụ thuộc vào mã và tạo các phần đó theo thứ tự thích hợp, có thể là sử dụng một bộ công cụ khác nhau cho từng phần. Nếu có bất kỳ phần phụ thuộc nào thay đổi, bạn phải lặp lại quy trình này để tránh phụ thuộc vào các tệp nhị phân cũ. Đối với cơ sở mã có kích thước vừa phải, quá trình này nhanh chóng trở nên tẻ nhạt và dễ xảy ra lỗi.

Trình biên dịch cũng không biết gì về cách xử lý các phần phụ thuộc bên ngoài, chẳng hạn như tệp JAR của bên thứ ba trong Java. Nếu không có hệ thống xây dựng, bạn có thể quản lý việc này bằng cách tải phần phụ thuộc xuống từ Internet, dán phần phụ thuộc đó vào thư mục lib trên ổ đĩa cứng và định cấu hình trình biên dịch để đọc các thư viện từ thư mục đó. Theo thời gian, sẽ rất khó để duy trì bản cập nhật, phiên bản và nguồn của các phần phụ thuộc bên ngoài này.

Còn tập lệnh shell thì sao?

Giả sử rằng dự án sở thích của bạn bắt đầu đủ đơn giản để bạn có thể xây dựng dự án đó chỉ bằng một trình biên dịch, nhưng bạn bắt đầu gặp phải một số vấn đề được mô tả trước đó. Có thể bạn vẫn không cho rằng mình cần một hệ thống xây dựng và có thể tự động hoá các phần tẻ nhạt bằng cách sử dụng một số tập lệnh shell đơn giản giúp xây dựng mọi thứ theo đúng thứ tự. Việc này sẽ hữu ích trong một thời gian, nhưng sẽ sớm gặp phải nhiều vấn đề hơn nữa:

  • Việc này trở nên tẻ nhạt. Khi hệ thống của bạn trở nên phức tạp hơn, bạn bắt đầu dành gần như nhiều thời gian để xử lý tập lệnh bản dựng giống như trên mã thực. Việc gỡ lỗi các tập lệnh shell rất khó khăn, vì ngày càng nhiều vụ tấn công được xếp chồng lên nhau.

  • Công cụ này chậm. Để đảm bảo bạn không vô tình phụ thuộc vào các thư viện cũ, tập lệnh bản dựng sẽ tạo mọi phần phụ thuộc theo thứ tự mỗi khi bạn chạy tập lệnh đó. Bạn sẽ cân nhắc việc thêm một số logic để phát hiện những phần cần được tạo lại, nhưng tập lệnh đó nghe có vẻ rất phức tạp và dễ gặp lỗi. Hoặc bạn suy nghĩ về việc chỉ định những phần nào cần được tạo lại mỗi lần, nhưng sau đó, bạn sẽ quay lại hình vuông.

  • Tin vui: đã đến lúc phát hành! Tốt hơn là bạn nên tìm ra tất cả các đối số cần truyền đến lệnh jar để tạo bản dựng cuối cùng. Đồng thời, hãy nhớ cách tải tệp lên và đẩy tệp vào kho lưu trữ trung tâm. Đồng thời, tạo và đẩy các bản cập nhật tài liệu, đồng thời gửi thông báo cho người dùng. Rất tiếc, có thể lệnh này gọi một tập lệnh khác...

  • Thảm hoạ! Ổ đĩa cứng của bạn gặp sự cố và lúc này, bạn cần tạo lại toàn bộ hệ thống. Bạn đủ thông minh để giữ tất cả các tệp nguồn của mình ở chế độ quản lý phiên bản, nhưng còn các thư viện bạn đã tải xuống thì sao? Bạn có thể tìm lại tất cả các tệp đó và đảm bảo các tệp đó có cùng phiên bản với lần đầu tải xuống không? Tập lệnh của bạn có thể phụ thuộc vào các công cụ cụ thể được cài đặt ở những vị trí cụ thể – bạn có thể khôi phục chính môi trường đó để tập lệnh hoạt động lại không? Còn tất cả các biến môi trường mà bạn đã đặt từ lâu để trình biên dịch hoạt động vừa phải nhưng sau đó lại quên mất thì sao?

  • Mặc dù gặp vấn đề, nhưng dự án của bạn đủ thành công để bạn có thể bắt đầu thuê thêm kỹ sư. Bây giờ, bạn nhận ra rằng các vấn đề trước đó không phải là một thảm hoạ – bạn vẫn cần phải thực hiện cùng một quy trình khởi động đau đớn mỗi khi có một nhà phát triển mới tham gia nhóm của bạn. Mặc dù đã nỗ lực hết sức, nhưng hệ thống của mỗi người vẫn có những điểm khác biệt nhỏ. Thông thường, những tính năng hoạt động trên máy của người này lại không hoạt động trên máy của người khác, và mỗi lần phải mất vài giờ đường dẫn công cụ gỡ lỗi hoặc phiên bản thư viện để tìm ra điểm khác biệt.

  • Bạn quyết định rằng mình cần tự động hoá hệ thống xây dựng. Về lý thuyết, việc này đơn giản như mua một máy tính mới và thiết lập để chạy tập lệnh bản dựng mỗi tối bằng cron. Bạn vẫn phải thực hiện quá trình thiết lập đầy khó khăn, nhưng giờ đây, bộ não con người không thể phát hiện và giải quyết các vấn đề nhỏ. Bây giờ, mỗi sáng khi truy cập, bạn sẽ thấy bản dựng tối qua không hoạt động được vì hôm qua, một nhà phát triển đã thực hiện một thay đổi có tác dụng với hệ thống của họ nhưng không hoạt động trên hệ thống xây dựng tự động. Đây là một bản sửa lỗi đơn giản, nhưng thường xảy ra đến mức bạn dành rất nhiều thời gian mỗi ngày để khám phá và áp dụng các bản sửa lỗi đơn giản này.

  • Các bản dựng sẽ càng chậm lại khi dự án tăng lên. Một ngày nọ, trong khi chờ đợi một công trình xây dựng hoàn thành, bạn nhìn thê thiết trước chiếc máy tính để bàn không hoạt động của đồng nghiệp đang đi nghỉ và ước gì có cách nào đó để tận dụng hết sức mạnh tính toán bị lãng phí.

Bạn đã gặp một bài toán kinh điển về quy mô. Đối với một nhà phát triển lập trình tối đa vài trăm dòng mã trong tối đa một hoặc hai tuần (có thể là toàn bộ trải nghiệm của một nhà phát triển cấp dưới mới tốt nghiệp đại học cho đến nay), bạn chỉ cần trình biên dịch là tất cả những gì cần thiết. Tập lệnh có thể đưa bạn xa hơn một chút. Tuy nhiên, ngay khi bạn cần điều phối giữa nhiều nhà phát triển và các máy của họ, thì ngay cả một tập lệnh bản dựng hoàn hảo là chưa đủ vì sẽ rất khó giải quyết những khác biệt nhỏ trong những máy đó. Tại thời điểm này, phương pháp tiếp cận đơn giản này sẽ bị hỏng và đã đến lúc đầu tư vào một hệ thống xây dựng thực tế.