存档

文章标签 ‘Programming’

转载:重构代码的7个阶段

2011年9月30日 admin 没有评论

原文地址: http://coolshell.cn/articles/5201.html 

你曾去想重构一个很老的模块,但是你只看了一眼你就恶心极了。文档,奇怪的函数和类的命名,等等,整个模块就像一个带着脚镣的衣衫褴褛的人,虽然能走,但是其已经让人感到很不舒服。面对这种情况,真正的程序员会是不会认输的,他们会接受挑战认真分析,那怕重写也在所不惜。最终那个模块会被他们重构,就像以前和大家介绍过的那些令人销魂的编程方式中的屠宰式编程一样。下面是重构代码的几个阶段,文章来自:The 7 stages of refactoring,下面的翻译只是意译。

第一阶段 – 绝望

在你开始去查看你想要重构的模块的,你会觉得好像很简单,这里需要改一个类,那里需要改两到三个函数,重写几个函数,看上去没什么大不了的,一两天就搞定了。于是你着手开始重构,然后当你调整重构了一些代码,比如改了一些命名,修理了一些逻辑,渐渐地,你会发现这个怪物原来体型这么大,你会看到与代码不符甚至含糊不清的注释,完全摸不着头脑的数据结构,还有一些看似不需要方法被调了几次,你还会发现无法搞清一个函数调用链上的逻辑。你感到这个事可能一周都搞不定,你开始绝望了。

第二阶段 – 找最简单的做

你承认你要重构的这个模块就是一个可怕的怪物,不是一两下就可以搞定的,于是你开始着干一些简单的事,比如重新命名一下几个函数,移除一些代码的阻碍,产生几个常量来消除magic number,等等,你知道这样做至少不会让代码变得更糟糕。

第三阶段 – 再次绝望

但是接下来的事会让你再次撞墙。你会发现那些代码的瑕疵是些不痛不痒的事,改正这些事完全于事无补,你应该要做的事就是重写所有的东西。但是你却没有时间这么干,而这些代码剪不乱理还乱,耦合得太多,让你再一次绝望。所以,你只能部分重写那些不会花太多时间的部分,这样至少可以让这些老的代码能被更多的重用。虽然不完美,但是至少可以试试。

第四阶段 – 开始乐观

在你试着部分重构这个模块几天之后,随着重构了几个单元后,虽然你发现改善代码的进度太慢了,但此时,你已知道代码应该要被改成什么样,你在痛苦之后也锁定了那些那修改的类。是的,虽然你的时间预算已经超支,虽然要干的事比较多,但你还是充满希望,觉得那是值得的。你胸中的那团火又被点燃了。

第五阶段  – 快速了结

在这个时候,你发现你已花了太多的时间,而情况越来越复杂,你感到你所面对的情况越来越让你越到不安,你明白你自己已经陷入了困境。你原本以为只需要一次简单的重构,然而现在你要面对的是重写所有的东西。你开始意识到原因是因为你是一个完美主义者,你想让代码变得完美。于是你开始在怠慢你文档,并想找到一个捷径来重写老的代码,你开始采用一些简单而粗暴,快速而有点肮脏的方法。虽然不是很完美,但你就是这样去做了。然后,你开始运行测试做UT,发现 UT报告上全是红色,几乎全都失败了,你恐慌了,于是快速地fix代码,然后让UT 能工作。此时,你拍拍自己胸口,说到,没问题 ,于是就把代码提交了。

第六阶段 – 修改大量的Bug

你的重写并不完美,虽然其过了测试,但是那些UT测试对于你的新的代码有点不太合适,虽然他们都没有报错,但是他们测试得范围太小了,没有覆盖到所有的情况和边界。所以,在这以后,你还需要几周或是更长的时间不得不来修正越来越多的bug,这使得你的设计和代码在每一次quick-fix后就变得越来越难看。此时,代码已经不像你所期望的那样完美了,但你依然觉得他还是比一开始要好一些。这个阶段可能历经几个月。

第七阶段  – 觉悟

经过了6个月,你重写的模块又出了一个比较严重的bug。这让你重构的那个模块变得更难堪。你发现出的这个问题是和当初的设计不一致,你还发现被你重构掉的那段老的代码并不是当初看上去的那么坏,那段老的代码确实考虑到了一些你未曾考虑到的事情。这个时候,你团队里有人站出来说这个模块应该被重构或是重写,而你却不动声色地一言不发,并希望那个站出来的人能在几个月后能觉悟起来。

——————

不知道这是不是你的经历,我经历过很多次这样的事。对于很多维护性质的项目,我犯过的错误让我成了一个实实在在的保守派,我几乎不敢动,那怕看到代码很不合口味。当然,那些从来没有写过代码的敏捷咨询师一定会说用TDD或是UT可以让你的重构更有效也更容易,因为这样会让他们显得更我价值,但我想告诉你,这种脱离实际的说法很不负责任,这就好比说—— 我在杀猪的时候遇到了一些麻烦,因为我对猪的生理结构不清楚,或是这本来就是一头畸形的猪,导致我杀的猪很难看,而伟大的敏捷咨询师却告诉我,要用一把更快更漂亮的刀。软件开发永远不是那么简单的事,杀猪也一样。

分类: 软件设计 标签:

Daniel-Journey Weekly Dose- 2010/12/4

2010年12月5日 admin 4 条评论

Programming

怎样把自己培养成为一个优秀的程序员

Database & SQL

用Twitter的cursor方式进行Web数据分页

Scalability

多IDC数据时序问题及方法论

RAID介绍

8 Commonly Used Scalable System Design Patterns

  1. Load Balancer – a dispatcher determines which worker instance will handle a request based on different policies.
  2. Scatter and Gather – a dispatcher multicasts requests to all workers in a pool. Each worker will compute a local result and send it back to the dispatcher, who will consolidate them into a single response and then send back to the client.
  3. Result Cache – a dispatcher will first lookup if the request has been made before and try to find the previous result to return, in order to save the actual execution.
  4. Shared Space – all workers monitors information from the shared space and contributes partial knowledge back to the blackboard. The information is continuously enriched until a solution is reached.
  5. Pipe and Filter – all workers connected by pipes across which data flows.
  6. MapReduce -  targets batch jobs where disk I/O is the major bottleneck. It use a distributed file system so that disk I/O can be done in parallel.
  7. Bulk Synchronous Parallel – a  lock-step execution across all workers, coordinated by a master.
  8. Execution Orchestrator - an intelligent scheduler / orchestrator schedules ready-to-run tasks (based on a dependency graph) across a clusters of dumb workers.

如何解决cache同时过期问题

解决办法:

在一个比较大的应用中,cache尽量使用服务的形式,跟web应用进行隔离开来,避免应用重启导致重建cache对后端的冲击。(其实这样能提高多个web下面的缓存利用率)

cache服务尽量使用多个,避免一个宕机重建全部cache对后端的冲击。多个cache服务尽量使用一致性hash的模式。

cache同时过期的问题,比如是30秒过期,可以找个业务可以接收的范围,比如25-40秒之间随机一个过期时间,可以减少同时过期的概率。

可以考虑使用多级cache。

事实上,在设计系统的时候,就需要考虑cache如果失效对系统产生的可能冲击影响,以及如何去避免这些问题的发生。重启系统可以考虑一个缓存预热的过程。

Project Management

项目经理的思维批判

Daniel-Journey Weekly Dose-2010/11/7

2010年11月7日 admin 1 条评论

Java

JAVA线程dump的分析 — jstack pid

  • 在 windows环境中,在启动程序的控制台里敲: Ctrl – Break,线程的 dump会产生在标准输出中( 缺省标准输出就是控制台,如果对输出进行了重定向,则要查看输出文件)。
  • 在 unix, linux和 MacOS 环境中,在控制台中敲: Ctrl-\,或者,;  用 “kill -3 <pid>” ,或者 “kill – QUIT <pid>”。 Pid是用所关注的 JAVA进程号,您可以用 “ps -ef | grep java” 找到;或者使用 JDK 5.0中的 “jps -v” 命令获得。
  • 在各个操作系统平台,都可以用 JDK 5.0工具包中的 jstack <pid>

Programming

每位开发人员都应铭记的10句编程谚语

    1. 无风不起浪
    2. 预防为主,治疗为辅
    3. 不要孤注一掷 (过度依赖某人)
    4. 种瓜得瓜,种豆得豆
    5. 欲速则不达
    6. 三思而后行
    7. 如果你惟一的工具是一把锤子,你往往会把一切问题看成钉子
    8. 沉默即赞同
    9. 双鸟在林,不如一鸟在手
    10. 能力越大,责任越大

    Scalability

    Amdahl定律

    分布式服务框架常被质疑的价值

    Other

    Windows命令行窗口日志输出重定向方法

软件开发沉思录阅读笔记一

2010年2月6日 admin 没有评论

软件开发沉思录简介

从编程技术到项目管理,Roy Singham、Martin Fowler、Rebecca Parsons等来自ThoughtWorks的思想领袖通过本书中的13篇美文,将自己多年沉思和实践所得倾囊相授,引领你走向敏捷软件开发的成功之路。
本书内容丰富,涵盖了软件开发的各个阶段,既包含DSL、SOA、多语言开发和领域驱动设计等热门主题,也有对象设计、一键发布、性能测试和项目管理等方面的经验之谈和独到见解。不论你是开发人员还是项目管理人员,都将从本书中获益匪浅。

第六章 对象健身操

  • 优秀设计背后的核心概念其实并不高深。比如内聚性、松耦合、零重复、封装、可测试性、可读性以及单一职责。这七条评判代码质量的原则就已经被广泛接受了。然而真正困难的是如何把这些概念付诸实践。理解了封装就是隐藏“数据、实现细节、类型、设计或者构造”,这只是设计出良好封装代码的第一步而已。
  • 更为严格的编码标准。
    • 方法只使用一级缩进
    • 拒绝使用else关键字
    • 封装所有的原生类型和字符串
    • 一行代码只有一个“.”运算符
    • 不要使用缩写
    • 保持实体对象简单清晰
    • 任何类型中的实例变量都不要超过两个
    • 使用一流的集合
    • 不使用任何Getter/Setter/Property
      • 这条规则通常被描述为“讲述而不要询问”(“Tell, dont’t ask”)
  • 如果努力地拥抱简单性,那么开发过程会快乐得多。
分类: 软件设计 标签: ,