博客

  • 跟同事在一起

    单位里年轻人相对多一些,身边满是年轻貌美的小医生小护士,相比之下,我算地道的黄脸婆了。帅哥看过照片给了肯定的评价,说我肯定是最老最丑的一个,我那心啊,哇凉哇凉的。

    不过跟她们在一起有个巨大的好处,就是可以跟着变年轻起来,每天看她们唧唧喳喳乐乐呵呵的样子,真是不错。昨天有两个过来试工的年长者也说跟年轻人在一起心情都不一样了云云,看来不光是我有这样的感觉啊,哈哈。有人说是男人都喜欢十七八的小姑娘,我真是无语了!

    还是看看我们年轻的护士长吧

    中间的护士长总说自己是奔五的人,大家看了却都说像三十几岁的样子,人和人的差距还真是大啊,行了,要想年轻得好好护理皮肤,早睡觉才行,不写了,嘿嘿。

  • 开发者必读博客Top100-2009年第一季版本

    http://www.noop.nl/2009/03/top-100-blogs-for-developers-q1-2009.html

    这个博客是我前一阵发现的,其中有篇文字100个软件面试问题还在最近一期的《程序员》杂志被人(不是我)翻译出来。

    这个主题,noop.nl在以前写过,但是已经有些过时了,那只是08年底啊。可以想见软件开发这个领域的后浪推前浪真是太猛了。

    懂英文的朋友,还是建议大家去看原文,里面有很多搞笑的文字,我也不全文翻译了。

    2009年Q1版本的变化主要是删掉了一些不更新的博客以及讨论主题不是软件开发的,仅专注某个开发语言(如ruby)的也被删掉,整个top100是基于google rank,alexa rank,twitter follow人数以及博客留言人数来作为评定基准的,收录的博客也都是讨论通用软件开发领域的。

    下面就是软件开发top100博客列表,前面是博客地址,后面是博客作者的twitter地址。第一个数字是本场名词,后面的LT是上次评比名词。权威不权威暂且不论,可以作为一个选择博客、扩大阅读知识面的参考。

    TT LT Blog / Site Author / Twitter

    1 1 Joel on Software Joel Spolsky

    祖尔谈软件依然是第一名,从文章质量来说,真是当之无愧,而且应该注意的是,不知是否是Noop.nl的一个故意所为,实际上后面第十名的stackoverflow也应该是Joel参与的一个网站。

    2 3 Coding Horror Jeff Atwood

    Coding horror最近一个介绍Peer review编程的文章很有意思,里面提到英雄也是有伙伴的,比如蝙蝠侠和罗宾,列侬与麦卡特尼,马里奥与路易等等。

    3 6 Martin Fowler’s Bliki Martin Fowler

    不用说了,看到Martin,就冒出敏捷啊、重构啊、模式啊,都是时髦词。

    4 11 The Daily WTF (various)

    WTF,是英文Worse than Failure的缩写,但是估计大家都会把它看成What the fuck。在博客的about里提到算是一个幽默型的博客,可惜对于西方人的幽默,有的不是很理解。

    5 67 Signal vs. Noise (various)

    信号vs噪声,看上去像是搞电子的啊,实际是37signals的一个博客,主题是设计、商业、经验等等。ROR的家,页面设计感觉很舒服。

    6 5 Scott Hanselman’s Computer Zen Scott Hanselman

    这个博客关注的是微软开发技术,从他的tags里就能看出来,有关注微软DotNet、Asp.net,可以去看看。

    7 10 Rands in Repose Michael Lopp

    这个博客的主题应该是管理,最新一篇文字Tweet的艺术很好玩。里面提到Say more with less(文字要精炼)以及Don’t Say What You’re Doing, Say Why You’re Doing It(不要说你正在做什么,而是说你为何做这个)

    8 7 Bokardo: Social Design Joshua Porter

    博客主题是社会性设计,里面谈论的是facebook、digg这样的社会性软件。我个人不是很感兴趣。

    9 8 Stevey’s Blog Rants Steve Yegge

    看不太出来主题,应该是动态语言、设计方面

    10 19 Stack Overflow Jeff Atwood

    近期很火爆的程序设计方面问答社区。

    后面的列表就不详述了,大家有兴趣的,可以一个个慢慢看,可以直接导入这个opml文件阅读整个top100列表。

  • 快乐的315

    315那天是我的阳历生日,妹妹的农历生日,临时决定把妹妹叫来一起过,咱姐妹俩一起过生日已经不是头一遭了,可惜我们年龄相差悬殊了点儿,人家风华正茂,我已经开始走下坡路,唉,郁闷啊。

    三个美女把脸凑在一起,比比谁更漂亮呢,看样子最自信的是小美女啦

    一家三口,其乐融融,虽然有人说我们有点儿太腻歪,可妹妹说这感觉贼好,那就出来秀秀好了,嘿嘿

  • 程序优化经验谈

    项目接近尾声,我们开始做各种各样复杂一些的测试,优化在这个时候成为一个比较明显的问题。

    也许有的朋友会说,为何一开始不考虑优化?作为一个老程序员,基本的一些常识还是有的,比如不去反复调用一些初始化操作,GetCount或者是GetSize这样的操作不放在循环里面进行,但是运行性能问题还是会发生。在最后的时候优化,算是一个比较好的时机,因为过早优化会没有目的性,既然客户端没有进行实际的调用,怎么知道那些操作会带来性能问题呢,只有跑起来才知道。

    我们项目是一个组件程序,通过COM接口被其他程序使用,设计为了简单,将一些数据放在注册表里存放,另外其他大部分数据都是读取一个格式化的文本文件(EDS)来获得的。程序的整个结构是单线程的,同一个进程中,任何一个复杂操作都会阻塞其它调用的进行。

    代码优化的重点是放在初始化这个阶段,因为我们需要读文件来构造整个系统,这其中牵扯到注册表操作以及文件操作和对文件解析生成特定的实例(instance)。

    注册表的优缺点暂不评论,但是它的性能真的是很成问题,注册表是典型的key-value结构,按理说读取速度应该很快,但是它真的很牵扯性能,这个地方的优化做了一些,但是本质上没办法做更多的优化,个人倒是比较喜欢一些简单的数据库作为程序后端存储,比如很多公司都用到的sqlite引擎,支持sql语言查询,性能还算是不错,应该可以作为一个很好的替代品。问题是类似东西可能有license引用的问题,这个就比较复杂了。

    我们组里另外一个同事针对注册表操作做了一些改进,估计这方面也不能做的更好了。所以注册表方面暂借不管,主要精力放在内部代码改进。

    首先必须要做的就是收集数据,看看那些函数调用费时间。好在我已经有现成的log以及高性能计时器类,只要包含一下就可以。有的朋友会说log文件有多线程问题,计时器有多cpu问题。没错,但是我们程序是单线程的(见前面说明),所以写文件时候不加锁,另外尽量只建立一个全局log实例,保证创建、关闭文件操作非常少,而且也不进行内存new/delete操作。为何不使用OutputDebugString?好问题,这个函数可能导致一些时序上的问题(可以搜索codeproject上面有介绍文字),可以用,但是不如写文件那么simple。感觉这些也许是问题,但是还是尽量简化这些工具,够用就好。

    经过性能数据收集,发现读取、解析文件使用时间不多,相比来说将数据序列化类实例比较耗时,因为我们加入了很多验证的函数调用,导致新的代码比前一个版本需要更多的调用。当然可以去掉这些验证,但是那我们还做这个新版本干嘛呢。

    根据现在得到的数据,主要下面一些改进:一个是将一些集合类加入对map的继承关系,相当于重新又包装了一次抽象。原因是我们在查询这些集合类的时候都是使用的循环for-loop调用,相比map的查询,就差了不少。(学过数据结构的朋友应该了解stl的map查询性能要好很多,因为内部一般是用树状结构实现的)。另外一个改动就是把一些不必要的初始化操作放在后面进行,这样就导致我们需要在一些函数调用时加上它相关的初始化调用,代码复杂了不少,但是也没有办法。还有一个常用的手法就是使用cache,把一些运算结果缓存起来,下一次就直接拿出结果使用。cache最好在后期有了具体数据在进行,因为过早的优化,过早的加入cache机制不见得是正确的。为什么这么说呢?因为cache有一个可能失效甚至出错的可能,真正的结果可能因为某些数据变化而产生变化,如果这个时候cache系统不知道,那么就出错了,如果加入事件消息来刷新cache,也许就会让代码变得过于复杂,不容易维护和理解,也许性能还不如简单的版本快呢,就如同奥卡姆剃刀原理提到的那样,复杂的往往都是错的,或者是错误的根源。

    总结说就是使用正确的数据结构,适当使用cache。如果这些还不行,那就得具体问题具体分析,后来我加入了更详细的log信息,发现用户端对于同一个文件做了多次的初始化调用,这也是优化时候需要注意的,客户端代码也需要相应的优化,也许它们的优化才是最关键的。虽然没有拿到客户端优化的结果,但我相信这个修改会比我前面做的任何改进都要显著,而且未必改动很复杂。

    总的来说,这次代码改进不算是很成功,主要是一开始的方向不太对,尽管后来发现了真正的原因。我想主要问题是一开始就把目光聚集到非常微观的范畴里,导致大的问题没有得到解决。另外对于程序优化这件事,必须有实际的运行数据,猜测哪个地方可能会慢或者有问题,都是不客观的,在优化问题中,不应该出现“我觉得、我想”的字眼,什么地方慢什么地方需要改动,一定要用数据来说话。优化必然要对代码做这样那样的变动,这时候我们累积的test case就非常有用了,可以帮助我们确定代码改动是否引入了错误。

  • 不要用一个模子制造所有东西 – 软件开发的复杂宣言

    http://www.noop.nl/2009/03/the-complex-manifesto.html

    noop.nl是一个比较关注开发方面的博客,里面有些文章很有意思,比如这篇。

    我平时喜欢到toplanguage这个开发群组里去看看有什么讨论的话题,发现很多人有一种习惯,自己比较喜欢的一种语言或者模式,就喜欢推荐给别人,当然,本意不是坏的。经常会出现类似情况,前面一个人提问一个相对还不怎么具体的问题,后面就跟上来“这个问题可以用xx解决”或者“这个是xx语言擅长的”,也许也对,但是未免以偏概全。用标题的句子来说就是试图用一个模子去制造所有的物件。

    就如同文章里提到的,人们倾向于简单的解决方式,可是我们也要意识到,真实世界比我们想象的更复杂。

    作者提出一个复杂宣言,大意如下,后面的注是我的想法。

    Each Problem Has Multiple Solutions

    每个问题都有不同的解决方案。

    注:显然如此,而开发者经常需要做的就是权衡抉择,从不同方案里尽快选择一个可行的。相比保证方案的完整性正确性,行动起来往往更重要。

    Solutions Depend on the Problem’s Situation

    解决方案依赖于问题的具体情形

    注:Erlang不是万能的,java、ruby、python不是万能的,软件开发没有银弹。一个问题,如果用basic就可以快速解决完成,那就是好的。一个高并发高性能的设计方案,如果没有真实运行起来,没有实际数据的证明,那就是个纸上谈兵,都是假的。

    Changing Context Requires Changing Solutions

    改变了环境(需求变化?),也需要变更解决方案。

    注:同样的,没有银弹,没有万灵药。

    Some Solutions are More Prevalent Than Others

    一些解决方案比其它的更流行

    注:没错,ruby on rails是很火爆,django也非常有名,但未必就一定适合你,选择好的不如选择对的,尽管有时候对的长得不一定好看。

    For Every Solution There is a Best Situation

    对于每个解决方案都有一个最佳的时机

    注:这句话稍有些拗口,不过可以这样理解,“这个方案为何不用c++?”ok,也许那时候c++还没有发明出来,“为什么会有1M内存限制这么傻的东西?”那时代,1M内存就是高配了。也许现在看来一些很愚蠢的选择,当时也许都有一些必须的原因。

    Solutions Change Themselves by Changing Their Situations

    解决方案通过改变它们的运行环境来改变它们自己

    注:解决方案改变了环境,环境改变又需要改变解决方案,一个互相影响互相作用的关系。

    Understanding Complexity Helps in Applying Simplicity

    对复杂度的理解可以帮助应用的简洁

    注:可不可以这样理解,对问题理解的更深刻,也许解决起来未必就很复杂。比如网上流传的那个电风扇吹空盒的故事。

    It Is Impossible to Predict the Best Solution

    不可能预见到最佳的解决方案

    注:邓公不是说过吗,摸着石头过河,不可能一下子就找到最佳的过河地点过河时机的。只有走出这一步,才是最重要的。

    最后有句话我非常非常欣赏,相比那些绚丽多彩的技术(敏捷、scrum、用例、用户卡片),我们更应该关心“什么时候用什么”。推荐大家读读此文。