2012,当我们谈论移动互联网创业时,我们在谈论些什么?

2012年的移动互联网市场可以用“冰火两重天”来形容。

根据Google官方数据,Android设备激活量在2012 年3-6月4个月内,由3亿部增长至4亿部,增长率为33%。据苹果官方数字,iOS设备激活量从2012年4-6月由3.6亿部增长至4.1亿部,增长 了12%。而对于中国市场,根据友盟的数据,2012年第二季度Android App启动次数增长159%;iOS活跃设备增长42%,iOS App启动次数增长112%。 这些数字都表明了移动互联网用户和终端量在2012年仍在高速增长。

但另一方面,移动互联网创业之路却愈发举步维艰:同质化竞争加剧,推广成本攀升,盈利模式迟迟未能清晰,投资者的钱也烧得差不多了……

但移动互联网始终是座巨大的宝藏,吸引着无数人甘愿冒险探寻。那么当前,如何度过寒冬,成功地求生是每个创业者、投资人都在思考的问题。本文中我将列举几个2012年移动互联网创业的关键点进行讨论,内容仅供引发思考,不做结论。


创业机会在哪里?

洗牌前期,巨头们开始以各种方式大肆进驻。一方面是以腾讯为代表的巨头正在进行全面的软件布局。目前腾讯已推出了几十款覆盖各个平台的App,涵盖了社交、 浏览、订阅、输入、同步、安全、音乐、游戏、阅读等领域,以强大的资金、渠道和人才优势与大批创业者直接竞争。另一方面,百度、阿里巴巴、奇虎360、盛 大等公司开始竞相推出搭载自己定制的操作系统的手机,抢占移动互联网的入口……

如果比拼渠道、资金和对人才的吸引,小公司毫好无胜算。因 此,在巨头驻足的通用领域,采取与巨头直接竞争的方式异常艰难。那么,在这种环境下创业者在创新方向选择时可能需要考虑“垂直化”和“行业化”,更多地去 挖掘那些还未被发现或者巨头没有兴趣去做的细分市场。在游戏、SoLoMo、O2O、移动电商、儿童教育等直接可以从消费者手上收钱的领域都有机会,在整 个行业的真实收入迅速攀升的基础上,移动广告、开发工具、各种外包等周边产业也会迎来相应的繁荣,与之相关的风险投资、孵化器、财务、法务、媒体、人力资 源等领域也会被拉动,各种企业的移动化也需要“行业化”应用的推动。在这些方向上,都尚未出现真正集大成、占据绝对优势的产品,如果能做出好产品加上合适 的分发渠道,创业者仍然有机会。

同时“硬件化”也是一个选择方向。随着中国二三线城市智能手机的普及,智能手机的细分市场也开始成型,针对 不同性别、层级、年龄段消费者的手机需要配套的软件和系统定制,因此这个层面上创业者与厂商间的软硬整合合作也存在一定的机会,当然,其中还包括平板、智 能电视等领域。

Native App还是Web App?

记得2011年时,Web App的概念大行其道,同时伴随着Adobe Flash Player的诸多不利消息,一时间HTML5被一些人捧上了制高点。但近期,Flash产品(首当其冲是游戏)开始全面爆发。依靠着Adobe AIR、Stage 3D等强大技术的布局,移动设备上开始涌现大量高品质的Flash游戏。而HTML5却从云端跌回残酷的现实:HTML5移动游戏领域的早期探索者 Moblyng倒闭,Mark Zuckerburg亲口承认Facebook的HTML5战略是个错误,Chrome Web Store里面力推的游戏表现都不甚理想……由于表现能力不足,自身标准一直未确定,并且缺少Web App分发和盈利的渠道,导致HTML5阵营中并未出现拿得出手的成功案例。也许就像一位开发者曾经说过那样:“HTML5是未来的趋势,但不是现在的优 势。”

毫无疑问,每种技术方案都各自有其优劣之处,必须要根据实际情况灵活选择。例如对于许多交互不多的传统内容型网站来说,HTML5已 基本可以覆盖全部需求。但在目前Web App受限于浏览器或前端技术未标准化的情况下,开发者可以考虑进行组合应用,对于侧重性能、体验、设备特性、本地数据管理等HTML5表现力达不到的部 分用Native来做,HTML5表现力能达到的部分就用HTML5来做。

总的来说,开发者应该掌握并提前布局多种技术,不能在一棵树上吊死。

最好的盈利模式?

无论怎样,成功不是一时半会儿的事,“活下去”是当前最重要的话题。由于投资锐减,创业者需要更多、更早地去考虑盈利问题。其实目前的移动互联网有一系列的盈利模式可供开发人员选择:

  • Pay-Per-Download。下载支付,为获得App使用权一次性支付费用。
  • In-App Purchasing。应用内购买,通常是一些应用的功能、提升游戏等级以及虚拟商品,目前是大陆最容易获得高收入的模式。
  • Subscriptions。订阅,一般是逐月为App付费,《程序员》杂志等阅读类App通常会采取这一模式。
  • Freemium。免费下载,提供增值付费服务,在Evernote等工具类应用中常见。
  • Commissioned Applications。提供外包服务。
  • In-App Advertising。App内展示广告模式和传统互联网的广告模式十分接近,被开发者大量使用,但效果渐减。
  • Product Placement。植入式广告,例如在游戏中的某一道具就是某品牌的饮料。
  • Purchase Intermediation。为从第三方App中带来的流量或其他资源拿到分成,但在大陆也常常演变为资源、流量互换。
  • Per-unit royalties。通常是与终端厂商和各大平台合作,例如厂商为手机上预装付费等。
  • Distribution Exclusivity Deals。针对独家应用商店发部应用,前段时间Rovio的《Amazing Alex》通过应用汇发布时似乎就采用了这种模式。

在 2012年6月VisionMobile对全球1500名创业者的调查中发现,Pay-Per-Download是当前最频繁使用的盈利模式。共有34% 的创业者选择了这种方式,较2011年相比略有下降。紧随其后的就是In-App Advertising,占33%。而从今年起,In-App Purchasing模式开始火热,已跻身高回报的收益模式之一。

但创业者需要明白,没有最好的模式,只有最适合的模式。而选择标准往往取 决于他们的产品模型、规模和目标市场。例如在大陆,游戏用户很难为一款未知的游戏下载付费,因此In-App Purchasing在今年大肆流行。而对于一些理财类工具,用户反而愿意付费来选择高品质的产品来保证自己的安全和隐私。同时,对于同一款产品,在不同 阶段“盈利模式”也可以转型,《Angry Birds》就是最好的例子,在长期霸占App收费榜前排位置之后,随着新产品的推出和游戏生命周期到来,小鸟们已从排行榜上跌落,却找到了更为稳健的盈 利模式:其周边产品和授权费为其带来了丰厚的回报,当然在大陆这种模式可能会被山寨得让人吐血。

生态系统困境

再好的产品也需要依靠良好的分发渠道和健全的市场,可2012年的中国移动互联网生态系统可谓满目疮痍,大部分开发者都多多少少面对迷局。对于中国开发者而言,山寨术依然是亘古不变的话题,而在这之外,新的问题接踵而来。

App Store一度帮助苹果打造了最优秀的移动生态系统。但2012年的种种迹象表明,这片生态系统似乎正在遭受侵蚀。刷榜问题日益严重,在2012年3月 时,App Store曾经采用技术更新的方式阻止刷榜,但也默认了对之前刷榜严重的公司不追究。果不其然,苹果的这种“不作为”态度让新算法仅见效2个多月,一股新 的刷榜风潮就开始愈演愈烈。有开发者认为苹果应该像Google Play那样摆出“令可错杀一千,不可放过一个”的态度,然假设如此,想必肯定会有无良对手花钱帮你“刷榜”,让你欲哭无泪。

同样,在 Android的第三方市场,刷榜也是同样泛滥。因此,有许多国内的开发者和媒体开始曝光和谴责这些产品。但从市场层面来看,这种影响并不会波及到消费 者,倘若刷榜风险和成本极小,加上一些投资人“有钱赚,怎么赚都是赚”的纵容态度,那么必定会有更多的人铤而走险。

除此之外,App Store审核周期常常是漫长且毫无规律可循;去对手产品下面刷差评;有程序员直接拿别人游戏安装包破解反编译加入自己的广告账号,放渠道上偷广告流 量……开发者不仅要注意暴风雨和暗礁,还需要迎战其他船只的攻击,移动互联网生态圈的困局还有多久才能解开?

不过在2012年9月17日,App Store出现7小时的“锁榜”现象(指整个榜单全部锁住,排名几乎不动,偶尔有一两名上下的波动只是因为某些限免App到期,从免费应用榜单下架所 致)。这个情况与2012年3月20日(上一轮排名算法完全改变的前2天)出现的7小时锁榜现象如出一辙。因此,有人预测排名算法即将再次大调整,希望会 带来一些积极有效的变革。

走向海外?

虽然有一些应用在中国也取得了不错的成绩,但暂时而言,大陆终归是付费意愿较低的市场,并且还有着前文提到的各种恶劣的竞争环境,在此状况下,走“国际化” 战略似乎是个不错的选择。实际上,如今中国移动互联网的很多明星团队已走向海外、专注海外甚至如《海豚浏览器》这样“来自海外”。

成功者固然令人艳羡,但成功的路却并非所见即所得。作为一个统称,海外市场实际上被细分成很多个不同的市场:欧美市场、日本市场、韩国市场、拉美市场、东南亚市 场……每个市场都依靠语言、文化、渠道特色、市场机制等地域特点建立了壁垒,倘若没有找对法门,可能不仅没有找到宝藏,反而撞得头破血流。简单地以日本市场为例,虽然其ARPU值非常高,但日本市场的用户口味与其他国家有很大区别,盈利主要来 自卡牌游戏,而且日本用户对于美术画风、各种细节的要求非常高(例如相比其他亚洲市场,欧美风格的产品可能更受欢迎)。

另外,也不是所有的产品都适合走向海外。很多产品一开始就拥有中国市场的基因,离开这个环节与其他本土产品竞争,很可能水土不服。在近期我采访的几位开发者中,他们在谈到海外市场时纷纷谈到中国团队的技术优势,看来这一点是每个想要异国求生的团队必须具备的素质。

我从创建四家技术公司中学到的事

限于篇幅,90件事部分摘录如下。

1. 找到公司该做的一件事情。它应同时满足以下三点:你和团队对此最有激情;你和团队有望最擅于斯;巨大的市场机会等待开发。

2. 如果不满足以上三点,则说明做的事情不对。

3. 只做自己的一件事。

4. 产品是第一位的。

5. 评判产品好坏的唯一标准是用户的使用度和它带来的价值。

6. 早期决定未来成功的关键因素是客户欢迎度。

7. 如果一年内得不到客户欢迎的话,就应转移目标。

8. 目标一旦转移,就应当专注,且不走回头路。

9. 须有自知之明。

10. 不要只想自己,激发身边人的能力才重要。

11. 不要只想自己,客户才重要。

12. 确保能找到卓越的、能独当一面的联合创始人。

13. 与你喜欢的人一起工作。

14. 你和联合创始人坐的位置要保证相互看得到。

15. 不要与不喜欢的人一起工作。

16. 创始人要亲自抓重要的工作或项目。

17. CEO还要做其他人做不到的事情。

18. 与那些敢于争论、敢于说不的人一起工作。

19. 在聘用高管时,最重要的考量是文化切合度。

20. 白天上班乐于激烈争吵,下班回家还是好同事。

21. CEO且只有CEO可以确立公司目标,前进途径和资源利用。

22. 果断决定。

23. 激励士气。

24. 促使身边人同你一样关注企业。

25. CEO要负责每个职位的招聘。

26. 聘用的人要有激情解决你们想要解决的具体问题。

27. CEO要引导企业氛围、风格、步调和期望。

28. 时而强硬。

29. 真实而透明。

30. 如果你瞧不上某人,那么其他人都会知道。

31. 解雇决定要提前一天安排好,然后迅速解雇。

32. 考虑好是培养并指导员工,还是苛责他们。

33. 好聚好散。

34. 提供反馈。

35. 高管亦须评估。

36. 你也有错的时候。

37. 向前看五步。

38. 全面构建自己的技术。

39. 从开始就将社交融入公司DNA。

40. 提前六个月考虑是移动优先还是Web优先。

简悦创始人云风谈程序员的职业素养

程序员是可以当作一生的职业。但首先,你需要热爱编程,而不是把它作为完成其他人生目标的工具,你要不断地反思自己在哪些方面的努力是更有效率的。我认为,无论在哪个子领域工作的程序员,都要在三个方面提高自己。


第一,保持对未知领域的好奇心,尽力开阔视野。如果你只精通一门编程语言,那么就赶快去学习另一门,最好和之前那门语言的亲缘关系越远越好。这可以让你从不同的视角去看待过去的问题。如果你只专注于一个领域,那么去深入地研究一下其他领域也会有很大帮助。

多数人都喜欢在熟悉的知识结构下解决问题,因为全新的东西总有学习门槛,需要了解很多基础知识才能展开实际的工作。能轻松地把相关信息组织起来调配,与借助 外部资料是很不一样的。后者要经历一个相当痛苦的过程。但一旦习惯经常地学习和积累新知识,你就可以逐步掌握一套自己的方法来减轻这种痛苦。而要做到这点 却很难,需要保持单纯的好奇心。

第二,把握各个层次上的细节。尽可能了解清楚系统每个层面的运行:硬件如何调度机器指令;数据在硬盘、内存、缓存、CPU间的流向;代码如何被编译链接,代码经历了何种过程被加载到内存,JIT怎样加速字节码的运行;操作系统怎样管理线程、处理I/O;软件 用到的第三方模块和工具如何处理数据;在网络环境中,数据流的通信协议;代码中每个模块逐个层次中的相互关系……

对细节掌握得越多,思路会越清晰。在每个层次上,你会看到不同层次的设备对上一层业务逻辑的抽象方式,直到最终你直接面对的业务。对业务的抽象能力,来自你对业务的熟悉程度,实际上这种能力更是随同对细节的把握能力同时具备的。

第三,提升对代码的直觉。优秀的程序员能很快地发现性能热点、找到系统崩溃的原因、找出不合理的代码……除此之外,准确的估算能力也非常重要,这要求程序员 能够快速心算出每个模块的开销和输入的数据量之间的关系。在写下每行代码时能够判断其对性能的影响,以简洁去挑战各个层次模块间的耦合复杂度。

要培养这种能力,除了不断地编写代码之外,别无良方。在写代码的同时,要时刻保持思考,要对不好的地方零容忍。要在最早的时刻动手,任何推倒重来的代价都不会太大;放任它们只会让局面演变到不可收拾的程度。

保持自己总有代码可写,不断地去发掘自己新的兴趣点,拓展新领域。要单纯一些,编程本身就是一件有趣的脑力活动,而不必仅仅为了解决一些问题而写程序。

为程序员开一剂提高职业素养的良方

我认为程序员和医生在某些方面很相似。医生是在解决人的问题,而程序员是在解决产品的问题。它们都有相似的职责,都是用理性的技术手段解决问题。程序员可以从医生的身上借鉴到很多东西,比如职业素养标准。

程序员的职业素养是建立在技术水平上的。对程序员来说,技术是解决问题的手段,类似医生给病人治病用药。很多人工作没几年便觉得技术“精通”了,工作没挑战了。孙老爷子(孙思邈)骂这种人:“世有愚者,读方三年,便谓天下无病可治。”以前端开发来说,HTML、CSS的语法规则一个小时内完全可以掌握,但离运用它解决问题还相去甚远。


技术范畴里有各种著名、非著名的开源类库、各种“大牛”的文章、书籍。这些都是别人在解决所遇问题积累下来的方 法和经验。在解决自己项目中的问题时,可以用,可以借鉴,但要了解其中的“至精至微之事”,绝不能用“至粗至浅之思”去用它们。我经常看到一些简历中,列出一长串开源库的名字。但掌握它们的用法,丝毫不能代表技术水平有多高。

除了上述现象以外,还有另外一种现象,很多程序员确实热爱技术,但他们不是在尽心地为所服务的对象解决问题,而是借项目机会不管三七二十一地练手。

相反,如果是一个解决问题能力超强的程序员,应该遵循什么样的行为准则呢?

第一,先敬业后乐业。关于敬业,梁启超说:“敬业就是凡做一件事,便忠于一件事,将全部精力集中到这事上头,一点不旁骛,便是敬。”敬业的程序员不一定要天 天加班、没日没夜地工作。导致加班的因素也许是开发方式不对、架构不灵活或是技术落后。敬业的程序员会凭借自己的技术能力和判断力,解决掉其中的症结,而 不是得过且过。

我有一位同事就是敬业典范,几年里他参与过公司很多项目的开发,并且做每一个项目都很投入。比如做了一段时间的在线阅读项目,便开始对排版产生浓厚兴趣,也因此比其他人在项目中收获更多东西。

当程序员不能深入一个问题到“至精至微”的程度时会产生很多问题:

  • 不能更好地利用技术(也就不能更好地解决问题);
  • 不能提高自己的技术水平;
  • 体会不到工作的乐趣。

梁启超解释乐业时说:“人生能从自己的职业中领略出趣味,生活才有价值。”很多人上来就追求乐业,有点本末倒置了。

第二,认真严谨的态度。孙老爷子说“不得于性命之上,率尔自逞俊快,邀射名誉,甚不仁矣”,是说不能在人命关天的大事上轻率地炫耀自己才能出众,猎取名誉, 这样做就太不仁德了!无论能力多强的程序员,都不该有炫技的想法,这样就偏离了解决问题的根本出发点,对整个团队的技术氛围也会产生不良影响。相反,能力 越强的程序员,看待问题越全面、越深入,对表面上看似简单的问题也不会轻易下结论,会考虑更多潜在的问题。

第三,乐于交流和分享。要知道你 在Google上搜到的都是别人无私奉献出来的知识和经验,利用这些开源技术解决难题,应有感恩之心。其实当程序员看到应用某种技术能将问题完美解决,也包括解决别人遇到的问题时,会有一种成就感。在公司里,程序员利用工作时间解决的问题、获得的经验,有责任主动分享出来,帮助他人节省开发时间。

技术人员创业后就不再适合继续编码了?

“如果你已经有一年或两年的编码经验,你还做编码,那么你就错了。”几年前当我开始创业时,有人曾对我这么说过。

哈,这是多么愚蠢的想法!我整天忙于新技术、开发新的东西,学习新工具,关心工作上的事情。

一般来说,初创公司通常会使用最新或者最牛的技术,前端时间我们使用了PHP支持静态HTML,接着利用Python支持PHP,最近开始使用Ruby on Rails或者node.js支持PHP……或也许未来Scala也是个不错的选择,至少它现在变得很流行。

有许多技术出身的创始人和我一样热爱编码,崇尚自由——渴望自己当老板,设置项目的最后期限,选择自己喜爱的技术,解决唯一重要的或者至少自己感兴趣的问题。

我想说,没有好的编码技能,想成为一个好的程序员几乎是不可能的。现实中的创始人与这个相差甚远。

一位成功的创始人需要具备:

  • 一个好的创始人需要投入50%的时间;
  • 一个好的创始人必须保持警灯常亮;
  • 一个好的创始人必须做好客户拓展;
  • 一个好的创始人要计划公司的发展愿景;
  • 一个好的创始人必须随时关注行业动态;
  • 一个好的创始人必须勇于承担责任;
  • 一个好的创始人经常获得客户支持;

等等这些事情都是初创公司需要关注的,没有人能帮你分担,这些重担都落在了创始人肩上,花费的时间要比常人要多很多。

编程是很难

无论你是多么优秀的程序员,无论你是多么有经验,总会遇到难题。编程无需太多人关注,只需要保持注意力就好。多数情况下你需要处理模糊的想法,想法很难被记住,想法通常以交互的方式进行,想法需要你铭记于心。在你头脑中必须要有个抽象的系统模型——如果你忘记某个函数或者忘记数据,亦或忘记在哪个文件里,那么你都无法编码。

编程需要全神贯注

当你进行重要项目时,你试过集中注意力了吗?也许你想集中注意力、想认真工作,但结果并非这样,是吗?

时间

编程需要时间,大量的、长期的、不间断的时间。

四个小时是个不错的周期。你的大脑需要大量的时间来思考,当项目完成时,你需要1-2个小时来休息、放松大脑,然后再开始下一项工作。

番茄工作法

如果你使用番茄工作法并找到合理的方式来运用,2个小时还是很不错的。记住,如果你的大脑里还有其他想法,那么这两个小时是无用的。

番茄工作法的做法

1.每天开始的时候规划今天要完成的几项任务,将任务逐项写在列表里(或记在软件的清单里)

2.设定你的番茄钟(定时器、软件、闹钟等),时间是25分钟。

3.开始完成第一项任务,直到番茄钟响铃或提醒(25分钟到)。

4.停止工作,并在列表里该项任务后画个X。

5.休息3~5分钟,活动、喝水、方便等等。

6.开始下一个番茄钟,继续该任务。一直循环下去,直到完成该任务,并在列表里将该任务划掉。

7.每四个番茄钟后,休息25分钟。

在某个番茄钟的过程里,如果突然想起要做什么事情——

a.非得马上做不可的话,停止这个番茄钟并宣告它作废(哪怕还剩5分钟就结束了),去完成这件事情,之后再重新开始同一个番茄钟;

b.不是必须马上去做的话,在列表里该项任务后面标记一个逗号(表示打扰),并将这件事记在另一个列表里(比如叫“计划外事件”),然后接着完成这个番茄钟。

作为公司的创始人需要管理员工……你认为多久召开一次四小时不间断的会议?没有会议,没有Skype呼叫,没有迫切的电子邮件,没有服务器崩溃,没人问问题吗?

倘若真如此,那么你就是幸运的。

给创业者的建议:

最好的方案就是你不再做程序员。你可以利用30%的时间或者更少的代码来保持这种编码感觉。除非你有足够的时间可以修改Bug,否则请保留你的美好形象吧。

不要再为公司而投身编码,除非请不起程序员。

必须要有一支强大的创业团队,以便你不再是一个人因这些事情而烦忧,技术创业者需要像小鸟一般自由。

无论做什么事情要跟随自己的心灵,开发者可以通过运动、散步等来锻炼自己,任何有助于你编码的事情(耐性)都可以去尝试。

尽快地雇佣更多的程序员,然后不惜一切代价保护他们。

我曾听说,有的则是白天当创始人,晚上当程序员。要知道这样做会把你搞垮的,记住千万不要这么做。

英文出自:Zemanta

 

 

软件开发者最重要的四大技能

现如今,可供选择的技术、语言及平台可谓五花八门,因此作为软件开发者,要弄明白哪里是花时间培养个人技能的最佳投资点也就难上加难。常常有人向我征求关于如何成为更强的程序员的建议。人们问得最频繁的问题可谓万变不离其宗,即他们是否应该把时间花在某种与众不同的特定编程语言或技术上。

最近我花了很多心思琢磨此问题,并想出了一些我认为最要紧且能让你受益终生的技能,一旦软件开发者掌握了这些技能,不仅会给他们带来最佳的工作机会,还会使他们变得卓有成效。

技能一:解决问题(Solving Problems)

以前我曾谈到需要学会如何解决问题,甚至给出了如何学会解决问题的若干步骤,因为我认为这种技能对任何软件开发者都是至关重要的。软件开发百分之百就是解决问题。

若毫无问题,就无需软件。

所有软件都被设计用于解决某些用户问题,而通用解决方案就是由许多能搞定的小规模问题所组成的阵列。要是你不能解决问题,就不会精通软件开发,而你所用的编程语言或技术也就无所谓了。在解决问题时,大多数开发者的表现简直糟糕透顶。

我常常会听到一些关于求职面试太难的抱怨,因为面试官会要求开发者去解决有一定难度的问题。我谈过为何有难度的面试挺好,而其中的部分原因在于,面试官就是要测试开发者解决问题的能力。我知道,许多开发者仍然不同意我对此问题的观点,而且他们也不明白像TopCoder[2]那样的网站为何要不遗余力地完善其开发技能,至少从我的亲身经历来看,那正是TopCoder解决问题的实践活动,而参与此类实践活动正是我职业生涯的转折点。

假想你是木匠。要想成为出色的木匠,也许你应该擅长切削木材。也许你应该亲手做过各种各样的部件,同时也用过许多不同的工具切削木材。

无论你的木工经验有多少年,抑或设计出的家具或橱柜有多漂亮,每次你也要想方设法切削木材,努力做出各个部件。切削木材是木工活的基础技能,就像解决问题是软件开发的基础技能一样。

技能二:自学(Teaching Yourself)

在生活中,可能没有比学会学习更重要的技能了。此种技能在软件开发中尤其重要,因为据我所知,任何领域的变化速度都超不过软件开发。你不可能无所不知、无所不晓。甚至你都来不及投入时间去成为某一特定框架或技术的大师——因为事物发展得太快了!反而,你需要这样的能力,即为完成手头任务而快速获取所需知识的能力。

要是你真想具备某种能让你在软件开发职业生涯中始终与时俱进的技能,那就学习如何自学吧。

提高此种技能的唯一方法就是付诸实践。走出去学习新的编程语言或技术,即使你认为决不会用得上它(也不妨学一下)。将来你会惊讶地发现,你竟然可以很快地把它捡起来,因为你早就对相关基础知识一清二楚了。要是你能迅速适应日新月异的软件开发市场、以及与之相关的各种技术和平台,你就会拥有那些总是很抢手的技能。

尽管我对蒂姆·费里斯(Tim Ferris)的某些主张有点儿怀疑,不过他写了本很棒的书,名为《4小时变身厨师》(4-Hour Chef),其中介绍了若干如何快速学习事物的绝招。(我那时也正打算写本与此主题有关的书。)

技能三:命名(Naming)

要是有人问起我成天在做什么,那我八成会说“研读其他人命名的事物,以及给事物命名。”诚然,若没人真那么问,我也不会真这么答,不过我的确有可能这么答哦。

软件开发就是在描述形而上学的内容。我们所构建的大多数内容都是看不见摸不着的。授权经理收到授权请求,然后发出授权响应,与此同时,用户资源库会调用用户工厂去组建新用户——我们必须根据以上描述在心中去构建起完整的环境。

每次你编码时,就是在给事物命名。当阅读自己或他人所写的代码时,你会从代码中的事物名称获得对代码的大部分理解。通过在开发者亲手编写的代码中查看方法、变量及类的命名方式,大多数情况下,我能准确预测出开发者的技能水平。要给代码中的概念及数据起合适的名字,而缺乏此能力的开发者就像个哑巴翻译。无论你能否明白某事,要是你不能妥善地解释它,那么此事会转瞬即逝。

提高此种技能的最佳方式就是不断实践。只要我在读代码时有所领悟,我往往会重命名代码中的事物。由于我开始明白某个方法到底在做什么,因此我会给方法改名,以便与我的理解相一致。在读代码时我会做这么做,即便代码没有产生任何逻辑变化,也照样会这么做。

你越关注给事物起合适的名字,你就会越擅长此道。这也是你代码中最显而易见的一面。简单看一眼你的代码,很难分辨代码正确与否或效率高低,但如果代码能让我一望而知,那么我会认为你知道自己在做什么。

技能四:待人接物(Dealing with People)

尽管我把此种技能排在最后,不过在许多情况下,你可能会说它是首要的或最要紧的技能。所到之处皆有人。除非你单独工作,且只为你自己开发软件,否则,作为软件开发者,其他人就会影响到你的职业生涯。我以前谈过为何你可能不想批评某人,不过我们更多地是与他人打交道,而不是惹人烦。我总是会重新捧起戴尔·卡耐基(Dale Carnegie)的那本名著《人性的弱点》(How to Win Friends and Influence People),因为这本书对于学习如何做一名成功人士是如此重要。我以前说过,倘若你想提高人们的技能,那就阅读此书吧!

基本问题是,人类不是合乎逻辑的生物,我们是情感生物。当然,我们喜欢为我们的推理能力而自豪,不过实际情况是,我们所做的大多数决策更多地受到情绪影响,而非理智。

作为软件开发者,此种技能对你的意义在于,除非你能妥善地处理与其他开发者、经理、甚至客户的关系,否则,即便你有许多好点子或很有用的技能,你还是会四处碰壁。一般说来,积极参与到软件开发社区中去也会对你的职业生涯有很大帮助。不要仅限于人际交流,而要把你的名字传播出去,并广结善缘。成功做到这一切直接取决于你待人接物的能力。(在学习如何待人接物时想走捷径?那很简单。请与人为善!)

怎样看待实用技能?

请注意,在我的列表中并未包括任何特定技术,甚至连Web开发或移动开发这样宽泛的技能也没有,这是何原因?在一些技术领域具有坚实的基础的确很重要,不过这些领域都不及我上面提到的这4种技能重要。要是你能够解决问题、快速学习事物、恰当命名事物、以及待人接物,那么与你专门从事任何特定技术相比,从长远来看,你将会取得更大的成功。

有这样一种说法,要深入学习一到两门编程语言,并从事某个通用的专业领域,这当然很重要,不过,只要你还没带着那些抉择在这条老路上走得太远,并把精力集中在提高这4种重要技能上,你自会万事大吉!(你甚至可以学习C++)

译文出自:图灵社区(译者/高翌翔

英文出自:Simpleprogrammer

 

 

程序员的20个常见瓶颈

在扩展性的艺术一书中,Russell给出了20个有意思的估计:大约有20个经典瓶颈。
Russell说,如果在他年轻时他就知道这些瓶颈该有多好!这些论断包括:

* Database (数据库)

  1. 数据规模超出了最大内存限制
  2. 大查询和小查询
  3. 写写冲突
  4. 大表join超占内存

* Virtualization (虚拟化)
  1. 共享磁盘,抢磁道,磁头各种抖
  2. 网络IO波动

* programming(编程)
  1. 线程:死锁、相对于事件驱动来说过于重量级、调试、线程数与性能比非线性
  2. 事件驱动编程:回调的复杂性、函数调用中如何保存状态(how-to-store-state-in-function-calls)
  3. 缺少profile工具、缺少trace工具、缺少日志工具
  4. 单点故障、横向不可扩展
  5. 有状态的应用
  6. 搓设计:一台机器上能跑,几个用户也能跑,几个月后,几年后,尼玛,发现扛不住了,整个架构需要重写。
  7. 算法复杂度
  8. 依赖于诸如DNS查找等比较搞人的外部组件(Dependent services like DNS lookups and whatever else you may block on.)
  9. 栈空间

* Disk (磁盘)
  1. 本地磁盘访问
  2. 随机磁盘IO
  3. 磁盘碎片
  4. 当写入的数据块大于SSD块大小时SSD性能下降

* OS (操作系统)
  1. Fsync flushing,Linux缓冲区耗尽(linux buffer cache filling up)
  2. TCP缓冲区过小
  3. 文件描述符数限制
  4. 电源管理(Power budget)

* Caching (缓存)
  1. 不使用memcached
  2. HTTP中,header,etags,不压缩(headers, etags, not gzipping)
  3. 没有充分使用浏览器缓存功能
  4. 字节码缓存(如PHP)
  5. L1/L2缓存. 这是个很大的瓶颈. 把频繁使用的数据保持在L1/L2中. 设计到的方面很多:网络数据压缩后再发送,基于列压缩的DB中不解压直接计算等等。有TLB友好的算法。最重要的是牢固掌握以下基础知识:多核CPU、L1/L2,共享L3,NUMA内存,CPU、内存之间的数据传输带宽延迟,磁盘页缓存,脏页,TCP从CPU到DRAM到网卡的流程。

* CPU
  1. CPU负载
  2. 上下文切换。一个核上线程数过多,linux调度器对应用不友好,系统调用过多
  3. IO等待->所有CPU都等起
  4. CPU缓存。(Caching data is a fine grained process (In Java think volatile for instance), in order to find the right balance between having multiple instances with different values for data and heavy synchronization to keep the cached data consistent.)
  5. 背板总线的吞吐能力

* Network (网络)
  1.  网卡的最大输出带宽,IRQ达到饱和状态,软件中断占用了100%的CPU
  2. DNS查找
  3. 丢包
  4. 网络路由瞎指挥
  5. 网络磁盘访问
  6. 共享SAN(Storage Area Network)
  7  服务器失败 -> 服务器无响应

* Process (过程)
  1. 测试时间
  2. 开发时间
  3. 团队规模
  4. 预算
  5. 码债(不良代码带来的维护成本)

* Memory (内存)
  1. 内存耗尽 -> 杀进程,swap
  2. 内存不足导致的磁盘抖动
  3. 内存库的开销
  4. 内存碎片(Java中需要GC的停顿,C中无解)

上面用英文表达的,是我还不太理解的,望诸位赐教。

========================================原文===========================

In Zen And The Art Of Scaling – A Koan And Epigram ApproachRussell
Sullivan
 offered an interesting conjecture: there are 20 classic bottlenecks. This sounds suspiciously like the idea that there only 20 basic story plots.
And depending on how you chunkify things, it may be true, but in practice we all know bottlenecks come in infinite flavors, all tasting of sour and ash.

One day Aurelien Broszniowski from Terracotta emailed me his list of bottlenecks, we cc’ed Russell in on the conversation, he gave me his list, I have a list,
and here’s the resulting stone soup. 

Russell said this is his “I wish I knew when I was younger” list and I think that’s an enriching way to look at it. The more experience you have, the more different types of projects you tackle, the more lessons you’ll be able add to a list like this. So when
you read this list, and when you make your own, you are stepping through years of accumulated experience and more than a little frustration, but in each there is a story worth grokking.

  • Database:

    • Working size exceeds available RAM
    • Long & short running queries
    • Write-write conflicts
    • Large joins taking up memory
  • Virtualisation:

    • Sharing a HDD, disk seek death
    • Network I/O fluctuations in the cloud
  • Programming:

    • Threads: deadlocks, heavyweight as compared to events, debugging, non-linear scalability, etc…
    • Event driven programming: callback complexity, how-to-store-state-in-function-calls, etc…
    • Lack of profiling, lack of tracing, lack of logging
    • One piece can\’t scale, SPOF, non horizontally scalable, etc…
    • Stateful apps
    • Bad design : The developers create an app which runs fine on their computer. The app goes into production, and runs fine, with a couple of users. Months/Years later, the application can\’t run with thousands of users and needs to be totally re-architectured
      and rewritten.
    • Algorithm complexity
    • Dependent services like DNS lookups and whatever else you may block on.
    • Stack space
  • Disk:

    • Local disk access
    • Random disk I/O -> disk seeks
    • Disk fragmentation
    • SSDs performance drop once  data written is greater than SSD size
  • OS:

    • Fsync flushing, linux buffer cache filling up
    • TCP buffers too small
    • File descriptor limits
    • Power budget
  • Caching:

    • Not using memcached (database pummeling)
    • In HTTP: headers, etags, not gzipping, etc..
    • Not utilising the browser\’s cache enough
    • Byte code caches (e.g. PHP)
    • L1/L2 caches. This is a huge bottleneck. Keep important hot/data in L1/L2. This spans so much: snappy for network I/O, column DBs run algorithms directly on compressed data, etc. Then there are techniques to not destroy your TLB. The most important idea
      is to have a firm grasp on computer architecture in terms of CPUs multi-core, L1/L2, shared L3, NUMA RAM, data transfer bandwidth/latency from DRAM to chip, DRAM caches DiskPages, DirtyPages, TCP packets travel thru CPU<->DRAM<->NIC.
  • CPU:

    • CPU overload
    • Context switches -> too many threads on a core, bad luck w/ the linux scheduler, too many system calls, etc…
    • IO waits -> all CPUs wait at the same speed
    • CPU Caches: Caching data is a fine grained process (In Java think volatile for instance), in order to find the right balance between having multiple instances with different values for data and heavy synchronization to keep the cached data consistent.
    • Backplane throughput
  • Network:

    • NIC maxed out, IRQ saturation, soft interrupts taking up 100% CPU
    • DNS lookups
    • Dropped packets
    • Unexpected routes with in the network
    • Network disk access
    • Shared SANs
    • Server failure -> no answer anymore from the server
  • Process:

    • Testing time
    • Development time
    • Team size
    • Budget
    • Code debt
  • Memory:

    • Out of memory -> kills process, go into swap & grind to a halt
    • Out of memory causing Disk Thrashing (related to swap)
    • Memory library overhead
    • Memory fragmentation

      • In Java requires GC pauses
      • In C, malloc\’s start taking forever


If you have any more to add or you have suggested fixes, please jump in.

Thanks to Aurelien and Russell for all their applied brain power.

架构设计的关键原则

关键的设计原则

在开始设计之前,思考一下关键的原则,将会帮助你创建一个最小花费、高可用性和扩展性的架构。

  • 分离关注点,将应用划分为在功能上尽可能不重复的功能点。主要的参考因素就是最小化交互,高内聚、低耦合。但是,错误的分离功能边界,可能会导致功能之间的高耦合性和复杂性,

  • 职责单一,每一个组件或者是模块应该只有一个职责或者是功能,功能要内聚。

  • 最小知识原则,一个组件或者是对象不应该知道其他组件或者对象的内部实现细节。

  • 不要重复你自己,你只需要在一个地方描述目的。例如,特殊的功能只能在一个组件中实现,在其他的组件中不应该有副本。

  • 最小化预先设计,只设计必须的内容。在一些情况,你可能需要预先设计一些内容。另外一些情况,尤其对于敏捷开发,你可以避免设计过度。如果你的应用需求是不清晰的,最好不要做大量的预先设计。

当设计一个应用和系统的时候,软件架构的目的是通过将设计分离到不同的关注点,来最小化复杂性。例如,用户接口UI,业务处理Business Process,数据访问Data
Access
就代表不同的关注点。在每个关注点内部,你设计的组件应该集中的内部实现,不应该和其他的组件混淆代码。例如,UI处理组件不应该包括直接访问数据源的代码,相反,应该使用业务组件或者是数据访问组建获取数据。

但是,你还是要为你的应用做一个投入|产出决定。在某些情况,你可能需要简化结构。例如,UI直接绑定到一个结果集。通常,也要从业务的角度考虑功能的边界。下面的这些高层次的原则将会帮助你从更广的范围上考虑影响设计、实现、部署、测试和维护系统的因素。


设计

在每一层保持设计模式的一致性。在一个逻辑层的内部,组件的设计对于特殊的功能应该保持一致性。

不要在应用中复制功能。只能在一个组件中提供指定的功能,这个功能不能在其他组件中复制。这将会保持组件的内聚性,而且如果功能需要修改的话,会变得很容易。

组合优先于继承。无论在什么地方,如果需要重用代码的话,优先使用组合而不是继承,因为继承增加了父类和子类的依赖关系,限制了子类的重用,

为开发建立代码风格和命名空间。建立统一的代码风格,使用和组织有关系的有意义的命名空间。

在开发的过程中,使用QA来保证系统的质量。在开发的过程中,使用单元测试和其他QA技术,例如,依赖分析和静态代码分析。为组建和子系统定义清晰的行为和性能指标,使用自动化QA工具来保证不影响整个系统的质量。


应用分层

分离关注点。将应用分离为不同的功能,这些功能保持尽可能小的重叠。主要的好处是一个功能可以最小化和其他功能的依赖关系。另外,如果一个功能失败了,不会导致其他功能的失败,对于其他功能来说是独立的。使得应用更容易理解和设计,简化复杂系统的管理。

明确层之间是如何通信的。

使用抽象实现层之间的松散耦合。可以通过定义接口来实现。另外,还可以通过使用接口类型或者是基类定义常用的接口。

在同一层,不要混合不同类型的组件。例如,UI层不应该包含业务处理组件,相反,应该包含处理用户输入和处理用户请求的组件。

在层和组件内部保持数据格式的一致性。混乱的数据格式,将会导致系统更难实现、扩展和维护。


组件、模块和功能

一个组件和对象不应该依赖于其他组件的内部实现细节。

组件的功能不要超出范围。例如,UI处理组件不应该包含数据访问代码,或者是试图提供其他的功能。

理解组件之间是如何通信的。这需要理解应用一定要支持的部署方案。你一定要决定是否所有的组件都运行在同一个进程中?是否一定要支持跨越物理或者是进程边界的通信?还是实现消息为基础的接口?

为组件定义一个清晰的职责。


你还要考虑下面的这些横向的关注点:

日志

认证

授权

异常管理

通信。选择合适的协议,最小化网络的通信量,在网络上保护传递的敏感信息。

缓存。为了提高系统的性能和响应速度,需要确定什么应该缓存?缓存在哪里?设计缓存的时候,要考虑到web服务器场和应用服务器场的问题。

产品重构

1、为什么要进行产品重构

    旧系统人员流失,系统的业务规则、原始需求谁都不清楚,需求文档、使用文档、架构文档极其缺乏,成为一个无底洞,可维护性很差。  

    旧系统越来越复杂,潜规则太多,原本修改一个小需求,一不小心搞得上线后影响一堆用户

    旧系统的业务架构、技术架构无法满足新的业务模式需要

    旧系统性能无法满足公司业务高速发展的需要

    旧系统的产品生命周期已经到头,需要延长期生命周期

    等等

2、产品重构  VS.  重做新产品

    对现有产品进行重构还是重新做一套全新的系统并没有标准答案。技术人员们都倾向于重做新系统,并都倾向于高估自身的管理能力、架构设计能力,大家都会承诺完美的架构、完美的产品规划。但如果没解决根本性的管理问题,重构或是重做宿命都是一样的。这些管理问题包括产品规划能力、业务架构能力、项目管理能力、架构管理能力、架构设计能力等等。   

   在管理能力尚未改善的情况下,怎样保证重做新系统时候不落入旧系统“新做系统,承诺完美架构->管理失衡,系统维护陷入混乱->再重做新系统”同样的命运。好的架构是管理出来的,不是设计出来的。

  产品重构第一困难的是反向工程过程阶段,必须搞清楚现有系统的遗产状况。对于一个在线运营的系统,不管是重构还是重做都必须经历此过程

  产品重构第二困难的是旧系统迁移到重构系统的过程。怎样做到不影响现有客户使用的情况下完成灰度切换,这是最大的挑战。不管是重构或是重做都必须经历此过程

3、关于产品重构的思考

Architecture Reconstruction,architecture recovery,产品重构,架构重构,反向工程,正向工程

系统架构设计应考虑的因素

1.  与构架有关的几个基本概念

1、 模块(module):一组完成指定功能的语句,包括:输入、输出、逻辑处理功能、内部信息、运行环境(与功能对应但不是一对一关系)。

2、 组件(component):系统中相当重要的、几乎是独立的可替换部分,它在明确定义的构架环境中实现确切的功能。

3、 模式(pattern):指经过验证,至少适用于一种实用环境(更多时候是好几种环境)的解决方案模板(用于结构和行为。在 UML 中:模式由参数化的协作来表示,但 UML 不直接对模式的其他方面(如使用结果列表、使用示例等,它们可由文本来表示)进行建模。存在各种范围和抽象程度的模式,例如,构架模式、分析模式、设计模式和代码模式或实施模式。模式将可以帮助我们抓住重点。构架也是存在模式的。比如,对于系统结构设计,我们使用层模式;对于分布式系统,我们使用代理模式(通过使用代理来替代实际的对象,使程序能够控制对该对象的访问);对于交互系统,我们使用MVC(M模型(对象)/V视图(输出管理)/C控制器(输入处理))模式。模式是针对特定问题的解,因此,我们也可以针对需求的特点采用相应的模式来设计构架。

4、 构架模式(architectural pattern):表示软件系统的基本结构组织方案。它提供了一组预定义的子系统、指定它们的职责,并且包括用于组织其间关系的规则和指导。

5、 层(layer):对模型中同一抽象层次上的包进行分组的一种特定方式。通过分层,从逻辑上将子系统划分成许多集合,而层间关系的形成要遵循一定的规则。通过分层,可以限制子系统间的依赖关系,使系统以更松散的方式耦合,从而更易于维护。(层是对构架的横向划分,分区是对构架的纵向划分)。

6、 系统分层的几种常用方法:

1)  常用三层服务:用户层、业务逻辑层、数据层;

2)  多层结构的技术组成模型:表现层、中间层、数据层;

3)  网络系统常用三层结构:核心层、汇聚层和接入层;

4)  RUP典型分层方法:应用层、专业业务层、中间件层、系统软件层;

5)  基于Java的B/S模式系统结构:浏览器端、服务器端、请求接收层、请求处理层;

6)  某六层结构:功能层(用户界面)、模块层、组装层(软件总线)、服务层(数据处理)、数据层、核心层;

7)  构架(Architecture,愿意为建筑学设计和建筑物建造的艺术与科学): 在RUP中的定义:软件系统的构架(在某一给定点)是指系统重要构件的组织或结构,这些重要构件通过接口与不断减小的构件与接口所组成的构件进行交互;《软件构架实践》中的定义:某个软件或者计算系统的软件构架即组成该系统的一个或者多个结构,他们组成软件的各个部分,形成这些组件的外部可见属性及相互间的联系;IEEE
1471-2000中的定义:the fundamental organization of a system emboided in its components,their relationships to each other,and to the enviroment and the principles guiding its design and evolution,构架是系统在其所处环境中的最高层次的概念。软件系统的构架是通过接口交互的重要构件(在特定时间点)的组织或结构,这些构件又由一些更小的构件和接口组成。(“构架”可以作为名词,也可作为动词,作为动词的“构架”相当于“构架设计”)

8)  构架的描述方式:“4+1”视图(用例视图、设计视图、实现视图、过程视图、配置视图)是一个被广为使用的构架描述的模型;RUP过程的构架描述模板在“4+1”视图的基础上增加了可选的数据视图(从永久性数据存储方面来对系统进行说明);HP公司的软件描述模板也是基于“4+1”视图。

9)  结构:软件构架是多种结构的体现,结构是系统构架从不同角度观察所产生的视图。就像建筑物的结构会随着观察动机和出发点的不同而有多种含义一样,软件构架也表现为多种结构。常见的软件结构有:模块结构、逻辑或概念结构、进程或协调结构、物理结构、使用结构、调用结构、数据流、控制流、类结构等等


2.  构架设计应考虑的因素概揽

模块构架设计可以从程序的运行时结构和源代码的组织结构方面考虑。

1、 程序的运行时结构方面的考虑:

1)  需求的符合性:正确性、完整性;功能性需求、非功能性需求;

2)  总体性能(内存管理、数据库组织和内容、非数据库信息、任务并行性、网络多人操作、关键算法、与网络、硬件和其他系统接口对性能的影响);

3)  运行可管理性:便于控制系统运行、监视系统状态、错误处理;模块间通信的简单性;与可维护性不同;

4)  与其他系统接口兼容性;

5)  与网络、硬件接口兼容性及性能;

6)  系统安全性;

7)  系统可靠性;

8)  业务流程的可调整性;

9)  业务信息的可调整性

10)  使用方便性

11)  构架样式的一致性

注:运行时负载均衡可以从系统性能、系统可靠性方面考虑。

2、 源代码的组织结构方面的考虑:

1)  开发可管理性:便于人员分工(模块独立性、开发工作的负载均衡、进度安排优化、预防人员流动对开发的影响)、利于配置管理、大小的合理性与适度复杂性;

2)  可维护性:与运行可管理性不同;

3)  可扩充性:系统方案的升级、扩容、扩充性能;

4)  可移植性:不同客户端、应用服务器、数据库管理系统;

5)  需求的符合性(源代码的组织结构方面的考虑)。


3.  程序的运行时结构方面的考虑

1、  需求的符合性:正确性、完整性;功能性需求、非功能性需求

软件项目最主要的目标是满足客户需求。在进行构架设计的时候,大家考虑更多的是使用哪个运行平台、编成语言、开发环境、数据库管理系统等问题,对于和客户需求相关的问题考虑不足、不够系统。如果无论怎么好的构架都无法满足客户明确的某个功能性需求或非功能性需求,就应该与客户协调在项目范围和需求规格说明书中删除这一需求。否则,架构设计应以满足客户所有明确需求为最基本目标,尽量满足其隐含的需求。(客户的非功能性需求可能包括接口、系统安全性、可靠性、移植性、扩展性等等,在其他小节中细述)

一般来说,功能需求决定业务构架、非功能需求决定技术构架,变化案例决定构架的范围。需求方面的知识告诉我们,功能需求定义了软件能够做些什么。我们需要根据业务上的需求来设计业务构架,以使得未来的软件能够满足客户的需要。非功能需求定义了一些性能、效率上的一些约束、规则。而我们的技术构架要能够满足这些约束和规则。变化案例是对未来可能发生的变化的一个估计,结合功能需求和非功能需求,我们就可以确定一个需求的范围,进而确定一个构架的范围。(此段From林星)

这里讲一个前几年因客户某些需求错误造成构架设计问题而引起系统性能和可靠性问题的小小的例子:此系统的需求本身是比较简单的,就是将某城市的某业务的全部历史档案卡片扫描存储起来,以便可以按照姓名进行查询。需求阶段客户说卡片大约有20万张,需求调研者出于对客户的信任没有对数据的总量进行查证。由于是中小型数据量,并且今后数据不会增加,经过计算20万张卡片总体容量之后,决定使用一种可以单机使用也可以联网的中小型数据库管理系统。等到系统完成开始录入数据时,才发现数据至少有60万,这样使用那种中小型数据库管理系统不但会造成系统性能的问题,而且其可靠性是非常脆弱的,不得不对系统进行重新设计。从这个小小的教训可以看出,需求阶段不仅对客户的功能需求要调查清楚,对于一些隐含非功能需求的一些数据也应当调查清楚,并作为构架设计的依据。

对于功能需求的正确性,在构架设计文档中可能不好验证(需要人工、费力)。对于功能需求完整性,就应当使用需求功能与对应模块对照表来跟踪追溯。对于非功能需求正确性和完整性,可以使用需求非功能与对应设计策略对照表来跟踪追溯评估。

“软件设计工作只有基于用户需求,立足于可行的技术才有可能成功。”

2、  总体性能

性能其实也是客户需求的一部分,当然可能是明确的,也有很多是隐含的,这里把它单独列出来在说明一次。性能是设计方案的重要标准,性能应考虑的不是单台客户端的性能,而是应该考虑系统总的综合性能;

性能设计应从以下几个方面考虑:内存管理、数据库组织和内容、非数据库信息、任务并行性、网络多人操作、关键算法、与网络、硬件和其他系统接口对性能的影响;

几点提示:算法优化及负载均衡是性能优化的方向。经常要调用的模块要特别注意优化。占用内存较多的变量在不用时要及时清理掉。需要下载的网页主题文件过大时应当分解为若干部分,让用户先把主要部分显示出来。

3、  运行可管理性

系统的构架设计应当为了使系统可以预测系统故障,防患于未然。现在的系统正逐步向复杂化、大型化发展,单靠一个人或几个人来管理已显得力不从心,况且对于某些突发事件的响应,人的反应明显不够。因此通过合理的系统构架规划系统运行资源,便于控制系统运行、监视系统状态、进行有效的错误处理;为了实现上述目标,模块间通信应当尽可能简单,同时建立合理详尽的系统运行日志,系统通过自动审计运行日志,了解系统运行状态、进行有效的错误处理;(运行可管理性与可维护性不同)

4、  与其他系统接口兼容性(解释略)

与网络、硬件接口兼容性及性能(解释略)

5、  系统安全性

随着计算机应用的不断深入和扩大,涉及的部门和信息也越来越多,其中有大量保密信息在网络上传输,所以对系统安全性的考虑已经成为系统设计的关键,需要从各个方面和角度加以考虑,来保证数据资料的绝对安全。

6、  系统可靠性

系统的可靠性是现代信息系统应具有的重要特征,由于人们日常的工作对系统依赖程度越来越多,因此系统的必须可靠。系统构架设计可考虑系统的冗余度,尽可能地避免单点故障。系统可靠性是系统在给定的时间间隔及给定的环境条件下,按设计要求,成功地运行程序的概率。成功地运行不仅要保证系统能正确地运行,满足功能需求,还要求当系统出现意外故障时能够尽快恢复正常运行,数据不受破坏。

7、  业务流程的可调整性

应当考虑客户业务流程可能出现的变化,所以在系统构架设计时要尽量排除业务流程的制约,即把流程中的各项业务结点工作作为独立的对象,设计成独立的模块或组件,充分考虑他们与其他各种业务对象模块或组件的接口,在流程之间通过业务对象模块的相互调用实现各种业务,这样,在业务流程发生有限的变化时(每个业务模块本身的业务逻辑没有变的情况下),就能够比较方便地修改系统程序模块或组件间的调用关系而实现新的需求。如果这种调用关系被设计成存储在配置库的数据字典里,则连程序代码都不用修改,只需修改数据字典里的模块或组件调用规则即可。

8、  业务信息的可调整性

应当考虑客户业务信息可能出现的变化,所以在系统构架设计时必须尽可能减少因为业务信息的调整对于代码模块的影响范围

9、  使用方便性

使用方便性是不须提及的必然的需求,而使用方便性与系统构架是密切相关的。WinCE(1.0)的失败和后来改进版本的成功就说明了这个问题。WinCE(1.0)有太多层次的视窗和菜单,而用户则更喜欢简单的界面和快捷的操作。失败了应当及时纠正,但最好不要等到失败了再来纠正,这样会浪费巨大的财力物力,所以在系统构架阶段最好能将需要考虑的因素都考虑到。当然使用方便性必须与系统安全性协调平衡统一,使用方便性也必须与业务流程的可调整性和业务信息的可调整性协调平衡统一。“满足用户的需求,便于用户使用,同时又使得操作流程尽可能简单。这就是设计之本。”

10、构架样式的一致性

软件系统的构架样式有些类似于建筑样式(如中国式、哥特式、希腊复古式)。软件构架样式可分为数据流构架样式、调用返回构架样式、独立组件构架样式、以数据为中心的构架样式和虚拟机构架样式,每一种样式还可以分为若干子样式。构架样式的一致性并不是要求一个软件系统只能采用一种样式,就像建筑样式可以是中西结合的,软件系统也可以有异质构架样式(分为局部异质、层次异质、并行异质),即多种样式的综合,但这样的综合应该考虑其某些方面的一致性和协调性。每一种样式都有其使用的时机,应当根据系统最强调的质量属性来选择。


4.  源代码的组织结构方面的考虑

1、  开发可管理性

便于人员分工(模块独立性、开发工作的负载均衡、进度安排优化、预防人员流动对开发的影响:一个好的构架同时应有助于减少项目组的压力和紧张,提高软件开发效率)、利于配置管理、大小的合理性、适度复杂性;

1) 便于人员分工-模块独立性、层次性

模块独立性、层次性是为了保证项目开发成员工作之间的相对独立性,模块联结方式应该是纵向而不是横向, 模块之间应该是树状结构而不是网状结构或交叉结构,这样就可以把开发人员之间的通信、模块开发制约关系减到最少。同时模块独立性也比较利于配置管理工作的进行。现在有越来越多的的软件开发是在异地进行,一个开发组的成员可能在不同城市甚至在不同国家,因此便于异地开发的人员分工与配置管理的源代码组织结构是非常必要的。

2) 便于人员分工-开发工作的负载均衡

不仅仅是开发出来的软件系统需要负载均衡,在开发过程中开发小组各成员之间工作任务的负载均衡也是非重要的。所谓工作任务的负载均衡就是通过合理的任务划分按照开发人员特点进行分配任务,尽量让项目组中的每个人每段时间都有用武之地。这就需要在构架设计时应当充分考虑项目组手头的人力资源,在实现客户需求的基础上实现开发工作的负载均衡,以提高整体开发效率。

3) 便于人员分工-进度安排优化;

进度安排优化的前提是模块独立性并搞清楚模块开发的先后制约关系。利用工作分解结构对所有程序编码工作进行分解,得到每一项工作的输入、输出、所需资源、持续时间、前期应完成的工作、完成后可以进行的工作。然后预估各模块需要时间,分析各模块的并行与串行(顺序制约),绘制出网络图,找出影响整体进度的关键模块,算出关键路径,最后对网络图进行调整,以使进度安排最优化。

有个家喻户晓的智力题叫烤肉片策略:约翰逊家户外有一个可以同时烤两块肉片的烤肉架,烤每块肉片的每一面需要10分钟,现要烤三块肉片给饥肠辘辘急不可耐的一家三口。问题是怎样才能在最短的时间内烤完三片肉。一般的做法花20分钟先烤完前两片,再花20分钟烤完第三片。有一种更好的方法可以节省10分钟,大家想想。

4) 便于人员分工-预防员工人员流动对开发的影响

人员流动在软件行业是司空见惯的事情,已经是一个常见的风险。作为对这一风险的有效的防范对策之一,可以在构架设计中考虑到并预防员工人员流动对开发的影响。主要的思路还是在模块的独立性上(追求高内聚低耦合),组件化是目前流行的趋势。

5) 利于配置管理(独立性、层次性)

利于配置管理与利于人员分工有一定的联系。除了逻辑上的模块组件要利于人员分工外,物理上的源代码层次结构、目录结构、各模块所处源代码文件的部署也应当利于人员分工和配置管理。(尽管现在配置管理工具有较强大的功能,但一个清楚的源码分割和模块分割是非常有好处的)。

6) 大小的合理性与适度复杂性

大小的合理性与适度复杂性可以使开发工作的负载均衡,便于进度的安排,也可以使系统在运行时减少不必要的内存资源浪费。对于代码的可阅读性和系统的可维护性也有一定的好处。另外,过大的模块常常是系统分解不充分,而过小的模块有可能降低模块的独立性,造成系统接口的复杂。

2、  可维护性

便于在系统出现故障时及时方便地找到产生故障的原因和源代码位置,并能方便地进行局部修改、切割;(可维护性与运行可管理性不同)

3、  可扩充性:系统方案的升级、扩容、扩充性能

系统在建成后会有一段很长的运行周期,在该周期内,应用在不断增加,应用的层次在不断升级,因此采用的构架设计等方案因充分考虑升级、扩容、扩充的可行性和便利

4、  可移植性

不同客户端、应用服务器、数据库管理系统:如果潜在的客户使用的客户端可能使用不同的操作系统或浏览器,其可移植性必须考虑客户端程序的可移植性,或尽量不使业务逻辑放在客户端;数据处理的业务逻辑放在数据库管理系统中会有较好的性能,但如果客户群中不能确定使用的是同一种数据库管理系统,则业务逻辑就不能数据库管理系统中;

达到可移植性一定要注重标准化和开放性:只有广泛采用遵循国际标准,开发出开放性强的产品,才可以保证各种类型的系统的充分互联,从而使产品更具有市场竞争力,也为未来的系统移植和升级扩展提供了基础。

5、  需求的符合性

从源代码的组织结构看需求的符合型主要考虑针对用户需求可能的变化的软件代码及构架的最小冗余(同时又要使得系统具有一定的可扩展性)。


5.  写系统构架设计文档应考虑的问题

构架工作应该在需求开发完成约80%的时候开始进行,不必等到需求开发全部完成,需要项目经理以具体的判断来评估此时是否足以开始构建软件构架。

给出一致的轮廓:系统概述。一个系统构架需要现有概括的描述,开发人员才能从上千个细节甚至数十个模块或对象类中建立一致的轮廓。

构架的目标应该能够清楚说明系统概念,构架应尽可能简化,最好的构架文件应该简单、简短,清晰而不杂乱,解决方案自然。

构架应单先定义上层的主要子系统,应该描述各子系统的任务,并提供每个子系统中各模块或对象类的的初步列表。

构架应该描述不同子系统间相互通信的方式,而一个良好的构架应该将子系统间的通信关系降到最低。

成功构架的一个重要特色,在于标明最可能变更的领域,应当列出程序中最可能变更的部分,说明构架的其他部分如何应变。

复用分析、外购:缩短软件开发周期、降低成本的有效方案未必是自行开发软件,可以对现有软件进行复用或进行外购。应考虑其对构架的影响。

除了系统组织的问题,构架应重点考虑对于细节全面影响的设计决策,深入这些决策领域:外部软件接口(兼容性、通信方式、传递数据结构)、用户接口(用户接口和系统层次划分)、数据库组织和内容、非数据库信息、关键算法、内存管理(配置策略)、并行性、安全性、可移植性、网络多人操作、错误处理。

要保证需求的可追踪性,即保证每个需求功能都有相应模块去实现。

构架不能只依据静态的系统目标来设计,也应当考虑动态的开发过程,如人力资源的情况,进度要求的情况,开发环境的满足情况。构架必须支持阶段性规划,应该能够提供阶段性规划中如何开发与完成的方式。不应该依赖无法独立运行的子系统构架。将系统各部分的、依赖关系找出来,形成一套开发计划。


6.  结语

系统构架设计和千差万别的具体的开发平台密切相关,因此在此无法给出通用的解决方案,主要是为了说明哪些因素是需要考虑的。对于每个因素的设计策略和本文未提到的因素需要软件构架设计师在具体开发实践中灵活把握。不同因素之间有时是矛盾的,构架设计时需要根据具体情况进行平衡。