Làm thế nào để đối phó với vấn đề (biên dịch) một cơ sở mã lớn?


10

Mặc dù tôi có thể viết mã, tôi chưa có kinh nghiệm làm việc trong các dự án lớn. Những gì tôi đã làm cho đến nay là mã hóa các chương trình nhỏ được biên dịch trong vài giây (các bài tập c / c ++ khác nhau như thuật toán, nguyên tắc lập trình, ý tưởng, mô hình hoặc chỉ thử dùng api ...) hoặc làm việc trên một số dự án nhỏ hơn được thực hiện bằng ngôn ngữ kịch bản (python, php, js) trong đó không cần biên dịch.

Vấn đề là, khi mã hóa bằng ngôn ngữ kịch bản, bất cứ khi nào tôi muốn thử nếu có gì đó hoạt động - tôi chỉ cần chạy tập lệnh và xem điều gì sẽ xảy ra. Nếu mọi thứ không hoạt động, tôi chỉ cần thay đổi mã và thử lại bằng cách chạy lại tập lệnh và tiếp tục làm điều đó cho đến khi tôi nhận được kết quả mà tôi muốn .. Quan điểm của tôi là bạn không phải chờ đợi bất cứ điều gì để biên dịch và do đó khá dễ dàng để có một cơ sở mã lớn, sửa đổi nó, thêm một cái gì đó vào nó hoặc đơn giản là chơi với nó - bạn có thể thấy các thay đổi ngay lập tức.

Để làm ví dụ tôi sẽ lấy Wordpress. Nó khá dễ dàng để thử và tìm ra cách tạo một plugin cho nó. Trước tiên, bạn bắt đầu bằng cách tạo một plugin "Hello World" đơn giản, sau đó bạn tạo một giao diện đơn giản cho bảng quản trị để làm quen với API, sau đó bạn xây dựng nó và làm cho một cái gì đó phức tạp hơn, đồng thời thay đổi giao diện của nó lần .. Ý tưởng phải biên dịch lại thứ gì đó lớn như WP hết lần này đến lần khác, sau mỗi thay đổi nhỏ để thử "nếu nó hoạt động" và "cách nó hoạt động / cảm thấy" có vẻ không hiệu quả, chậm và sai.

Bây giờ, làm thế nào tôi có thể làm điều đó với một dự án được viết bằng ngôn ngữ biên dịch? Tôi muốn đóng góp cho một số dự án nguồn mở và câu hỏi này cứ làm tôi khó chịu. Tình huống có thể khác nhau từ dự án này đến dự án khác, trong đó một số trong số chúng được cho là khôn ngoan sẽ được "mô-đun" theo một cách nào đó trong khi những cái khác sẽ chỉ là một đốm lớn cần được biên dịch lại nhiều lần.

Tôi muốn biết thêm về cách thực hiện đúng. Một số thực tiễn phổ biến, cách tiếp cận và thiết kế dự án (mẫu?) Để đối phó với điều này là gì? Làm thế nào "mô-đun" này được gọi trong thế giới lập trình viên và tôi nên google để tìm hiểu thêm về điều này? Có phải thường các dự án phát triển ra khỏi tỷ lệ suy nghĩ đầu tiên của họ sẽ trở nên rắc rối sau một thời gian? Có cách nào để tránh biên dịch dài các dự án được thiết kế không tốt? Một cách nào đó để mô đun hóa chúng (có thể loại trừ các phần không quan trọng của chương trình trong khi phát triển (có ý tưởng nào khác không?))?

Cảm ơn.


4
Ob XKCDáo phông thinkgeek có liên quan * 8 ')
Mark booth

1
Nếu bạn làm việc trong một dự án đủ lớn với ngân sách đủ lớn, bạn có thể nhận các máy chủ xây dựng để biên dịch cho bạn :)
SoylentGray

@Chad - Tôi biết điều đó, nhưng hiện tại nó chỉ là máy tính để bàn gnu / linux của tôi và tôi :)
pootzko

@Chad Ok, vậy bạn đang nói với chúng tôi rằng chúng tôi cần các máy chủ chuyên dụng để đối phó với hàng loạt ngôn ngữ được biên dịch của Java (hoặc bất kỳ ngôn ngữ được biên dịch nào khác)? Đó hoàn toàn là chuyện tào lao
Kolob Canyon

1
@KolobCanyon - Không tôi đang nói có một quy mô bạn có thể làm việc ở đó sẽ yêu cầu họ. và rằng bây giờ chúng đủ rẻ để có một VM theo yêu cầu dành riêng cho việc biên dịch nhanh và tự động kiểm tra là đủ dễ dàng để quy mô không lớn.
SoylentGray

Câu trả lời:


8

Giống như đã nói, bạn không bao giờ biên dịch lại toàn bộ dự án mỗi khi bạn thực hiện một thay đổi nhỏ. Thay vào đó, bạn chỉ biên dịch lại phần mã đã thay đổi, cũng như tất cả mã tùy thuộc vào nó.

Trong C / C ++, việc biên dịch khá đơn giản. Bạn biên dịch dịch từng tệp nguồn thành mã máy (chúng tôi gọi chúng là tệp đối tượng * .o) và sau đó bạn liên kết tất cả các tệp đối tượng của mình thành một tệp thực thi lớn.

Giống như MainMa đã đề cập, một số thư viện được tích hợp vào các tệp riêng biệt, sẽ được liên kết động trong thời gian chạy với tệp thực thi. Các thư viện này được gọi là Đối tượng chia sẻ (* .so) trong Unix và Thư viện được liên kết động (DLL) trong Windows. Thư viện động có nhiều ưu điểm, một trong số đó là bạn không cần phải biên dịch / liên kết chúng, trừ khi mã nguồn của chúng thay đổi một cách hiệu quả.

Có các công cụ tự động hóa xây dựng giúp bạn:

  • Chỉ định các phụ thuộc giữa các phần khác nhau của cây nguồn của bạn.
  • Khởi chạy đúng giờ, các phần tổng hợp kín đáo chỉ trong phần đã được sửa đổi.

Những phần nổi tiếng nhất (make, ant, maven, ...) có thể tự động phát hiện phần nào của mã đã được thay đổi kể từ lần biên dịch cuối cùng và chính xác những gì đối tượng / nhị phân cần được cập nhật.

Tuy nhiên, điều này có chi phí (tương đối nhỏ) khi phải viết một "tập lệnh xây dựng". Đó là một tệp chứa tất cả thông tin về bản dựng của bạn, như xác định mục tiêu và phần phụ thuộc của chúng, xác định trình biên dịch bạn muốn và tùy chọn nào sẽ sử dụng, xác định môi trường xây dựng, đường dẫn thư viện của bạn, ... Bạn có thể nghe về Makefiles (rất phổ biến trong thế giới Unix) hoặc build.xml (rất phổ biến trong thế giới Java). Đây là những gì họ làm.


2
Ant (Java) không thể xác định những gì cần biên dịch lại. Nó xử lý phần tầm thường của công việc, biên dịch lại mã nguồn đã thay đổi, nhưng hoàn toàn không hiểu phụ thuộc lớp. Chúng tôi dựa vào IDE cho điều đó và chúng sẽ sai nếu chữ ký phương thức được thay đổi theo cách không yêu cầu thay đổi mã gọi.
kevin cline

@kevincline Tôi thứ hai này - ANT biên dịch mọi thứ trừ khi bạn chỉ định một cái gì đó khác trong build.xmltệp
Kolob Canyon

7

Bạn không biên dịch lại toàn bộ dự án mỗi lần. Ví dụ: nếu đó là ứng dụng C / C ++, có khả năng nó sẽ được tách thành các thư viện (DLL trong Windows), mỗi thư viện được biên dịch riêng.

Bản thân dự án thường được biên dịch hàng ngày trên một máy chủ chuyên dụng: đó là những bản dựng hàng đêm. Quá trình này có thể mất một lượng lớn thời gian, bởi vì nó không chỉ bao gồm thời gian biên dịch, mà còn bao gồm cả thời gian chạy các bài kiểm tra đơn vị, các bài kiểm tra khác và các quy trình khác.


3
Nếu tôi không biên dịch lại tất cả thì khi nào tôi sẽ có thời gian chơi với Trebuchet
SoylentGray

5

Tôi nghĩ rằng tất cả các câu trả lời cho đến nay cũng đã được ám chỉ, đó là các dự án phần mềm lớn hầu như luôn được chia thành các phần nhỏ hơn nhiều. Mỗi phần thường được lưu trữ trong tập tin riêng của nó.

Những mảnh này được biên dịch riêng để tạo đối tượng. Các đối tượng sau đó được liên kết với nhau để tạo thành sản phẩm cuối cùng. [Theo một cách nào đó, nó giống như việc xây dựng những thứ từ Legos. Bạn không cố gắng tạo ra thứ cuối cùng từ một miếng nhựa lớn, thay vào đó bạn kết hợp một loạt các mảnh nhỏ hơn để tạo ra nó.]

Chia dự án thành các phần được biên dịch riêng lẻ cho phép một số điều gọn gàng xảy ra.

Tòa nhà tăng dần

Trước hết, khi bạn thay đổi một mảnh, bạn thường không phải biên dịch lại tất cả các mảnh. Nói chung, miễn là bạn không thay đổi cách các phần khác tương tác với tác phẩm của mình, những phần khác không cần phải biên dịch lại.

Điều này dẫn đến ý tưởng xây dựng gia tăng . Khi thực hiện xây dựng gia tăng, chỉ những phần bị ảnh hưởng bởi thay đổi mới được biên dịch lại. Điều này làm tăng đáng kể thời gian phát triển. Thật vậy, bạn có thể vẫn phải chờ đợi mọi thứ được phát lại, nhưng đó vẫn là một khoản tiết kiệm so với việc phải biên dịch lại và xem lại mọi thứ. (BTW: Một số hệ thống / ngôn ngữ hỗ trợ liên kết gia tăng để chỉ những thứ đã thay đổi phải được xem lại. Chi phí cho việc này thường là ở hiệu suất và kích thước mã kém.)

Kiểm tra đơn vị

Điều thứ hai mà việc có các mảnh nhỏ cho phép bạn làm là xem xét riêng từng mảnh trước khi chúng được kết hợp. Điều này được gọi là thử nghiệm đơn vị . Trong Kiểm thử đơn vị, mỗi đơn vị được kiểm tra riêng trước khi được tích hợp (kết hợp) với phần còn lại của hệ thống. Các bài kiểm tra đơn vị thường được viết để chúng có thể được chạy nhanh mà không liên quan đến phần còn lại của hệ thống.

Trường hợp giới hạn của việc áp dụng thử nghiệm được thấy trong Phát triển hướng thử nghiệm (TDD). Trong mô hình phát triển này, không có mã nào được viết / sửa đổi trừ khi nó là để sửa lỗi thử nghiệm thất bại.

Làm cho nó dễ dàng hơn

Vì vậy, phá vỡ mọi thứ có vẻ tốt, nhưng dường như cũng cần rất nhiều công việc để xây dựng dự án: bạn cần phải tìm ra những phần của chúng tôi đã thay đổi và những gì phụ thuộc vào những phần đó, biên dịch từng phần, và sau đó liên kết mọi thứ lại với nhau.

May mắn thay, các lập trình viên lười biếng *, vì vậy họ phát minh ra rất nhiều công cụ để làm cho công việc của họ dễ dàng hơn. Cuối cùng, nhiều công cụ đã được viết để tự động hóa nhiệm vụ trên. Nổi tiếng nhất trong số này đã được đề cập (make, ant, maven). Các công cụ này cho phép bạn xác định những phần nào cần được ghép lại để tạo dự án cuối cùng của bạn và cách các phần phụ thuộc vào nhau (nghĩa là nếu bạn thay đổi điều này, điều này cần phải được biên dịch lại). Kết quả là việc ban hành chỉ một lệnh sẽ chỉ ra những gì cần được biên dịch lại, biên dịch nó và làm lại mọi thứ.

Nhưng điều đó vẫn để lại cách mọi thứ liên quan đến nhau. Đó là rất nhiều công việc và như tôi đã nói trước đây, các lập trình viên rất lười biếng. Vì vậy, họ đã đưa ra một lớp công cụ khác. Những công cụ này đã được viết để xác định sự phụ thuộc cho bạn! Thông thường các công cụ là một phần của Môi trường phát triển tích hợp (IDE) như Eclipse và Visual Studio, nhưng cũng có một số công cụ độc lập được sử dụng cho cả ứng dụng chung và cụ thể (makenep, QMake cho các chương trình Qt).

* Trên thực tế, các lập trình viên không thực sự lười biếng, họ chỉ thích dành thời gian làm việc cho các vấn đề, không thực hiện các nhiệm vụ lặp đi lặp lại có thể được tự động hóa bởi một chương trình.


5

Đây là danh sách những thứ bạn có thể thử để tăng tốc các bản dựng C / C ++:

  • Bạn có thiết lập để chỉ xây dựng lại những gì đã thay đổi? Hầu hết các môi trường làm điều này theo mặc định. Không cần biên dịch lại tệp nếu nó hoặc không có tiêu đề nào thay đổi. Tương tự, không có lý do để xây dựng lại một dll / exe nếu tất cả các liên kết trong objs / lib không thay đổi.
  • Đặt nội dung của bên thứ 3 không bao giờ thay đổi và các tiêu đề được liên kết trong một số khu vực thư viện mã chỉ đọc. Bạn chỉ cần các tiêu đề và nhị phân liên quan. Bạn không bao giờ cần phải xây dựng lại điều này từ nguồn khác hơn là có thể một lần.
  • Khi xây dựng lại mọi thứ, hai yếu tố hạn chế trong trải nghiệm của tôi là số lượng lõitốc độ đĩa . Có được một lõi tứ, máy siêu phân luồng với một hdd thực sự tốt và hiệu suất của bạn sẽ được cải thiện. Xem xét một ổ đĩa trạng thái rắn - hãy nhớ rằng những cái giá rẻ có thể tồi tệ hơn một hdd tốt. Cân nhắc sử dụng đột kích để tăng hdd của bạn
  • Sử dụng một hệ thống xây dựng phân tán như Incredibuild sẽ phân chia việc biên dịch trên các trạm làm việc khác trên mạng của bạn. (Hãy chắc chắn rằng bạn có một mạng lưới vững chắc).
  • Thiết lập một bản dựng thống nhất để cứu bạn khỏi liên tục tải lại các tệp tiêu đề.

Theo kinh nghiệm của tôi (không nhiều, nhưng tốt) tốc độ đĩa bắt đầu trở nên không liên quan nếu dự án của bạn vượt quá "rất nhỏ". Chỉ cần nghĩ về những gì bạn nói trong gạch đầu dòng tiếp theo của bạn: bạn đang sử dụng mạng để tăng tốc độ biên dịch. Nếu đĩa là một nút cổ chai lớn, việc dùng đến mạng không có vẻ là một động thái rất tốt.
R. Martinho Fernandes

Một giải pháp rẻ tiền khác là biên dịch trong một tmpfs. Có thể tăng đáng kể hiệu năng nếu quá trình biên dịch bị ràng buộc IO.
Artefact2

4

Ý tưởng phải biên dịch lại thứ gì đó lớn như WP hết lần này đến lần khác, sau mỗi thay đổi nhỏ để thử "nếu nó hoạt động" và "cách nó hoạt động / cảm thấy" có vẻ không hiệu quả, chậm và sai.

Thực hiện một cái gì đó diễn giải cũng rất không hiệu quả và chậm, và (được cho là) ​​sai. Bạn đang phàn nàn về các yêu cầu về thời gian trên PC của nhà phát triển, nhưng việc không biên dịch gây ra các yêu cầu về thời gian trên PC của người dùng , điều này được cho là tồi tệ hơn nhiều.

Quan trọng hơn, các hệ thống hiện đại có thể thực hiện các bản dựng lại tăng dần khá tiên tiến và không phổ biến để biên dịch lại toàn bộ cho các thay đổi nhỏ - các hệ thống được biên dịch có thể bao gồm các thành phần tập lệnh, đặc biệt phổ biến cho những thứ như UI.


1
Tôi tin rằng câu hỏi của tôi không có nghĩa là được giải thích so với tranh luận về cách tiếp cận. Thay vào đó tôi chỉ xin lời khuyên về cách phát triển một dự án lớn (được biên soạn) được thực hiện đúng. Cảm ơn cho ý tưởng xây dựng lại gia tăng mặc dù.
pootzko

@pootzko: Chà, thật không công bằng khi thảo luận về những nhược điểm của việc biên dịch khi bạn không nói về những nhược điểm của việc diễn giải.
DeadMG

1
không, không phải vậy. đó là một cuộc tranh luận khác và không liên quan gì đến câu hỏi của tôi. Tôi không nói rằng đó là điều không nên thảo luận. nó nên, nhưng không phải ở đây.
pootzko

@pootzko: Sau đó, bạn không nên dành phần lớn câu hỏi của mình để liệt kê những gì bạn không thích về việc biên dịch. Bạn nên viết một cái gì đó ngắn hơn và ngắn gọn hơn, như, "Làm thế nào để giảm thời gian biên dịch của các dự án lớn?".
DeadMG

Tôi không biết tôi phải hỏi ai đó về cách tôi "nên" hỏi câu hỏi của mình ..? : OI đã viết nó như tôi đã làm để giải thích rõ hơn quan điểm của tôi để những người khác có thể hiểu rõ hơn về nó và giải thích cho tôi cách đạt được điều tương tự / tương tự với các ngôn ngữ được biên dịch. Tôi một lần nữa - đã không - yêu cầu bất cứ ai nói với tôi nếu ngôn ngữ được giải thích gây ra yêu cầu về thời gian tồi tệ hơn trên PC của người dùng. Tôi biết điều đó, và nó không liên quan gì đến câu hỏi của tôi - "nó được thực hiện như thế nào với các ngôn ngữ được biên dịch", xin lỗi. Những người khác dường như đã tìm ra những gì tôi đã hỏi mặc dù vậy, vì vậy tôi không nghĩ rằng câu hỏi của tôi không đủ rõ ràng ..
pootzko

4
  • Tái tạo một phần

Nếu dự án thực hiện DAG phụ thuộc biên dịch đúng thì bạn có thể thoát khỏi chỉ với việc biên dịch lại các tệp đối tượng mà thay đổi của bạn ảnh hưởng.

  • Nhiều quá trình biên dịch

Cũng giả sử một DAG phụ thuộc biên dịch thích hợp, bạn có thể biên dịch bằng nhiều quy trình. Một công việc cho mỗi lõi / cpu là tiêu chuẩn.

  • Kiểm tra thực thi

Bạn có thể tạo nhiều tệp thực thi để kiểm tra chỉ liên kết các tệp đối tượng cụ thể.


2

Ngoài câu trả lời của MainMa, chúng tôi cũng vừa nâng cấp các máy chúng tôi làm việc. Một trong những giao dịch mua tốt nhất chúng tôi đã thực hiện là SSD khi bạn không thể giúp biên dịch lại toàn bộ dự án.

Một đề nghị khác là thử một trình biên dịch khác. Trước đây, chúng tôi chuyển từ trình biên dịch Java sang Jike và bây giờ chúng tôi đã chuyển sang sử dụng trình biên dịch đi kèm với Eclipse (không biết nó có tên) để tận dụng lợi thế của bộ xử lý đa lõi hay không.

Dự án tệp 37.000 của chúng tôi mất khoảng 15 phút để biên dịch lại từ đầu trước khi chúng tôi thực hiện những thay đổi này. Sau khi thay đổi, nó đã được cắt xuống còn 2-3 phút.

Tất nhiên, đáng để nhắc đến quan điểm của MainMa một lần nữa. Đừng biên dịch lại toàn bộ dự án mỗi khi bạn muốn thấy một sự thay đổi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.