博客

  • 针对12306问题乱弹架构设计

    关于12306网站架构,不少人提出了自己的设计思路,有的人很简单,比如说nodejs就行,nosql一定可以,或者是某某方案最适合了。看了不少文章,感觉还是coolshell的最实际靠谱 http://coolshell.cn/articles/6470.html 。由于末学对网站架构方面翻译的文章很少,不敢说自己是大型网站架构师,实战经验更是没有,就不充大头提什么技术方案了,只从比较虚的架构设计方面说说自己的一些见解。

    一个实际的不成功例子

    最近组内一个内部项目,从设计到实现一起群体智慧完成,但是进度和完成质量却比我想象的差了很多。项目很简单,大概就是一千多条数据,使用Asp.net MVC3搭建。为了技术练手,把后台部分大部分逻辑做成webservice,使用WCF搭建。业务内容也相当简单,不过就是CRUD。因为数据库使用Access(客户决定),所以SQL都是手写,包装成DBHelper给业务使用。就这样一个简单设计,却也经过了两次总体设计,比预期进度慢了很多,完成度和设计优美程度都比预期的差。个人感觉而言,项目不能说失败,但也称不上成功。好在我们当时的想法就是用这个项目来锻炼团队,这样想心里还能好受些。

    自我反思,不成功原因很简单,最主要是团队在这方面经验不足造成的(还有其它原因不方便说)。某个人是否能很好地完成一项工作,首要的是态度,其次是能力,所以选择的时候这两方面都需要考虑清楚。另外,对于新人不要设置太高标准,需要适当给以监督和辅导。

    从这个实际例子就可以看出来,架构问题不会也不可能是简单的说几句话,指个方向就能完成。再好的纸上谈兵,放在现实中也可能出现预料不到的困难。所以最好的办法是找靠谱的人,最好是有相关经验的靠谱的人,去做靠谱的事;从试错的过程中吸取教训,不断完善架构设计。架构师的工作不仅仅是把简单问题复杂化或者复杂问题简单化,而是根据项目具体需要,以及相关环境约束,平衡取舍得到一个最合适的方案。

    12306的问题

    由于春节出行需要,在12306上购买了往返车票,在购买春节前车票的时候,遇到了无法登录的问题,大约花了将近两个小时,才登录成功,并且在下订单时也碰到几次问题,但是总体而言,相比去火车站排队还是要轻松很多,另外提前12天购票也让购票更提前了。

    没有准确数据,很难估计12306在高峰时的并发和负载到底是什么样的。如同下面报道中的数据一样,不少说法要么不专业,要么有水分,很难让人信服。http://bschool.sohu.com/20120117/n332409067.shtml 另外铁老大的封闭性以及项目本身可能具有的保密性,谁设计实现,花了多少钱,大致架构如何,也都是个迷。

    在9月份以后大致有两个并发相关的大事件,一个是京东促销,两次促销两次接近当机,成绩只能说不及格。另外是淘宝还是淘宝商城的双十一促销,没有怎么关注,据说效果还不错。

    除了淘宝比较开放一些,架构方面的宣传比较多,京东这个新晋小生一样是对架构讳莫如深,或者从另一个方面说明,刘强东这个人并不怎么重视信息系统建设。

    相比这两个事件而言,12306的成绩不算太好,但也不算差,如果我评分,会给一个70分,已经是及格以上。12306的问题不是技术问题,而是人的问题,或者说是一个权势角力的结果。技术选择从来都不是从底层技术人员发起的。

    另外有人评论:界面丑,用户体验差。这个真的不是问题。不少微博上叫唤的欢实的,他们自己公司内部系统的界面和用户体验可能会更差,尤其以报销系统或者人事系统更甚。说句实在的,他们连自己boss都说服不了,让他们自己换换这些差系统,还提出这个那个方面,实在是没有说服力啊。

    架构再好,也要团队,软件开发的关键是人

    有不少人一说高负载分布式,动辄就是什么nodejs,nosql,缓存,文件系统,大数据这些关键词,好像这些关键词一说,问题立马就解决了。问题在于,这些关键词只是一些点,架构设计和实现其实是一个面或者是立体的。

    举一个简单的例子,一个团队,其中的成员大部分是dotnet背景或者是java背景,他们熟悉的是sqlserver或者是oracle,了解的是项目中用到的那些技术,超出这个范围的,不知道不了解都是理所应当的。这样一个团队,如果某个架构师听说nodejs或者nosql可以解决他们的问题,边学边做,照猫画虎,摸着石头过河。你觉得这样的项目会成功吗?!

    所以,只有团队整体素质够高,才能够产生一个比较完美的解决方案。这样的团队,只能是有腔调的技术带头人加上比较靠谱的执行者才行。

    合适的架构是磨出来的,没有一开始完美无瑕的方案

    @fire9 在微博上说好的架构不是设计出来的,而是运维出来的,我对运维这个方向了解很少,对此不评论。我的观点是合适架构是磨出来的,需要一个持之以恒,反复迭代的过程,在某个阶段,也许还需要涅磐重生,关于这个观点,在《The Pragmatic Programmer: From Journeyman to Master》书里就有一个完美草地的例子。

    架构设计必须满足几个条件,一个是满足客户需求,在微博上不少人提出种种解决方案,但是越看越像是在炫技,是他们自己有这方面的需要和想法,与客户需求没有一毛钱关系。合适的架构也要获得高层的支持和投入,这一点在中国尤其重要。还有一点,合适的架构要考虑到执行效果,仅仅设计出来,无法实现也是不行的。好的架构师必须保证控制自己的欲望,不要什么技术都往上堆,什么需求都想满足,否则项目的结果只能是失控。

    如何磨一个架构?我的经验不多,简单说一些务虚的内容。首先是态度积极,真心想把事情做好,而不是凑付。另外要保证项目的长期性,让团队有归属感。技术上保证不断学习,整个团队一直保持上升势头。另外是团队搭配合理,主力程序员,程序员,项目经理搭配工作,没有很明显的短板。有了这些软件支持,磨出一个好架构不是难事。

    方案是经验的体现

    回到12306的设计方案可以看出,云风的方案有点类似网游服务器,酷壳陈皓在服务器开发和Amazon积累的经验,让他能够介绍一些关于业务上的问题。 他们以往的经验很好的反映在设计方案中。

    如果真的要设计方案,谷歌百度腾讯这些公司里面的大规模并发/大数据/高可用性这些方面的专家很有帮助,但我更相信,来自淘宝Amazon这样电商公司的经验更准确有力,因为他们对业务更熟悉,对于业务流程设计中可能有的风险问题会有更好的体会。技术必须契合业务,才能发挥正面作用。任何时候都不应该是先提技术后谈需求,可惜这样本末倒置的事情经常发生。

    12306该怎么做,这个其实不是问题,因为铁道部根本没有问过这个问题,就如同给京东提建议给支付宝提建议无人响应一样,都不过是技术人手痒产生的意淫罢了。不过这些讨论还是可以看出很多闪光点,让我们在以后的设计中采用或者注意类似的方案。

  • 如何开发高质量软件?及软件测试观点

    也许是因为我经常在twitter上鼓吹“代码质量来自code review和单元测试”,老赵的这篇文字 http://blog.zhaojie.me/2012/01/a-case-requirement-to-practice-unit-testing-or-tdd.html 也at我一下,抱歉的是最近欠债太多,正在着手完成答应侯伯薇的那篇关于appengine的文字。

    趁着兴头和最近的一些工作简单谈谈我的软件测试观点。

    上周五小组对前一阵的一个项目做了整体的代码review,然后对单元测试代码也简单review了一下,大概二十几个测试用例完全通过,mstest中一条条绿杠杠让人很开心。

    今天英语加技术学习,看了这篇 http://net.tutsplus.com/tutorials/ruby/the-intro-to-rails-screencast-i-wish-i-had/ 其中正好讲解了如何使用TDD开发rails程序,酷毙了,其中guard,rspec,capybara这些Ruby的好玩意让我等DotNet程序员羡慕不已。

    如何进行高质量软件开发?是我这大半年一直在思考和研究的问题。对于我们大部分项目的流程,简单总结起来就是,前期需求review,设计review,风险评估,开发中期review,代码结束review,维护阶段。

    前期review主要是保证项目不要过早的投入编码,设计上不够成熟或者没有考虑的很清晰。我发现不少人是以编码代替设计,或者说还没有想好怎么设计,代码就号称写完百分之八十了,很无语。前期review以主力程序员担当设计和主要技术攻关,并且反复确认设计中不清晰的地方。在前期设计阶段也会对任务进行分派,其中有程序实现,单元测试实现,手动测试实现,代码review等不同角色。理论上说单元测试应该由程序实现者完成,但是由于项目特点决定,我们对于某些项目的单元测试是有另外的程序员实现,稍大一些的项目(或者说story)就需要有三个人熟悉设计和代码实现,大致是一到两个实现者,一到两个代码review人员,这样有些人担心的“对项目不熟悉代码不熟悉,怎么进行code review?“的问题就不存在了,而且也很好的保证了万一有人请假有事,其他人也可以很快完成任务。

    开发中期review,主要是对整体思路再次检查一遍,另外确保项目整体质量是OK的,上个月就在中期review的时候,果断叫停某个质量很低的项目,调入一个主力程序员重新设计,虽然浪费了一些时间,但是代码质量比前一个版本要好很多。

    代码结束review,是整个小组对项目实现进行逐行的分析解读,貌似这样会比较浪费时间。但是我们现在团队初建,很多技术甚至是常识都需要反复强调,这种小组review很有必要,也是很好的学习过程。

    再着重谈谈单元测试。通过比较NUnit和MSTest后选择MSTest作为测试框架,另外也会选择集成测试或者是接口测试等不同测试级别,主要是看项目需要,并不拘泥于非要单元测试。现在的问题是单元测试本身设计的还不够,基本上只考虑”正常、异常、上临界、下临界、空值、复杂值“这些情况,没法做到很好的代码覆盖率,希望这个在以后能慢慢提高。MSTest的使用很简单,基本上跟Nunit没啥区别,好处是可以直接集成在VS2010高级版中,另外也可以通过mstest命令行调用,持续集成也很容易。

    我们基本上会在项目设计阶段就对测试用例同时进行设计考虑,然后会留出大约百分之三十到四十的时间给单元测试或者自动测试。这个比例根据项目重要程度或者复杂程度也会相应地调整。

    另外一个很关键的问题是”如何测试GUI?”对于asp.net mvc,我们基本上只会自动测试controller,对于view部分,是准备使用自动的browser测试框架来做,现在还是以手动测试为主;对于wpf程序,主要是测试viewmodel部分,但是现在也主要以手动测试为主。对于需求倾向于前端的应用,基本上不会考虑单元测试。但是为了很好地保证质量,我们会把关键的需求点作为测试用例,然后有人专门做手动测试。也开发了一个自动记录回放的小软件,但是效果一般,基本没用。

    团队初建,我个人经验不足,所以很多也是在摸索调整,希望以后能有更完整高效的开发流程可以分享给各位。

  • 简单重构 very careful about your code

    代码编写需要有一种统一的对称的美感。
    比如下面的代码,在对称上有问题。

    问题一,为何在E ()中有减一的操作,回答是需要考虑最后一块,不make sense,暂且放着。
    问题二,为何for循环在E 是 <= ,而在D 中却是 < ,这是第二个不对称的地方,理由也是为了考虑最后一块数据。
    其他问题与主题无关,暂且不提。

    可以看到在E ()中为了最后一块数据,引入了两个需要额外解释说明的地方,
    这样就让E ()这个函数与它的对应函数D ()从形式上很不一样,这就是所谓的代码味道不够好。

    但是最后不整齐的数据是一个问题,可以将问题使用额外代码隔离开,这样逻辑就比较清晰。

    修改后添加的代码单独为了最后一部分数据加入,
    前面的for循环与D ()函数中的for循环已经有着统一风格,也没有奇怪的<= 和”减一操作”出现了。

     

  • 近期的一些技术新闻

    我在《敏捷之旅2011大连站暨QClub大连站2011年第三期》上跟着凑热闹,也有一个关于GAE的session,大连的朋友欢迎捧场。

    http://agiletour.cn/dalian/

     

    IronPython2.7.1发布了,写了一个关于IronPython的PPT,大家可以看看,蜻蜓点水介绍一下DotNet下使用IronPython。

    http://www.slideshare.net/ak47/python-with-dot-net-and-vs2010

    IronPython使用Sqlite.net

    http://code.google.com/p/csharp-sqlite/

    http://stackoverflow.com/questions/3513981/using-sqlite3-with-ironpython-2-6-for-net4

     

    如果想在Windows下使用Lua的整合安装包,除了Lua for Windows,可以试试这个Idle编程一样,是Lua的变体。

    http://idle.thomaslauer.com/

     

    一个跟Lua游戏开发相关的(love2D)github账号

    https://github.com/BlackBulletIV

     

    generic socket control mechanism for large numbers of connections 

    https://github.com/icgood/ratchet

     

    有性格的Mike Pall(LuaJit作者)强文,关于他碰到的俩搞笑开发故事

    http://article.gmane.org/gmane.comp.lang.lua.general/84483

     

    斯坦福大学一个学习视频,关于Web应用开发

    http://openclassroom.stanford.edu/MainFolder/CoursePage.php?course=WebApplications

     

    有人在LuaList问能否把Lua GC摘出来,不是很容易,不过IOLanguage有

    http://www.dekorte.com/projects/opensource/libgarbagecollector/

     

    (Python)同步tweets和feeds更新到facebook/新浪微博/腾讯微博/豆瓣/人人/饭否等

    https://github.com/lyxint/wet

  • 我的code review规则

    1) 是否有语法错误,编译错误,编译警告。
    做法:下载最新代码,将编译警告级别提升到最高,检查output信息。
    
    2)是否符合需求,完成requirement文档要求的内容,不能多,也不能少。
    注意:即使发现有问题代码,如果与需求关联不大,不要涉及。
    应该让每次enhancement和bug fix最简洁,牵涉范围最小,影响到组件最少。
    
    3)是否符合编码规范:
    	a) 注意等号前后,操作符前后的空格和tab,行尾不要有多余空白字符
    	b) 注意命名规范,少用缩写形式,少用2/3/ex这种增强版
    	c) 对于循环局部变量,注意少用I,j在较长代码中(三四行OK)
    	d) ..
    
    4)代码美感
    	a) 不能有嵌套的if-for-switch-while出现
    	b) 不能有非常复杂的条件判断表达式(用于if-while之类)
    	c) 足够的注释,对于复杂操作,对于条件判断,可以注释。尽量让代码自己说明自己。
     	d) 如果代码不能在短时间内理解,或者稍作解释就可以理解,应该看看能否有更简洁的方式
    	e) 函数不要过长,不能超过一屏显示,最多不应该超过2-3屏。
    	f)经常问自己是否有更好的办法,更简洁明了的代码形势
    	g) 一个函数只做一件事,如果需要多个功能,再写一个
    	h) 少用boolean 作为参数切换功能,用withXXXcase, usingXXXcondition函数名字来自说明。道理同g)
    	i) 少用重载功能,没必要类似函数用一个名字,既然有不同函数实现,那么应该有不同条件描述,可参考h)的命名
    	j) 抽象层次不要过多,不要过早和过多考虑设计模式/抽象/抽取通用功能这些事情,这些在代码重构阶段可以修改调整。
    
    5)逻辑
    	a) 参考上一条4),基本上有足够美感的代码,逻辑上问题都不大
    
    6)杂项
    	a) 性能的关注应该基于profiling data,而不是猜测
    	b) 代码的正确与否,不是基于猜测而是基于test case
    	c) 扩展性不需要考虑过多,有一点点就好
    	d) 时时问自己,这个函数/变量/逻辑判断/.. 有没有必要,是不是可以删掉的
    	e) 时时问自己,如果不用手动测试,自动化测试自己这段代码,可以不可以?如何实现?(MEF or 数据界面分离… )可否通过脚本、工具自动化某些流程?