mirror of
https://github.com/zhwei820/learn.lianglianglee.com.git
synced 2025-09-17 08:46:40 +08:00
1355 lines
39 KiB
HTML
1355 lines
39 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
|
||
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
|
||
<head>
|
||
|
||
<head>
|
||
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
|
||
|
||
<link rel="icon" href="/static/favicon.png">
|
||
|
||
<title>05 敏捷开发到底是想解决什么问题?.md.html</title>
|
||
|
||
<!-- Spectre.css framework -->
|
||
|
||
<link rel="stylesheet" href="/static/index.css">
|
||
|
||
<!-- theme css & js -->
|
||
|
||
<meta name="generator" content="Hexo 4.2.0">
|
||
|
||
</head>
|
||
|
||
|
||
|
||
<body>
|
||
|
||
|
||
|
||
<div class="book-container">
|
||
|
||
<div class="book-sidebar">
|
||
|
||
<div class="book-brand">
|
||
|
||
<a href="/">
|
||
|
||
<img src="/static/favicon.png">
|
||
|
||
<span>技术文章摘抄</span>
|
||
|
||
</a>
|
||
|
||
</div>
|
||
|
||
<div class="book-menu uncollapsible">
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li><a href="/" class="current-tab">首页</a></li>
|
||
|
||
</ul>
|
||
|
||
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li><a href="../">上一级</a></li>
|
||
|
||
</ul>
|
||
|
||
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/00 开篇词 你为什么应该学好软件工程?.md.html">00 开篇词 你为什么应该学好软件工程?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/01 到底应该怎样理解软件工程?.md.html">01 到底应该怎样理解软件工程?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/02 工程思维:把每件事都当作一个项目来推进.md.html">02 工程思维:把每件事都当作一个项目来推进.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/03 瀑布模型:像工厂流水线一样把软件开发分层化.md.html">03 瀑布模型:像工厂流水线一样把软件开发分层化.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/04 瀑布模型之外,还有哪些开发模型?.md.html">04 瀑布模型之外,还有哪些开发模型?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
<a class="current-tab" href="/专栏/软件工程之美/05 敏捷开发到底是想解决什么问题?.md.html">05 敏捷开发到底是想解决什么问题?.md.html</a>
|
||
|
||
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/06 大厂都在用哪些敏捷方法?(上).md.html">06 大厂都在用哪些敏捷方法?(上).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/07 大厂都在用哪些敏捷方法?(下).md.html">07 大厂都在用哪些敏捷方法?(下).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/08 怎样平衡软件质量与时间成本范围的关系?.md.html">08 怎样平衡软件质量与时间成本范围的关系?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/09 为什么软件工程项目普遍不重视可行性分析?.md.html">09 为什么软件工程项目普遍不重视可行性分析?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/10 如果你想技术转管理,先来试试管好一个项目.md.html">10 如果你想技术转管理,先来试试管好一个项目.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/11 项目计划:代码未动,计划先行.md.html">11 项目计划:代码未动,计划先行.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/12 流程和规范:红绿灯不是约束,而是用来提高效率.md.html">12 流程和规范:红绿灯不是约束,而是用来提高效率.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/13 白天开会,加班写代码的节奏怎么破?.md.html">13 白天开会,加班写代码的节奏怎么破?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/14 项目管理工具:一切管理问题,都应思考能否通过工具解决.md.html">14 项目管理工具:一切管理问题,都应思考能否通过工具解决.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/15 风险管理:不能盲目乐观,凡事都应该有B计划.md.html">15 风险管理:不能盲目乐观,凡事都应该有B计划.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/16 怎样才能写好项目文档?.md.html">16 怎样才能写好项目文档?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/17 需求分析到底要分析什么?怎么分析?.md.html">17 需求分析到底要分析什么?怎么分析?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/18 原型设计:如何用最小的代价完成产品特性?.md.html">18 原型设计:如何用最小的代价完成产品特性?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/19 作为程序员,你应该有产品意识.md.html">19 作为程序员,你应该有产品意识.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/20 如何应对让人头疼的需求变更问题?.md.html">20 如何应对让人头疼的需求变更问题?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/21 架构设计:普通程序员也能实现复杂系统?.md.html">21 架构设计:普通程序员也能实现复杂系统?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/22 如何为项目做好技术选型?.md.html">22 如何为项目做好技术选型?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/23 架构师:不想当架构师的程序员不是好程序员.md.html">23 架构师:不想当架构师的程序员不是好程序员.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/24 技术债务:是继续修修补补凑合着用,还是推翻重来?.md.html">24 技术债务:是继续修修补补凑合着用,还是推翻重来?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/25 有哪些方法可以提高开发效率?.md.html">25 有哪些方法可以提高开发效率?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/26 持续交付:如何做到随时发布新版本到生产环境?.md.html">26 持续交付:如何做到随时发布新版本到生产环境?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/27 软件工程师的核心竞争力是什么?(上).md.html">27 软件工程师的核心竞争力是什么?(上).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/28 软件工程师的核心竞争力是什么?(下).md.html">28 软件工程师的核心竞争力是什么?(下).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/29 自动化测试:如何把Bug杀死在摇篮里?.md.html">29 自动化测试:如何把Bug杀死在摇篮里?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/30 用好源代码管理工具,让你的协作更高效.md.html">30 用好源代码管理工具,让你的协作更高效.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/31 软件测试要为产品质量负责吗?.md.html">31 软件测试要为产品质量负责吗?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/32 软件测试:什么样的公司需要专职测试?.md.html">32 软件测试:什么样的公司需要专职测试?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/33 测试工具:为什么不应该通过QQ微信邮件报Bug?.md.html">33 测试工具:为什么不应该通过QQ微信邮件报Bug?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/34 账号密码泄露成灾,应该怎样预防?.md.html">34 账号密码泄露成灾,应该怎样预防?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/35 版本发布:软件上线只是新的开始.md.html">35 版本发布:软件上线只是新的开始.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/36 DevOps工程师到底要做什么事情?.md.html">36 DevOps工程师到底要做什么事情?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/37 遇到线上故障,你和高手的差距在哪里?.md.html">37 遇到线上故障,你和高手的差距在哪里?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/38 日志管理:如何借助工具快速发现和定位产品问题 ?.md.html">38 日志管理:如何借助工具快速发现和定位产品问题 ?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/39 项目总结:做好项目复盘,把经验变成能力.md.html">39 项目总结:做好项目复盘,把经验变成能力.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/40 最佳实践:小团队如何应用软件工程?.md.html">40 最佳实践:小团队如何应用软件工程?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/41 为什么程序员的业余项目大多都死了?.md.html">41 为什么程序员的业余项目大多都死了?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/42 反面案例:盘点那些失败的软件项目.md.html">42 反面案例:盘点那些失败的软件项目.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/43 以VS Code为例,看大型开源项目是如何应用软件工程的?.md.html">43 以VS Code为例,看大型开源项目是如何应用软件工程的?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/44 微软、谷歌、阿里巴巴等大厂是怎样应用软件工程的?.md.html">44 微软、谷歌、阿里巴巴等大厂是怎样应用软件工程的?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/45 从软件工程的角度看微服务、云计算、人工智能这些新技术.md.html">45 从软件工程的角度看微服务、云计算、人工智能这些新技术.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/一问一答第1期 30个软件开发常见问题解决策略.md.html">一问一答第1期 30个软件开发常见问题解决策略.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/一问一答第2期 30个软件开发常见问题解决策略.md.html">一问一答第2期 30个软件开发常见问题解决策略.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/一问一答第3期 18个软件开发常见问题解决策略.md.html">一问一答第3期 18个软件开发常见问题解决策略.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/一问一答第4期 14个软件开发常见问题解决策略.md.html">一问一答第4期 14个软件开发常见问题解决策略.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/一问一答第5期 22个软件开发常见问题解决策略.md.html">一问一答第5期 22个软件开发常见问题解决策略.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/学习攻略 怎样学好软件工程?.md.html">学习攻略 怎样学好软件工程?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/特别放送 从软件工程的角度解读任正非的新年公开信.md.html">特别放送 从软件工程的角度解读任正非的新年公开信.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/软件工程之美/结束语 万事皆项目,软件工程无处不在.md.html">结束语 万事皆项目,软件工程无处不在.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
|
||
|
||
<div class="sidebar-toggle-inner"></div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<script>
|
||
|
||
function add_inner() {
|
||
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
|
||
inner.classList.add('show')
|
||
|
||
}
|
||
|
||
|
||
|
||
function remove_inner() {
|
||
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
|
||
inner.classList.remove('show')
|
||
|
||
}
|
||
|
||
|
||
|
||
function sidebar_toggle() {
|
||
|
||
let sidebar_toggle = document.querySelector('.sidebar-toggle')
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let content = document.querySelector('.off-canvas-content')
|
||
|
||
if (sidebar_toggle.classList.contains('extend')) { // show
|
||
|
||
sidebar_toggle.classList.remove('extend')
|
||
|
||
sidebar.classList.remove('hide')
|
||
|
||
content.classList.remove('extend')
|
||
|
||
} else { // hide
|
||
|
||
sidebar_toggle.classList.add('extend')
|
||
|
||
sidebar.classList.add('hide')
|
||
|
||
content.classList.add('extend')
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
function open_sidebar() {
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
|
||
sidebar.classList.add('show')
|
||
|
||
overlay.classList.add('show')
|
||
|
||
}
|
||
|
||
function hide_canvas() {
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
|
||
sidebar.classList.remove('show')
|
||
|
||
overlay.classList.remove('show')
|
||
|
||
}
|
||
|
||
|
||
|
||
</script>
|
||
|
||
|
||
|
||
<div class="off-canvas-content">
|
||
|
||
<div class="columns">
|
||
|
||
<div class="column col-12 col-lg-12">
|
||
|
||
<div class="book-navbar">
|
||
|
||
<!-- For Responsive Layout -->
|
||
|
||
<header class="navbar">
|
||
|
||
<section class="navbar-section">
|
||
|
||
<a onclick="open_sidebar()">
|
||
|
||
<i class="icon icon-menu"></i>
|
||
|
||
</a>
|
||
|
||
</section>
|
||
|
||
</header>
|
||
|
||
</div>
|
||
|
||
<div class="book-content" style="max-width: 960px; margin: 0 auto;
|
||
|
||
overflow-x: auto;
|
||
|
||
overflow-y: hidden;">
|
||
|
||
<div class="book-post">
|
||
|
||
<p id="tip" align="center"></p>
|
||
|
||
<div><h1>05 敏捷开发到底是想解决什么问题?</h1>
|
||
|
||
<p>你好,我是宝玉,我今天想跟你聊聊“敏捷开发”。</p>
|
||
|
||
<p>关于敏捷开发的实际应用,现在无外乎有以下几种常见的情形:</p>
|
||
|
||
<ul>
|
||
|
||
<li>
|
||
|
||
<p>很多团队想敏捷开发,但不知道该怎么上手;</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>有的团队已经应用了一些敏捷开发的实践,然而效果不理想,不知道是敏捷开发的问题,还是自己实践方式不得当;</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>有的团队听说了敏捷开发,但是并不知道它是什么。</p>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
<p>为什么会这样呢?今天我们就围绕敏捷开发来谈一谈,看看敏捷开发是什么,能帮助我们解决哪些问题,要不要实施敏捷开发,以及怎么能应用好敏捷开发。</p>
|
||
|
||
<h2>什么是敏捷开发?</h2>
|
||
|
||
<p>那什么是敏捷开发呢?有人认为:</p>
|
||
|
||
<ul>
|
||
|
||
<li>
|
||
|
||
<p>敏捷开发就是 Scrum、极限编程;</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>敏捷开发就是每天站立会议、每两周一个 Sprint(字面意思是冲刺,可以理解为迭代);</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>敏捷开发就是把需求变成故事,把故事写在便签上贴到白板,然后根据状态移动到不同的列;</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>敏捷开发就是用看板软件来管理项目。</p>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
<p>然而,这些是敏捷开发的真正含义吗?</p>
|
||
|
||
<p>要理解敏捷开发,我们先要了解其诞生背景。在 2001 年那会,瀑布模型还是主流,我们知道,瀑布模型是一种“重型”的开发模式,整个流程走完通常周期很长,少则数月,多则数年。长周期导致风险增加、难以响应变化。</p>
|
||
|
||
<p>于是由瀑布模型衍生出很多模型,试图去改善瀑布模型存在的问题,我已经在上一篇文章中给你介绍了一些。不过除了介绍的那些以外,在当时还有一些不怎么有名,而现在却如雷贯耳的轻量级开发方法,例如极限编程(Extreme Programming,XP)、Scrum 等。</p>
|
||
|
||
<p>2001 年初,17 位代表上述各种轻量级软件开发过程流派的领军人物聚集在一起,讨论替代瀑布模型这种重量级软件开发过程的新方法。</p>
|
||
|
||
<p>但是没能达成一致,所以退而求其次,把大家都认同的理念整理出来,也就是后来的敏捷宣言。这些人还一起成立了敏捷联盟。</p>
|
||
|
||
<p><img src="assets/d5f757c6b60a51dfe3dab3bde8a736ea.png" alt="img" /></p>
|
||
|
||
<p>图片来源:敏捷开发宣言</p>
|
||
|
||
<p>我们再回头来看前面大家对敏捷的定义,其实都是在从方法论、工具等方面解释敏捷开发。而敏捷宣言指出:</p>
|
||
|
||
<blockquote>
|
||
|
||
<p>敏捷不是一种方法论,也不是一种软件开发的具体方法,更不是一个框架或过程,而是一套价值观和原则。</p>
|
||
|
||
</blockquote>
|
||
|
||
<p>现实中关于敏捷的讨论,更多的是在讨论各种方法论和工具。不可否认,这些方法论和工具,能帮助团队“敏捷”起来,但它们和敏捷开发之间的关系,更像是“术”和“道”的关系。</p>
|
||
|
||
<blockquote>
|
||
|
||
<p>各种敏捷框架、方法论和工具,就像是“术”,告诉你敏捷开发的方式,而敏捷则是“道”,是一套价值观和原则,指导你在软件项目开发中做决策。</p>
|
||
|
||
</blockquote>
|
||
|
||
<p>这么说还是比较抽象,我给你举个例子。</p>
|
||
|
||
<p>敏捷开发中流行的站立会议,主要目的是为了保证团队成员充分的沟通,遇到困难可以及时寻求帮助。但是如果每天的站立会议流于形式,并不能起到有效的目的,则应该减少频度,甚至取消换成其他方式。</p>
|
||
|
||
<p>要不要在你的项目开发中使用站立会议,判断的依据就在于这样做是不是符合敏捷的价值观和原则。</p>
|
||
|
||
<p><strong>也就是说,当你开发做决策的时候,遵守了敏捷开发的价值观和原则,不管你是不是用 Scrum 或者极限编程,那么都可以算是敏捷开发。</strong></p>
|
||
|
||
<h2>敏捷开发想解决什么问题?</h2>
|
||
|
||
<p>如果你仔细读了敏捷宣言,你会发现,宣言中右边的内容其实都是瀑布模型核心的内容:流程和工具、详尽的文档、合同谈判、遵循计划。</p>
|
||
|
||
<p>虽然敏捷开发并未对瀑布模型的价值进行否定,但也表明了瀑布模型做的还不够好,同时提出了一套自己的价值观。</p>
|
||
|
||
<p>比如说,我们开始做一个新项目,需要从客户那里收集整理需求,如果按照传统的软件开发模式,我们需要在开发前获得所有需求,然后和客户签订合同,在发布前都不会轻易修改需求。</p>
|
||
|
||
<p>但是如果我们采用敏捷开发模式来开发项目,那这样做显然违背敏捷的价值观:“客户合作高于合同谈判”。</p>
|
||
|
||
<p>所以如果是敏捷开发,在每个迭代后,都应该向客户收集反馈,然后在后面的迭代中,酌情加入客户反馈修改的内容。</p>
|
||
|
||
<p>结合敏捷开发提出的背景,你其实不难发现,敏捷开发就是想解决瀑布模型这样的重型软件开发方法存在的问题,用一种轻量的、敏捷的方法来改善甚至是替代它。</p>
|
||
|
||
<p>这些年敏捷开发也是一直这么做的。<strong>瀑布模型的典型问题就是周期长、发布烦、变更难,敏捷开发就是快速迭代、持续集成、拥抱变化。</strong></p>
|
||
|
||
<h2>如果用敏捷的方式盖房子</h2>
|
||
|
||
<p>在讲瀑布模型的时候,我拿盖房子举了个例子,如果改成用敏捷开发的模式盖房子,则会是这样子的:</p>
|
||
|
||
<ul>
|
||
|
||
<li>
|
||
|
||
<p>客户想要盖一栋房子(<strong>初步的想法</strong>)。</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>产品经理和客户进行了初步的沟通,把用户的需求写成了一个个用户故事(<strong>用简单的用户故事代替繁重的需求文档</strong>),例如:</p>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
<blockquote>
|
||
|
||
<p>作为一个上班族,我想要一个卧室,以便于休息;</p>
|
||
|
||
<p>作为一个家庭主妇,我想要一个厨房,以便于做饭。</p>
|
||
|
||
</blockquote>
|
||
|
||
<ul>
|
||
|
||
<li>
|
||
|
||
<p>施工人员根据用户故事和客户进一步沟通(<strong>客户合作高于合同谈判</strong>),然后对用户故事进行设计和实现;</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>每个用户故事开发时,还要给一个测试机器人编写测试脚本,让机器人可以自动测试(<strong>大量采用自动化测试</strong>),并且做好的用户故事可以随时被测试验收(<strong>随时发布,持续集成</strong>);</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>每个 Sprint 四个星期时间(<strong>时间盒子,迭代时间固定</strong>);</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>第一个 Sprint 搭了个草棚,一张床就是卧室,厕所就挖了一个坑,厨房还来不及搭建(<strong>每个 Sprint 会选择高优先级的用户故事</strong>),屋顶还在漏水(<strong>每个 Sprint 会定期发布,客户可以随时看到可用版本,即使还不完整</strong>);</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>第二个 Sprint 有了简易厨房,同时修复了屋顶漏水的毛病(<strong>每个 Sprint 不仅完成用户故事,还会修复 Bug</strong>);</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>第三个 Sprint 升级成了小木屋,但是忘记加上窗户(<strong>敏捷推崇自动化测试,但可能会测试不完备</strong>);</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>第四个 Sprint 升级成了砖瓦房,窗户也开好了,客户可以入住。但是这时候客户发现一家三口的话,完全不够用,需要扩建到 3 个卧室。于是决定下个迭代改成 3 个卧室(<strong>咱们还是讨论情感 房子 票子 比较好</strong> );</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>第五个 Sprint,升级成了 3 个卧室,升级过程中把厨房下水道弄坏了(<strong>迭代过程中可能会导致质量不稳定</strong>);</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>第六个 Sprint,修复了下水道的问题,房子也装修好了(<strong>迭代中不断完善</strong>);</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>客户验收使用(<strong>上线</strong>)。</p>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
<p>用敏捷开发的方式,不再像瀑布模型那样有严格的阶段划分,会在迭代中不断完善;不再写很多文档,而是和客户一起紧密合作;不再抵制需求变更,而是即时响应变更;不再等到测试阶段才发布,而是随时发布,客户随时可以看到东西。</p>
|
||
|
||
<p>当然,采用敏捷开发的模式也存在一些问题,例如全程需要客户参与,由于测试相对少一些 ,问题也会相应多一些。</p>
|
||
|
||
<h2>敏捷开发和瀑布模型的差异</h2>
|
||
|
||
<p>由于我大学时学软件工程,那时学的就是瀑布模型,毕业后很多年的项目开发都是以瀑布模型为主的,所以我在刚开始去看敏捷开发,总会以瀑布模型的方式类比敏捷开发,实践的时候也难以摆脱瀑布模型的影响。</p>
|
||
|
||
<p>直到近些年,我完整的在日常项目中反复实践敏捷开发,才逐步领会到瀑布模型和敏捷开发的一些差别。</p>
|
||
|
||
<p>这些年敏捷开发,已经逐步发展出一套 “Scrum + 极限编程 + 看板” 的最佳实践,Scrum 主要用来管理项目过程,极限编程重点在工程实践,而看板将工作流可视化。</p>
|
||
|
||
<p>我将基于 Scrum 和极限编程的实践,来对比一下敏捷开发模型和瀑布模型的差异。</p>
|
||
|
||
<ol>
|
||
|
||
<li><strong>敏捷开发是怎么做需求分析的?</strong></li>
|
||
|
||
</ol>
|
||
|
||
<p>瀑布模型的一个重要阶段就是需求分析,要有严谨的需求分析,产生详尽的需求分析文档。而敏捷开发的需求,主要是来源于一个个小的用户故事,用户故事通常是写在卡片上的一句话,在 Sprint 的开发中,再去确认需求的细节。</p>
|
||
|
||
<p>比如一个用户登录网站的需求,在用户故事里面就是一句话:</p>
|
||
|
||
<blockquote>
|
||
|
||
<p>作为用户,我想登录网站,这样可以方便浏览。</p>
|
||
|
||
</blockquote>
|
||
|
||
<p>好处是减少了大量需求文档的撰写,可以早些进入开发。但这个对开发人员在需求理解和沟通的能力上要求更高了。</p>
|
||
|
||
<ol start="2">
|
||
|
||
<li><strong>敏捷开发是怎么做架构设计的?</strong></li>
|
||
|
||
</ol>
|
||
|
||
<p>瀑布模型在需求分析完了以后,就需要根据需求做架构设计。而在敏捷开发中,并不是基于完整的用户需求开发,每个 Sprint 只做一部分需求,所以是一种渐进式的架构设计,当前 Sprint 只做适合当前需求的架构设计。</p>
|
||
|
||
<p>这种渐进式的架构设计,迭代次数一多,就会出现架构满足不了需求的现象,产生不少冗余代码,通常我们叫它技术债务,需要定期对系统架构进行重构。</p>
|
||
|
||
<ol start="3">
|
||
|
||
<li><strong>敏捷开发怎么保证项目质量?</strong></li>
|
||
|
||
</ol>
|
||
|
||
<p>瀑布模型在编码完成后,会有专门的阶段进行测试,以保证质量。在敏捷开发的 Sprint 中,并没有专门的测试阶段,这就依赖于开发功能的同时,要编写单元测试和集成测试代码,用自动化的方式辅助完成测试。</p>
|
||
|
||
<p>相对来说,这种以自动化测试为主的方式,质量确实是要有些影响的。</p>
|
||
|
||
<p>微软的 Windows 就是个很好的例子,在 Windows 10 之前,Windows 的开发模式是传统的类瀑布模型,有很长一段测试的时间,质量有很好的保障,Windows 10 开始,采用的是敏捷开发的模式,每月发布更新,稳定性要稍微差一些。</p>
|
||
|
||
<ol start="4">
|
||
|
||
<li><strong>敏捷开发是怎么发布部署的?</strong></li>
|
||
|
||
</ol>
|
||
|
||
<p>瀑布模型通常在编码结束后,开始部署测试环境,然后在测试阶段定期部署测试环境。测试验收通过后,发布部署到生产环境。</p>
|
||
|
||
<p>在敏捷开发中,这种持续构建、持续发布的概念叫持续集成,因为整个过程都是全自动化的,每次完成一个任务,提交代码后都可以触发一次构建部署操作,脚本会拿最新的代码做一次全新的构建,然后运行所有的单元测试和集成测试代码,测试通过后部署到测试环境。</p>
|
||
|
||
<p>持续集成是一个非常好的实践,极大的缩短和简化了部署的流程,而且自动化测试的加入也很好的保证了部署产品的质量。前期搭建整个持续集成环境需要一定技术要求。</p>
|
||
|
||
<ol start="5">
|
||
|
||
<li><strong>敏捷开发的 Sprint 和迭代模型的迭代有什么区别?</strong></li>
|
||
|
||
</ol>
|
||
|
||
<p>在上一章我介绍了增量模型和迭代模型,这两种也是一种快速迭代的方式,那么敏捷开发和迭代模型的区别是什么呢?</p>
|
||
|
||
<p>我们假设有两个团队,都要实现一个简单的用户系统,一个团队用迭代模型,一个团队用敏捷开发(Scrum),一个迭代 /Sprint 的时间周期都是 2 周(10 个工作日)。</p>
|
||
|
||
<p>迭代模型所在的团队,产品经理会先花 2 天时间去分析需求,写成需求分析文档,架构师会花 3 天时间来做设计,程序员会花 3 天时间编码,测试再花 2 天时间去测试,最后上线用户系统。</p>
|
||
|
||
<p>再看敏捷开发的团队,Product Owner(类似于产品经理)会把需求拆分成了几个简单的用户故事:用户登录、用户注册、找回密码、修改资料,然后放到当前 Sprint 的 Backlog(任务清单),Team(开发团队)成员开始从 Backlog 选择用户故事。</p>
|
||
|
||
<p>程序员 A 选了“用户登录”这个用户故事,他会去找 Product Owner 确认需求细节,之后动手实现这个用户故事。</p>
|
||
|
||
<p>功能完成后,同时程序员 A 还写了单元测试代码和集成测试代码,对登录的功能写了自动化测试。完成后,通过持续集成工具测试和部署到测试环境。部署完成后,用户登录功能就可以进行使用了。</p>
|
||
|
||
<p>这个过程,程序员 A 可能花了 4 天时间,做完“用户登录”这个用户故事之后,他又开始继续选取“找回密码”的用户故事来做,4 天时间也完成了。</p>
|
||
|
||
<p>其他程序员也和程序员 A 一样,他们也会从 Backlog 选择一些用户故事来做。</p>
|
||
|
||
<p>当团队中第 1 个用户故事部署完之后,测试人员就开始帮助测试,发现的 Bug 都提交到了 Backlog,程序员们在完成用户故事后,开始着手修复这些 Bug,正好在最后 2 天都修复完成。</p>
|
||
|
||
<p>从上面的例子,你可以看出,迭代模型本质上是一个小瀑布模型,所以在一个迭代里面,需要完整的经历从需求分析,到设计、编码、测试这几个完整的阶段。</p>
|
||
|
||
<p>所以像瀑布模型一样,刚开始测试的时候是不稳定的,到测试后期才逐步稳定下来,一般迭代前期也会相对轻松一点,而后期测试阶段可能会时间很紧张。</p>
|
||
|
||
<p>敏捷开发的 Sprint 中,没有像瀑布模型那样严格的开发阶段划分,而是一个个循环迭代的 Sprint。举例来说,一个瀑布模型的项目,可能会按照阶段分成:2 周需求分析,2 周设计,4 周编码,2 周测试,然后上线发布,一共 10 周。如果用敏捷开发的方式来进行,那么可能会是每 2 周一个 Sprint,每个 Sprint 结束后,都会发布上线,每次发布的可能只是完整功能的一部分,但是每次发布的都是一个可用的版本,通过多个 Sprint 的迭代,最终完成项目开发。</p>
|
||
|
||
<p>具体到每一个 Sprint 的开发周期中,在一个 Sprint 中会有多个小的开发任务,这些开发任务主要是新功能的开发和 Bug 的修复。由于每个 Sprint 周期很短,所以不能像瀑布模型那样有充足的时间去做需求分析、设计和测试,那么敏捷开发中怎么保证质量呢?</p>
|
||
|
||
<p>在敏捷开发中,通常用“用户故事”这样的方式来代替传统的需求分析,也就是以用户故事的形式,对一个需求进行简单的描述,配合关键的测试用例,并且和需求方的紧密沟通,让开发人员可以理清楚需求;通过“只做刚刚好的设计”来节约设计上的时间;通过“自动化测试”、“持续集成”来提升测试效率。</p>
|
||
|
||
<p>相对来说,敏捷开发中,整个 Sprint 的节奏是比较恒定,产品也是相对稳定的,即使用户故事没有完成,也不影响版本的发布。</p>
|
||
|
||
<p>因此,敏捷开发更注重软件开发中人的作用,需要团队成员以及客户之间的紧密协作。</p>
|
||
|
||
<h2>该不该选择敏捷开发?</h2>
|
||
|
||
<p>该不该选择敏捷开发,是很多团队纠结的问题。毕竟关于敏捷,有很多在中国落地失败的例子,是不是这种方法在国内水土不服?</p>
|
||
|
||
<p>其实,敏捷开发无论国内还是国外,大厂还是小厂,都已经有无数成功案例。这些年,软件工程中一些好的实践,像持续集成、测试驱动开发、结对编程、看板等都来自于敏捷开发。可以肯定,敏捷开发是一种非常好的软件开发模式。</p>
|
||
|
||
<p>但在应用上,也确实需要满足一些条件才能用好,例如:</p>
|
||
|
||
<ul>
|
||
|
||
<li>
|
||
|
||
<p>团队要小,人数超过一定规模就要分拆;</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>团队成员之间要紧密协作,客户也要自始至终深度配合;</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>领导们的支持。敏捷需要扁平化的组织结构,更少的控制,更多的发挥项目组成员的主动性;</p>
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
<p>写代码时要有一定比例的自动化测试代码,要花时间搭建好源码管理和持续集成环境。</p>
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
<p>所以在选择敏捷开发这个问题上,你先要参考上面这些条件。</p>
|
||
|
||
<p>因为敏捷开发对项目成员综合素质要求更高,做计划要相对难一些。如果团队大、客户不配合、领导不支持,再好的敏捷方法也很难有效实践起来。</p>
|
||
|
||
<p>如果你要实践敏捷开发,建议先找个小项目进行试点,能证明可行了,再进一步推广。有条件的话,可以和一些顾问公司合作,请人做专门的培训和指导。</p>
|
||
|
||
<p>如果不具备条件,应该考虑先把其中一些好的实践用起来,比如说持续集成、每日站会、自动化测试等。</p>
|
||
|
||
<h2>总结</h2>
|
||
|
||
<p>我们今天一起学习了什么是敏捷开发,也就是敏捷开发是一套价值观和原则。也对比了瀑布模型和敏捷开发,其中的差异还是很大的。</p>
|
||
|
||
<p>瀑布模型面向的是过程,而敏捷开发面向的是人。敏捷开发要解决的,恰恰是瀑布模型中存在的一些问题。</p>
|
||
|
||
<p>最后,在要不要用敏捷开发这个问题上,不用过于纠结,看好敏捷开发,那就放心去用,觉得时机还不成熟、还不够了解,就先试点或者只是先借鉴其好的实践。</p>
|
||
|
||
<p>软件开发,最核心的是人,而不是用什么方法,以前没有敏捷开发只有瀑布模型的时候,也一样诞生了大量伟大的软件,像 Windows、Office。现在有敏捷开发,更多的是让我们多了一些选择。</p>
|
||
|
||
<p>在下一篇文章,还会再从大厂如何应用敏捷开发的角度,继续讲一讲敏捷开发的应用。</p>
|
||
|
||
<p>另外,敏捷开发涉及内容还是比较多,如果想有更多了解,可以阅读一些书籍作为专栏的补充。</p>
|
||
|
||
<p>除了“学习攻略”中推荐的一些书,还有像《用户故事与敏捷方法》《敏捷武士︰看敏捷高手交付卓越软件》等这些敏捷实践的书籍也可以辅助看看。</p>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div>
|
||
|
||
<div style="float: left">
|
||
|
||
<a href="/专栏/软件工程之美/04 瀑布模型之外,还有哪些开发模型?.md.html">上一页</a>
|
||
|
||
</div>
|
||
|
||
<div style="float: right">
|
||
|
||
<a href="/专栏/软件工程之美/06 大厂都在用哪些敏捷方法?(上).md.html">下一页</a>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||
|
||
</div>
|
||
|
||
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70997c352de43cfa","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
|
||
|
||
</body>
|
||
|
||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||
|
||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
|
||
|
||
<script>
|
||
|
||
window.dataLayer = window.dataLayer || [];
|
||
|
||
|
||
|
||
function gtag() {
|
||
|
||
dataLayer.push(arguments);
|
||
|
||
}
|
||
|
||
|
||
|
||
gtag('js', new Date());
|
||
|
||
gtag('config', 'G-NPSEEVD756');
|
||
|
||
var path = window.location.pathname
|
||
|
||
var cookie = getCookie("lastPath");
|
||
|
||
console.log(path)
|
||
|
||
if (path.replace("/", "") === "") {
|
||
|
||
if (cookie.replace("/", "") !== "") {
|
||
|
||
console.log(cookie)
|
||
|
||
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
setCookie("lastPath", path)
|
||
|
||
}
|
||
|
||
|
||
|
||
function setCookie(cname, cvalue) {
|
||
|
||
var d = new Date();
|
||
|
||
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
|
||
|
||
var expires = "expires=" + d.toGMTString();
|
||
|
||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||
|
||
}
|
||
|
||
|
||
|
||
function getCookie(cname) {
|
||
|
||
var name = cname + "=";
|
||
|
||
var ca = document.cookie.split(';');
|
||
|
||
for (var i = 0; i < ca.length; i++) {
|
||
|
||
var c = ca[i].trim();
|
||
|
||
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
|
||
|
||
}
|
||
|
||
return "";
|
||
|
||
}
|
||
|
||
|
||
|
||
</script>
|
||
|
||
|
||
|
||
</html>
|
||
|