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

Báo cáo vấn đề Xem nguồn Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

Trang này thảo luận về hệ thống xây dựng, 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 trình biên dịch và tập lệnh xây 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ô. Đây là hướng dẫn dành cho những nhà phát triển chưa có nhiều kinh nghiệm với hệ thống bản dựng.

Hệ thống bản dựng là gì?

Về cơ bản, tất cả hệ thống bản dựng đều có một 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 mà còn cho phép các máy móc tự động tạo bản dựng, cho dù là để kiểm thử hay phát hành cho sản xuất. Trong một tổ chức có hàng nghìn kỹ sư, hầu hết các bản dựng thường được kích hoạt tự động thay vì do kỹ sư kích hoạt trực tiếp.

Tôi không thể chỉ dùng trình biên dịch sao?

Nhu cầu về 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 tạo bản dựng trong khi học lập trình: hầu hết đều 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ột môi trường phát triển tích hợp (IDE). Chỉ cần tất cả mã nguồn nằm trong cùng một thư mục, một lệnh như thế này sẽ hoạt động bình thường:

javac *.java

Lệnh này 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à chuyển tệp đó thành tệp lớp nhị phân. Trong trường hợp đơn giản nhất, bạn chỉ cần làm như vậy.

Tuy nhiên, ngay khi mã mở rộng, các vấn đề phức tạp bắt đầu xuất hiện. javac đủ thông minh để tìm trong các thư mục con của thư mục hiện tại nhằm tìm mã để nhập. Nhưng nó 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 được chia sẻ bởi nhiều dự án). Nó 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ữ duy nhất có thể tạo 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, việc tạo mã không còn là một quy trình gồm một bước nữa. Giờ đây, bạn phải đánh giá những gì mà mã của bạn phụ thuộc vào và tạo các phần đó theo đúng thứ tự, có thể sử dụng một bộ công cụ khác 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 một cơ sở mã có kích thước vừa phải, quy 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 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 bản 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, đặt phần phụ thuộc đó vào thư mục lib trên ổ 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, rất khó để duy trì các bản cập nhật, phiên bản và nguồn của những phần phụ thuộc bên ngoài này.

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

Giả sử dự án sở thích của bạn bắt đầu đủ đơ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 nghĩ rằng mình không cần hệ thống bản 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 để xử lý việc tạo các thành phần theo đúng thứ tự. Điều này giúp ích trong một thời gian, nhưng chẳng bao lâu sau, bạn bắt đầu 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 sẽ bắt đầu dành gần như nhiều thời gian để làm việc trên các tập lệnh bản dựng như trên mã thực. Việc gỡ lỗi tập lệnh shell rất khó khăn, ngày càng có nhiều giải pháp được xếp chồng lên nhau.

  • Tốc độ chậm. Để đảm bảo bạn không vô tình dựa vào các thư viện cũ, bạn phải 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 những phần cần được tạo lại, nhưng điều đó có vẻ quá phức tạp và dễ xảy ra lỗi đối với một tập lệnh. Hoặc bạn nghĩ đến việc chỉ định những phần cần được tạo lại mỗi lần, nhưng sau đó bạn lại quay về điểm xuất phát.

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

  • Thảm hoạ! Ổ đĩa cứng của bạn bị hỏng và giờ 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 trong tính năng kiểm soát phiên bản, nhưng còn những thư viện mà 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 rằng chúng là phiên bản giống như khi bạn tải xuống lần đầu không? Có thể các tập lệnh của bạn phụ thuộc vào những công cụ cụ thể được cài đặt ở những vị trí cụ thể. Bạn có thể khôi phục môi trường đó để các tập lệnh hoạt động trở lại không? Còn tất cả các biến môi trường mà bạn đã thiết lập từ lâu để trình biên dịch hoạt động chính xác rồi quên mất thì sao?

  • Bất chấp những vấn đề đó, dự án của bạn vẫn đủ thành công để 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ó thảm hoạ thì các vấn đề trước đây mới xuất hiện – bạn cần phải trải qua quy trình khởi động đầy khó khăn tương tự mỗi khi có một nhà phát triển mới gia nhập nhóm của bạn. Và mặc dù bạn đã nỗ lực hết mình, 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ì những gì hoạt động trên máy của một người sẽ không hoạt động trên máy của người khác, và mỗi lần như vậy, bạ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 nhằm tìm ra điểm khác biệt.

  • Bạn quyết định rằng bạn cần tự động hoá hệ thống bản 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 để 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 phức tạp, nhưng giờ đây, bạn không còn được hưởng lợi từ khả năng phát hiện và giải quyết các vấn đề nhỏ của bộ não con người. Giờ đây, mỗi buổi sáng khi đến nơi, bạn thấy rằng bản dựng tối qua không thành công vì hôm qua, một nhà phát triển đã thực hiện một thay đổi hoạt động trên hệ thống của họ nhưng không hoạt động trên hệ thống tạo tự động. Mỗi lần đều là một lỗi đơn giản, nhưng nó xảy ra thường xuyên đến mức bạn mất rất nhiều thời gian mỗi ngày để phát hiện và áp dụng những 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ờ quá trình tạo bản dựng hoàn tất, bạn buồn bã nhìn vào màn hình máy tính đang ở chế độ chờ của đồng nghiệp (người đang đi nghỉ) và ước rằng có cách nào đó để tận dụng tất cả 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 trên 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ộ kinh nghiệm cho đến nay của một nhà phát triển cấp dưới vừa tốt nghiệp đại học), thì trình biên dịch là tất cả những gì bạn cần. Kịch bản có thể giúp bạn tiến xa hơn một chút. Nhưng ngay khi bạn cần phối hợp với 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ó để giải thích những khác biệt nhỏ trong các máy đó. Đến thời điểm này, phương pháp đơn giản này sẽ không còn hiệu quả và bạn cần đầu tư vào một hệ thống bản dựng thực sự.