适应随机多变的客户需求的系统建设

一.引言

为了使得阅读过程生趣形象,先来分享两个故事。

  • 第一个是我亲身经历的事情:2013年一次偶然的机会,在工作中接触到复旦大学的一个朋友,有天他带我去复旦大学软件学院的一个实验室里,这是一个5个人的研发团队,他们正在做CRM系统(客户管理+电话坐席系统)。我之前在软件公司工作过,给客户做过CRM产品,在我印象中项目的整套流程是:

1.客户提出需求
2.产品经理对接,绘制产品原型
3.产品原型交给项目经理
4.项目经理开会讨论需求,分配开发任务,制定开发计划
5.开发完交付给测试人员
6.测试完交付给客户
……
整套系统从0到交付给客户,大概需要2个多月时间,如果后期有类似客户也做一套CRM系统,那么复制之前的那套系统,根据需求来修修改改,大概一个月时间完成。那个复旦大学实验室的团队leader告诉我们:“我们帮客户做一套CRM系统,只需要一杯咖啡的时间,差不多20分钟吧”。我被当时的场景所震惊,可能会记住一辈子吧。

  • 另一个故事是在计算机刊文中看到的:在芬兰有一家游戏公司叫supercell,是世界顶级游戏公司巨头,开发过全球热门游戏,比如《部落冲突》《海岛奇兵》《皇室战争》《荒野乱斗》等等,但是公司规模不大,只有一百多人(对比国内的游戏公司,动辄上千人的规模,有点惭愧),他们自己开发游戏,自己运营,同时也为全球很多公司开发游戏,类似于游戏外包。腾讯在收购supercell之前,启动一个项目一般要组建百八十人的开发团队,并且996工作节奏,大概需求N..天的周期。但是芬兰supercell公司开发一款新游戏,需要大概十个人规模的团队,并且在非常快的时间内交付产品,后来腾讯眼馋了,收购了supercell。当时看到这里同样是震惊,怎么有似曾相识的感觉…

二.客户画像

揣摩别人的心思是大忌,玩得好能得势,玩不好要栽跟头。和珅善于揣摩乾隆的心思,得势一生。反例:李善长喜欢揣摩朱元璋的心思,爱耍小聪明,结果被诛九族…但是现在是民主文明社会,对于我们做产品的人就应该要善于揣摩客户的心思,有时候恨不得想成为客户肚里的蛔虫。

  • 客户有两方面需求:一个是业务需求,一个是服务需求。简单描述为:客户在业务上需要使用系统平台,能满足他各方面的功能需求,界面通俗易懂,操作便捷,能够7×24小时随时待命,任何时候都不卡顿,数据只对他喜欢的人可见,不喜欢的人一律不可见,数据永远不会丢失。凡是现实生活中享受不到的服务,他都想享受到,活在梦幻中是每个客户的梦想。
  • 客户有两个使用产品的方式,一种是定制化软件,独立部署在客户的服务器上;另一种是云软件,客户打开浏览器或者下载APP或者直接在微信中使用第三方软件。分析下两种方式的利和弊,客户需要的是能满足他业务使用,但是不想自己公司内增加一个软件维护人员,希望委托软件服务商来帮他维护软件,如果是独立部署模式,假如软件出现故障或者需求要改动,他们联系软件服务商尽快解决,软件服务商回复他:更新好了会通知您的。然后客户就会陷入漫长的等待过程,所有涉及到软件方面的业务全部暂停。如果软件服务商给很多客户部署了类似的产品,那么一旦软件中出现一个突发性的故障,软件服务商只能挨个给客户修复,改完这个客户再到下个客户。优先级怎么排呢?当然是大客户优先,小客户慢慢等着吧,那些小客户就悲催了。如果是云软件模式,软件中突然出现一个故障,这个故障会对所有使用该功能的用户可见,即使客户自己不向软件服务商反馈,其他客户也会向软件服务商反馈的,软件服务商会立马修复,并且只需要修改一处,所有客户都会更新,不用挨个客户去修复。好比如:我如果想用办公软件,我宁愿用钉钉,我也不愿意用软件公司给我定制的一套办公软件,即使钉钉每个月让我付钱,我也愿意…
  • 至于软件升级考虑,一般软件一个版本的寿命平均不超过两年,如果是独立部署软件,版本升级的工作对每个客户都是重复性的工作,对软件服务商会损失耗能,而云软件只需要做一次工作即可。
  • 至于数据隔离和安全考虑,不论是独立部署软件还是云软件,维护工作都是由软件服务商来做的,数据没办法对软件服务商隐蔽,软件服务商还是能获得到客户的数据,只能通过签订保密协议等方式来规避。
  • 综上所述,从各个方面分析得出,云软件模式对客户和软件服务商双方都是利大于弊。

三.常规软件建设原理

一般性软件建设的流程是(复制上面的):

1.客户提出需求 -> 2.产品经理对接+绘制产品原型 -> 3.产品原型交给项目经理 -> 4.项目经理开会讨论需求+分配开发任务+制定开发计划 -> 5.开发完交付给测试人员 -> 6.测试完交付给客户 -> ...

如果是类似的软件,把之前开发的软件复制一份,在此基础上来动手术,改造成符合客户需求的软件,但是还是存在问题:如果新的软件较老的软件,流程上有大的变动,那么新软件开发是个大型外科手术,可能要修改核心功能和架构,要知道改造规模过大还不如重建的好,工程量就会增加了。
用通俗接地气的文字,简单介绍传统软件建设过程:

1.终端

最终呈现给客户的是一个个操作界面(浏览器页面,APP页面等),每个页面里有各种数据字段,字段包含列表字段,详情字段,表单录入字段(必填字段或非必填字段);页面中包含按钮,提供用户操作;页面中包含弹框,我们可以称之为子页面;页面中有对话框,用来和用户进行信息交流。总结为:最终给到客户的是页面和子页面,字段,按钮,对话框和交互。

2.页面和子页面

在软件中,通俗来说:一个页面对应一个软件模块。不过也包括,多个相关联的页面对应的是同一个模块,比如订单列表页面,订单编辑和订单详情页面对应的是同一个模块:订单模块。在项目工程中这些页面对应是具体的程序文件,程序文件控制着页面的显示。所以当客户提出需求,需要开发某个页面的时候,开发工程师要做的工作是:1.编码出相对应的程序文件;2.根据模块设计对应的数据表,比如订单模块对应订单表,但是此时数据表是空白的,没有字段,因为要经过下一步才能在表中增加字段(普及一下:数据库是一个存储数据的机器,数据库包含很多数据表,比如订单表,车辆表,每张表里有很多字段)。你可以想象成当前只是定义好了tab名称的空白Excel表格
image.png

3.字段

需求模块对应页面,那么信息数据对应的是字段。字段包含独立字段,关联字段。独立字段如姓名,身份证等,一个字段表示一个具体的数据信息;关联字段如银行名和银行编码,银行名和银行编码是一一对应关系,再例如:安徽省和合肥市,芜湖市属于关联字段,它们之间存在某种关系。另一类关联字段如:产品类型和产品规格,比如裤子和尺寸+腰围,货车和载重+吨位,它们之间本身并没有直接的关联,而是在具体的业务场景里,人们主观上把它们牵连到一起,最终形成了一种惯性思维,他们具有行业特有属性,以至于提到货车,自然会想到载重+吨位,但是载重+吨位也适用于其他的领域;开发工程师得到客户给出的字段之后,他们的工作是:1.把这些字段定义为程序文件里的属性,变量;2.在相应的数据表里增加字段。当前可以想象成定义好格式的Excel文件,只是没有数据而已…
image.png

4.按钮

页面和字段是用户获取信息的基本单元,用户与软件之间交互需要通过按钮来传达。按钮包含:打开,关闭,编辑,查看,跳转,事件操作(确认付款,审核通过,审核驳回等等)。数据信息通过页面来展示给用户,但是页面是静态的,用户需要动态的与数据信息交互,通过按钮可以实现创建数据,浏览数据,修改数据。开发工程师为每一个按钮所对应的事件编码相应的程序文件,程序文件里包含很多功能函数,一个按钮对应一个特定的功能函数,比如保存按钮对应一个功能函数,查看按钮对应一个功能函数…如果按钮事件要修改数据,那么功能函数里所要做的工作是:1.从数据库或者文件里获取源数据;2.对数据加工处理得到新数据;3.新数据写回源数据的位置;如果按钮事件是需要与外部通讯,比如把数据发送到省平台,那么功能函数里所要做的工作是:1.从数据库或者文件里获取源数据;2.按照省平台的要求,把数据组装成对方要求的格式;3.把格式化后的数据通过网络发送到省平台的主机;4.省平台回应接收成功,该事务完结。

5.弹框

弹框是页面的补充,也可以理解为一个子页面,弹框里可以包含页面+字段+按钮,在软件里,把弹框也当做页面来处理,开发工程师所做的工作和上面的内容一样。

6.跳转

以上介绍了一个完整页面所包含的内容,也介绍了开发工程师开发一个页面所做的工作。一个软件或者系统,通常由很多个页面组成,页面之间的关联来自于现实业务间的关联,业务的关联性通过跳转来呈现。开发人员视作一个页面为一个开发单元,这也是软件工程所提倡的,比如一个软件工程由多人参与,把一个页面作为一个开发任务,然后任务分配到每个人身上,这也是团队协作开发的基础模式。那么开发完单独页面之后,页面之间的关联性在程序文件中通过“传参”的方式来达到契合。举个栗子:电商平台里,从购物车页面进入到付款页面,购物车页面对应一个程序文件,付款页面对应一个程序文件,付款页面的程序文件怎么才能辨别出是某某用户选择了某些商品呢?其实就是:购物车程序文件通过“数据传参”的方式传达到付款程序文件,“数据传参”携带有具体的用户和具体的商品,这样在付款页面就可以对具体用户和具体商品来处理,比如为孟康这个用户创建付款单数据,修改商品的库存等等……

7.数据仓库

软件的数据包含:业务数据,文件数据,行为管理数据。

  • 业务数据指每个业务场景对应的数据,这些数据通过不同的数据表来隔离(数据库由多个数据表组成),比如运单相关数据组成一个数据表叫运单表,车辆相关数据组成一个数据表叫车辆表,数据表具有固定的格式,数据是按照矩阵方式来组成的,类似于上面的Excel表格,每一行代表一条数据,其中的某一列表示这条数据的属性(属性可以理解为字段),比如用户创建了一条运单数据,这条数据占据一行,运单里有装货地字段,装货地就是这条数据的一个属性。而数据可以包含很多属性字段,开发工程师根据用户的需求来设计数据表,用户提出的业务需求中需要哪些字段,开发工程师就建哪些字段(加字段可以理解为在Excel中加一列)。用户创建数据就是在数据表中插入一行数据,每一行数据对应唯一的ID,查看数据就是从数据表中通过ID查询一条数据,修改数据就是在数据表里通过ID修改整行数据或者只修改部分属性字段。
  • 文件数据指软件中非文本类数据,包含图片,合同文件,表格文件等。这些数据不存储在数据库中,它们存储在磁盘中,由用户上传而产生,这种数据很容易理解,一个文件占据一块磁盘空间,不多解释了。
  • 行为管理数据指非用户需求数据,包含用户行为数据,系统检测数据,权限划分数据等。用户行为数据是用户在软件中的操作行为日志数据,用于追踪用户的行为轨迹,日后在业务操作中产生纠纷,可以作为凭证。系统检测数据是指系统检测用户提交的数据,或者外部发送过来的数据,也包含系统自身检测所产生的数据。权限划分数据指不用人员授权操作的数据,不同的人员只能授权软件的部分页面或者操作。

8.鸟瞰

通过上面的描述,基本了解了一个软件工程的原理。软件工程起源于客户的需求,是一个工程的发起点。客户的需求传导到产品设计人员,产品设计人员绘制出产品草图,然后给到开发人员,开发人员按照业务来划分模块,然后每个页面对应着不同的程序文件,为页面中每个按钮和事件编写功能函数,不同模块对应着不同的数据表,页面中的字段对应数据表的某个属性,业务流程通过页面跳转来衔接,对应不同程序文件之间使用“传参”来达成契合。好了,软件工程就按照这样的模式有条不紊的进行下去,直到开发结束->测试结束->交付客户。

四.思考和挑战

上一章节完整描述了传统软件建设的方案,从客户需求出发,然后按部就班的开发,再到交付客户,是一个完整的闭环。环环相扣,每个环节都不能脱钩,形成一种强耦合效应。

  • 提出问题:那么试想如果客户的需求有变动怎么办?源头有变动,那么从源头到尾部所有环节跟着变动,这也是当前软件行业超过95%以上的项目所存在的问题(我也看过Windows操作系统的代码,他们的都是定制化的代码风格)。我们设想:如果客户的需求模糊,或者未来随时变动,那么我们怎么用最小的成本和最高的效率来应对呢?比如:1.某个页面调整了,页面里的字段删除一部分,新增一部分;2.按钮也改动了一部分,导致逻辑有变动;3.业务模式和流程变了,本来一笔创建完订单后直接进入售后环节,但是现在改成了需要在创建订单之后增加审核的流程。如果发生诸如此类的需求变动,那么页面跟着修改,功能函数跟着修改,数据表结构跟着改动,页面的跳转方式也跟着改动…
  • 发起挑战:如果是按照传统软件工程模式,我想复旦大学实验室就无法实现一杯咖啡的时间为客户做出一套CRM系统。那么他们是怎么做到的?这个问题我思考了很多年,因为我所工作过的所有公司,开发软件的模式都是传统软件工程模式,而且类似于复旦大学这种模式的开发资料肯定是不会外泄的,网上也搜不到,只能自己研究。于是这些年的工作经验加上自己的思考,总结出一套“局部试错法”:我把每个环节想象成动态的,而非固定的,比如页面中的字段随时会变动,那么程序文件中就不能使用“硬编码”。硬编码描述:比如页面中第一列显示客户名称,第二列显示客户手机号,那么程序文件中是按照固定格式来显示页面的,伪代码如下:
    show web page:    # 显示页面
    table first line:"客户名称"    # 第一行显示客户名称
    table second line:"客户手机号"    # 第二行显示客户手机号
    ...
    这种就属于“硬编码”,页面需要显示什么,程序文件中就按照固定的格式来编码,如果页面修改了,那么程序文件紧跟着也需要修改。“硬编码”显然无法适应未来的随机变动,所以使用另一种模式:“动态编码”。页面中的字段是动态存储的,而程序文件编码时从动态存储中获取。比如我们建一张数据表用来存储页面中需要显示的字段,然后程序文件从数据表中获取到页面需要的字段,然后编码出一个动态显示页面的程序文件,伪代码如下
    show web page:
    loop query page fields: {    # 循环从数据表中获取
      table <n> line:"fields.n.field"    # 显示从第1~N行的字段
    }
    “硬编码”模式下,客户需求变动之后,开发工程师需要修改程序文件,功能函数和数据表。而“动态编码”模式下,所有的字段都是存储在数据表中,程序文件是从数据表中查出所有字段,程序文件根据不同的字段类型来做不同的处理,一旦客户需求变了,只需要修改数据就可以,这个工作量是非常小的,并且不需要开发工程师的介入,一个系统运营人员在后台修改一下即可。前者的工作量以工作日为单位,并且需要开发人员来修改软件项目,后者的工作量是以分钟为单位,并且不需要开发人员的介入。
    前面提到“局部试错法”,但是说到现在好像跟这个也没关系,只提到“动态编码”,其实还有其他的,具体请看下一章节。

五.SaaS平台建设方案

从软件项目的稳定性和可靠性来说,传统定制化开发模式的软件肯定是最好的,因为每一个页面,字段,按钮和跳转都是一一对应着程序文件和数据表,但是社会发展迅猛,行业在不断地变革,产品的更新迭代非常频繁,所以它无法适应快速变化的客户需求,无法用最小成本来改造软件项目等等。

SaaS平台又称“多租户云平台”,只要浏览器或者下载了软件,在有网络的地方随时随地就可以访问。市面上有不少这样的产品,比如办公软件钉钉也属于SaaS平台,但是钉钉这款产品不适用多变的客户需求,他做出来的产品是什么样子,客户只能按照他的产品来使用,所以它属于单一产品模式的SaaS平台。财务软件金蝶,一直想走SaaS模式,但是他走的依然是独立部署模式,它的产品有多种形态,但其实是多个产品类似的软件项目,不能算SaaS平台。任何公司,任何软件项目想转型成“动态产品形态的SaaS平台”都不是一件简单的事,如果是重建项目还好,不用考虑老项目架构和老用户使用的问题,不过从0开始建设不是一件容易的事;如果是有了一些年限的软件项目想转型的话,难度就更大了。

难归难,但也并不是不可能,我的战略是“局部试错法”,战术包括“动态编码”,“功能清单”,“选择性跳转”。简单描述:我们按照传统软件模式来建设雏形版本,雏形版本可以根据自己公司业务需求而开发出的软件。然后结合同行业的业务模式,分析出软件里每个模块中需求会随机变动的部分,比如页面的字段会变动,页面中会有不同的按钮,业务流程和页面跳转会变动,或者只有某个公司特有的需求功能等等。根据这些随机变动的业务需求,把我们把整个软件架构设计成“功能组件化”模式,每个组件在有限范围内可随机修改(因为SaaS具有行业属性,不能把制造业的SaaS平台突然转型为电销类SaaS平台),并且整个软件是由各个组件组装而成,而非整机模式。如果我们贸然把软件项目里的每个会变动的地方都改造成“随机动态”模式,每一个改造都构成一个不确定风险点,整个软件里所有改造同时进行的话,不确定性风险会叠加形成巨大风险,最终会对整个软件造成毁灭性的打击。“局部试错法”是先局部改造,等某个局部改造得到充分考验之后,再进入下一个局部的改造。

通过模拟业务场景来阐述我的方案和思想:

1.首先架构改造,把整体架构模式改造成每个单独组件服务架构模式。比如原先的架构是:先建一个叫“安捷智运”的项目,然后在项目里创建“运单模块”,“车辆模块”,“财务模块”,各个模块使用“传参”方式来衔接;但是新的架构模式是:创建“运单”微项目,创建“车辆”微项目,创建“财务”微项目等等。把以前的各个模块换成为了“微项目”,这样有什么好处呢?在同一个项目里的各个模块之间关联性很强,要求开发人员之间的配合度和契合度很强,但是换成微项目之后,每个微项目之间是相互独立的,很方便扩展:比如货运行业里,各个货运公司在运单方面的需求差异很大,那么开发人员就集中火力投入到“运单”微项目里,而其他的微项目根本不需要动。如果是传统的模块化的架构,只要改一个模块,其他相关联的模块都需要改动,而且不方便扩展。所以新的架构下的软件,是由很多个微项目组成。

2.根据自己公司的业务需求开发SaaS平台的雏形版本。俗话说:只有自己玩过,才知道坑有多深。这时候开发出来的版本是SaaS V1.0。

3.挖掘同行业的需求。有的公司用极少数的员工创造出巨大的产值,但是有的公司人员规模庞大却产值很小。这种现象在互联网公司里太多了,货运行业应该也存在这种情况,所以尽可能多的挖掘同行业的需求有助于提升产品的广度和深度。这个环节非常重要,起到重要作用的人就是产品人员。产品人员能够秒懂客户的心思,并且能在客户提出的基础上给出具有建设性意义的思路,帮助客户改善不良需求,引导客户往更合理的方向发展,得到客户的认可之后,能把肚里所有的货传达给开发人员。传统意义上的产品人员仅仅是把客户的需求收集来,绘制出开发人员能看懂的产品图,然后交付给开发人员。但是这远远达不到参与SaaS平台建设的产品人员,产品人员不仅要能收集需求,还能发现客户公司业务模式里的问题,主动跟客户沟通交流,引导客户向更先进的业务模式去发展,使每个方案都具有创新性。建设SaaS平台的初衷并不仅仅是给客户提供服务,同时也是帮助客户往更好的方向去发展。

4.得到同行业的需求之后,产品和开发一起分析客户的需求和自己公司需求的差异。上面介绍过传统软件模式,需求方面的差异具体到软件工程里其实就是:页面差异,字段差异,按钮差异,跳转差异等。从这些差异中提炼出哪些方面是随机动态的,并且根据轻重缓急来标注优先级。

5.先从最简单的开始:字段差异。我们自己公司简称“安捷”,我们设想存在这样一个客户,这个客户的业务需求覆盖了同行业绝大部分公司的需求,这个客户叫:安杰运输有限公司(后面简称安杰),第一阶段,假如安杰公司的业务模式和安捷一样,但是页面中字段和安捷有差异,安捷存在的一些字段安杰不存在,安杰存在的一些字段安捷不存在。想象一种极端的情况:所有页面的字段都有差异。这时候我们来改造我们的SaaS平台,改造的结果是:既能满足安捷的业务需求,也能满足安杰的业务需求。我使用的战术是:动态编码。程序文件不使用硬编码模式,所有字段都是随机动态存取。安捷的字段和安杰的字段都是在后台配置的,安捷有一套字段表,安杰也有一套字段表。经过改造之后,终于实现了相同页面但是字段存在差异。

6.接着改造页面的其他部分:按钮,弹框和逻辑。安杰说页面中很多操作无法满足他们公司的需求,要在安捷的基础上增加和修改一些按钮或者弹框,比如运单页面不仅要录单功能,需要增加导入运单的按钮来实现导入功能;在车辆管理页面,不想用人工录入功能,使用“一键”AI自动识别行驶证的功能等。这时候我使用的战术是:功能清单。我们为每一个功能开发出一个对应的功能函数,然后提供功能清单让客户来选择。这就要求系统里有个功能函数库,随着接触的客户越来越多,需求越来越多,功能函数库越来越庞大,功能清单里的选项也越来越丰富。这个环节的工作量非常大,因为要为每个页面提供功能清单,但是业务需求有轻重缓急,我们根据业务需求把页面按照优先级分为各种级别,对业务影响越大的越优先来处理。这项工作是伴随着SaaS平台的整个生命周期,我们会不断地扩充我们的功能函数库。

7.接下来改造业务的流程:跳转。跳转可以说成业务跳转,也可以是页面跳转。安杰对我们反馈:他们的业务流转需要调整,原来安捷的业务流程是:1.录入司机和车辆信息 -> 2.创建订单 -> 3.订单配车 -> 4.生成运单 -> 5.财务对账 -> 6.省略部分环节… -> 7.上报到省平台;但是安杰需要改动两处业务流程:1.直接从表格导入订单,导入完之后增加审核的功能;2.有部分已完成的线下运单,可以直接导入上传到省平台。安杰提出的流程需求,是目前安捷里没有出现过的业务需求,所以需要改造页面跳转,使得软件系统满足安杰和安捷两种业务流程,但是我们的目标是:改造之后要同时满足安杰和安捷,并且为后面其他客户提出的流程改造留出可扩展性空间。这里我使用的战术是:选择性跳转。我们把所有业务环节的点设置为“跳转点”,然后把所有“跳转点”连成一条业务线,从左向右的方向,这是一条“超级业务线”,包含每家公司的“跳转点”,是所有公司“跳转点”的并集,然后给每个客户提供“选择性跳转”,根据客户自己的业务流程从“超级业务线”中选择部分“跳转点”来组成自己的业务线,但是必须遵守:选择“跳转点”只能按照“超级业务线”从左往右,不能沿着相反方向,这是不合逻辑的。

8.未完待续:总有我们想不到的问题,总有我们没有遇到过的需求场景。不断地遇到问题和丰富多变的需求造就了一款得到市场认可的产品。所以我们要放宽心态,敢于迎接各种问题和需求,在后面的研发过程中会不断创造出新的战术,未来可期…

六.感慨

一个SaaS平台的建设是一个不断累积的过程,累积大量的需求,累积各种功能函数库,累积各种解决问题的战术。需要工匠精神才能开发出一套市场认可的产品。它没有终点,客户在变,市场在变,SaaS平台也一直在变…

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 1

欢迎产品和技术同道中人进来一起讨论,也欢迎有相关需求的公司进来咨询。

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!