我经常被要求对由真正的火箭外科医生建造的系统进行维护工作.这有很多错误,很难知道从哪里开始.
不,等等,我将从一开始就开始:在项目的早期阶段,设计师被告知系统需要扩展,他会读到可扩展性问题的根源是应用程序和数据库之间的流量服务器,所以他确保最小化这种流量.怎么样?通过将所有应用程序逻辑放在SQL Server存储过程中.
认真.大量的应用程序由HTML前端制定XML消息.当中间层接收XML消息时,它使用文档元素的标记名作为它应调用的存储过程的名称,并调用SP,将整个XML消息作为参数传递给它.它接收SP返回的XML消息并将其直接返回到前端. 应用程序层中没有其他逻辑.
(这里是在中间层验证对架构库传入的XML消息的一些代码,但我删除了,经查1后)只有消息的极少数曾与架构,2)消息实际上并没有符合对于这些模式,以及3)在验证消息之后,如果遇到任何错误,该方法将丢弃它们."这款保险丝盒可以节省时间 - 它来自工厂预装的便士!")
我以前见过那些做错事的软件.很多.我写了很多.但我从来没有见过任何像钢铁般的决心做出错误的事情,在每一个可能的转折点,这都体现在这个系统的设计和编程中.
好吧,至少他跟他所知道的一样,对吧?嗯.显然,他所知道的是Access.他并不真正理解 Access.或数据库.
以下是此代码中的常见模式:
SELECT @TestCodeID FROM TestCode WHERE TestCode = @TestCode SELECT @CountryID FROM Country WHERE CountryAbbr = @CountryAbbr SELECT Invoice.*, TestCode.*, Country.* FROM Invoice JOIN TestCode ON Invoice.TestCodeID = TestCode.ID JOIN Country ON Invoice.CountryID = Country.ID WHERE Invoice.TestCodeID = @TestCodeID AND Invoice.CountryID = @CountryID
好的.您也不信任查询优化器.但是这个怎么样?(最初,我打算在你曾经遇到过的源代码中最好的评论中发布这个内容吗?但我意识到还有更多的内容要写,而不仅仅是这一条评论,事情就失控了.)许多实用程序存储过程结束时,您将看到如下所示的代码:
-- Fix NULLs SET @TargetValue = ISNULL(@TargetValue, -9999)
是的,那段代码完全是你不能让自己相信它正在做的事情,以免你被激怒.如果变量包含NULL,则通过将其值更改为-9999来警告调用者.以下是这个数字的常用方法:
-- Get target value EXEC ap_GetTargetValue @Param1, @Param2, OUTPUT @TargetValue -- Check target value for NULL value IF @TargetValue = -9999 ...
真.
对于这个系统的另一个方面,请参阅thedailywtf.com上题为" 我想我会称他们为交易"的文章.我没有做任何这个.我发誓.
当我在这个系统上工作时,我常常想起沃尔夫冈·泡利对一名学生的着名回应:"这是不对的.这甚至都没有错."
这不可能是有史以来最糟糕的计划.这绝对是我在整个30年(yikes)职业生涯中所做过的最糟糕的一次.但我还没有看到一切.你看到了什么?
我曾经试过写一个MP3解码器.它没用.
我维护了ExtUtils :: MakeMaker.MakeMaker肯定不是我必须维护的最糟糕的代码; 这实际上是一个工程奇迹.然而,正是在这种独特的编码恐怖类别中,最关键的任务代码也是最恐怖的.
MakeMaker是大多数Perl模块的安装程序.当您运行"Makefile.PL"时,您正在调用MakeMaker.如果MakeMaker中断,Perl就会中断.Perl可以在所有内容上运行,因此MakeMaker必须在所有内容上运行.当我说出一切我的意思是一切.每个离奇的Unix变种.Windows 95上.和VMS.是的,VMS.
MakeMaker做什么?Makefile.PL是一个Perl程序,它编写一个包含shell命令的Makefile,它通常运行Perl来构建和安装Perl模块.让我再说一遍:它编写shell命令来运行Perl.Perl,替换shell脚本的语言.
哦,它还可以编译和链接C代码.它还可以将Perl模块静态链接到perl.哦,它可以管理RCS结账.哦,滚动你的发行版的tarball ...和zip文件.并且做所有这些与模块安装模糊相关的事情.
它必须以便携式,向后兼容的方式完成所有这些工作.它必须处理变种和错误...
make(GNU make,BSD make,nmake,dmake,mms,mmk等等)
贝壳
Perl的
文件系统(如果你不认为这是一个大问题,请尝试VMS)
C编译器和链接器
它绝对,积极地不能失败,必须保持100%向后兼容.
哦,它几乎没有真正的扩展API,所以它必须保持兼容人们必须做的扩展它的ad hoc Makefile hackery.
为什么这样做呢?15年前Perl只在Unix上运行时,这似乎是一个好主意.为什么在使用make时编写整个构建系统?Perl是一种文本处理语言; 我们只是用它来编写Makefile!
幸运的是有一个替换,Module :: Build,我寄希望于它会迅速杀死MakeMaker.但它的吸收速度很慢,社区对这种变化非常有抵抗力,所以我坚持维护MakeMaker.
你必须维持的最不健全的计划是什么?
我写过的所有东西!
认真.我阅读的博客越多,收听播客,关注这样的网站,我每天学的越多.每天我基本上都意识到我昨天写的一切都是错误的.我觉得在我的职业生涯早期保留我写的东西的可怜的傻瓜.
我刚刚开始的那个.
无源控制.
所有来源都是现场编辑的.为了阻止错误,有像db-access.php.070821这样的备份文件乱丢源树.
代码非常脆弱 - 错误检查的方式很少,如果确实没有回退.
我曾经不得不维护一个遗留的C应用程序,该应用程序以前是由一些程序员编写和维护的,这些程序员已经失去了编程(并且可能存在)的意愿.它有太多的WTF要提,但我记得一个布尔函数,在各种特殊情况下会返回TRUE + 1,TRUE + 2等.
然后我读了Roedy Green的文章并笑了很多,直到我意识到我发现它很有趣的原因是我从我维护的代码中认识到了大部分的例子.(这篇文章在多年的添加中变得有点臃肿,但它仍然值得一看.)