当我们面对一个架构方面的决策时,通常会处于某种两难的境地,选A还是选B,”市面上”同时存在各种丰富多彩的说法,单独看去,往往各自言之成理,如果仔细对比,又往往莫衷一是。
在我目前所就职的公司,前段时间我刚刚做了一个架构决策:原来的系统,开发人员采用PHP编写后台执行的进程脚本,处理各种需要高性能的业务;另外,他们又用CoffeeScript编写了一个Web控制台,以配置、管理和监控这个系统。这令我感觉相当的怪异,因此我决定,后台关键进程,重新用nodejs编写,而Web控制台,则重新用PHP编写。
这个决策背后的逻辑是:一个复杂的系统,越来越多的是由多语言混合编写而成的,而在实际的系统中,所谓的架构决策,就是在不同的部分,选择不同却适合的语言和技术。
这个结论,我一直相当心安理得。直到上周,我去参加了ThinkInLAMP组织的PHP2013开发者大会。在会上,我听到了来自台湾的梁枫先生的一场演讲《在WEB之外——PHP》,在演讲中,他反复在问一个问题:PHP真的只能写Web吗?而他的开发实践相当的有趣,他在用PHP编写工业自动化控制方面的应用,编写串口通信的代码,同样的功能,用PHP编写的时间是2周,而用C语言编写的时间是8个月,而且PHP的2周,是他一个人完成的。这样的演讲,令人印象非常深刻,也引发了我更多的思考。
会后,我找到了梁先生,提出了我的疑问,举的就是我在公司里,颠倒两种语言的架构决策。蔡先生的回答是:对啊,当初我只用了2周,但是后来我们还是又花了8个月呀。PHP,主要可以快速的拿出原型,真正的产品,还要C语言去开发一遍的呀。
经过这番讨论,我得到了一个新的富有启发的结论:在快速原型的阶段,就可以选择快速开发的语言,而在实用的阶段,就应该选择更加实用的语言。
这么肤浅的结论,真的值得大肆宣扬,再写一篇Blog吗?自然不是,因为我在后来的一周里,一直在脑子里反复思考这个问题,然后,突然想明白了一些:
在一些极端的领域,效率至上与实用至上,可以毫不相干,各自有所追求,前期追求效率的开发产品,由于成本极低,大多是可以随时抛弃的。而真正的困难在于想要兼得。常见的与架构相关的两种痛苦:一种是,刚开始为了追求快速开发,在技术选型上怎么快怎么来,结果系统越来越大,越来越复杂,等到想要考虑架构优化,想要重构的时候,却已经积重难返,改起架构来伤筋动骨。另一种是一开始想得太多,架构做得太复杂,杀鸡用牛刀的技术用得太多,往往还没有等到系统开发完成,就已经Game Over了。
还有一个现象,也很常见,我们常常能够见到各种技术方面的争论,各执一词的原因,往往是由于各自的立场不同:你说某某语言效率极高,他说等到复杂了这个语言就撑不住了。一些常常被人引用的例子是:某某知名网站,放弃了PHP技术、放弃了.NET技术,放弃了Ruby技术等等,对立阵营的同学们,就感到欢欣鼓舞:看吧,就知道你们那个语言,只能拿来开发玩具应用…
长长的引言部分结束,开始系统性的阐述我的观点:
1. 选择技术,往往不是选择某种单一的技术,而是选择一个技术栈;
2. 有些技术一开始的出发点就是追求开发效率,然后在后续的发展中,逐步开始追求实用;
3. 有些技术一开始的出发点就是追求实用性,然后在后续的发展中,逐步开始追求开发效率;
4. 想要兼得鱼和熊掌,的确困难,但是并非没有可能,我们可以找到一些优秀的、可选的技术集合(兜售私货的伏笔);
5. 对于技术选型的判断,需要考虑理论情况与实际情况;
效率考虑
技术复杂度(复用性):学习并掌握一组技术栈,需要了解多复杂的技术;相应的,当我们掌握了这门技术,他可以在多少地方复用?
技术友好度(优雅性):在开发的过程中,会不会有各种莫名其妙的陷阱,会不会让我纠缠于各种莫名其妙的细节?
实用考虑
业务复杂度(组织性):随着业务的复杂,我们的代码会不会最终无法驾驭?无法维护?无人能懂?
性能提升度(潜力):随着业务的增长,压力的提升,我们会不会最终被迫放弃现有的技术架构,重头开始?
也许,我们可以凭借这四个维度,做一个雷达图,以便更加准确的评价候选的技术,这里就先靠文字描述粗略的表达一下吧。
LAMP,当然是最为知名也最为成熟的技术栈,随着技术的发展,Nginix、Memcached、Redis、LVS等等技术,也非常自然的加入到这个体系之中,常常有人宣称:LAMP是全能的,而我在大多数时候,也相当同意这一点。如果将LAMP拆开来看,除了PHP,其他的几项技术,并非LAMP独有,如果我们单独来看PHP的话,他在开发效率方面相当优秀,但是略弱于Ruby&Rails;在实用方面,却略胜于Ruby&Rails,因此:PHP始终是一个不算坏的选择。
Ruby&Rails,是一个较新的技术栈(当然,我们可以说它仅仅替换了LAMP中的P),但是,Rails在快速开发领域的贡献是划时代的,具有开风气之先的意义。现在的Rails,也开始越来越大,越来越复杂,逐步的开始追求实用,这也造成了另一个有趣的现象:Ruby whitout Rails的兴起。甚至可以认为:Ruby社区一个非常显著的特点,就是强烈的追求开发效率,不太强烈的追求实用性。
nodejs,是目前最新的一个技术栈,他最大的一个优势,就是前后端只需要一种编程语言,使得原本就熟悉JavaScript的程序员,爆发了极大的向后端进军的热情。而另一方面,由于nodejs的异步响应的高效特性,使得其在实用性方面,有相当宽广的未来。但是,现在的nodejs,对于业务复杂度的支持,还远远不够。
Java是一门老牌的语言,说实话,我已经早就背叛了这个阵营,原因很简单,Java仅仅在组织复杂业务代码的能力上,有不小的优势;但是:这是以一开始就引入的架构复杂度为代价的。Java社区的众多框架,似乎也忘记了对开发效率的追求,一门心思为了展现更多的设计模式…(纯吐槽,请无视)
HTML5,也是相当火爆的热门领域,很大的一个原因,就在于:HTML5的知识,可以复用于Browser、Mobile、Tablet等原本差异极大的多个领域,因此在开发效率上,对程序员产生了极大的诱惑。只是在实用性方面,目前还有一些疑问。经常听人提到的HTML5&Native混合编程,我的直觉是:这样只会造成更多复杂的问题需要解决。
Golang、Erlang,本身就是根植于实用性(尤其是性能)追求的技术,在开发效率方面弱于其他技术,原本就是合理和正常的,对于某些预期肯定会非常复杂的系统,一开始就选择这样的技术,可以说是相当正确的选择。
Redis是一个好的技术,无论是自己一个人做个玩具小应用,还是在关键领域,承担核心性能组件。REST是一个好技术,无论是开发一个DEMO,还是用于整个SOA架构的核心,都非常合适。这样的技术,的确不多。