用Unix的设计思想来应对多变的需求
之前,@风枫峰 在“这是谁的错?”中说过开发团队对需求来者不拒,而@weidagang 也在“需求变更和IoC”中说过用IoC来最大程度地解决需求变更。今天我也想从Unix设计思想的角度来说说什么是好的软件设计,什么样的设计可以把需求变更对开发的影响降低。(注意:这并不能解决用户或是PM的无理需求,面对无理需求,需要仔细分析需求,而用技术的手段无法搞定这个事,但是可以减轻需求变更带来的痛苦) 我曾经在《Unix传奇》的下篇中写过一些Unix的设计哲学和思想(这里重点推荐大家看一下《The Art of Unix Programming》,我推荐过多次了),以前也发过一篇《一些软件设计的原则》,不过,这些东西都太多了,记不住。其实,这么多年来,我的经验告诉我,无论是Unix设计,还是面向对象设计,还是别的什么如SOA,ECB,消息,事件,MVC,网络七层模型,数据库设计,等等,他们都在干三件事——解耦,解耦,还是解耦!所谓解耦,就是让软件的模块和模块间尽量少地依赖起来。
现实当中的例子
让我先举几个现实生活中的例子:
1、现实社会中,制造灯具的工厂完全不关心制造灯泡的工厂,制造灯泡的工厂完全不关心制造灯具的工厂,但是,灯泡和灯饰可以很完美地组合成用户所喜欢的样子(这和@weidagang 在“需求变更和IoC”说到的那个PC的例子相仿)。他们是怎么做到的?
2、互联网上,做网站的人完全不用关心用户在用什么样的操作系统,什么样的客户端浏览器(当然事实上,浏览器的不标准让网站那边很头痛,这里只是举个例),反过来,上网的人也不关心做网站的人在用什么的技术开发网站。但是大家在完全不关心对方的情况下,可以很正常地协同工作在一起。为什么?
这样的例子太多了。为什么可以做成这样呢?因为大家依赖的是一个接口,灯具和灯泡并不互相依赖,他们依赖的是一个接口,做网站的人和浏览网站的人依赖的还是接口——HTTP协议。这就是面向对象的核心思想——依赖于接口而不是实现,这就是解耦。当你看过这两个例子以后,我希望你以后设计的软件至少不能比我们现实社会中的这些方法要差。不然,你就是在让社会倒退了,呵呵。 你会说,这和Unix,和应对需求变化有什么关系?好让我们再来看一下Unix的设计。
Unix设计的例子
下面是几个Unix下的例子:
1、Unix下,所有的硬件都可以通过文件的方式存取。其统统在/dev下。于是,软件和硬件的耦合被解开了,操作系统只需要把硬件统统变成文件,而程序只需要使用三个东西,一个是fd,一个是read(),一个是write(),就可以来操作任意的硬件了,这就是抽象,简单到不行。
2、Unix下,所有的命令都可以用管道串起来(管道绝对是个伟大的发明),这样,所有的命令间的交互全部解耦到只依赖于STD_IN, STD_OUT设备上。最酷的是,用户可以使用管道任意地拼装那些命令,以完成各式各样的功能。管道这个设计思想可以映射为今天的Web Service,你可以任意地拼装各种Web Service。
看到这里,你会发现,这还是解耦,本质上来说,也是一种依赖倒置——OOD的精髓。但是,Unix还不仅仅是这些。我们再来看几个例子:
1、Unix下,软件都是绿色地安装。在iOS上更明显——各个程序间基本上互不干扰,这个程序产生的垃圾文件不会影响到另一个程序。你删掉一个程序不会让另一个程序不举,各是各的空间。你可以删除这些程序,只要把内核心留着,系统照样可以启动。
2、Unix下,你可以通过设置一些环境变量,让多种环境同时存在,比如:某个LAMP用的是Apache 2.0, Mysql 4.0, PHP 4.0,某个LAMP用的是Apache 2.2, Mysql 5.0,PHP5.3,你不但可以方便地在系统中切换这两个环境,你甚至还可以同时启动他们。
3、Unix下,你可以随意地替换你想要的程序。比如,你不喜欢bash,你可以替换成ksh/csh等,你不喜欢awk ,你可以替换成 gawk ,所有的东西都像零件一样,你不喜欢什么,你就可以替换什么。
这三个例子告诉了我们——当你把你的软件设计地耦合度非常地低时,你可以随意地组合,随意地安排你的系统。相当的灵活,灵活到Windows到今天都学不会。
应对需求变化
看到这里,你可能明白我想说的是什么了,你可能开始觉得怎么样的系统设计会更有效了。如果你还记得《Steve Y 对平台的长篇大论》,你就会知道我想说什么了。是的,我想说的就是,当你真正了解了Unix的设计思想后,你会觉得今天的很多东西都是对Unix设计思想的一种传承或是变种。这种东西就是:
1)解耦,解耦,解耦。尽量地让你的模块不要在实现上耦合,而是耦合某个规范,某个标准。
2)KISS,KISS,KISS。要做到高度解耦,你的模块就一定要很简单,当然不是说简单到只有几行代码,而是简单到只干一件事,并把这件事干到极致。然后通过某个标准拼装起来。
3)拼装,拼装,拼装。我想不起来是谁说的了,这句话是这样的,当我想用一个模块的时候,我直接调用就好了,没有必要像C或Java一样,还要编译。是的,拼装需要一个框架,需要一种标准协议,然后让所有的系统都耦合在这种规范上,各自独立运行,就像一个机器上的各个部件一样,当我觉得这个部件不爽,换了就是了。(例如,当我们在尝试不同的算法的时候)
想想建材和家俱市场,无论用户过来想装修什么,我都可以满足用户的不同需求,只要你是和家装相关,我基本上都能满足你,不是吗?无论你怎么变,只要不变态,我基本上都可以满足你。这就是解耦,拼装带来的好处。 你可能会说我说得太简单了,另一方面,你可能觉得有一些系统这样做没必要,我承认,不过,你可以有选择的或多或少地试试。(其实,我相信你已经在不自觉得或多或少地使用这种方式开发软件了) (全文完)
(转载本站文章请注明作者和出处 酷 壳 – CoolShell ,请勿用于任何商业用途)
《用Unix的设计思想来应对多变的需求》的相关评论
@chen-xiao
是的,*nix系统的依赖关系如同微软一些痼疾一样难以解决。不去重新发明轮子的代价就是选择越来越少
的确,没有“银弹”
解耦是很好的设计思想,在做设计,写代码的时候,把解耦作为一个重要的指导思想是很不错的。
不过现实是很残酷的,解耦带来了灵活性,自由度,对需求的应变能力有了很大的提高。
不过我们不要忘了,为什么要大谈“解耦”,那是因为有耦合的存在且很多。存在即合理,为什么会存在这么多的耦合呢,正如前面有人举例 iPhone 的体验好,因为耦合在牺牲了灵活度的同时,对具体问题,具体对待,提升了体验,提高了性能。
所以,在设计的时候,不要太过纠结,在解耦作为指导思想的同时,把握一个”度”,同时一定程度上具体问题具体分析。
It is easy to add a layer of indirect. The hard part is how to reduce the overhead.
UNIX 重构了多少钱才实现稳定的?对于单一应用来说,过多考虑兼容性,灵活性,会极大的影响开发进度,而且灵活的设计需要一个完善的前期系统设计,大部分团队在开发应用前都没有能力做到
你对Unix的崇拜已经达到了一种意识形态的地步
这很危险
当然 我也喜欢Unix
只是没你那么狂热
解耦,解耦,还是解耦.
「解耦,解耦,还是解耦」,这个真是太赞了。
我和同事讨论前端,动辄就提模块化模块化,希望他们能 HTML / JS / CSS 模块化,不要存在相同或者类似的代码,他们都不是很理解,感觉复制粘帖很轻松。
也许是因为他们不用 *NIX 吧~
今天遇到行业信息化整合的讨论,我提接口,互访问性,接着第一想到的是你翻译的那篇《Steve Y 对平台的长篇大论》,过来后又看到这篇文章……
@alswl
给出充分的理由出来,相同你同事也会接受的。
@Anana
这关unix什么事,这只是一种思想,把unix只是使用了这种思想而已,什么设计模式,数据抽象等等无非也是类似的的一种思想
很好,学习了。
Unix思想太深奥了,只能一点点的去啃
这里一个提法忽视了一个问题域的本质问题,解耦到底是目的还是手段?我很赞同解耦的重要性,但是我认为强调解耦并不能帮助看官们如何解决问题,一定会问我怎么才能解耦,如何解耦才是合适的。纯个人观点,对事务的抽象,对需求的高层次抽象是非常重要的手段。所以我认为抽象能为解耦做出最有力保障。反观unix中一些完美的解耦方案是如何获得的,我想也不难理解抽象的重要性。
好棒的思想
似乎是挖坟了。不过这个文章说得太偏颇了。
“任何灵活性都是有代价的”,这句话时刻需要记住。
就用文中的例子:
LAMP体系可以用各种组合——那么应用程序就不能用PHP新版本的新特性,比如lambda,静态迟绑定,等等。在PHP4下完全无法启动。为了能够适应各种组合,就要在编写应用程序的时候付出大量的代价,而在很多情况下,这种代价完全没意义,比如开发某个项目,一般来说控制服务器环境的成本远低于在程序中提供适应多种服务器环境的成本。
文件概念。文件概念看起来很方便,但是实际使用的时候会碰到很多问题,因为它把一些不同的东西包装的看似相同,但是却并没有能够封装隔离掉他们的不同。比如说读写一个远程文件需要考虑延迟,读写本地文件一般不太需要,那么还要写一些代码去尝试探测…
当你把你的软件设计地耦合度非常地低时,你可以随意地组合,随意地安排你的系统。相当的灵活,灵活到Windows到今天都学不会。
学不会是不是说明这个技术太复杂了?
解耦也需要权衡,不能无限的解耦. 也有度的问题. 不能看到一个东西好就无限的扩大化.
解耦过多,会使部件太零碎,组合时就会变成一个大问题.
这就是为什么很多人喜欢一键安装包,而不是许多零件单独安装. 这就是你的汽车是分成外壳,发动机,车轮什么的而不是螺丝螺母, 这就是为什么你的电脑分成主板CPU显卡硬盘电源,而不是分成电容电阻电线啥.
也是一种依赖倒置——OOD的精髓 ?
OOD?还是 IOC?