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ô. Tài liệu này dành cho những 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ả hệ thống xây dựng đều có một mục đích đơn giản: chuyển đổi mã nguồn do kỹ sư viết thành tệp nhị phân có thể thực thi mà máy có thể đọc. Hệ thống xây dựng không chỉ dành cho mã do con người tạo; mà còn cho phép máy tự động tạo bản dựng, cho dù là để kiểm thử hay phát hành công khai. Trong một tổ chức có hàng nghìn kỹ sư, thông thường, 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?
Bạn có thể không nhận ra ngay nhu cầu về một hệ thống xây dựng. Hầu hết các kỹ sư không sử dụng hệ thống xây dựng trong khi 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
trực tiếp từ dòng lệnh hoặc tương đương trong môi trường phát triển tích hợp (IDE). Chỉ cần tất cả mã nguồn đều nằm trong cùng một thư mục, thì lệnh như sau sẽ hoạt động tốt:
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 và biế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 trong các thư mục con của thư mục hiện tại để tìm mã cần nhập. Nhưng trình tìm kiếm không có cách nào tìm thấy mã được lưu trữ trong các phần khác của hệ thống tệp (có thể là một thư viện do nhiều dự án chia sẻ). Công cụ này cũng chỉ biết cách tạo mã Java. Các hệ thống lớn thường bao gồm 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 đó, nghĩa là không có trình biên dịch nào cho một ngôn ngữ có thể tạo ra 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ể sử dụng một bộ công cụ khác nhau cho từng phần. Nếu có 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 trung bình, quá trình này nhanh chóng trở nên tẻ nhạt và dễ gặp 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, gắ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, bạn sẽ khó duy trì các 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ử dự án mà bạn làm theo sở thích bắt đầu khá đơn giản để bạn có thể tạo 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 đề đã 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ự. Điều này giúp ích trong một thời gian, nhưng chẳng bao lâu bạn sẽ bắt đầu gặp phải nhiều vấn đề hơn:
Việc này trở nên tẻ nhạt. Khi hệ thống 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 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.
Chạy chậm. Để đảm bảo bạn không vô tình dựa vào các thư viện cũ, bạn có tập lệnh bản dựng tạo mọi phần phụ thuộc theo thứ tự mỗi khi chạy tập lệnh đó. Bạn nghĩ đến việc thêm một số logic để phát hiện phần nào cần được tạo lại, nhưng điều đó nghe có vẻ phức tạp và dễ xảy ra lỗi đối với một tập lệnh. 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 là đã đến lúc phát hành! Tốt hơn hết, bạn nên tìm hiểu tất cả đối số mà bạn cần truyền vào lệnh jar để tạo bản dựng cuối cùng. Và hãy nhớ cách tải lên và đẩy tệp đó vào kho lưu trữ trung tâm. Đồng thời, hãy tạo và đẩy nội dung cập nhật tài liệu cũng như gửi thông báo cho người dùng. Hmm, có lẽ cần phải có một tập lệnh khác...
Thảm hoạ! Ổ đĩa cứng của bạn gặp sự cố và giờ đây, bạn cần tạo lại toàn bộ hệ thống. Bạn đã đủ thông minh để giữ tất cả tệp nguồn của mình trong chế độ kiểm soát phiên bản, nhưng còn những 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 đúng cách nhưng sau đó lại quên mất?
Mặc dù gặp vấn đề, nhưng dự án của bạn đã thành công đến mức bạn có thể bắt đầu tuyển dụng thêm kỹ sư. Giờ đây, bạn nhận ra rằng không cần phải có sự cố nào xảy ra thì các vấn đề trước đó mới phát sinh. Bạn cần phải trải qua 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 gia nhập nhóm. 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 gì hoạt động trên máy của người này sẽ không hoạt động trên máy của người khác, và mỗi lần sẽ mất vài giờ để gỡ lỗi đường dẫn công cụ hoặc phiên bản thư viện để tìm ra sự khác biệt.
Bạn quyết đị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ư việc mua một máy tính mới và thiết lập máy tính đó để chạy tập lệnh bản dựng mỗi đêm bằng cron. Bạn vẫn cần phải trải qua quy trình thiết lập rườm rà, nhưng giờ đây, bạn không có lợi ích của bộ não con người có 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 để tìm hiểu và áp dụng các bản sửa lỗi đơn giản này.
Các bản dựng ngày càng chậm hơn khi dự án phát triể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ê thảm 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 phải một vấn đề kinh điển về quy mô. Đối với một nhà phát triển làm việc với 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ể giúp bạn làm được nhiều việc 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à máy của họ, ngay cả một tập lệnh bản dựng hoàn hảo cũng không đủ vì rất khó để tính đến những khác biệt nhỏ trong các máy đó. Tại thời điểm này, cách 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ế.