经验杂谈:软件工程在实践中的应用
Shaka / 2023-07-09
在软件工程中前期花的时间越多,后期就越舒坦。
—— 五星上将 道格拉斯·麦克阿瑟 ( ・◇・)?
0. 背景
作为一名程序员,为了娱乐或者学习,在工作之外我写过不少业余项目,然而大部分中途夭折,即使少数坚持到完成,也因为无人问津而放弃。究其原因,有以下几种:
- 想法很大,时间很少
- 过于追求技术,缺少约束
- 不注重过程管理、缺少产品理念
这其实是不运用软件工程管理的典型失败案例。如何用软件工程知识解决这些现实问题?我们先来看看前人积累的经验。
1. 瀑布模型
软件工程分为六个阶段:规划、需求分析、设计、编码、测试、运行维护。瀑布模型就像流水线一样将它们从上往下依次完成。
瀑布模型是实践中最常用的方法,因为它符合我们惯用的思考方式,做完一件事,然后下一件。它最大的问题是不能及时响应需求变更,越到后期变更的代价越大,然而现实环境中,需求往往是经常变动的。另外,瀑布模型就像单线程作业,效率低,并且项目周期很长,发布慢,客户需要很久才能看到产品。
2 敏捷开发模型
敏捷开发模型被广泛应用在互联网公司中,可以用两个字形容它:“快”、“变”。它利用“快速迭代、持续集成、拥抱变化“来解决瀑布模型的典型问题。敏捷开发怎么做的呢?我们来看看一般的互联网模式:
- 团队结构:业务(需求、设计)、研发、运维。
- 研发团队:首席架构师、研发经理(技术主管)、研发组长、研发工程师。
- 敏捷看板:可以想象一个看板上贴着任务小贴纸(需求、Bug、重构等),纵坐标是人员,横坐标是时间。明确每个人、每个周期的目标,追踪每个目标的状态,整个团队的状态、规划一目了然。
- 主要流程:每日早会轮流发言,追踪进度、反馈问题、确定任务。大家根据看板查看当前的任务、已完成的任务、后续的任务。
当然,敏捷模型下如何做需求分析、架构设计、测试、发布部署,也有其特点,这里先不展开。个人认为敏捷开发关键在于团队,需要全员参与配合。如果团队规模大,在沟通协作上会存在障碍;但团队规模太小,成员身兼数职(比如个人开发,集需求、研发、测试、部署于一身),敏捷往往流于形式,失去意义。
3. 测试驱动开发模型
测试驱动开发模型(TDD),这是一种不同于传统软件开发流程的方法。敏捷开发、增量、原型模型等都是对传统瀑布模式的改进,而 TDD 与传统开发流程不同,它是先写单个目标测试代码,再写对应的功能代码,通过只编写使测试通过的功能代码,让测试通过(功能代码可用),然后再重构代码,如此重复。简单来说,就是不可运行->可运行->重构。
TDD 是现代较前沿的理论,我在学校里没有接触过这一理论。友人誉之为“圣杯”,但这也意味着捧起它需要很多努力。这里先不展开它的优点,它可能存在以下问题:
- 项目进度不容易掌控。TDD 模式不太注重需求分析、设计规划,遇到问题时很容易打乱节奏,并且容易忽略实际需求。对应到 TDD 模式中,就是说如何确定测试任务安排不容易。
- 软件质量不容易保障。TDD 模式是先尽最小的努力写可用的代码,然后测试通过后重构代码。但在不断变化中很难写出高质量的结构和代码。另外实际上也难有条件去重构代码。
- 对测试条件要求高。研发人员需要从传统的“先研发后测试”观念转变为“先测试后研发”。测试用例的质量要求高。
实际上,TDD 对团队的规划、研发、测试要求较高。
4. 增量模型
增量模型适用在业余项目、高风险项目、山寨项目。它解决的问题:周期长;要求:需求稳定。它把产品系统按功能模块化,按模块分批次交付。它的优点可以从适用范围里看出来,这里就不展开了,需要注意的是它对系统架构的水平要求较高。
4. 最小可行产品
前面都是工程管理的角度,这里从产品设计的角度来探讨。
最小可行产品(MVP),就是一开始只推出最核心的功能,满足用户最核心的需求,然后在用户的使用过程中收集反馈,进一步升级迭代。它的目的在于尽早接触客户,在不断反馈中迭代开发,极大减少试错成本。
5. 选择策略
实际上每种管理模型都有它的优缺点、适用范围。在现实复杂的环境中,我们需要根据实际情况选择。同时,我们不必拘泥于某种模型,我们可以借鉴优秀的思想方法、实践中好用的流程。比如敏捷模型中的看板、早会、协作方式,增量模型中注重的架构设计等。
回到最初的问题,作为娱乐、学习或者其他目的的个人项目,怎么做好呢?针对我的个人情况,我的方案是:
首先是借鉴增量模型中的架构设计,设计好系统的底层框架(各种底层库),大致划分好功能模块。因为一个好的架构设计可以为大型项目提供强有力的支撑,另外底层框架的搭建可以为开发者提供信心,且不用耗费太多时间。但不能照搬增量模式,将功能模块划分清楚依次完成,因为实际上功能需求是不稳定的,并且我需要尽快看到完整的产品。这时候就要考虑最小可行产品策略,花最小代价实现核心功能,完成一个最小产品,提供给别人试用,得到反馈,就修 bug 及添加新功能。这一步开始稳定之后,就可以考虑“高内聚、低耦合”重构功能模块,后续就是不断添加新功能,不断迭代了。在研发的过程中,需要制定计划(最后期限),不断调整待做事项,给自己进度的压力。