搜课云网 > 郑州北大青鸟 > 资讯总汇 > 闲谈软件设计

闲谈软件设计

机构:郑州北大青鸟 时间:2015-11-12 10:05:00 点击:569

  说起软件设计,到了今天,在这个Lean/Agile横扫一切的年代,设计似乎有了被边缘化的倾向,做事的周期如此之快,似乎已容不下人们更多的思考。MVP(Minimal Viable Produce)在很多团队里演化成一个形而上的图腾,于是工程师们找到了一个完美的借口:我先做个MVP,设计的事,以后再说。

  如果纯属个人玩票,有个点子,hack out还说得过去;但要严肃做一个项目,还是要下工夫设计一番,否则,没完没了的返工会让你无语泪千行。

  要知道,设计首先得搞懂要解决的问题。

  工程师大多都是很聪明的人,聪明人有个最大的问题就是自负。很多人拿到一个需求,还没太搞明白其外延和内涵,代码就已经在脑袋里流转。这样做出来的系统,纵使再精妙,也免不了承受因需求理解不明确而导致的返工之苦。

  搞懂需求这事,说起来简单,做起来难。需求有正确的但表达错误的需求,有正确的但没表达出来的需求,还有过度表达的需求。所以,拿到需求后,先不忙寻找解决方案,多问问自己,工作伙伴,客户follow up questions来澄清需求模糊不清之处。

  搞懂需求,还需要了解需求对应的产品,公司,以及(潜在)竞争对手的现状,需求的上下文,以及需求的约束条件。人有二知二不知:

  I know that I know

  I know that I don’t know

  I don’t know that I know

  I don’t know that I don’t know

  澄清需求的过程,就是不断驱逐无知,掌握现状,上下文和约束条件的过程。

  这个主题讲起来很大,且非常重要,但毕竟不是本文的重点,所以就此带过。

  寻找(多个)解决方案

  如果对问题已经有不错的把握,接下来就是解决方案的发现之旅。这是个考察big picture的活计。同样是满足孩子想要个汽车的愿望,你可以:

  去玩具店里买一个现成的

  买乐高积木,然后组装

  用纸糊一个,或者找块木头,刻一个

  这对应软件工程问题的几种解决之道:

  购买现成软件(acuquire or licensing),二次开发之(如果需要)

  寻找building blocks,组装之(glue)

  自己开发(build from scratch, or DIY)

  大部分时候,如果a或b的TCO [1] 合理,那就不要选择c。做一个产品的目的是为客户提供某种服务,而不是证明自己能一行行码出出来这个产品。

  a是个很重要的点,可惜大部分工程师脑袋里没有钱的概念,或者出于job security的私心,而忽略了。工程师现在越来越贵,能用合理的价格搞定的功能,就不该雇人去打理(自己打脸)。一个产品,最核心的部分不超过整个系统的20%,把人力资源铺在核心的部分,才是软件设计之道。

  b我们稍后再讲。

  对工程师而言,DIY出一个功能是个极大的诱惑。一种DIY是源自工程师的不满。任何开源软件,在处理某种特定业务逻辑的时候总会有一些不足,眼里如果把这些不足放在,却忽略了人家的好处,是大大的不妥。前两天我听到有人说 "consul sucks, …, I’ll build our own service discovery framework…",我就苦笑。我相信他能做出来一个简单的service discovery tool,这不是件特别困难的事情。问题是值不值得去做。如果连处于consul这个层次的基础组件都要自己去做,那要么是心太大,要么是没有定义好自己的软件系统的核心价值(除非系统的核心价值就在于此)。代码一旦写出来,无论是5000行还是50行,都是需要有人去维护的,在系统的生命周期里,每一行自己写的代码都是一笔债务,需要定期不定期地偿还利息。

  另外一种DIY是出于工程师的无知。「无知者无畏」在某些场合的效果是正向的,有利于打破陈规。但在软件开发上,还是知识和眼界越丰富越开阔越好。一个无知的工程师在面对某个问题时(比如说service discovery),如果不知道这问题也许有现成的解决方案(consul),自己铆足了劲写一个,大半会有失偏颇(比如说没做上游服务的health check,或者自己本身的high availability),结果bug不断,辛辛苦苦一个个都啃下来,才发现,自己走了很多弯路,费了大半天劲,做了某个开源软件的功能的子集。当然,对工程师而言,这个练手的价值还是很大的,但对公司来说,这是一笔沉重的无意义的支出。

  眼界定义了一个人的高度,如果你每天见同类的人,看同质的书籍/视频,(读)写隶属同一domain的代码,那多半眼界不够开阔。互联网的发展一日千里,变化太快,如果把自己禁锢在一方小天地里,很容易成为陶渊明笔下的桃花源中人:乃不知有汉,无论魏晋。

  构建灵活且有韧性的系统

  如果说之前说的都是废话,那么接下来的和真正的软件设计能扯上些关系。

  分解和组合

  软件设计是一个把大的问题不断分解,直至原子级的小问题,然后再不断组合的过程。这一点可以类比生物学:原子(keyword/macro)组合成分子(function),分子组合成细胞(module/class),细胞组合成组织(micro service),组织组合成器官(service),进而组合成生物(system)。

  一个如此组合而成系统,是满足关注点分离(Separation of Concerns)的。大到一个器官,小到一个细胞,都各司其职,把自己要做的事情做到极致。心脏不必关心肾脏会干什么,它只需要做好自己的事情:把新鲜血液通过动脉排出,再把各个器官用过的血液从静脉回收。

  分解和组合在软件设计中的作用如此重要,以至于一个系统如果合理分解,那么日后维护的代价就要小得多。同样讲关注点分离,不同的工程师,分离的方式可能完全不同。但究其根本,还有有一些规律可循。

  总线(System Bus)

  首先我们要把系统的总线定义出来。人体的总线,大的有几条:血管(动脉,静脉),神经网络,气管,输尿管。它们有的完全负责与外界的交互(气管,输尿管),有的完全是内部的信息中枢(血管),有的内外兼修(神经网络)。

  总线把生产者和消费者分离,让彼此互不依赖。心脏往外供血时,把血压入动脉血管就是了。它并不需要知道谁是接收者。

  同样的,回到我们熟悉的计算机系统,CPU访问内存也是如此:它发送一条消息给总线,总线通知RAM读取数据,然后RAM把数据返回给总线,CPU再获取之。整个过程中CPU只知道一个内存地址,毋须知道访问的具体是哪个内存槽的哪块内存 —— 总线将二者屏蔽开。

  学过计算机系统的同学应该都知道,经典的PC结构有几种总线:数据总线,地址总线,控制总线,扩展总线等;做过网络设备的同学也都知道,一个经典的网络设备,其软件系统的总线分为:control plane和data plane。

  更多软件设计的讨论,请访问郑州软件工程师培训学校