gpt4 book ai didi

anti-patterns - 您在生产企业环境中见过的最邪恶的代码是什么?

转载 作者:行者123 更新时间:2023-12-03 05:17:25 25 4
gpt4 key购买 nike

就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the help center为指导。




9年前关闭。










锁定。这个问题及其答案是locked因为这个问题是题外话,但具有历史意义。它目前不接受新的答案或互动。








您在公司的生产环境中见过的最邪恶或最危险的代码片段是什么?我从未遇到过我认为是故意恶意和邪恶的生产代码,所以我很想知道其他人发现了什么。

我见过的最危险的代码是一个存储过程,距离我们的核心生产数据库服务器有两个链接服务器。该存储过程接受任何 NVARCHAR(8000) 参数并通过双跳 sp_executeSQL 命令在目标生产服务器上执行该参数。也就是说,sp_executeSQL 命令执行了另一个 sp_executeSQL 命令,以便跳转两个链接的服务器。哦,链接服务器帐户在目标生产服务器上具有系统管理员权限。

最佳答案

警告:前面有很长的可怕帖子

我写过关于我在 herehere 之前工作过的一个应用程序。简单来说,我公司从印度继承了13万行垃圾。该应用程序是用 C# 编写的;这是一个柜员应用程序,当你去银行时,柜员在柜台后面使用的那种软件。该应用程序每天崩溃 40-50 次,而且根本无法重构为可运行的代码。我的公司不得不在 12 个月的时间里重新编写整个应用程序。

为什么这个应用程序是邪恶的?因为看到源代码就足以让一个理智的人发疯,一个理智的疯子。用于编写此应用程序的扭曲逻辑可能只是受到洛夫克拉夫特式噩梦的启发。此应用程序的独特功能包括:

  • 在 130,000 行代码中,整个应用程序包含 5 个类(不包括表单文件)。所有这些都是公共(public)静态类。一个类称为 Globals.cs,其中包含 1000 和 1000 和 1000 个公共(public)静态变量,用于保存应用程序的整个状态。这五个类总共包含 20,000 行代码,其余代码嵌入在表单中。
  • 你一定想知道,程序员是如何在没有任何类的情况下编写如此大的应用程序的?他们用什么来表示他们的数据对象?事实证明,程序员仅仅通过组合 ArrayLists、HashTables 和 DataTables 就成功地重新发明了我们都学到的关于 OOP 的一半概念。我们看到了很多这样的:
  • 哈希表的 ArrayLists
  • 带有字符串键和 DataRow 值的哈希表
  • 数据表的 ArrayLists
  • 包含 ArrayLists 的 DataRows 包含 HashTables
  • 数据行的 ArrayLists
  • ArrayLists 的ArrayLists
  • 带有字符串键和哈希表值的哈希表
  • HashTables 的ArrayLists 的ArrayLists
  • 你能想到的 ArrayLists、HashTables、DataTables 的所有其他组合。

  • 请记住,上面的数据结构都不是强类型的,因此您必须将列表中的任何神秘对象转换为正确的类型。仅使用 ArrayLists、HashTables 和 DataTables 就可以创建什么样的复杂的、类似于 Rube Goldberg 的数据结构,真是令人惊奇。
  • 要分享如何使用上面详述的对象模型的示例,请考虑帐户:原始程序员为帐户的每个可能的属性创建了一个单独的哈希表:一个名为 hstAcctExists、hstAcctNeedsOverride、hstAcctFirstName 的哈希表。所有这些哈希表的键都是“|”分隔的字符串。可以想到的 key 包括“123456|DDA”、“24100|SVG”、“100|LNS”等
  • 由于整个应用程序的状态很容易从全局变量访问,程序员发现没有必要将参数传递给方法。我会说 90% 的方法采用 0 参数。在少数这样做的情况下,为了方便起见,所有参数都作为字符串传递,而不管字符串代表什么。
  • 不存在无副作用的函数。每个方法都修改了 Globals 类中的 1 个或多个变量。并非所有的副作用都有意义;例如,其中一种表单验证方法有一个神秘的副作用,即为存储 Globals.lngAcctNum 的任何帐户计算贷款的超额和短额付款。
  • 尽管有很多形式,但只有一种形式可以统治它们:frmMain.cs,其中包含高达 20,000 行的代码。 frmMain 做了什么?一切。它查帐、打印收据、发放现金,它什么都做。

    有时其他形式需要调用 frmMain 上的方法。与其将表单中的代码分解为一个单独的类,不如直接调用代码:
    ((frmMain)this.MDIParent).UpdateStatusBar(hstValues);
  • 为了查找账户,程序员做了这样的事情:
    bool blnAccountExists =
    new frmAccounts().GetAccountInfo().blnAccountExists

    尽管它已经创建了一个不可见的表单来执行业务逻辑,但您认为该表单如何知道要查找哪个帐户?这很简单:表单可以访问 Globals.lngAcctNum 和 Globals.strAcctType。 (谁不喜欢匈牙利符号?)
  • 代码重用是 ctrl-c、ctrl-v 的同义词。我发现 200 行方法在 20 个表单中复制/粘贴。
  • 应用程序有一个奇怪的线程模型,我喜欢称之为线程和计时器模型:每个产生线程的表单都有一个计时器。产生的每个线程都会启动一个有 200 毫秒延迟的计时器;一旦计时器启动,它会检查线程是否设置了一些魔法 bool 值,然后它会中止线程。产生的 ThreadAbortException 被吞了。

    您可能认为这种模式只会看到一次,但我至少在 10 个不同的地方发现了它。
  • 说到线程,关键字“锁”从未出现在应用程序中。线程无需锁定即可自由操作全局状态。
  • 应用程序中的每个方法都包含一个 try/catch 块。每个异常都被记录并吞下。
  • 谁需要在打开字符串时打开枚举也很容易!
  • 一些天才发现您可以将多个表单控件挂接到同一个事件处理程序上。程序员是怎么处理的?
    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;
    }
    }
    }
  • 同样的天才也发现了光荣的三元算子。下面是一些代码示例:
    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))
  • 下面的代码片段演示了 StringBuilder 的典型误用。请注意程序员如何在循环中连接字符串,然后将结果字符串附加到 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();
    }
  • 表上不存在主键、索引或外键约束,几乎所有字段都是 varchar(50) 类型,并且 100% 的字段可以为空。有趣的是,位域不用于存储 bool 数据;相反,使用了 char(1) 字段,字符“Y”和“N”分别用于表示真和假。
  • 说到数据库,这里有一个存储过程的代表性例子:
    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)

  • 尽管如此,这个 130,000 行应用程序的最大问题是:没有单元测试。

    是的,我已将这个故事发送给 TheDailyWTF,然后我辞去了工作。

    关于anti-patterns - 您在生产企业环境中见过的最邪恶的代码是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/434414/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com