软件开发过程中的思维方法
软件开发绝对是个消耗脑力的过程,在这个过程中,是需要一些思维方法的。而这些思维方法是需要训练和总结的。
软件抽象来讲是在一定的输入情况下,产生一定的输出,这个“过滤器”就是我们的软件。
豆浆机就是个“软件”,黄豆和水进去,豆浆出来,那么这个过滤器就是豆浆机。
解码器也是,“二进制流”进去,正弦波出来。
怎么把我们的软件设计好,这就涉及到软件开发思维了。我自己总结的有这么几个:划分,抽象(归纳),推演,概
率。
1.划分就是找到你感兴趣的点从而形成一个大家公认的概念,这个划分是有具体要求的,干净,充满美感。比如”人“
这个概念,为什么单单人体定义成”人“的概念,而不把人和一把”椅子“定义成一个人呢?也许你要说:人一走动,人的身体
就会一起动,而椅子不会,所以人和椅子是两个不同的概念,要分开定义。但是人如果把椅子罩在脑袋上,学着一只蜗
牛背着一个壳一样,我们是否也能把人椅合体定义为”人“呢?这个划分就有些玄妙了。可见,”划分“是有一定依据的,这个
依据没有绝对的指标。是个概率事件。但是这个原则就是你获得的”概念“,尽量干净,利落,讲究美感。对应起软件开发过
程中的对象和函数来说,那就是一个臃肿的对象和一个近似万能的函数是不讨人喜欢的。
2. 抽象和归纳是个很重要的方法。绝大部分的软件开发工作我们都涉及在此了。
请看上面这幅图,要你用程序写出这个图像。这是个4*18的方框,每个红点的位置不一样。如果有些小伙子不太善于
发现的话可能用两个for嵌套语句,然后if((i==1&&j==1)||(i==1&&j==4)||....)填充红色。这种方法就相当于点阵素描
了,一个个信息是抠出来的。但是我们如果把这个矩阵想象一维的,那么每个点的坐标就是i^2,即1,4,9,16,25,
36....这样,我们的程序就可以更加优异的写出来。但是等等,事实上,有这么巧合让我们归纳出这个数列函数来吗? 现实
是不一定的,如果我把第5个点左移一位,那么这个函数发生了变化,变的很不容易归纳,或者归纳的成本变高。
3.概率。这个世界不是平坦的,也不是都是一个个实打实的函数可以描述的,行星的运动可以用万有引力,开普勒,拉普
拉斯方法描述。但是世界是随机的,认识到这个问题,我们用软件解决问题的思路会开阔一些。我们会采用近似解,而不是
精确解,我们会采用统计性能,而不会用单个性能来衡量。从web负载均衡到快速排序,都采用了随机的量化思想。
4. 推演。推演更像个逻辑题,我们在软件系统中建立了某种体系,规则,所有的行为必须按照这个规则和体系。否则就会
矛盾。推演不是具体体现在编程过程中,是在满足变化中你需要注意的地方。一个女生要去商店买被子,告诉老板:老板,
我要一个又暖又轻又好看又便宜的被子。老板会立刻告诉她:木有!这样的过程总是会发生在我们开发过程中,客户老是希
你用大便给他造个满汉全席。你可以用你线性代数和动态规划的知识解这个不等式组,结果就是无解!埋头苦干的程序员总
是埋头苦干,想立刻赢得快感。开始做的好好的,越做越爽,但是收尾的时候,发现了大麻烦,无法从逻辑上合拢。然后
重新设计了一种方案,结果还是不行,搞来搞去,最后还想着我把这个问题搞定,我就是高手了。其实如果静下心来,仔细
用数学的方法来分析,推到一下,会发现这是个不可能的任务,事实上存在这样的问题吗?相当多的。当然这样的矛盾一般
是不容易出现的。比方说某人娶了他二舅的大爷的三姑的侄子的表兄的弟弟的母亲的外孙的三姨的哥哥的三叔的小姨子的儿
子的女儿,从而得出自己是自己的爸爸的荒谬结论一样。这个矛盾的过程很长,但是某个阶段都是无矛盾的,但是把这个环
给圆了,那是不可能的。
一般来说,软件开发都是一个对上并且对下的过程。对上就是我们需要满足什么样的输出,对下,我们建立什么样的基
础上,有什么用的平台。先从整体上把握,我们会罗列出软件需要满足的条件。再从下层来分析,我们手头有哪些素材,能
有什么样的能力。我个人最反感的就是大家讨论项目,一上来就是谈怎么怎么实现,哥哥的。有的人连什么问题都不清楚,
这样入题是非常愚蠢的,大家的思维都没有限定,怎么发挥想象力,想象力也是在一定范围内约束的想象啊!开题之前,介
绍一下项目的前因后果,达成目标,对接系统的素材,能力等等这些其实都是十分重要的,这样大家的思维就会在一个比较
安全的范围内思考,而不会漫无边际。
理想和现实---软件的开放和封闭(安全和稳定的相对讨论)。软件是收外界的刺激的,能受外界刺激的种类越多,输
出种类也多,说明其开放性很高,复杂度也高。反之,软件封闭性很高,也越安全,也稳定。开始软件很小,不是很复杂,
很封闭,很安全,但随着需求增长,越来越开放,稳定性会下降,直到不可使用。有没有一种方法能使软件在日渐开放的
过程中能永生呢,答案是否定的。这就好比盖楼一样,为了盖50层的楼,我要10层脚手架支持,为了盖500层的楼,这
么,我需要50层脚手架,同理50层脚手架,也需要额外的10层脚手架固定支撑。一栋楼好比一个体系,为了这个体系不
倒,不矛盾,我需要额外支撑,当然软件需要第二栋楼,这栋楼也很高,也需要额外脚手架,虽然这些楼互不相交(矛盾,
抵触),但是脚手架会挤占这些体系之间的空隙,直到矛盾。也就意味系统的终结。可能这个比方很粗糙,但是理论学家
确实证明了,可以参考
大概意思就是世界不可能用一个规则来归纳,比如牛顿力学不能解释整个世界,需要量子力学,量子力学同样不可能完全解释世界,这两种力学体系可能存在冲突。其实我也不懂这个定理在说什么。
范例:
什么是好的划分?
在项目中,最先遇到的是直觉。直觉是可靠的吗,不一定。直觉是简单的吗?也许是简单的。首先,我们要把“直
觉”加工提炼。
分解--》验证--》综合。
现在举一个色彩组合的例子。
这个例子和软件的构建过程十分类似,希望我能使你感觉到我是在讲软件开发,呵呵
色彩有无限种,如果我们要输出“任意”一种色彩,一种一种去制造是绝对“耗时”的。那么正确答案就是“三原色”组、
合,按照不同的比例,浓度来调节,总是能合成我们需要的色彩。我们来分析这个过程,色彩的“分解”,然后我们“验证” ,
试验一下,发现可行,然后“综合”一下,编程,交出结果。“分解”的过程十分有趣,有没有不好的分解呢,当然有的,可能
你分解出来的“原色”,永远也合成不出一个任意需要的色彩,这就是差的分解。软件的需求是不断增加的,开始我们对问题
的把握由于case没有那么多,总是能用一种近似的方法来得到,比如,我们需要一种“暗紫”色,我们的直觉就是制造一个
”暗紫“,当我们再需要一种色彩的话,我们还是用直觉再给出一种色彩,当我们不断在被老板要求的时候,我们就可能想想
用组合色彩的办法了,如果需求的色彩不是很多,我们是能够用一种非”三原色“的”基础色“来调出来的,但是当需求变成
任意,就无能为力了。好的分解,如何得到呢,好像是智慧,这种智慧并不是经验,不管你有多少年的软件开发经验,这个
和”智慧“没有关系,经验只是一种熟练程度而已,你所拥有的经验别人总是能学到,或者总结出来。但是智慧不是,需要数
学,物理等方面的训练。
好的分解都是有共同点的,这是一个力学的分解图,正交分解。这样我们求解”合力“就会变的非常机械化,程式化。
这无疑是个很好的”分解“。那么好的分解的共同特点就是“维度的正交化”,正交化才能减少冗余,差的分解总是包含着
无穷无尽的”冗余“,对项目来说,开始还OK了,后来越来越垃圾,直到崩溃。自己扪心自问,你们的项目经理,系统工程
师,有没有”制造“出逻辑无比混乱的概念,风骚银荡的规则,和这些规则之外的例外情况?这些就是活生生的失败”分解“,
没有抓住问题的本质,或者看的不够深远。
作为一个程序员我感到很悲哀。系统工程师设计完了,我就要马不停蹄的开始coding, 开始还好。但是随着项目的增
大,会有”打散“(原来就是指树的深度变浅这个概念,树的深度很深,现在为了使树的深度变浅,称之为”打散“,老子还以
为要把碗打烂呢!),等许多
莫名其妙的词汇和概念,为什么呢?装逼吗,天知道,只是这些概念十分幼稚,完全可以用一些大家都了解的数学概念来称
呼嘛!像“树”,“交集”,“并集”等等,我操,很多项目经理和系统工程师都从来不用一些通用语言的,总是自以为是的发
明。再然后我就要陷入无限的泥沼中。我会开始有如下的coding.
通常一般采用这个规则
{
rule();
}
but if( case 1)
{
rule()之外,有些小变化,rule1()
}
if( case 2)
{
rule()之外,有些小变化,rule2()
}
if( case 3)
{
rule()1,rule2()之外,甚至还要rule3()
}
写到这里,你肯定要fuck了,一个好的规则应该是“简单,正交,充满美感”,如果你很多额外的代码是为了维持你
的规则继续生存下去,那就考虑一下这个设计是否合理,有没有必要重构,让其更加简单,直白。
以后再写!