Fork me on GitHub

软件工程—思考项目开发那些事(一)

阅读目录:

  • 1.背景
  • 2.项目管理,质量、度量、进度
  • 3.软件开发是一种设计活动而不是建筑活动
  • 4.快速开发(简单的系统结构与复杂的业务模型)
  • 5.技术人员的业务理解与产品经理的业务理解的最终业务模型
    • 5.1.产品的业务理解(业务流程、数据流程及场景)
    • 5.2.技术人员的业务理解(领域模型、设计模型、抽象建模)
  • 6.技术债务(腐烂的遗留代码)
  • 7.软件项目管理与软件工程的鸿沟(项目管理得有语境上下文)
    • 7.1.软件项目管理其实应该多去重视一些技术层面的管理
    • 7.2.软件工程才是指导软件开发的科学方法论
    • 7.3.代码质量、可持续迭代、快速开发(需要软件方法论的支撑才能做好软件项目管理)
  • 8.敏捷、极限编程,精益思想
    • 8.1.重软件项目管理不等于重软件项目质量(否则瀑布模型就不会失败)
    • 8.2.Scrum不等于敏捷开发只能算是敏捷过程(此时只是重视过程而不是最终的软件质量)
      • 8.3.结合XP最终落实到软件质量上(比如结对编程、互相code review、快速重构)
  • 9.偿还技术债务的成本(拖得越久成本越大,而且是指数级的)
    • 9.1.技术债务与快速开发
    • 9.2.技术债务的偿还方式是有技术门槛的
    • 9.3.偿还技术债务只是其一,关键是如何避免技术债务(重新开发不等于不会有新的技术债务)
  • 10.软件过程瓶颈
    • 10.1.代码最终会成为你的最大的开发瓶颈(而且是无法解决的瓶颈)
  • 11.不合格的技术人员对公司的副作用是很大的(要做一名合格的技术人员)
    • 11.1.技术人员应该重视编程而不是各种高大上的技术名词和互联网浮躁的心态
  • 12.总结

1.背景

最近对软件开发有了一个新的认识,这个认识源自连续看了两本Craig larman大师的书籍《UML与模式应用》《精益与敏捷开发大型应用实战》和公司目前的项目情况这两件事情一起碰撞导致的感悟。

先说下前者,为什么会想到看Craig larman大师的书籍。其实我收藏的书籍已经上千本,在各个电商平台上都有帐号,目的只有一个就是收藏好的书籍。家里也堆了很多,没事浏览新书是我现在最大的乐趣。我相信有这种感觉和爱好的不止我一个人,家里堆上几十本书的在IT行业算是很正常的。

书多了有时候不知道要看些什么也很正常,我的原则就是随时调整,看目前所面临的困惑。根据我以往的经验总结,在实际问题面前寻找答案最容易让你有新的感悟和提升。我相信书中自有黄金屋、书中自有颜如玉,要在对的时间看对的书,说白了就是在有困惑的时候就去寻找给你答案的这方面书籍。为什么要看Craig larman大师的书,是因为最近的工作内容有很多自己搞不懂的地方,希望能通过大师的指点有所感悟,果然受益匪浅。

再说下后者,最近一直在和这几个事情打交道:遗留代码技术债务项目管理项目质量开发进度快速开发重构单元测试敏捷开发ScrumXP,你可能会有点疑惑,有些东西是重复的,比如项目管理中包含了项目质量、开发进度,再比如敏捷开发与Scrum和XP,似乎我在把一个大的概念拆解成多个小重复的概念。我之所以这么做,是因为我想强调这些概念的区别和真正的相互作用,从软件工匠的艺术角度出发来真正的看待这些概念。比如说,项目质量与代码有关系吗,开发进度与遗留代码有关系吗,项目管理与技术债务有关系吗等等,这些问题的本质是完全不同的,作为技术人员尤其是应用开发的技术人员一定要强调概念,一定要明白不同的概念的本质含义,如果你不强调概念我想你的代码是写不好的,对业务的理解也不会深刻。

最近我将自己的技术生涯的目标定为“软件工匠”,其实说实话我不在乎title,我只在乎自己的工作内容是什么。软件工匠是没有边界的,只要和软件开发有关系的内容都是属于工匠需要去专研的领域。如果工匠离开工具就丧失了工匠的真正价值所在,所以说千万别放弃写代码。不管你是一名架构师还是一名开发经理,代码永远是产品的最终设计,一旦你离他而去就离产品的质量越来越远,后面我也会讲下为什么代码如此重要。

2.项目管理,质量、度量、进度

这节的标题是不受欢迎的,大家知道为什么吗。技术人员是能明白的,有过长达5-10年的开发出生的管理者也是能明白的,唯一不明白的就是没有太多开发经验的管理者,或者那些不喜欢开发的管理者,那些逃避开发的管理者,因为他们离真正的产品实现太遥远,他们离软件开发领域真正的问题太遥远,管理一旦忽视代码质量问题就会慢慢找上你,你的项目往后的质量越无法控制,度量、开发进度都会遇到瓶颈。

说个当下的现象,我从事一线开发也有好几年了,陆陆续续看到很多人转作管理,但是你会发现做管理的人一般都是技术水平一般的人,或者对技术没有太多追求的人,更夸张的是在有些小公司的管理者可能就没写过代码。

为什么会出现这种现象,其实主要原因有两个,首要的就是个人的职业规划,在就是公司的价值导向。先说价值导向,往往写代码的人的价值没有项目管理的价值大,这在一些中小公司还是很普遍的,真正的科技型公司这类问题几乎没有。而职业规划是完全可以接受的,毕竟每个人的兴趣和追求不同,这无可厚非,应该尊重每个人的选择。但是这里的问题是,一旦没有太多技术底蕴的技术人员坐上项目管理者的职位后会对技术的理解360度大转弯。这其实是不对的,项目的成败不可忽视技术。

不继续讨论这个话题了,这不是本篇文章的重点,人各有志,选择是正常的,但是要明白的是选择的本质不是价值导向,而是兴趣导向,这才不会让你忽视另外一个角度,因为一个软件产品的最终成功是要靠项目管理和软件工程相共同的努力,缺一不可。

这里想聊聊项目管理的三个重要的方面,质量、度量、进度。首先我不是一个专业的项目管理者,但是我是一名专业的软件工程师,我不知道项目管理的具体内容有哪些,但是我知道项目管理的最终目标是和软件工程的目标是一致的,都是为了项目高质量的完成。

项目的成败光靠项目管理是解决不了的,如果可以就不会出现《软件工程》《设计原本》了。保证软件项目的真正成功是需要软件工程的支撑才行,而管理更加是对开发的组织、协调、沟通上的,这是两个层面两个角度互相作用的。项目管理中不会有设计、抽象、可维护性等这些内容。

这里尤其想讨论的就是软件项目的质量,现在看来衡量软件项目的质量忽视了代码的质量,客户验收、功能完成、稳定上线,没耽误进度,这就是完成了一个项目,我们忽视了一个就是代码的质量,为什么要关心代码的质量。

度量,度量是对开发周期内所有发生的事情进行数据可视化,BUG数、发布回退数、代码行数(比较特殊)、需求变更数等等,还有些我不是太清楚的度量数据,总之应该会有很多。度量的目的是为了什么,是为了能够在这些数据出来后改善项目的各方面质量,控制各个不稳定的方面。

开发进度,“质量”一段中我最后抛出了一个问题“为什么要关心代码的质量”,因为他直接决定了你的项目进度,当你的代码质量越来越差的时候你就失去了对项目进度的控制。你再多的度量指标都是无意义的,就算你可以统计出BUG数上升了,但是你也控制不了BUG数下降,因为你已经偏离正常航线太远,就算你可以控制需求变更的速度和次数,但是你无法控制适应变更的代码的速度和次数。变更是无法避免的,你的代码无法面对这些复杂的变化,因为你的代码不是设计出来的而是堆出来的。最后你的项目质量也无法很好的保证。

(图1:项目管理与软件工程的结合才是完整的软件开发)

 

最近在看Michael C. Feathers 大师的《修改代码的艺术》一书,感触颇多。里面讲到了我们面对遗留代码的时候,为了增加一个新的功能要付出多少时间和精力,出现明显的BUG机率有多高,出现隐藏的BUG机率有多高。遗留代码直接决定了上述三个项目管理的方面。Michael C. Feathers 大师强调了很多关于我上面讲到的项目管理和代码质量之间的关系,这本书很值得看。

其实真正推动软件开发不断发展的是软件工程、开发方法论,项目管理只是辅助于软件工程在时间和空间上有效实施。

这里还要区别下就是项目管理和团队管理的区别,这两个东西是不一样的。项目管理基本上不需要软件工程的支持,但是团队管理在某些方面是需要软件工程的支持才能做的更好。

3.软件开发是一种设计活动而不是建筑活动

在《精益与敏捷开发大型应用实践》一书中是这样描述软件设计和架构的:

1:“软件架构借鉴了建筑的架构,但结果证实这是个不太恰当的类比,而且给软件开发带来了有趣的副作用。建筑是硬的,因为在这个领域,设计只在施工前进行一次,然后该建筑或者设计就几乎是永久不变的了。注意建筑师和施工工人是不同的。但是软件不是一座建筑,软件是软的,而且编程也不是施工的过程,“软件架构”只不过是一大堆比喻列表中可以选择的一个不太完美类比而已”。

2:“......唯一确实看起来满足工程设计条件的软件文档是源代码“。

3:"我意识到图表和文档并不是真正的设计,而源代码才是真正的设计。再次重申“......唯一确实看起来满足工程设计条件的软件文档是源代码“。

这几句话足以证明软件开发是一个非常复杂的过程,是思维密集型脑力活动,而且体现在每一个编码过程中。在很多项目管理中都认为软件开发是一个非常简单的活动,主要架构设计好编码是比较简单的,难道真的是这样吗,我们再看看书中怎么说的:

1:”源代码是真正的蓝图“。

2:”真正的架构在哪里,无论好坏、有意或偶然的?是在架构团队维护的文档中?还是在上万个文件中?显然是后者,源代码是真正的设计,而且它的总和反映了真实的大型设计或架构。架构就是架构,不是某人的意愿“。

现在很多开发者还有一个明显的技术理解错误就是”写代码“是比较简单的活动。复杂的是软件架构,只要架构设计好后写代码应该是程序员的事儿,这里明显有一个错误的价值观,认为写代码的人都是廉价的,不具有任何的设计和创造新。这其实是一个很不专业的看法。真以为一个简单的PPT、WORD文档中的架构图就表示架构了。其实这个想法是很幼稚和肤浅的。用Craig larman大师的话讲,在整个软件生命周期的活动中,复杂的是编写代码,而代码才是架构,所以说架构的就是代码。你原本理解的架构才是真正难的地方其实也就是代码才是真正难的地方,不可浮于表面,这样才能更加的接地气才能真正的有价值。

架构师应该深入到一线参与一些开发,这时会发现很多问题,然后将问题带到架构的位置,用架构的视角设计方案,在亲自把这个方案带到一线落实下去,这才是架构落地一个技术方案的正确方法。

软件开发是一项设计活动而不是建筑活动,软件是会不断变化的,而建筑一旦敲定是不会改变的。

4.快速开发(简单的系统结构与复杂的业务模型)

这节我想聊聊快速开发。在圈子里面对快速开发的理解大部分都是和快速开发框架对应起来,觉得应该有一个框架来支持快速开发。只要有了一个框架就可以进行快速开发。这样的看法或想法其实是错误的,对快速开发的理解太狭隘。

《设计原本》作者,计算机科学巨匠Frederick P. Brooks说过,对于软件开发来说没有银弹存在,没有所谓的能够用简单发方法来开发复杂的系统。越复杂的系统开发起来不会简单的,开发一个满足100个人使用的系统和开发一个满足1000个人使用的系统在复杂性上已经完全不同了。量变引起质变,当业务量、访问量、数据量等等这些软件指标超出一定的范围之后就和最初的设计完全不同,设计思路也完全不同。

回到当下。我现在经常面临这样的一个问题,我现在所从事的业务是比较复杂的,对系统的设计要求很高。如果用量来比喻的化,其实我现在所面对的业务量是比较大的,业务量中的业务复杂性的量其实相比于访问量、数据量等方面的量在设计方法要难的很多。通常做设计的架构师都只会考虑并发量、访问量而忽视业务量,比如业务的多变性、业务的扩展性,业务本身的复杂性,这尤其考研设计能力,考验抽象能力。这跟你用什么编程语言用什么数据库是没太大关系的。你脑袋里运用的是OO、实体关系,这些与具体技术框架没关系的设计思维。

业务量对于编写代码要求要高很多,同比于其他几个量来说很难落地。访问量、并发量可以通过基础架构的调整优化升级来解决,而业务量的问题域是业务逻辑,是领域模型,当前所面对的业务域,任何一个细小的业务都需要在代码中体现。

最近陆续在做一些系统重构的工作,就在前两天我重构了一段代码,不是基础性的代码,是业务逻辑代码。大概情况是这样的。

在系统中有一个重要的领域概念“重量”,这个重量的概念存在很多个业务量的质变可能性,就是说它本身不是简单不变的,随时存在着变化,当我们品类扩充的时候就立马会变化。

重量的定义是这样的:重量=单件重×数量,看上去好像很简单的样子,其实不是,这里的单件重是会变化的,有些时候是保留3位小数有些时候是保留6位小数。而且这个重量的业务逻辑是在N多个地方都需要用到的,查看代码下来大概有几十个地方都在重复着编写“重量“的业务逻辑。

后来我在同事的协助下重构了这块业务模型,为什么我这里不用业务逻辑来形容我的重构工作,是因为我考虑业务的时候不会是过程式的,如果用”业务逻辑“来思考业务就会给人造成一个错觉就是”过程式“的代码结构。所以我考虑任何业务都是”模型驱动开发“方法,业务要抽象为模型才能重用、扩展、抗变化性。这其实是OOA/D的精髓。业务逻辑只是在模型中的一小块一小块的具体动作,它是在模型的范围内使用的,而不能一上来就是业务逻辑,业务逻辑太细小不便于抽象化。

 (图2:重量、单件重模型)

我用上面的这个模型对重量业务模型进行了重构。将原本很重要的业务概念重量、单件重、不同类型的单件重,进行了概念显示化,保证这些重要的领域模型不被过程式的代码淹没。且用两个工厂封装了创建重量和单件重的业务逻辑。这样做之后我们的模型就具有抗变化性,以后要是对Weight有任何的创建逻辑的变动我们就可以在WeightFactory中处理,如果有新的品类扩充进来后需要对单件重相关的处理我们只需要扩展下ItemCategory和PieceWeightFactory两个模型。如果你需要做为完全配置化,这个时候模型就更有价值。比如,我们可以将IitemCategory拿出去,通过品类扩展的时候自动生成相关的类型,如果你觉得这还不够完美,我们可以进一步将PieceWeightFactory中有关于“根据ItemCategory创建PieceWeight(Decimal) “,做成”Mapper模型“在进行配置化。

这里你会发现一个很奇妙的地方就是,一旦模型化后业务的量变引起的质变可以通过逐步重构模型、提取模型、精华模型来解决。

所以说简单的系统结构是无法表示复杂的业务模型的,如果可以的话OO语言就不会发展成今天的这样子。复杂的业务无法通过简单的系统结构或者说所谓的简单的快速开发框架之类的东西可以解决的。

5.技术人员的业务理解与产品经理的业务理解的最终业务模型

很多时候我们都在强调“多去了解业务、多去熟悉业务”,在业务驱动型公司这是必须的,公司中的任何角色的单位都需要熟悉公司的业务范围。这没有问题,我想说的是不同的角色对于业务的理解最终的业务模型是不同的。

不管是在传统的软件企业中还是互联网企业中,我们要用软件来服务于我们或者客户,当然这里所说的是业务系统。业务系统的核心就是业务,系统的精神就是业务模型及模型之间的关系。

这节我想说的是,技术人员去了解业务后和产品经理去了解业务后最终的业务模型是怎样的。技术人员与产品经理是不同的角色,具有不同的职业背景,不同的知识结构和专业度。现在存在一个普遍的认识错误是,技术人员理解业务后与产品经理理解的业务后的最终的模型是一样的,是怎样的呢。是无法抽象的业务,大概的业务,场景化的业务,无法落地到系统中的业务。此时技术人员并没有用自己的专业度来对业务进行抽象和建模,并没有直接带来真正的价值,而是在交谈和理解需求的时候感觉上的价值错觉。

技术人员不能够业务技术化其实对于公司所说的“当技术人员理解业务后产生的价值是巨大的”其实是不准确的。

5.1.产品的业务理解(业务流程、数据流程及场景) 

产品对于业务的理解是整体上的,包括业务流程、数据流程,场景,在他们的脑子里是真实的业务场景,是必须要还原的业务场景,不能够有任何的其他模型在作怪。如果产品用任何的其他知识来抽象和强制理解业务是会出现问题的。

产品对于业务的最终模型是业务流程、数据流程和一个不需要表现的场景。

(图3:产品的业务理解最终模型—业务流程图)

 

由于数据流程图比较简单,当前例子中只会有“订单”的数据实体,画出来意义不大,我这里就只画一个业务流程图来表达意思即可。

在这个程度上是无法直接将流程图落到系统上的,它距离真正编写软件还有一段过程要进化,而下面那段过程才是技术人员理解业务后要发挥的价值和作用。

5.2.技术人员的业务理解(领域模型、设计模型、抽象建模)

技术人员的了解业务要有所侧重,你理解的业务和产品理解的业务是不一样的,技术人员需要将业务最终技术化才行。技术人员的最终的业务模型是有正确的模式可以参考的,就拿“创建订单”这个流程来说,等待技术人员需要去提取和抽象的东西是比较多的也是比较复杂的,需要结合很多的知识来进行设计活动。

比如订单,你需要结合“四色原型”模式来提取“订单”的模型,包括“订单的类型“、”订单的跟踪“,需要结合设计模式来抽象”创建订单的逻辑“,根据”不同的订单类型创建不同的最终订单“。还需要进行设计模型的抽象,比如创建订单,各个对象的交互是如何的,每个交互的输入和输出是什么。这些都需要技术人员理解了业务后应该具有的业务模型,如果需要将模型语言化就需要结合使用UML来建模。

如果技术人员理解业务后和产品经理理解业务后的结果是一样的,那技术人员要去理解有什么价值。技术人员理解业务后要系统化的将各个业务模型落地到具体的领域内或者说某个子系统子服务中,然后各个系统和服务是如何交互的,逻辑的归属到底是哪边的。最终你写出来的代码才是满足业务的代码模型,才是有核心竞争力的业务系统有别于无核心竞争力的系统差距。

技术人员了解业务后,针对不同的业务场景开始创建领域模型草图,根据领域草图再进行设计模型草图创建,当然这是一个敏捷的迭代的过程。

(图4:“创建订单”相关的领域模型)

有了领域模型之后就需要创建设计模型,也就是各个模型之间的协作关系。还是要强调下,这是一个快速迭代的过程,且勿将其看成是瀑布的依赖过程。领域模型的精华也是没有止境的,当后面进行设计模型的过程时会有对领域模型有补充的灵感,此时不可以教条,要快速的精华领域模型然后再进行设计模型的过程。

(图5:“创建订单”相关的设计模型)

基于领域模型创建设计模型中的对象协作模型,设计模型不仅仅只有协作模型一种还有其他的。协作模型是必须的也是最重要的。有了协作模型之后我们就可以走查场景是否满足“创建订单”的这么一个业务动作。当八九不离十的时候就可以进入到编写代码阶段,进行一个快速的构建代码模型,因为这个时候还是会有问题出现,只有在代码模型中没有问题后才是真的没有了。

我这里只是假设一个简单的业务场景作为示例,目的是为了介绍技术人员区别于产品对于业务理解后的最终模型是不同的。技术人员一定要有完善的能将业务技术化的知识结构,这样才能真正的将业务发挥价值。

6.技术债务(腐烂的遗留代码)

技术债务其实是无法避免的,各种原因,时间进度、需求变更、市场迫切等,都迫使研发开始堆积技术债务,代码逐渐开始腐烂,难道我们作为技术人员就只有抱怨和推卸责任吗。这里我有一些个人看法,这些个人看法可能跟你的理解不一样,你可能会说我太理想主义了,但是我想说的是:“作为一个技术人员一定要有情怀,一定要有追求。”用我最尊敬好朋友冯老师的话说:“写代码一定要考究“。就算在时间比较紧的时候可以先写,但是要记住你的工作并没有完全完成。

我是从开发做到架构,经历过很多项目磨练,也深知在项目时间比较紧急的时候自己是在一个什么精神状态下写代码的,自己也干过到处复制代码粘贴代码的时候,加班到12点,眼睛基本上已经很难看清代码,敲代码的速度已经赶不上功能交付的速度。我只能说这也没有办法,市场决定了项目的进度。我们可以吐槽,但是不能抱怨,更不能消极。

其实现实情况下我们做开发的基本上都是在这个节奏下工作,但是我是怎么处理这个问题的呢。首先写好代码是个人对技术的一个追求和职业素养的问题,如果你对代码没有美感你很难能编写出好的代码,你的代码也会到处留有坏味道,时间长了就是腐烂的遗留代码,严重的技术债务,研发整天怨声四起,各种抱怨,吐槽,这样下去其实是不好的,团队里有追求的技术人员会流失。

实话实说,当自己今天晚上12点写好了代码提交了测试,但是我的工作并没有完成,我通常会在早上很早就醒了,我会很早的来到公司对自己的代码进行重构和梳理,早上是大脑特别清醒的时候,在这个时候你进行代码的整理是非常不错的,而且这个时候公司一般都没什么人,特别安静,当你重构完代码舒服舒服的再去整理自己每天早上来的其他事务。

你可能会说那是你个人问题,我不一定会在第二天早上能起的那么早,就算起的来我到了公司也不会对第二天的代码进行整理,因为那已经上线了已经是完成的功能,我该继续下一个需求。

用我的价值观来看的话,其实你的工作只完成了一半,你并没有保质保量的完成工作,你的软件交付质量在产品层面是完成了,但是你在技术层面是有残缺的。你给软件带来了很多的技术债务,你给某个对象带来了腐烂代码的开始。

这点我现在的公司是非常不错的,公司高层对项目的管理者首要的要求就是必须懂技术。

我一没事就会和我的好朋友也是好同事冯老师交流技术,互相review代码,提意见,在互相重构,彼此学习。我们有一个共鸣,就是让写代码有追求的人来把控项目是非常不错的,可以保质保量的完成功能,当然不是光说有写代码能力就OK的,需要综合性的。其实说白了,让一个精通技术的人在去精通业务做出来的软件应该是不错的。 (这里所说的精通技术是指应用开发方面的精通,不是指技术专家、系统层的技术专家)

作为应用开发人员,要时刻记住你所应该具有的专业的职业素养,写代码要讲究,要记住对你来说代码意味着什么。

 

未完待续。。。。。。

 

posted @ 2015-08-01 16:14  王清培  阅读(11043)  评论(26编辑  收藏  举报