03|通过知识过程重新理解软件工程

你好,我是徐昊,今天我们来继续学习 AI 时代的软件工程。

通过前面的学习,我们知道:

  • 所谓知识过程,就是从知识管理的角度理解我们的工作,将我们的工作看作产生、传递、应用、消费知识的过程;

  • 不可言说的知识是复杂工作中真正发挥作用的知识;

  • 不可言说知识需要从经验中获取,很难通过语言或其他形式传播;

  • 不可言说知识的学习与传递会产生不同的认知行为模式;

  • 不同认知模式具有不同的效率。

那么,我们可以通过知识过程中,产生的不同知识,以及这些知识传递过程中产生的认知行为模式,来理解整个知识过程。通过不同认知行为模式,来理解整个知识过程的效率。

今天我们就将以软件工程为例,将它转化成知识过程,并识别其中的认知行为模式。

软件中包含的知识

软件本身是载体,并不是真正的产品,真正的产品是包含在其中的知识。

在这一点上,软件与书籍是一样的。虽然站在读者的角度看,书籍是产品,但作家真正关心的并不是书,而是其中的人物、情节、故事线。对于非虚构书籍而言,可能是观点、结构、论据等。真正有价值的并不是书,而是书中所蕴含的内容。所以作家可能不会过多地考虑书是如何被印刷出来的,但是要对如何组织其中的内容深思熟虑。对于作家而言,内容才是真正的产品,书籍只是内容的载体。

对于软件,真正的产品是软件中所包含的知识,软件自身仅仅是知识的载体。

软件中包含的最重要的知识就是业务知识,也就是我们所说的业务流程、组织架构、行业规则、领域知识等等。这些知识描述了软件是如何帮助客户解决某一类问题,或是一家企业是如何运营其业务的,或是以何种形式与用户互动等等。

作为产品的业务知识可以脱离软件存在,但是作为载体的软件却不能脱离其内在的知识存在(技术上虽然可以,但是没必要存在)。那么,除了软件之外还有其他形式的知识载体吗?

一个显而易见的答案是人。纵然大部分情况下,在效率和成本上大大不如软件,但人一旦学会并掌握软件中所蕴含的知识,就可以提供与软件类似的能力。比如,按公式计算结果、产品报价、汇聚数据生成报表这些常见的软件功能。其中真正对应的产品是:计算所需的公式、报价规则和报表内在的数据逻辑。在学会这些知识后,人也可以完成相应的工作。

另一个类似的答案是按照流程规则交互的部门,或者说按照知识协作的组织。比如,商品支付、商品出库、商品上架等常见的功能流程。其中对应的真正产品是转账流程、商品出库登记与移交流程、商品上架登记与移交流程。同样,在掌握这些知识后,组织也可以完成相应的工作。

知识的三种载体

除去业务知识之外,软件中还包含关于“软件系统该如何实现”的知识,也就是我们所说的软件架构。架构定义了系统中组件的类型以及组件间交互的方式。架构有两个目的:帮助我们理解系统现状,以及当有新需求出现时我们要如何实现它们。

对于理解系统现状而言,架构知识是显式知识。它会通过不同的视图描述系统中具体的组件以及组件间的交互。

对于应对新需求的变化,需要将需求分解到对应的组件中去,并严格依照组件间的交互方式完成业务逻辑。此时,架构的主要作用是作为系统需求功能拆分的指导,是以不可言说知识的形式在发挥作用。

当然软件中还会承载其他的知识,比如软件的运营知识等等,但是从构造软件的角度上讲,最重要的两类知识就是业务知识和架构知识。一个是关于什么是“正确的软件”的知识,另一个则是关于“如何正确地构造软件”的知识。

将软件的研发过程构造为知识过程,就需要围绕这两种知识的提取与传递构造知识过程。

将软件研发过程构造为知识过程

首先是业务知识,业务知识并不是软件的功能点。业务知识更多地体现为现实中要解决的问题,在现实中存在的限制与制约,以及现实中存在的解决方案。当业务知识通过软件这个载体呈现的时候,才会表现为软件功能点。

哪怕在业务上已经存在解决方案,映射为软件的时候,也不一定就与现实中的方案一致。比如现实中存在一个审批流程,那么通过软件呈现时,可以借由设立邮件组或微信群的方式支撑这个流程,也可以通过在 OA 系统中增加特定工作流的方式完成。

由于业务知识并不仅仅存在于软件中,人和组织中也会存在业务知识。当引入软件承担一部分业务知识时,或是修改软件所承担的业务知识范围时,也会引起对应的组织变更。比如,从邮件为主的办公环境,过渡到以微信为主的办公模式时,组织上的流程也会有所改变。

因而,在构造软件之前,我们无法 100% 确定所构造的软件是否能够满足业务的需求,是否能够在现有的知识结构下发挥作用。所以,软件研发的过程,从宏观上来看,是这些部落知识传递与学习的过程,只能是复杂的认知模式。

这也是为什么当今主流的研发流程,或多或少都包含迭代的元素。因为每一次迭代的过程,都是一次探测(根据已知情况构造软件)- 感知(收集反馈以验证当前软件是否有效)- 响应(根据反馈改进方案以及后续计划)的过程。

说句题外话,如果将软件过程放大到整个产品生命周期,那么我们可以通过精益创业(Lean Startup)的视角,将软件产品看作一个持续学习过程,即构建(Build)- 度量(Measure)- 学习(Learn)不断反复迭代的过程。这个过程仍然是复杂认知模式:构建(Build/Probe)- 度量(Measure/Sense)- 学习(Learn/Respond)。

进入交付流程之前,我们需要按照当前对于业务知识的理解,构造一个目标解决方案。这个目标解决方案可以是业务架构愿景或是选定的解决方案。然后按照目标解决方案将业务知识转化为软件需求,也就是将软件功能分配给不同的业务模块。

这是目标解决方案知识的应用,此时我们处在庞杂模式:感知(对于要解决的问题已有初步理解)- 分析(按照业务架构 / 解决方案处理问题)- 响应(得到不同软件系统的软件需求)。

一旦根据软件需求确立了研发 / 交付计划,进入交付流程之后,对于软件构造全部都会围绕质量展开。这包括功能性质量和非功能性质量两个方面。功能性质量关注软件是否能够执行其预定的功能。非功能性质量通常是用户不直接感知、但对整体用户体验至关重要的方面,比如性能、可靠性、可扩展性等等。

功能性质量由软件需求决定,而非功能性质量则是由架构知识决定的,软件架构的设计决策直接影响系统的性能、可扩展性和可靠性。架构知识也是一种目标解决方案,所不同的是,架构知识是从技术视角出发的解决方案,是针对性能、可靠性、可扩展性等问题的解决方案。

因为架构知识发挥作用的方式与目标解决方案类似,也是在任务分解过程中发挥作用,即将软件需求在架构所规定的组件范围内,进一步做任务分解。此时我们同样处在庞杂模式:感知(对于要解决的问题已有初步理解)- 分析(按照软件架构处理问题)- 响应(得到针对不同架构组件的任务)。

因而架构腐化并不单单指最终的结果,更多是在分解任务的时候,架构不能有效起到指导作用,持续产生不正确的任务划分,架构就会腐化。

在软件构造过程中,功能性和非功能性质量是相辅相成的。一个功能完备但性能低下的软件或者性能优异但功能缺陷多的软件,都不能算是高质量的产品。因此,软件团队需要平衡这两方面,确保软件不仅能够完成其核心任务,而且在性能、安全性、可用性等方面也能满足甚至超越用户的期望。

在实践中,这通常意味着在整个开发生命周期中要采用综合的质量保证措施,包括但不限于代码审查、多层次的测试策略、性能优化、安全分析等。不同的质量保证措施,实际也处在不同的认知行为模式上。

比如最常用的代码审查,这种质量保证措施建立在反馈的基础上,所以它处在复杂模式。代码审查涉及的行为是探测(由成员根据对架构的认知先完成功能)- 感知(由架构师或团队其他成员对于已完成的功能进行反馈与评价,寻找不符合架构约束的地方)-响应(指明整改和改进的方向)。

与之对应,测试策略的基础是分析情况并挑选正确测试方式,因此是一种处在庞杂模式的质量保障措施。测试策略的行为是感知(理解需要解决的需求边界)- 分析(将需求功能按不同边界,分解为不同种类的测试)- 响应(最后根据分解的结果完成测试)。

小结

通过前面的讨论,我们可以从知识传递的角度这样来理解软件工程:

从宏观过程来看,软件研发的过程是一个对于业务知识学习的过程,是复杂认知行为模式。

进入到交付过程之前,我们需要将业务知识转化为软件功能需求,这是目标解决方案的应用,是一个不可言说知识应用的过程,是庞杂认知行为模式。

架构知识也可以看作是从技术视角出发的解决方案。按照架构构造软件的过程,是一个不可言说知识应用的过程,是庞杂认知行为模式。

在软件构造过程中,功能性和非功能性质量保障措施会带来不同的认知行为模式。

理解了软件工程中的知识传递,与它们带来的不同认知行为模式,我们自然可以评价不同的研发方法带来效率的差别。我们工作中常用的方法,可能是低效的,而看起来奇怪的方法可能是高效的。

比如,Debug 实际是低效的复杂认知行为模式,探测(打断点)- 感知(通过断点周围的数据和调用栈,寻找问题成因)- 响应(定位问题)。

Debug 实际表示我们并不知道代码到底是如何运转的,正在学习当前代码库。而看起来奇怪的测试驱动开发(Test Driven Development)则是庞杂认知行为模式。

将软件开发过程理解成知识过程,更重要的作用,则是帮助我们更进一步理解 LLM 能带来哪些改变,这是我们在后面要学习的内容。

思考题

请从知识传递的角度,分析你所处的团队有哪些低效的行为?

欢迎在留言区分享你的想法,我会让编辑置顶一些优质答案供大家学习讨论。