怎么发明软件,软件是怎么开发的


怎么发明软件,软件是怎么开发的

文章插图
作者|周
编辑|小智
本文是周技术管理专栏的第四篇文章 。今天我们主要讲软件开发的过程 。
写在前面
今天,我们将回到我们的主题,继续关于技术管理的第三篇文章,主要谈论软件开发过程 。
说到软件R&D过程,可能有些同学看不起这个标准化的过程,觉得先不说3721,马上开始编码才是王道,要求可以以后再明确,设计是完全没有必要的一步,否则觉得速度太慢 。他们称之为互联网软件开发的精神 。互联网软件开发的精神是什么?开源共享,模块化编程,极客精神,而不是野蛮开发 。
读《聊聊架构》的时候,写了一篇读后感,感叹终于有一本可以看很久的建筑学书,而不是所谓的1、2小时就能看完的* *牛逼的建筑学书 。我们经常遇到这样的面试官 。你让他画整体架构图的时候,他可能都没听说过 。如果改变提问方式,问他采用了什么框架 。他马上给你讲SSH、Spark、Mesos,还有很多 。但是当你让他画建筑图的时候,他会不知所措 。当然,你甚至不要指望他会思考为什么Hadoop的MapReduce并行计算模型使用Map和Reduce之间的Pull模式,而不是Push模式 。为什么会有火花等等 。我将在后续文章中讨论这些问题,但我只想在这里说,事实上,这些框架来自于在R&D进程的框架设计中逐渐发现和积累的解决方案 。
以基线产品开发过程为例
通常情况下,企业在开发软件时,会以基线和定制两种并行的方式进行项目开发工作 。无论是什么公司,都需要遵循一套成熟的产品研发流程体系,才能生产出更优质的产品 。因此,如果项目较多,定制前的基线和里程碑要合理安排,让基线产品尽可能收集用户的一般需求,实现对定制项目进度的技术支持,减少定制项目中大量代码变更和新模块的发生 。此外,产品R&D流程体系需要根据实际业务时间需求进行变更,而不是拘泥于瀑布或敏捷管理,一切都需要找到自己的方式 。只有脚知道鞋子合不合适 。
这里,我们以一个基线产品开发过程作为过程解释的基础 。需要注意的是,对于下面描述的每个阶段,都需要明确每个阶段的目标,在项目实施前明确计划并及时沟通,确保每个阶段所有成员对项目有一致的理解 。
项目启动会议
项目启动会议的目标是阐明产品开发项目的目标 。目标不是孤立存在的 。目标和计划相辅相成 。目标指导计划 。计划的有效性影响目标的实现 。所以在实施目标的时候,要把自己的行动计划考虑清楚,如何更有效地完成目标,是每个人都要有明确细节的问题 。否则,目标越不明确或过高,项目的实际结果就会受到影响 。
项目启动会议需要解释项目目标、阶段划分、组织结构、管理流程等关键问题 。并将这些内容写入PPT(最好有固定的格式和模板纸,这样团队或公司才能一起遵守规范),这就需要大家达成一致 。对于关键角色的任命,也需要事先听取相关领导和主要项目干系人的意见 。
用户需求
在软件开始开发之前,需要确定成本和获得的价值之间的比较,即投资回报率(ROI) 。一旦确定需要创建,就需要安排一系列资源来支持软件的生存 。这是对需求最原始的描述 。
为什么既要有用户需求,又要有产品需求?因为两者有区别,用户需求是用户提出的,技术一般不描述,只描述产品目标 。产品需求是根据用户需求转化而来的技术实现需求,需要根据用户提出的产品目标进行细分,对每个具体的功能点进行总结,然后将每个功能点细分为各种操作流程,对每个操作流程进行技术定义 。
用户需求和产品需求很容易不一样,因为虽然大家都在说需求,但出发点可能不一样,导致关注点和思维方式不同 。用户需求关注系统如何支持业务流程,以及其背后的需求”
实现业务目标” 。技术人员关注的是合理技术方案,背后的需求是“工作量”、“实现难度”和“系统性能” 。
产品需求
我们需要弄清楚产品经理或项目需求提出者为什么要做这个项目?这是最本质的业务需求 。需求分析确定的业务需求,都是从业务需求推导出来的,都必须为业务需求服务 。
产品需求一般包括产品需求规格说明书和产品需求矩阵 。产品需求矩阵一般按照子系统、功能集、执行单元的结构列出所有的功能需求,每列则对应每项功能的工作步骤以及每个步骤的工作量 。
产品需求写完后,需要进行评审 。在需求评审会上,产品、技术详细评审需求是否完整,产品功能的正常场景是什么?是否形成闭环?异常场景是什么?是否考虑周全?
需求评审后,开发和测试负责人,分别编写技术方案和测试用例 。技术方案评审,开发负责人拉上涉及到其他系统的负责人一起讨论,技术方案中必须要有业务流程图和时序图,业务流程图是为了梳理开发对业务的理解,是否和需求一致 。时序图是了梳理本次需求涉及的系统交互 。技术方案评审通过后,确认工作量和交付时间,反馈给产品 。
总体设计
设计阶段的目标主要是对待开发系统的构架进行分析和设计,并建立系统构架的基线,以便为之后的实施工作提供一个稳定的基础 。
设计阶段包括了系统架构的输出,一个好的系统架构设计可以帮助人类梳理业务逻辑且抓住核心需求,设计稳定可扩展的业务系统,评估业务开发周期和开发成本,有效的规避风险 。例如盖房子的时候得有建筑图纸,有了图纸,才能核算施工周期 。
总体设计是整个系统的框架型设计,意义及其重大,一般情况下不能省略(只有维护项目可以省略总体设计,因为基准项目已经设计完毕),所有的产品开发项目均需要首先进行总体设计,它是设计首要步骤,决不允许本末倒置,不能出现先编码后设计的情况,这是软件开发的第二大痛点(第一大是需求不明确、任意变更需求) 。
总体设计分为三个阶段:
  • 第一阶段:初始设计 。在对给定的数据流图进行复审和精化的基础上,将其转化为初始的模块结构图 。
  • 第二阶段:精化设计 。依据模块“高内聚低耦合”的原则,精化初始的模块结构图,并设计其中的全局数据结构和每一模块的接口 。
  • 第三阶段:设计复审阶段,对前两个阶段得到的高层软件结构进行复审,必要时还可能需要对软件结构做一些精化工作 。
概要设计
概要设计的目的是描述系统的每个模块的内部设计,对总体设计和详细设计承担承上启下的作用 。
概要设计按照结构化设计方法进行设计 。结构化设计方法的基本思路是:按照问题域,将软件逐级细化,分解为不必再分解的的模块,每个模块完成一定的功能,为一个或多个父模块服务(即接受调用),也接受一个或多个子模块的服务(即调用子模块) 。模块的概念,和编程语言中的子程序或函数是对应的 。
概要设计阶段把软件按照一定的原则分解为模块层次,赋予每个模块一定的任务,并确定模块间调用关系和接口 。
在这个阶段,设计者会大致考虑并照顾模块的内部实现,但不过多纠缠于此 。主要集中于划分模块、分配任务、定义调用关系 。模块间的接口与传参在这个阶段要制定得十分细致明确,需要编写严谨的数据字典,避免后续设计产生不解或误解 。概要设计一般不是一次就能做到位,而是反复地进行结构调整 。典型的调整是合并功能重复的模块,或者进一步分解出可以复用的模块 。在概要设计阶段,应最大限度地提取可以重用的模块,建立合理的结构体系,节省后续环节的工作量 。
概要设计文档最重要的部分是分层数据流图、结构图、数据字典以及相应的文字说明等 。以概要设计文档为依据,各个模块的详细设计就可以并行展开了 。
详细设计
详细设计阶段就是依据概要设计阶段的分解,设计每个模块内的算法、流程,为每个模块完成的功能进行具体的描述,要把功能描述转变为精确的、结构化的过程描述 。
详细设计这个阶段,各个模块可以分给不同的人去并行设计 。设计者的工作对象是一个模块,根据概要设计赋予的局部任务和对外接口,设计并表达出模块的算法、流程、状态转换等内容 。这里要注意,如果发现有结构调整(如分解出子模块等)的必要,必须返回到概要设计阶段,将调整反应到概要设计文档中,而不 能就地解决,不打招呼 。详细设计文档最重要的部分是模块的流程图、状态图、局部变量及相应的文字说明等 。一个模块对应一篇详细设计文档 。
概要设计阶段通常得到软件结构图,详细设计阶段常用的描述方式有:流程图、N-S 图、PAD 图、伪代码等 。而详细设计的目的是描述某一个模块内部的处理流程、开发方法和编码技巧 。一般来说,详细设计由项目简介、模块说明(具体说明每一个模块内部的流程、功能、逻辑、消耗以及未解决问题)、接口设计(包括内部接口和外部接口)、数据结构设计(包括物理结构和逻辑结构)、特殊处理等几个部分构成 。软件的详细设计,最终是将软件系统的各个部分的具体设计方法、逻辑、功能采用文字方式进行表述 。这样在实现过程中,编码人员原则上严格按此进行代码实现即可 。
编写代码
编写代码可以遵循以下几点原则:
  1. 先做核心模块的压测:很多程序员,习惯把东西做完,然后等着快上线的时候才做性能测试,那么如果前面设计出了问题,这个就很头大了 。当然,后期快上线的时候也要做性能测试,但前期的我认为还是很重要的 。当然,做好这一点,需要懂一些业务,你要知道业务压力在哪里,业务请求的重心在哪里,很多时候,产品经理不讲,你也要问清楚 。
  2. 确保过程可控:代码执行时一定要保持中间的输出,比如说,每处理 10 万条日志,写一条状态日志,记录处理的日志条目数和当前的执行时间 。
  3. 多打日志:很多时候,代码写的自己也不是很满意,比如某个处理效率不够优化,某个处理的方法不够简洁,或者扩展性比较差,代码写的很弱智,但可能短时间没有办法想清楚最合理的解决方案,考虑到上线初期这里并不是重心所在,所以也不会特意去优化它,但这种情况下我往往会留下注释,并说明下一步优化的可能思路是什么,或者想到的可行方案是什么 。
  4. 简单易懂的逻辑:千万不要把自己绕进去了,时间一长,谁都看不明白你的逻辑 。如果逻辑真的很难在一个函数内完成,尝试切分 。
  5. 不要沉迷于框架:框架最大的问题是什么?是过于繁冗的嵌套 。为什么我一直很烦框架?因为经常遇到需要一秒钟几千次请求的处理场景,那么调优的时候,要从数不清的框架中寻找数据处理的逻辑,寻找性能卡点,可能改动代码只有两行,但是找问题需要两天 。程序员记住,你的技术能力绝对不能被框架约束住 。
  6. 使用熟悉、成熟的技术:很多人根本没搞明白自己的障碍和问题在哪里,根本不知道相关技术产品的优势和劣势在哪里,看一堆第三方的数据测评,脑子一热,去学新技术,然后,掉进坑里出不来,如果是创业公司,可能项目就死在里面了 。使用新技术前,建议全面了解该技术的特征,适用范围,以及不适用的范围 。
代码审核
众所周知,在团队中进行代码审查(Code Review)可以提升代码质量,分享项目知识、明确责任,最终达到构建更好的软件、更好的团队 。
代码审核及其重要,一般来说每周都要做一次代码审核 。首先,代码审核有利于你跟踪项目进展情况,我们能真实地看到手下的人进展如何,并且更早发现他们是否误入歧途 。有时候,手下人会说“完成得差不多了!”,你去看代码时发现什么都没有或者只是一堆垃圾,诸如此类,总之离完成还很遥远 。在管理中,这种情况是最让人讨厌的,所以我认为代码审查是避免这种麻烦的最佳途径 。
单元测试
要认识单元测试,首先要明白什么是“单元(Unit)” 。所谓“单元”指的是代码调用的最小单位,实际上指的是一个功能块(Function)或者方法(Method) 。所以单元测试指的就是对这些代码调用单元的测试 。
单元测试是一种白盒测试,就是必须要对单元的代码细节很清楚才能做的测试 。所以,单元测试的编写和执行都是由软件工程师来做的 。相对于单元测试,还有集成测试 。集成测试基本都是黑盒测试,主要是由测试人员根据软件的功能手册来进行测试,需要有专门的测试环境配合 。集成测试又分功能测试、回归测试等 。
需要单元测试的代码实际上是开发人员自己写的逻辑,测试逻辑所依赖的环境是否正常不是单元测试的目的 。在环境访问代码中引入逻辑,只会让逻辑更难测试,导致逻辑代码无法进行单元测试 。因此,可单元测试的代码,才能够采用单元测试 。判断可测试的代码还有一个方法,就是看这个方法能否用一个 main 函数直接运行,如果可以的话就是可单元测试的代码 。可测试的代码还有另一个特征,就是该方法单元的参数,开发人员可以自由模拟,不需要依赖外部环境 。
集成测试
集成测试,也叫组装测试或联合测试 。在单元测试的基础上,将所有模块按照设计要求组装成为子系统或系统,进行集成测试 。实践表明,一些模块虽然能够单独地工作,但并不能保证连接起来也能正常的工作 。一些局部反映不出来的问题,在全局上很可能暴露出来 。
集成测试是在软件系统集成过程中所进行的测试,其主要目的是检查软件单位之间的借口是否正确 。它根据集成测试计划,一边将模块或其他模块组合成越来越大的系统,一边运行该系统,以分析所组成的系统是否正确,各个组成部分是否合拍 。集成测试的策略主要有自顶向下和自底向上两种 。也可以理解为在软件设计单元、功能模块组装、集成为系统时,对应用系统的各个部件(软件单元、功能模块接口、链接等)进行的联合测试,以决定他们能否在一起共同工作,部件可以是代码块、独立的应用、网络上的客户端或服务器端程序 。
系统测试
系统测试阶段包括系统测试方案及用例编写、功能性测试、性能测试、稳定性测试 。
为了验证需求分析确定的功能是否齐全并被正确实现,同时还要对安装、部署、适应性、安全性、界面等非功能性需求进行测试 。系统测试也有测试人员负责,应该在需求分析完成后进行设计,在集成测试完成后进行实施 。
功能性测试一般由独立测试小组采用黑盒方式来测试,主要测试系统是否符合“需求规格说明书” 。在经过以上各阶段测试确认之后,把系统完整地模拟客户环境来进行的测试 。系统测试是将已经确认的软件、计算机硬件、外设、网络等其他元素结合在一起,进行信息系统的各种组装测试和确认测试,其目的是通过与系统的需求相比较,发现所开发的系统与用户需求不符或矛盾的地方,从而提出更加完善的方案 。
性能测试验证系统的稳定性和效率,检查系统是否满足规定的性能要求 。性能测试通常选择一些典型的功能,检验这些功能在大量用户同时使用系统时系统是否稳定 。性能测试由测试人员负责,可以在系统测试完成后进行,也可以对重要模块先进行性能测试,可以贯穿整个测试周期,目的是尽早发现系统的性能瓶颈并提早解决 。
稳定性测试和性能测试都必须等到系统基本没问题、趋于稳定时再进行才有效果,否则很难顺利测下去,出现异常也不能定位究竟是系统架构的问题,还是功能上的缺陷 。
稳定性测试(亦可称可靠性测试)通过给系统加载一定的业务压力,让系统持续运行一段时间(一般为 7x24 小时),检测系统是否能够稳定运行 。
产品发布
产品发布是系统测试结束后的最后一步,通常在软件产品开发过程中不需要产品试制环节,可以直接上线,只需要系统测试员输出系统测试报告并批准产品发布(上线)就可以了 。
产品发布前需要通过产品发布说明会形式,对整个产品开发过程从立项开始回溯过程,指出整个过程中的不足点,总结经验,为下一个项目提供经验案例 。这一会议可以通过正式会议形式召开,需要召集产品经理、主要开发人员、测试人员、上级领导等参与,准备充分,尽最大可能说清楚这个产品发布之后的效果、效益,为上线后的价值评估做准备 。这一环节不可缺少,即便在互联网公司,迭代速度很快的情况下,这一环节也需要满足 。
开发过程复盘
其实开发过程体系里并没有这一过程,但是我个人认为它非常重要 。
所有的总结,只有带着问题去思考才会有收获,这就是复盘 。不论我说多少,如果没有过类似的经验,就很难有很强的共鸣 。我觉得看清一个问题最好的方式,就是你曾经处在一个问题的两个不同的角色中 。
总结项目经验教训的目的,在于总结问题、分析原因,避免以后犯同样的错误,而不是追究谁的责任 。
假设一个需求理解的缺陷,如果在需求阶段发现,修改一下可能只要一个小时,但是如果到了设计完成时发现这个缺陷,因为涉及的人员、文档增多,估计要一天时间,而如果等到代码都编写完成时才发现这个缺陷,可能需要十天八天了 。如果缺陷没被发现,而是直接到了生产系统中呢?这就不是工作量的问题了,估计损失就难以估计了 。在质量管理的理论中,缺陷每延迟一个阶段被发现,修复的代价就要乘上十倍 。
写在最后
敏捷开发、极限开发等等模型是为了解决需求不明确、时间紧迫情况下的快速迭代,而不是为了从根本上否定研发流程,该设计还是要设计,只是将生命周期进行切分,将过程横向切分为若干个周期 。软件开发是一门工程性要求很严谨的学科,让我们坚持严谨的态度、高效的工作方式,打造高可用、高质量的软件产品 。

作者介绍周明耀,2004 年毕业于浙江大学,工学硕士,国外投资银行 12 年工作经验,4 年分布式系统,物联网工作经验,10 年技术团队管理经验 。IBM 开发者论坛专家作者,Infoq 专栏作者 。已出版书籍《大话 java 性能优化》、《深入理解 JVM 和 G1 GC》,即将出版书籍《技术领导力 - 如何带领一支软件研发团队》 。已提交分布式计算领域发明专利超过 15 项 。微信号 michael_tec 。
打个广告
2017 年,有哪些值得关注的运维技术热点?智能化运维、Serverless、DevOps ......CNUTCon 全球运维技术大会将于 9 月上海举办,12 位大牛联合出品,揭秘最前沿运维技术,推荐学习!点击“阅读原文”,先睹为快!

今日荐文点击下方图片即可阅读

怎么发明软件,软件是怎么开发的

文章插图
【怎么发明软件,软件是怎么开发的】Instagram 使用 Python 的经验