2008-10-18 29 views
24

Tôi định kỳ kêu gọi thực hiện công việc bảo trì trên một hệ thống được xây dựng bởi một bác sĩ phẫu thuật tên lửa thực sự. Có rất nhiều điều sai trái với việc thật khó để biết bắt đầu từ đâu.Chương trình không chắc chắn nhất mà bạn phải duy trì là gì?

Không, chờ đợi, tôi sẽ bắt đầu từ đầu: trong những ngày đầu của dự án, nhà thiết kế đã được thông báo rằng hệ thống sẽ cần phải mở rộng quy mô và anh ta đọc rằng một vấn đề về khả năng mở rộng là lưu lượng truy cập giữa các máy chủ ứng dụng và cơ sở dữ liệu, do đó, anh ta đã đảm bảo giảm thiểu lưu lượng truy cập này. Làm sao? Bằng cách đặt tất cả các logic ứng dụng trong các thủ tục lưu sẵn SQL Server.

Nghiêm túc. Phần lớn các hàm ứng dụng của giao diện người dùng HTML tạo thành các thông điệp XML. Khi tầng giữa nhận được một thông báo XML, nó sử dụng tên thẻ của phần tử tài liệu làm tên của thủ tục lưu sẵn mà nó sẽ gọi và gọi SP, chuyển nó toàn bộ thông điệp XML như một tham số. Nó lấy thông điệp XML mà SP trả về và trả về trực tiếp trở lại giao diện người dùng. Không có logic nào khác trong tầng ứng dụng.

(Có một số mã trong tầng giữa để xác nhận các thông điệp XML đến chống lại một thư viện các lược đồ. Nhưng tôi lấy nó, sau khi xem xét nếu 1) chỉ một số nhỏ các thông điệp đã tương ứng schemas, 2) các thông điệp không thực sự phù hợp với các lược đồ này và 3) sau khi xác thực các thông báo, nếu có bất kỳ lỗi nào gặp phải, phương thức đã loại bỏ chúng. "Hộp cầu chì này là một máy tiết kiệm thời gian thực - nó xuất phát từ nhà máy với các đồng xu được cài sẵn!")

Tôi đã thấy phần mềm làm điều sai trái trước đây. Rất nhiều của nó. Tôi đã viết khá một chút. Nhưng tôi chưa bao giờ thấy bất cứ điều gì như quyết tâm đúng đắn để làm điều sai trái, tại mọi lượt có thể, được thể hiện trong thiết kế và lập trình của hệ thống này.

Vâng, ít nhất anh ấy đã làm theo những gì anh ấy biết, phải không? Um. Rõ ràng, những gì anh biết là Access. Và anh ấy thực sự không hiểu quyền truy cập. Hoặc cơ sở dữ liệu.

Dưới đây là một mô hình phổ biến ở mã này:

 
SELECT @TestCodeID FROM TestCode WHERE TestCode = @TestCode 

SELECT @CountryID FROM Country WHERE CountryAbbr = @CountryAbbr 

SELECT Invoice.*, TestCode.*, Country.* 
    FROM Invoice 
    JOIN TestCode ON Invoice.TestCodeID = TestCode.ID 
    JOIN Country ON Invoice.CountryID = Country.ID 
    WHERE Invoice.TestCodeID = @TestCodeID AND Invoice.CountryID = @CountryID 

Được rồi, được rồi. Bạn cũng không tin tưởng trình tối ưu hóa truy vấn. Nhưng làm thế nào về điều này? (Ban đầu, tôi sẽ đăng bài này trong số What's the best comment in source code you have ever encountered? nhưng tôi nhận ra rằng có quá nhiều thứ để viết về hơn là chỉ một bình luận này, và mọi thứ đã vượt khỏi tầm tay.) Vào cuối nhiều thủ tục lưu trữ tiện ích, bạn sẽ thấy mã trông giống như sau:

 
-- Fix NULLs 
SET @TargetValue = ISNULL(@TargetValue, -9999) 

Có, mã đó đang thực hiện chính xác những gì bạn không thể cho phép mình tin rằng điều đó làm bạn sợ bị điên. Nếu biến chứa NULL, anh ta cảnh báo người gọi bằng cách thay đổi giá trị của nó thành -9999. Dưới đây là cách số này thường được sử dụng:

 
-- Get target value 
EXEC ap_GetTargetValue @Param1, @Param2, OUTPUT @TargetValue 
-- Check target value for NULL value 
IF @TargetValue = -9999 
    ... 

Thực sự.

Để biết kích thước khác của hệ thống này, hãy xem bài viết trên thedailywtf.com có ​​tiêu đề I Think I'll Call Them "Transactions". Tôi không thực hiện bất kỳ điều này. Tôi thề.

Tôi thường được nhắc nhở, khi tôi làm việc trên hệ thống này, phản ứng nổi tiếng của Wolfgang Pauli đối với một sinh viên: "Điều đó không đúng. Nó thậm chí không sai."

Đây thực sự không phải là chương trình tồi tệ nhất bao giờ hết. Đó chắc chắn là điều tồi tệ nhất mà tôi đã từng làm trong toàn bộ 30 năm (sự nghiệp) của tôi. Nhưng tôi chưa từng thấy mọi thứ. ?

+2

Vì vậy .... Điều này thực sự không phải là một câu hỏi nhiều như một lỗ thông hơi! Tôi đoán bạn đang yêu cầu một cách hùng biện: Bạn có thể đầu này! ... Hmmm ... –

+0

Điều này có vẻ phù hợp hơn với blog của bạn hoặc trang web [dành riêng cho thảo luận] (http://meta.stackexchange.com/questions/13198/). –

+0

Tôi đã đặt câu hỏi bởi vì tôi nghĩ (và suy nghĩ vẫn còn) câu trả lời cho nó có thể hữu ích. Phân tích lỗi trong phần mềm thường chỉ được thực hiện sau khi phần mềm đã thất bại hoàn toàn (nếu sau đó); những thân thể khủng khiếp chỉ được giữ sống thông qua các loại đất thường chỉ thực sự được hiểu bởi một hoặc hai người. Làm thế nào xấu một phần mềm có thể được và vẫn còn hữu ích? Làm thế nào những điều như vậy trở thành hiện hữu, và những nỗ lực nào được yêu cầu để hỗ trợ họ?Thật khó để có hệ thống khám phá những câu hỏi đó, nhưng chúng đáng để khám phá. –

Trả lời

40

một khi tôi đã cố gắng để viết một bộ giải mã MP3. Nó đã không làm việc.

+1

Giả sử chơi chữ được dự định, bạn nhận được upvote của tôi thưa ông, tốt đẹp nhất, và nó không giống như những câu hỏi chủ quan xứng đáng bất kỳ câu trả lời nghiêm trọng anyway. – Seldaek

+0

Tôi không thấy chơi chữ ... –

+13

"không chắc chắn", tôi đoán vậy. Không phải là hình phạt tốt nhất mà tôi từng nghe: P – Blorgbeard

6

Người tôi vừa bắt đầu vào.

  1. không kiểm soát nguồn.
  2. Tất cả các nguồn được chỉnh sửa trực tiếp Để ngăn chặn những sai lầm, có sao lưu các tập tin như db-access.php.070821 xả rác cây nguồn.
  3. Mã đặc biệt giòn - có rất ít trong cách kiểm tra lỗi và hoàn toàn không bị rơi trở lại nếu có.
+2

Hãy chắc chắn để chờ một vài ngày trong khi họ bực bội về cố gắng để hoàn tác sai lầm của họ. Nó làm cho nét mặt kết quả thú vị hơn nhiều. –

+1

Đó là một dự án internet được phân phối nhưng bằng tiền mặt thực. Tôi đã được búa về về svn và cho đến nay không có gì đã xảy ra. –

+0

chỉ cần phá vỡ xây dựng. Sau đó để nó bị hỏng trong một tuần. Sau đó, có thể họ sẽ thấy lợi ích của việc sử dụng điều khiển phiên bản = D –

19

Tôi duy trì ExtUtils::MakeMaker. MakeMaker chắc chắn không phải là mã tồi tệ nhất mà tôi phải duy trì; nó thực sự là một ngạc nhiên về kỹ thuật. Tuy nhiên, đó là trong lớp học độc đáo của nỗi kinh hoàng mã hóa trong đó mã nhiệm vụ quan trọng nhất cũng là đáng sợ nhất.

MakeMaker là trình cài đặt cho hầu hết các mô-đun Perl. Khi bạn chạy "Makefile.PL", bạn đang gọi MakeMaker. Nếu MakeMaker phá vỡ, Perl phá vỡ. Perl chạy trên mọi thứ, vì vậy MakeMaker phải chạy trên mọi thứ. Khi tôi nói tất cả mọi thứ tôi có nghĩa là tất cả mọi thứ. Mọi biến thể Unix kỳ quái. Windows 95 trở lên. Và VMS. Có, VMS.

MakeMaker làm gì? Makefile.PL là một chương trình Perl viết một Makefile chứa các lệnh shell, thường chạy Perl, để xây dựng và cài đặt một mô-đun Perl. Hãy để tôi lặp lại: Nó viết lệnh shell để chạy Perl. Perl, ngôn ngữ thay thế kịch bản lệnh shell.

Ồ, nó cũng có thể biên dịch và liên kết mã C. Và nó cũng có thể liên kết tĩnh các mô-đun Perl thành perl. Oh, và nó có thể quản lý RCS checkouts. Oh, và cuộn tarballs của phân phối của bạn ... và các tập tin zip. Và làm tất cả những thứ khác mơ hồ liên quan đến việc cài đặt các mô-đun.

Và nó phải làm tất cả điều này theo kiểu di động, tương thích ngược. Nó có để đối phó với các biến thể và lỗi trong ...

  • làm (GNU thực hiện, BSD thực hiện, nmake, dmake, mms, MMK đến tên một vài)
  • vỏ
  • Perl
  • các hệ thống tập tin (nếu bạn không nghĩ rằng đó là một vấn đề lớn, hãy thử VMS)
  • trình biên dịch C & linkers

Nó hoàn toàn, tích cực không thể thất bại và phải duy trì 100% backw ards tương thích.

Ồ, và nó có rất ít trong cách của một API mở rộng thực sự, do đó, nó vẫn phải tương thích với các quảng cáo hoc Makefile hackery mọi người phải làm gì để mở rộng nó.

Tại sao thực hiện tất cả điều này? 15 năm trước, khi Perl chỉ chạy trên Unix, điều này dường như là một ý tưởng tuyệt vời. Tại sao viết một hệ thống xây dựng toàn bộ khi bạn chỉ có thể sử dụng làm? Perl là một ngôn ngữ xử lý văn bản; chúng ta sẽ sử dụng nó để viết một Makefile!

May mắn thay có thay thế, Module::Build và tôi đã hy vọng rằng nó sẽ nhanh chóng giết được MakeMaker. Nhưng sự hấp thu của nó đã chậm và cộng đồng rất chống lại sự thay đổi, vì vậy tôi bị mắc kẹt khi duy trì MakeMaker.

1

Tôi đang duy trì ứng dụng web lập lịch mà chúng tôi sử dụng trong mạng nội bộ của mình. Khi tôi được hỏi liệu tôi có thể loại bỏ một đại lý từ bộ lập lịch mà tôi nghĩ, chắc chắn tại sao không. Khi tôi xem xét mã nguồn, tôi đã tìm ra rằng mỗi giờ của ngày đại lý này được mã hóa riêng. Vì vậy, mỗi ngày trong tuần của anh ấy. Và như vậy là mỗi tuần của tất cả các đại lý của khu vực này. Và như vậy là mọi khu vực của khoảng 5 khu vực. Các fies Html giữ mã asp trên toàn bộ địa điểm.

Một ngày tôi dành chút thời gian để đoán có bao nhiêu dòng mã trong các tệp khác nhau này và tôi ước tính khoảng 300000. Ba trăm nghìn dòng mã một lần viết tay rồi sao chép và dán mã.

Nhưng con số này đã thuyết phục người quản lý của tôi khá nhanh rằng chúng tôi sẽ cần một ứng dụng lên lịch mới rất nhanh chóng.

12

Chương trình không chắc chắn nhất mà bạn phải duy trì là gì?

Mọi thứ tôi từng viết!

Nghiêm túc. Càng đọc nhiều blog, nghe podcast, và theo dõi các trang như thế này, tôi càng học nhiều hơn mỗi ngày. Và mỗi ngày tôi về cơ bản nhận ra tất cả mọi thứ tôi đã viết ngày hôm qua là sai theo một cách nào đó. Tôi cảm thấy những khoảng trống nghèo nàn đang duy trì những điều tôi viết sớm trong sự nghiệp của mình.

+3

Ồ, tôi cũng thế. Nhưng có một sự khác biệt về thể loại giữa mã xấu và mã cơ bản, sai lầm kinh khủng. Phải mất nhiều thời gian hơn để viết loại mã đó; phải mất một lượng lớn sự tự tin không đáng tin cậy. –

2

Tôi từng là lập trình viên COBOL (rùng mình). Tất cả các mã của chúng tôi rơi vào thể loại "không rõ ràng". Trong COBOL, bạn không có không gian tên, tất cả các biến là toàn cầu và có rất nhiều sự trùng lặp bắt buộc của tên tệp và các tài nguyên khác. Để gọi một thủ tục, bạn thiết lập các biến toàn cầu, gọi thủ tục, và sau đó kiểm tra nội dung của các biến toàn cục đó (hoặc các biến khác có thể được thiết lập).

Điều tồi tệ nhất là duy trì một chương trình COBOL được viết trước khi tôi được sinh ra (tôi sinh năm 1967) và phương pháp kiểm soát luồng độc quyền của nó là GOTO. Đó là một mớ hỗn độn tuyệt đối và không thể làm theo. Thay đổi nhỏ đối với loại biến có thể mất vài ngày để giải quyết. Không có thử nghiệm tự động và kế hoạch kiểm tra thủ công nào chưa được lưu, do đó, mọi thay đổi đều yêu cầu một kế hoạch kiểm tra thủ công mới được viết ra, theo dõi đầy đủ và được chuyển sang mã.

Trớ trêu thay, đây là điều khiến COBOL thành công. COBOL thường được thực hiện bởi Ngôn ngữ kiểm soát công việc (JCL). Vì COBOL quá yếu nên các chương trình không làm được gì nhiều, vì vậy JCL sẽ phân bổ một số không gian đĩa (thường xuống mức xi lanh) và thực hiện một chương trình COBOL nhỏ để đọc dữ liệu và sau đó chỉ ghi dữ liệu bạn cần. Sau đó, JCL có thể gọi một chương trình sắp xếp để sắp xếp tệp kết quả. Sau đó, một chương trình COBOL khác sẽ được gọi để đọc tệp đã sắp xếp và tóm tắt dữ liệu và có thể trích xuất lại các kết quả cần thiết. Và có lẽ JCL sẽ được sử dụng một lần nữa để di chuyển tệp ở một nơi khác và một chương trình COBOL khác sẽ được gọi để đọc kết quả và lưu trữ chúng trong cơ sở dữ liệu, v.v. Mỗi chương trình COBOL có xu hướng chỉ làm một điều và một phiên bản nguyên thủy của mô hình đường ống Unix đã được tạo ra - tất cả vì COBOL quá khó để duy trì hoặc làm bất cứ điều gì phức tạp với. Chúng tôi đã ghép nối lỏng lẻo và gắn kết chặt chẽ (giữa các chương trình, không phải trong họ) bởi vì nó gần như không thể viết COBOL bất kỳ cách nào khác.

0

Duy trì các ứng dụng ASP cho một công ty cụ thể thuê nhà phát triển để duy trì việc thuê trước của họ ... Tất cả các ứng dụng này không được ghi chép, không có bất kỳ nhận xét nào.

Mọi chức năng được sao chép và dán trong mọi trang ASP. Vì vậy, không có chức năng được xác định hoặc bất cứ điều gì ... Mỗi ngày tôi bị tê liệt bởi môi trường của họ, bởi vì tôi đã lần đầu tiên từ xa đến một máy chủ, để bỏ qua các DMZ. Sau đó tôi phải từ xa vào một máy chủ sản xuất, nơi tôi phải thực hiện các thay đổi.

5

Tôi đã từng phải duy trì một ứng dụng C cũ mà trước đây đã được viết và duy trì bởi một số lập trình viên đã mất ý chí tham gia chương trình (và có thể hoạt động). Nó có quá nhiều WTF để đề cập đến, nhưng tôi nhớ một hàm boolean trong nhiều trường hợp đặc biệt sẽ trả về TRUE + 1, TRUE + 2, v.v.

Sau đó, tôi đọc Roedy Green's essay và cười rất nhiều, cho đến khi tôi nhận ra rằng lý do tôi thấy nó buồn cười là tôi nhận ra hầu hết các ví dụ từ mã tôi đang duy trì. (Bài luận đó đã trở nên hơi cồng kềnh trong nhiều năm bổ sung, nhưng nó vẫn đáng để xem.)

0

Tôi đã từng được gọi vào để giúp theo dõi sự cố định kỳ trong đầu đọc EDIF. Gần như ngay lập tức tôi bắt đầu bị đau đầu. Tác giả ban đầu dường như cảm thấy rằng Yacc sẽ phạt anh ta cho khoảng trắng, và ngữ pháp Yacc của anh là một mớ hỗn độn dày đặc, không thể đọc được. Tôi đã dành một vài giờ định dạng nó, thêm quy tắc cho các thiết bị đầu cuối bị mất khi chúng nổi lên, cấu trúc các khai báo để tránh sự tăng trưởng ngăn xếp, và thì đấy, sự cố đã bị dập tắt.

Vì vậy, hãy nhớ rằng, mỗi khi bạn đợi trong khi Yacc xử lý ngữ pháp của bạn, sẽ có hàng nghìn lượt chạy với trình phân tích cú pháp được tạo. Đừng có giá rẻ với khoảng trắng!

0

Bất cứ điều gì tôi từng viết được cho là nguyên mẫu nhanh và kết thúc ở lại một lúc. Miền vấn đề của tôi đòi hỏi rất nhiều nguyên mẫu tự do. Đối với những nguyên mẫu này, đôi khi rất hợp lý để vi phạm mọi thực hành tốt nhất và quy tắc có phong cách tốt, chỉ cần hoàn thành và làm sạch sau này nếu nguyên mẫu kết thúc là đáng để giữ. Tuy nhiên, đôi khi những nguyên mẫu này kết thúc là rất khó khăn để có được làm việc đúng cách, nhưng sau đó kết thúc được giữ. Trong những trường hợp này, tôi thường kết thúc việc sắp xếp lại/viết lại điều đó vô thời hạn bởi vì tôi e rằng tôi sẽ không bao giờ làm cho nó hoạt động trở lại. Làm giảm thêm động lực của tôi là ông chủ của tôi là một chuyên gia miền không có chương trình nào cả.

1

Hệ thống quản lý liên hệ trực tuyến bằng PHP/MySQL, nơi bảng liên hệ không có khóa tự nhiên. Đã có rất nhiều trường hợp của các trường cơ sở dữ liệu chứa dữ liệu tổng hợp dưới dạng một chuỗi được phân tách mà sau đó cần phải được phân tích bằng mã ứng dụng.

HTML và logic được đan xen, hầu như không có chức năng nào được sử dụng, nhưng thay vào đó mã được cắt và dán vào hàng tá tệp mã nguồn. Dữ liệu không được khử trùng và do đó các trường có (như) các tab dọc được nhúng khiến XML trả về bởi các cuộc gọi Ajax đến trục trặc, và trên hết, các tệp có hàng tá nếu không phải hàng trăm câu lệnh trống bao gồm các dấu ngoặc đóng ngay sau dấu chấm phẩy : "};"

0

Trình thông dịch cho ngôn ngữ xử lý hình học CAD/CAM (P1 = 10,10; P2 = 20,20; L1 = P1, P2; - loại điều đó), được viết bằng Microsoft BASIC Professional Development System (PDS) , với tên biến chiều dài tối thiểu (nó chạy ra khỏi các chữ cái một cách nhanh chóng, do đó, chuyển sang hai chữ cái. PP, PQ, PR, bất kỳ ai?). Và, để công bằng, một số ý kiến ​​. Ở Ý.

Funnily đủ, nó thực sự làm việc, và tôi đã có thể thêm một số chức năng để điều đó, nhưng nó giống như nha khoa amateur - đau đớn, và chắc chắn không được khuyến khích ...

2

phải ra khỏi trường grad tại Lucent tôi đã được đưa ra một trình biên dịch và thông dịch viên để duy trì, được viết bằng PL/I.Ngôn ngữ được biên dịch mô tả một tập hợp các ràng buộc toàn vẹn, và trình thông dịch chạy những ràng buộc đó đối với một tập dữ liệu lớn mà sau này sẽ được tạo thành cơ sở dữ liệu ban đầu điều khiển công tắc 4ESS. 4ESS là, và vẫn là một công tắc mạch cho lưu lượng thoại đường dài.

Mã đã bị xáo trộn. Có một nhãn cho chi nhánh được gọi là "NORTH40". Tôi hỏi nhà phát triển ban đầu ý nghĩa của nó.

"Đó là nơi kiểm tra phạm vi được thực hiện, bạn biết đấy, kiểm tra để đảm bảo mỗi trường có giá trị chính xác".

"Nhưng tại sao 'NORTH40'?"

"Bạn biết đấy, 'Nhà riêng, nhà ở trên phạm vi.'"

"Huh?"

Hóa ra 'NORTH40' có nghĩa là một trang trại ở phía bắc 40 mẫu Anh, trong tâm trí thành phố của ông có một kết nối tối nghĩa với một trang trại gia súc.

Một mô-đun khác có hai mảng song song được gọi là TORY và DIREC, được cập nhật song song và do đó là một nỗ lực sai lầm rõ ràng để mô hình hóa một mảng chứa các cặp dữ liệu. Tôi không thể tìm ra tên và hỏi nhà phát triển. Hóa ra chúng có nghĩa là được đọc cùng nhau: "direc-tory". Tuyệt quá.

Những người nghèo phải viết các ràng buộc về tính toàn vẹn không có hướng dẫn sử dụng để hướng dẫn họ, chỉ là một truyền thống miệng cộng với ghi chú viết tay. Tệ hơn nữa, trình biên dịch đã không kiểm tra cú pháp, và rất thường xuyên họ vết thương xác định một ràng buộc đã được ánh xạ lặng lẽ vào logic sai, thường với những hậu quả rất xấu.

Tệ hơn nữa sẽ đến. Khi tôi đi sâu vào ruột của thông dịch viên, tôi phát hiện ra nó được xây dựng xung quanh một quá trình phân loại khổng lồ. Trước khi sắp xếp là một quá trình đầu vào tạo ra dữ liệu đầu vào sắp xếp từ dữ liệu thô và các ràng buộc toàn vẹn. Vì vậy, nếu bạn có một bảng có 5.000 định nghĩa thân cây trong đó và mỗi bản ghi chính có ba giá trị trường duy nhất trên toàn bộ tập dữ liệu đầu vào, quá trình nhập sẽ tạo 3 * 5.000 = 15.000 bản ghi đầu vào sắp xếp, mỗi bản ghi bản ghi dữ liệu được đặt trước bởi số ràng buộc toàn vẹn và một bản sao của giá trị trường được sắp xếp. Thay vì làm ba loại 5.000 bản ghi, nó đã làm một loại 15.000 bản ghi. Vào thời điểm bạn tính toán hàng trăm ràng buộc toàn vẹn trong nội bộ và liên bảng, và một số bảng rất lớn, bạn đã có một cơn ác mộng tổ hợp.

Tôi đã có thể cấu trúc lại một chút, ghi lại ngôn ngữ và thêm kiểm tra cú pháp với thông báo lỗi dễ hiểu, nhưng vài tháng sau đó đã chuyển sang một nhóm mới.

1

Tôi đã từng làm việc trên một ứng dụng CAD viết bằng BASIC nơi chính sách công ty là mỗi chương trình phải bắt đầu bằng câu:

On Error Resume

JMM

+0

whats the point ??? : P –

Các vấn đề liên quan