`
andyjames
  • 浏览: 31022 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

我一辈子见过最糟糕的代码

    博客分类:
  • Java
阅读更多

我一辈子见过最糟糕的代码
翻译的很烂,具体请看原文: http://blog.cherouvim.com/the-worst-codebase-ive-seen-in-my-life/
最近,我接了一个庞大的老项目(我们称之为FailApp),其中包括很多不合格的代码。 我们将其分为三类。
 1) LoLs: 低级笑话代码(LOL是文字聊天里的大笑表情)
 2) WTFs: 他妈的烂代码(what the fuck)
 3)ShowStopper: 超级危险代码,致命的,制造P1级事故的代码!
直接举例:

LoL#1
在应用程序上下文中使用“Prod”这个的名称。
导致后面的这个测试环境http://123.12.34.123:7001/FailAppProd看起来像生产环境

LoL#2
EscapeIlegalWords eiw = new EscapeIlegalWords();
foo = eiw.escapeIlegalWords(foo);
public static String escapeIlegalWords(String code) {
    code = code.replaceAll("&lt;", "<");
    code = code.replaceAll("&gt;", ">");
    code = code.replaceAll("&amp;", "&");
    code = code.replaceAll("&apos;", "'");
    code = code.replaceAll("&quot;", "\"");
    code = code.replaceAll("&#13;", "");
    return code;
}
 - 我的妈呀,这是调用静态方法的新的实例吗?
 - HTML过滤,还是非法字符过滤?
- 过滤是单向的吗?
- 起这样的类名字有意义吗?
- 这样的算法,性能如何?

LoL#3
session.setAttribute("contentXML", null);
session.removeAttribute("contentXML");
session.setAttribute("contentOwnerList", null);
session.removeAttribute("contentOwnerList");
session.setAttribute("structuresVector", null);
session.removeAttribute("structuresVector");
session.setAttribute("selectedThematic", null);
session.removeAttribute("selectedThematic");
session.setAttribute("selectedTarget", null);
session.removeAttribute("selectedTarget");
session.setAttribute("targetList", null);
session.removeAttribute("targetList");
session.setAttribute("thematicList", null);
session.removeAttribute("thematicList");
session.setAttribute("metadatas", null);
session.removeAttribute("metadatas");
 –确定吗?请确保你真的想从seesion删除变量...删两次吗?
LoL#4
ArrayList arrActions = new ArrayList();
HashMap order = new HashMap();
public ArrayList getHighLights(int idStructure, int language, int home) { ...
 - 非常感谢你对类型的具体声明。 不过你听过接口和集合API的设计理念没?

LoL#5
ArrayList avlanguages=null;
if (request.getAttribute("avlanguages")!=null){
    avlanguages=(ArrayList)request.getAttribute("avlanguages");
}
<%if (avlanguages!=null && avlanguages.size()>0){%>
<%for(int x=0;x<avlanguages.size();x++) { %>
 -是的,这是太多的Java代码的JSP页面内,而不是使用JSTL <c:forEach...

 LoL#6
一些拼写错误,出现在日志和代码中:
  END GENERTAION THEMATICS.
 
  updateStatusDocumentDeplubishCron()

 LoL#7
  CommonDatosPopUp pop = new CommonDatosPopUp();
pop = (CommonDatosPopUp)popUp[i];

 - 这是伟大的!!! 感谢实现了之后,就把它扔掉。

 LoL#8
 ArrayList List = new ArrayList();
List = (ArrayList) baseManagerDao.getPosition(baseItemIdVar);
for (int i = 0; i < List.size(); i++)

- 再次,创建空ArrayList(),然后把它扔掉
- 变特殊命名List接口看起来像List (我不知道为什么这样的语言允许在这里污染自己)
- 看了这样的代码,你还有其他什么样的感想?
WTF#1
if (cm.getBlockLevels() != null) {
    request.setAttribute("blocklevel", cm.getBlockLevels());
}
if (cm.getUsers() != null) {
    request.setAttribute("users", cm.getUsers());
}
if (pm.getSigGroupPub() != null) {
    request.setAttribute("siggroups", pm.getSigGroupPub());
}
 - cm,pm(非常糟糕的局部变量名 – 这两个类是DAO)委托调用DAO的这些方法(很可能访问数据库)被调用两次
 - 为什么我们要在第一时间nullcheck? 如果结果是null,我们可以简单地把空(删除)压入request  attrs。 
 WTF#2
搜索“siggroup”。 在同一个controller(2000线),我找到了下面的代码:
 request.setAttribute(“siggroups”,pm.getSigGroupPub());
 request.setAttribute(“sigGroups”,sigGroups);
 request.setAttribute(“SigGroups”,hm.getSigGroups(Integer. ..
 - 一致性是程序员的生命之盐...

在模版之中:
List sig = (List) request.getAttribute("sigGroups");
if(sig == null) {
    sig = (List) request.getAttribute("SigGroups");
}
 - 如果你运气够好的话,你可以找到是哪一个对象
 WTF#3
没有javadoc,而且部分应用程序中最关键的是comment使非本土语言,包括非ASCII字符。 需要http://translate.google.com/帮助
 WTF#4
Classes with 2000 lines of code methods and 14 level nested ifs. These are usually do-everything controllers which serve many unrelated things from the same codebase (page results, binary downloads, csv). These are usually replicated 10 times with minor differences to accomodate slightly different use cases. Nough said
类文件包含2000行代码的方法和14个嵌套层级的if…else。经常是控制器做一切事情,这类控制器服务于许多来自同一个代码库不相关的事情(页面结果,二进制下载,cvs等)。还经常复制10次代码去适应略微不同的用例。
 WTF#5
pubHighlights = cm.getHighLights(structId, userLang,
                    Constants.PREDEFINED_SEARCH);
 – 大家正在利用变化的常量,而不是不同的方法或继承的方法:
public ArrayList getHighLights(int idStructure, String lang, int home) {
    ...
    if (home == 1) {
        listado = commonDao.getHightLightHome(idStructure);
    } else {
        listado = commonDao.getHightLightPredefinedSearch(idStructure);
    }
- facepalm for home==1 instead of Constant. good luck with debugging when that constant changes (home == 1, 为什么不使用常量?)

- by the way it turns out that the initial call should send Constants.HOME instead of Constants.PREDEFINED_SEARCH. It just happens that both equals 1.
顺便说下,应该用Constants.HOME来代替Constants.PREDEFINED_SEARCH常量,这两个常量只是凑巧都等于1.
 WTF#6
Absense of templating reuse. The 150+ JSP templates contain everything from html declarations to website footer (with copyrights and everything). Only with minor and insignificant differences due to inconsistent copy pasting of headers and whole pages with minor changes. Ever heard of include?
模板缺少复用。多于150个的jsp模板包含从html声明到站点页脚的一切东西。
 WTF#7
强大的表单验证, 看了下面的代码,你的感想是什么?:
if (appForm.getFileCV() == null || StringUtils.isEmpty(appForm.getFileCV().getFileName())){
    errors.add("fileCV", new ActionError("error.fileCV.required"));
}else if (!appForm.getFileCV().getFileName().toLowerCase().endsWith(".doc") && !appForm.getFileCV().getFileName().toLowerCase().endsWith(".pdf")
        && !appForm.getFileCV().getFileName().toLowerCase().endsWith(".rtf") && !appForm.getFileCV().getFileName().toLowerCase().endsWith(".sdc")
        && !appForm.getFileCV().getFileName().toLowerCase().endsWith(".zip") )
    errorExtension = true;
if (appForm.getFileLetter() == null || StringUtils.isEmpty(appForm.getFileLetter().getFileName())){
    errors.add("fileLetter", new ActionError("error.fileLetter.required"));
}else if (!appForm.getFileLetter().getFileName().toLowerCase().endsWith(".doc") && !appForm.getFileLetter().getFileName().toLowerCase().endsWith(".pdf")
        && !appForm.getFileLetter().getFileName().toLowerCase().endsWith(".rtf") && !appForm.getFileLetter().getFileName().toLowerCase().endsWith(".zip")
        && !appForm.getFileLetter().getFileName().toLowerCase().endsWith(".zip"))
    errorExtension = true;
/* if (fileForm == null || StringUtils.isEmpty(fileForm.getFileName())){
    errors.add("fileForm", new ActionError("error.fileForm.required"));
}else*/
if(appForm.getFileForm() != null && !StringUtils.isEmpty(appForm.getFileForm().getFileName()))
    if (!appForm.getFileForm().getFileName().toLowerCase().endsWith(".doc") && !appForm.getFileForm().getFileName().toLowerCase().endsWith(".pdf")
        && !appForm.getFileForm().getFileName().toLowerCase().endsWith(".rtf") && !appForm.getFileForm().getFileName().toLowerCase().endsWith(".sdc")
        && !appForm.getFileForm().getFileName().toLowerCase().endsWith(".zip"))
    errorExtension = true;
if(appForm.getFileOther1() != null && !StringUtils.isEmpty(appForm.getFileOther1().getFileName()))
    if (!appForm.getFileOther1().getFileName().toLowerCase().endsWith(".doc") && !appForm.getFileOther1().getFileName().toLowerCase().endsWith(".pdf")
            && !appForm.getFileOther1().getFileName().toLowerCase().endsWith(".rtf")&& !appForm.getFileOther1().getFileName().toLowerCase().endsWith(".sdc")
            && !appForm.getFileOther1().getFileName().toLowerCase().endsWith(".zip"))
        errorExtension = true;
if(appForm.getFileOther2() != null && !StringUtils.isEmpty(appForm.getFileOther2().getFileName()))
    if (!appForm.getFileOther2().getFileName().toLowerCase().endsWith(".doc") && !appForm.getFileOther2().getFileName().toLowerCase().endsWith(".pdf")
            && !appForm.getFileOther2().getFileName().toLowerCase().endsWith(".rtf")&& !appForm.getFileOther2().getFileName().toLowerCase().endsWith(".sdc")
            && !appForm.getFileOther2().getFileName().toLowerCase().endsWith(".zip"))
        errorExtension = true;
if(appForm.getFileOther3() != null && !StringUtils.isEmpty(appForm.getFileOther3().getFileName()))
    if (!appForm.getFileOther3().getFileName().toLowerCase().endsWith(".doc") && !appForm.getFileOther3().getFileName().toLowerCase().endsWith(".pdf")
            && !appForm.getFileOther3().getFileName().toLowerCase().endsWith(".rtf")&& !appForm.getFileOther3().getFileName().toLowerCase().endsWith(".sdc")
            && !appForm.getFileOther3().getFileName().toLowerCase().endsWith(".zip"))
        errorExtension = true;
 WTF#8
There are methods which return Vector (yes, 1999 called) and it turns out that the result is never being used but instead the purpose of the method is to mutate the parameters. Smart.
许多方法返回Vector并且结果证明它们已经不在被使用了。而这些方法存在的目的只是为了达到参数变异效果。聪明(讽刺^_^)。
 ShowStopper#1
cm.getHighLights is an expensive operation (calculates the nested menu of the website) and the following code is supposed to introduce caching into the game:
cm.getHighLights是一个代价昂贵的操作(生成网站树状菜单),下面的代码应该是引入缓存:
ArrayList pubHighlights = (ArrayList)request.getSession().getAttribute("publicationsHighlights");
if(pubHighlights == null || pubHighlights.size() == 0)
pubHighlights = cm.getHighLights(structId, userLang, Constants.PREDEFINED_SEARCH);
request.getSession().setAttribute("publicationsHighlights", pubHighlights);
 - it stores the result in the http session so there is a lot of waste of memory in case we have many users
把结果保存在http session中,在用户很多的场景下比较浪费内存
- the generated menu takes into account “structId” and “userLang”. The cache key is only one though (“publicationsHighlights” in the session), so if the user changes structId or userLang, the menu stays the same
生成的菜单需要考虑“structId” 和 “userLang”。而缓存的key只用到“publicationsHighlights”一个,因此当用户改变structId 或 userLang,菜单保持不变。
- changes on the menu structure are not reflected to already cached clients. They’ll see these changes only if they get a new session (come back later, use another browser etc)
当菜单结构变化时不会反映到已经缓存的客户端。只有他们获取新的会话才能看到改变的结果。
showstopper#2
Application “does things” to the database on view. Things == if stuff are not there it silently creates them, so for example if you visit the about page of the French site and there is no content there (either from CM error or data corruption) it simply creates an empty one and inserts it into the database. This is nice and useful especially when the application thinks that there isn’t any content there, so after a couple of days you’ll find thousand of empty “about” pages under the French site waiting to be fixed by you.应用程序在视图层做一些数据库操作。
showstopper#3
Total incompetence in exception design and handling. The usual anti-pattern of swallow and return new ArrayList() is followed through the system. Database errors are masked and the system goes on doing what it was doing (e.g continuing with other parts of data changes, email dispatching etc).
showstopper#4
“Change navigation element==edit property” anti-pattern. This is sick. Imagine a CRUD page with a couple of filters on top and an entities listing below. In the year filter you choose 2010 and hit GO. The listing is updated with entries from 2010. Now you change the year filter to 2011 but do not hit GO. Instead you hit EDIT on one of the 2010 entities below. What happens is that the 2011 value from the filter is transfered into the (hidden) element of the edit form. As soon as you hit SUBMIT the entity now belongs on 2011. Nice.
showstopper#5
The search is FUBAR. A single search for “foo” issues 200.000 db queries and requires 5 minutes on the production server because:
- it first does “select *” the whole publications database in sorted batches of 1000 back to a collection.
- it then feeds this collection into a method which filters things out.
- while filtering some entity methods are accessed and due to bad fetch plan from hibernate tons of N+1 statements are executed.
showstopper#6
“Toxic servlets hierarchy”. All actions extend something (a base class) which extends servlet. The base class provides a public static spring factory field which is initialized on boot of the servlet. Yes, the only reason of existence of this base class is to provide this field and the actions extend it in order to get access to this public static field. Great.
“有毒的servlet层次”。所有action继承一个基类,这个基类继承servlet。基类提供一个公开的静态的spring工厂变量,此变量在servlet启动的时候初始化。基类存在的唯一理由就是提供这个变量,而action继承基类就是为了访问变量。太棒了(讽刺^_^)。
showstopper#7
Log4j & hibernate initialization rediscovered! Both libraries are being configured in the following fashion:
- read the log4j.properties and hibernate.cfg.xml configuration files from a custom location using a ContextListener
- write contents into a new file in the server’s root folder
- load from there
- documentation states that if application cannot boot the application’s configuration files should be removed from the server’s root folder!

The end.

分享到:
评论

相关推荐

    TerrariaClone:spa难以理解的意大利面条式代码

    但是在我意识到这个想法多么愚蠢之前,我制作了11,000行,迄今为止,这是我一生中见过的最残酷的代码。 我在这里提供该文档主要是作为警告性的故事,说明如果您不注意代码的质量会发生什么。 (以我为例,经验教训...

    Monokai-ST3-theme-for-vscode:崇高文字3的叉子Monokai主题

    ST3的Monokai Fork Sublime的标志性Monokai Orig主题是我一生中见过的最漂亮的Coding主题。更新日志历史多年以来,我一直在开发漂亮的Sublime Text(具有Monokai主题的不同版本)。 在开始使用vscode之后,我发现...

    tensorflow-101:TensorFlow 101:TensorFlow中的Python深度学习简介

    我一生都在机器学习领域工作,从未见过像深度学习这样的算法能超越其基准测试-Andrew Ng 该存储库包括我从头开始完成的基于深度学习的项目实现。 您可以在分步教程中找到源代码和文档。 模型结构和预训练权重也可以...

    智能制造的数字化工厂规划qytp.pptx

    智能制造的数字化工厂规划qytp.pptx

    罗兰贝格:德隆人力资源管理体系gltp.pptx

    罗兰贝格:德隆人力资源管理体系gltp.pptx

    JAVA3D的网络三维技术的设计与实现.zip

    JAVA3D的网络三维技术的设计与实现

    setuptools-11.3.1.tar.gz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    基于J2EE的B2C电子商务系统开发.zip

    基于J2EE的B2C电子商务系统开发

    麦肯锡_xx保险员工培训咨询报告gltp.pptx

    麦肯锡_xx保险员工培训咨询报告gltp.pptx

    JAVA社区网络服务系统.zip

    JAVA社区网络服务系统

    备自投tp.pptx

    备自投tp.pptx

    setuptools-10.1-py2.py3-none-any.whl

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    基于JSP的高校教务排课管理系统源码.zip

    JSP高校教务排课管理系统,管理员角色包含以下功能:课程申请管理,课程设置管理,课程情况查看,专业设置查看,排课管理,系办人员管理,教师管理,学生管理,教室管理,班级管理,管理员登录等功能。教师角色包含以下功能:教师角色登录,申请增加课程,学生管理,成绩录入管理,课程安排管理等功能。学生角色包含以下功能:学生角色登录,基本信息查看,选课功能安排,课程表查看,成绩查询等功能。 本项目实现的最终作用是基于JSP高校教务排课管理系统 分为3个角色 第1个角色为管理员角色,实现了如下功能: - 专业设置查看 - 学生管理 - 排课管理 - 教室管理 - 教师管理 - 班级管理 - 管理员登录 - 系办人员管理 - 课程情况查看 - 课程申请管理 - 课程设置管理 第2个角色为教师角色,实现了如下功能: - 学生管理 - 成绩录入管理 - 教师角色登录 - 申请增加课程 - 课程安排管理 第3个角色为学生角色,实现了如下功能: - 基本信息查看 - 学生角色登录 - 成绩查询 - 课程表查看 - 选课功能安排

    第21章spring-mvc之缓存

    第21章spring-mvc之缓存

    华为网盘高级版

    华为网盘高级版

    setuptools-18.0.tar.gz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    Java聊天室程序(java).zip

    Java聊天室程序(java)

    产品线经理转身赋能zzn.pptx

    产品线经理转身赋能zzn.pptx

    JAVA泡泡堂网络游戏的设计与实现.zip

    JAVA泡泡堂网络游戏的设计与实现

    setuptools-11.0-py2.py3-none-any.whl

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

Global site tag (gtag.js) - Google Analytics