# 2020BUAA软工——“初窥构建之法”

博客园链接：[Link](https://www.cnblogs.com/CookieLau/p/12440246.html)

|         项目         |                                                                 内容                                                                |
| :----------------: | :-------------------------------------------------------------------------------------------------------------------------------: |
|     这个作业属于哪个课程     |                           [2020春季计算机学院软件工程(罗杰 任建)](https://edu.cnblogs.com/campus/buaa/BUAA_SE_2020_LJ)                           |
|     这个作业的要求在哪里     |                            [个人博客作业](https://edu.cnblogs.com/campus/buaa/BUAA_SE_2020_LJ/homework/10414)                           |
|     我在这个课程的目标是     | <p>完成一次<strong>完整</strong>的软件开发经历<br>并以<strong>博客</strong>的方式记录开发过程的心得<br>掌握<strong>团队协作</strong>的技巧<br>做出一个优秀的、持久的、具有实际意义的产品</p> |
| 这个作业在哪个具体方面帮助我实现目标 |                                          <p>通过邹欣老师的《构建之法》<br> 在开始团队项目前先了解清楚“团队”和“项目”</p>                                          |

## 学会提出问题

第一次真正意义上的软件工程个人博客作业，要求是速读邹欣老师编著的[《构建之法》](https://www.cnblogs.com/xinz/archive/2011/11/27/2265425.html)，并提出5-10个问题。这个任务非常有趣，他不是传统的读书作业似的让同学们写读后感，我想可能是读后感这种东西比较偏向个人，而且大多的读后感其实是对文章目录的总结，并没有深度到某一个文字段落中去。但是，提出问题，一是同学必须要真正深度到段落文字，二是强迫你在阅读的时候思考，没有思考就不会提出问题。在[周舜钦：学习金字塔的误解](https://www.douban.com/note/344117673/)中，作者为**阅读**这一学习行为进行了辩护，认为很多人通过**读完之后能记忆多少**来考察阅读的效果是不正确的，应该夹以考虑**阅读的深度和广度**，是否有在阅读的过程中积极思考，参与讨论。对书本中不理解的地方提出问题，即是一种思考的方式。

### 问题零：课程的打分是否合理？

参见《构建之法》—— 给任课老师和助教的建议

> 这堂课如何打分？很简单：把每次作业的表现分为N档，最优秀的几个同学得满分，第2档的同学得1/2的分数，第3档的同学得1/3的分数，依次类推下去，这就是1/N的打分体系。迟交作业0分，不交作业倒扣分。就像下图实线显示的那样。虚线是传统的“大家都能及格”的分数分布，如此分布看似皆大欢喜，其实是对优秀学生的极大不公。\
> ![1/N评价方案](https://i.niupic.com/images/2020/03/08/6Z54.png)

为什么是问题零呢？大家已经看出来，这个问题是在书中的正式内容开始之前的部分，甚至是 “给任课老师和助教的建议部分”，而不是关于软件工程的部分。但是我还是想斗胆提出自己的质疑，这样的 **1/N打分体系** 是否合理？是否有走极端的嫌疑？

首先，分档给分是有依据的，这里我也在arxiv上找到了一篇[Grading by Category(GBC)](https://arxiv.org/ftp/arxiv/papers/1304/1304.0222.pdf)关于讨论如何能够更好的给同学不仅仅是分数，而带有反馈。文中提到了三个关键点：\
1\. 分类标准是由学生的总体水平决定的，而不是事前给出的分数。如：应该是占当年学生的百分之多少，而不是达到了多少分。\
2\. 先分类再给定分数，这也透露出分档不是最后的得分。\
3\. 分类的标准是学生没做什么或者做错了什么，而不是做对了什么。\
这里的分档给分，论文中也给出了例子，对于一道物理题，分了多达8个等级：

|   等级   |             原因             |  占比 |
| :----: | :------------------------: | :-: |
| Q(4.0) |     完整的回答，有清晰的步骤和整洁的作图     | 27% |
| M(3.5) |  也是完整的回答，但可能在步骤或作图上出现一些瑕疵  |  6% |
| L(3.2) |     大致完整的回答，但作图错误或表述不清     | 10% |
| C(2.5) | 回答中对图片没有完整的定义，作图也出现错误或表述不清 |  6% |
| P(2.0) |     知道回答需要的方程，并能知道方程的定义    | 14% |
| S(1.0) |  知道回答需要的方程，但是并不能正确理解方程的含义  | 22% |
| N(0.5) |    能够写出一些有意义的回答，但是没有完成题目   | 10% |
| Z(0.0) |        物理意义和实际意义上的白卷       |  4% |

论文的作者表示，通过给出细分的等级，有以下几点好处：\
1\. 学生可以根据得到的等级快速定位到自己的问题，以至学生能够在未来的测试中根据自己等级对应的不足自己有目标努力。\
2\. 学生更加关注的是自己没有做到什么，而不是自己做到什么，从而暴露出自己的不足和缺陷，去重视自己的缺陷。\
3\. 老师在给分时可以三思，因为GBC评分方式是等到所有学生的回答都给定等级之后再进行细致的数值上的分数。这可以让老师在给定具体数值分数的时候可以不需要重新审阅所有同学的回答，而是在大体的等级区域内给出细致的分数，也不会让同学得到比应得更低的分数。\
4\. GBC评分制度提供给了老师一个量化分析的手段，因为在给定等级的过程中就已经对同学们所犯的错误或者不足进行的分类，所以出现同一问题的同学的比例就可以直接由该等级得到，从而进一步调整教学方式和教学重点。\
5\. GBC评分制度提供了一个更简便的 re-grade 方式。也就是说如果学生对于自己的成绩有异议，可以告诉老师自己的预期等级是多少，但学生在提出异议之前会先对自己进行一个等级上的评价，也就是将成绩的合理性的证明从老师的身上转移到了学生的身上，给对评分不满的学生提出了“自证”的要求。

论文作者通过实际践行这一方法得到了积极的反馈，学生们从各个角度都认同了这种等级制评分方式。

所以在这里，我想提出的问题就是，邹老师在《构建之法》中提到的 1/N 体系是否太过于仓促果断了，我们可以按照分档给分的方式去衡量每个人的作业，但是在衡量具体的作业之前就将对应的等级的分数给出，如1/2，1/3等等，是否有点对学生的工作不负责任？在这里我想表达的是，我相信每个学生都是认真完成作业并在作业的过程中带有自己的思考的，可能有些地方做的确实不是很完美，但是是否应该按照同学在哪里做的不够好或者不足去具体的细分等级，而不是只要犯错就立刻少了一半的分数，我相信这样一种“狼性文化”，会在同学们刚开始的时候起到很好的竞争的效果，但是与此同时对于学生的打击也是巨大的。

也算是斗胆对课程组提出自己小小的建议，不妨尝试一下这种 Grade by Category的评分方式，可以给同学们的作业按照不足进行分档，在等级内再进行细致的给分，我相信这会是一个不错的尝试。

### 问题一：是否真的没有银弹

参见《构建之法》—— 第一章第2节

> CD/DVD上但是这些非本质、临时的特性并不能决定软件工程的本质问题。例如，有人发明了一种新的程序设计语言，或者又出现了一个新的软件开发流程，或者网上出现了又一个程序员技术社区……这些事并不能改变软件工程的根本难度，这也是著名的“没有银弹（No Silver Bullet）”论断所阐述的道理。软件的这些本质特性让“做一个好软件”变得很难，同时也让软件工程有它独特的挑战和魅力。

首先我们看银弹是什么，根据维基百科上[没有银弹的词条](https://zh.wikipedia.org/wiki/%E6%B2%A1%E6%9C%89%E9%93%B6%E5%BC%B9)：\
《没有银弹：软件工程的本质性与附属性工作》是IBM大型机之父佛瑞德·布鲁克斯所发表一篇关于软件工程的经典论文，该论述中强调由于软件的复杂性本质，而使真正的银弹并不存在；所谓的没有银弹是指没有任何一项技术或方法可使软件工程的生产力在十年内提高十倍。\
布鲁克斯在他的论述中将软件开发的困难分为两类，一是本质性的困难，是软件本身在概念（conceptual）建构上存先天的困难；二是附属性的困难，在于将概念上的构思施行于电脑上，所遭遇到的困难。并提出了四点造成本质性困难的原因：\
1\. 复杂性（complexity）：软件要解决的问题，通常牵扯到计算步骤，这是一种人为、抽象化的智能活动，多半是复杂的。\
2\. 隐匿性（invisibility）：尚未完成的软件是看不见的，即使利用图标说明，也常无法充分呈现其结构，使得人们在沟通上面临极大的困难。\
3\. 配合性（conformity）：在大型软件环境中，各子系统的接口必须协同一致。由于时间和环境的演变，要维持这样的一致性通常十分困难。\
4\. 易变性（changeability）：软件所应用的环境常是由人群、法规、硬件设备、应用领域等，各因素所汇集而成，而这些因素皆会快速变化。

虽然布鲁克斯提出了四点困难的原因，但是为了提升软件工程的生产力，也有许多人在奋力搜寻“银弹”的存在，如从汇编语言到高级语言，大幅提升了生产力，降低了程序员的编程门槛；分是技术的出现提升了人们工作的效率，通过时间片轮转等技术实现了程序的并行，同时不降低使用体验等等。

除了没有银弹的声音外，还有一些存在银弹的反响，其中以 Brad Cox 的 [《There is a Silver Bullet》](https://www.drdobbs.com/there-is-a-silver-bullet/184407534/) 和 Divid Harel 的 [《Biting the Silver Bullet》](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.20.5628) 为主要论点。

我自己的观点是辩证地讨论这个问题，这个问题需要结合实际的现实而不是在任何时候都可以扬言——“没有银弹”。我们知道软件开发的生产力不仅被本质困难所影响，还被附属困难所左右。今天我们之所以能够站在这里万众开发，就是因为先人们已经帮助我们一定程度上解决了附属性困难。比如集成开发环境的产生使得所有人都能轻松运行和开发程序，比如面对对象编程的出现，使得所有人都能够在构建和开发时编写出更加理解易懂好维护的代码。所以说，Harel还提出的一项假象实验，将没有银弹的说法发表在再向前三十年的1952年而不是1986年，在当时的外部附属难度颇高的环境下，没有人会预料到后续的三十年内人们将附属困难逐一攻破，十年内软件工程的生产力提高十倍很可能成为现实。\
其次，我也非常同意[Jones的观点](https://www.amazon.com/Assessment-Control-Software-Risks-Capers/dp/0137414064)——“把重点放在质量上，生产力将随之而来”。对于生产力的衡量不仅仅是量还有质。Jones提出，缺乏有系统的质量控制与发生时程落后的灾难，这两者之间有强烈的相关性。这就引出了我们所需要学习和思考的**如何对团队进行系统且有效的进度控制和质量控制**。\
我之所以对银弹是否存在持有怀疑态度是因为在大环境下，有一些本可以提高的生产力没有提高，还有很多团队会出现文档与实现分离的情况，出现进度卡在某一个人负责的环节的情况，这些情况都是我们会在后续的团队编程中可能会遇到的，所以我觉得现在就应该思考，如何在团队中破除没有银弹的诅咒，提升团队的整体水平和能力。

### 问题二：如何选择合适的团队模式

参见《构建之法》第五章第2节

> 体育团队从一窝蜂抢球演变到有明确的分工、阵型、战术的团队，需要时间。类似地，软件团队的模式，最初是混沌的一窝蜂形式：一群人开始写代码，希望能写出好软件。随着团队的成熟和环境的变化，团队模式会演变成下面几种模式之一。

对于本学期的重头戏：Alpha 和 Beta 阶段的团队编程，心中既激动好奇又惴惴不安，以前从来没有进行过任何大项目开发的我们，该如何打好第一次战役？\
在团队的选择中，我们首先是舍友三人组成了一个小的团体，一是对于大家的能力和责任心都比较放心，二是团队中大部分人相熟可以迅速在团队中破冰。后来加入了一位女生和两位男生，组成了6人的团队。但是问题是大家都没有从事过软件开发，这就给我们的团队模式的选择带来了困扰。\
结合我们目前的情况来看，由于没有一个技术高手进行统领，比较实际的是在社区模式和业余剧团模式中进行选择，然而社区模式在我的理解下，是像Linux社区那样的，需要原先就具有一定的基础，结合一个成熟的审核团队进行质量控制，所以剩下的只有业余剧团模式，文中对于业余剧团模式的描述确实比较业余，在网络上也没有找到相关的描述，**想请教老师和助教，业余剧团模式的具体形式能够结合助教的经历或是老师的观察给一个更加清晰的讲述吗？**

### 问题三：每日例会的效果如何？

参见《构建之法》第六章第2节

> 每天这样写代码，我们离冲刺的终点线到底是更近了，还是更远了？如果流于形式，无论多么敏捷的每日立会也会被忽悠\[注释5]。一个改进是，定义好任务究竟是什么？任务的完成（Done）到底意味着什么？每个人的任务必须是明确定义的，狗熊们不能笼统地说“我在掰棒子”，而是要说明标号为123的棒子现在是什么状态，你做好之后交给谁了。

在我的实习生活中，只遇到过周会，还没经历过紧张刺激的日会，每天完成的任务量有时候小到难以和前一天区分开的时候，我们真正能从日会中获得什么吗？比如现在我们除了软件工程之外，还有计算机网络、计算机网络实验，几乎每位同学还有额外的两三门一般专业课，当时间真的一天18个小时不够用的时候，我们的例会可能发言就变成了“我和昨天一样在掰棒子”甚至是“今天没有动代码”。我非常担心我们团队到了后期也会出现这种问题，我相信我们的团队每一个人都不是浑水摸鱼的类型，但是时间管理方面出现严重的缺陷时，我们该如何应对？\
**这是我特别想向老师和助教请教的一个问题**

由这个问题引申出的一个问题：**敏捷开始是否是一个伪命题？**\
在我阅读第六章的内容前，这个疑问一直在我的脑海，我观念里面的敏捷开发，就是三点：一是快；二是快；三还是快。这种快速可能会带来质量上的损失，比如《构建之法》的图6-5，大量微博用户反映自己的微博丢失的情况。但是当我看到第六章最后的“酒后问答”，很多我的疑问都被老师一一解答了。\
敏捷开发确实是快，但是并不是只要参与了敏捷开发，原本工期长的项目就可以立刻得到缩短，最后提前完成。用老师的回答来说——“敏捷的方法能帮助你**更早地知道你是否能如期完成任务**，仅此而已。敏捷的方法（迭代的方式）能帮你尽快让用户看到项目的部分价值。当你尽早交付部分价值时，也许用户对你目前交付的东西**已经很满意**了，这样你就**不用再花时间来实现其他需求**。另一种可能是，用户看到了部分系统，**他们有新的需求，这样你就可以实现新的需求**，而不用再浪费时间实现过时的需求了。”\
老师的回答和[轮子哥在知乎上的回答](https://www.zhihu.com/question/31157532/answer/633444690)有着异曲同工之妙。敏捷不是一群开发者对着甲方的第一版需求猛做几天，而是在做的过程中始终和甲方进行有效的、不间断的沟通，来帮助甲方更加清晰地认清自己的需求，也帮助整个团队确定一个当前的完成进度，也就是一个迭代中的**需求分析和验收**。

### 问题四：为什么除了微软很少见到Program Manager

参见《构建之法》第九章第1节

> Program Manager：微软的职位名称。微软产品团队三足鼎立的角色分配就是PM、开发、测试。PM负责除产品开发和测试之外的所有事情。从某种意义上说，是前面两种角色的综合。微软通常有专门的产品策划（Product Planner），他们和市场部门的专职人员一起，负责产品的长期发展和市场推广。

在第九章中提到了PM，有三种含义，分别是 Product, Project和 Program Manager。作者也在书中提到，其中的Program Manager 是微软的三驾马车之一，另外两个分别是测试和开发。我又在网络上搜寻了有关Program Manager的资料，发现这个程序经理依然是微软的特色之一，不禁思考，为什么其他的公司不效仿微软，将Product Manager 升级为 Program Manager呢？

对此，我首先看了一下[微软的员工眼里两者的区别](https://www.zhihu.com/question/20165440/answer/14188711)，其中，作者说道：“最基本的一条是程序经理不承担人员和资源的管理任务。微软通常把技术路线称为Individual Contributor，而把管理路线称为Management。而程序经理在职业规划上属于前者。” 此外，该作者还总结了程序经理的任务：\
1\. 负责和提出需求的客户打交道，并且负责撰写功能规范，也就是Product Feature Spec。\
2\. 协调部门间的合作关系。

但是在看了这些资料之后，我还不是特别能够区分开两者的区别，希望老师和助教能够给我提供一个具体的样例，即**程序经理有什么是产品经理做不了的，有什么是产品经理能做而程序经理做不了的，有没有除了微软的其他公司也设立了 Program Manager 这一个职位，这家公司和微软有什么相似的地方？**

### 问题五：对于小团队而言小强地狱是否可行？

参见《构建之法》第十一章第5节

> 随着项目的深入，每个人同时既要开发新的功能，也要修复以前的缺陷。由于没有明确的优先次序，一般人都愿意把时间花在开发新功能上。但是我们的确需要平衡进度和质量。有这样的一种方法：小强地狱（Bug Hell）。如果开发人员的小强（Bug）数量超过一规定值，则此君被送入“小强地狱”，在地狱中，他唯一能做的就是修复小强，直到小强数量低于此阈值。这一阈值由团队根据实际情况来确定，要注意：开发人员同时“入狱”的人数应在全体成员的5%——30%之间，若比例太高，则要考虑阈值或小强数量的计算方式是否合理（是否只包括某一严重程度以上的Bug）。在项目过程中，阈值不宜频繁调整，最好事先宣布阈值。

从这个团队的例子中我们可以看到很多人身上的影子——如何处理**待开发的新功能**和**已存在的Bug**？相信很多人在编写C/Cpp程序的时候，都会先写完所有功能，然后再进行覆盖性的测试，去找出所有的bug。但是当我们是以一个团队的身份开发一个项目的时候，**不同点在于我们不再是单打独斗**，我们有专门的一部分人负责测试工作，如果像书中的例子一样开发人员也是一味追求新功能而将自己的bug都藏着掖着，就会导致测试人员进度了等待的状态。\
这里提到的小强地狱确实很美好，他将每个人产生的小强的个数限定在一个**提前设定好的阈值之内**，每个人的bug数目只要达到阈值就要开始专门的修复bug阶段。这种方案对于大型团队而言无可置疑是高效的，但是对于一个小型团队而言，这种小强地狱的方案是否会对整个项目的进度带来严重的影响？或者我们是否可以**让测试也承担起一部分修缮bug的责任**？

网络上对于小强地狱这种工作方式寥寥无几，所以希望有丰富的经验的老师和助教们能以自身的经历或者见闻解答一下我的这个疑惑——**“小强地狱对于小型开发团队团队而言适合吗？如果不适合，有什么其他的适合方案呢？如果适合，如何解决开发至多三人带来的团队进度被影响的问题呢？”**

### 问题六：迷思之六：技术的创新是关键？

参见《构建之法》第十六章第1节

> 铱星有用户么？当然有，那些登山运动员，在南极科学考察的人士，想只身驾船周游世界的孤胆英雄们，他们希望有一部这样的电话。但是这样的用户在全世界有多少呢？铱星电话现在变成了一项租赁业务，为这些几千、几万的用户提供短期服务。与此同时，全世界的手机用户早已突破了10亿。

作者在这里举出的例子是铱星计划(Iridium)的手机，论述的是铱星计划虽然有技术的创新但是没能成功，在这里我有一点小小的疑惑。因为对铱星计划不是非常了解所以就查了一下。

> 对于摩托罗拉的工程师巴里·伯蒂格来说，它来自于妻子在加勒比海度假时的抱怨，说她无法用手机联系到她的客户。回到家以后，巴里和摩托罗拉在亚利桑那州工作的卫星通信小组的另外两名工程师想到了一种铱星解决方案——由77颗近地卫星组成的星群，让用户从世界上任何地方都可以打电话。由于金属元素铱有 77 个电子，这项计划就被称为了铱星计划，虽然后来卫星的总数降到了 66 个。\
> ——来自[百度百科对铱星计划的介绍](https://baike.baidu.com/item/%E9%93%B1%E6%98%9F%E8%AE%A1%E5%88%92/465869?fr=aladdin)。

我分享一下我的感受：技术的创新我依然认为是关键，铱星计划的失败只不过是没有把握住最好的时机。如果铱星计划能够早那么10年，我相信又是另一幅格局。用户基数一旦形成就难以撼动，不是技术不够创新，而是很大程度上由于人的惰性造成的，人们不愿意踏出舒适区去为了一点点微小的利益而改变，倘若摩托罗拉的铱星计划能够比基站通信更早地俘获大量的用户并且稳定用户，我相信铱星计划还是能够成功的。而且铱星计划也没有完全失败，说不定在未来又有他的出彩之处，如果能够基站和铱星结合起来，相互补充，我相信这将是通信历史上浓墨重彩的一步。

### 问题七：最难的问题——排座次

参见《构建之法》第十七章第3节

> 一群人在一起做事，事成之后，就有排座次、论功劳的问题——在有些团队里，事成之前就为功劳的事吵翻了。软件团队如何做人员的绩效管理？这个问题较难回答，因为所有人的工作被集成在一个软件产品中，互相依赖，产品功能受到用户赞扬或批评，都不能简单地完全对应于某一个人的工作。

在《构建之法》的最后一章的内容中，还是提到了无法回避的问题，如何给团队里面的人排座次。作者通过多个角度论证了座次的排列不能但从一个角度，而是多个角度一起考虑的结果。最后给的二维评价考核表特别有趣，我觉得是一种非常新颖而且值得尝试的方式。但是这些方式都是一些比较偏理论的，那如果在比如我们这种软件工程的课程里面，和同年级的同学组成的小组里面进行贡献度分配的时候，有什么具体的实用的方式吗？我也参考了[知乎上的回答](https://zhuanlan.zhihu.com/p/46520033)，但是上面所罗列的 KPI （Key Performance Indicator） 关键业绩指标法、BSC（Balanced Score Card） 平衡记分卡、OKR （Objectives and Key Results）目标与关键成果法 和 360度考核法 虽然特别完善和强大，但是对于小型团队而言似乎又太过于专业化了，而且会带来额外的巨大的工作量，所以想请教一下助教们，当初你们在完成软件工程这门课的最后是如何进行小组内的考核评比的呢？

## “软件” 和 “软件工程” 这些词汇是如何出现的 - 何时、何地、何人？

**软件**：从[维基百科中](https://en.wikipedia.org/wiki/John_Tukey)可以看到“软件”一词最早在 Turkey 于 1958 年所发表的 "The Teaching of Concrete Mathematics" 一文中被使用。

**软件工程**：在对[Margaret Hamilton的专访](https://linux.cn/article-4778-weibo.html)中，我们得知，是她在编写阿波罗登月计划的项目期间创造的软件工程一词。Margaret Hamilton 致力于为软件以及那些发明者争取应有的正统性与尊重，所以开始使用“软件工程”这样的字眼来将之与硬件还有其他工程学类做出区别。

## 关于软件工程的小故事

### 世界上第一个计算机病毒

世界上第一个病毒是由巴基斯坦兄弟俩巴斯特（Basit）和阿姆捷特（Amjad）在1987年写下的，但他们写出这个病毒并不是为了去损害别人的利益，恰恰相反，**是为了维护自己的利益**。\
两兄弟开了一家电脑公司，主要经营电脑和软件业务。刚开始的时候公司经营非常好，生意兴隆，但是慢慢的，市面上浮现出了盗拷的行为，导致他们辛苦写的程序被别人广泛传播，于是兄弟两人从父亲往鱼塘里面丢树枝防止别人撒网偷鱼的做法中得到了灵感，编写了第一个病毒软件。一旦他们的发行程序被盗拷，这个病毒就会在计算机中发作，将盗拷者计算机剩余的内存空间全部占据，这使得不少盗拷的人因为计算机无法使用来向他们认错，请求他们帮助修复计算机。他们一不留神写下了世界上第一个病毒，人类与计算机病毒之间的较量由此展开。

### Linus & Git

> 参考资料：[Linus 在 2007 年 Google Talk 上介绍 Git](https://www.bilibili.com/video/av34867224)

Linus 相信没有学习计算机专业的人不认识的，独自开发Linux系统，开发了Git源程序管理软件，性格乖戾脾气暴躁，都是他的tag。2005年的时候，Git还没诞生，Linux内核代码托管在 BitKeeper 上，Linus 本人对 CVS 十分厌恶，但是对 BitKeeper 钟爱有加。他认为 BitKeeper 的工作流和分布式等理念是值得学习和尝试的。但是由于 BitKeeper 是一款商业软件，Linux 是一款开源的工作，为了防止情况的恶化(此处也没找到具体的是什么恶化)，于2005年的时候 Linus 发布了 Linux-2.6 ，于是开始自己开发一个 BitKeeper 的替代品。也就是说，如果不是BitKeeper 和 Linux 的一些不合，可能大家就不能看到 Git 的诞生了。对于Linus 给软件的起名也特别有趣，Linux系统是Linus一开始起的名字，在发布的时候Linus曾经想过换一个名字，但是被旁人制止，觉得使用自己的名字作为一款系统的名字比较有意义。而对于第二款Source Code Management 源代码管理工具——Git，则是英国俚语中“坏小子”的意思，Linus也曾经说过，自己是一个傲慢的混蛋，所以他的创作都用自己起名，Git也不例外。

## 源程序管理软件和项目管理软件调研

|       软件       |    使用人数    | 优点                                                                                                                    | 缺点                                                                                                             |
| :------------: | :--------: | --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|       Git      |   Unknown  | <p>1. 分布式<br> 2. 轻量 <br> 3. 可以和其他仓库(如 GitHub GitLab Gitee)结合使用 <br> 4. 可以随时随地离线使用，联网时再update</p>                      | <p>1. 上手困难 <br> 2. 出现偏差时难以纠正 <br> 3. 指令太多，部分指令的表现与理解存在偏差</p>                                                   |
|     GitHub     | 31,000,000 | <p>1. 是当前最大的开源免费代码仓库，现在private仓库也免费使用 <br> 2. 提供开发者一个交流合作的平台，通过pr和issue帮助拥有者维护开源程序 <br> 3. 还提供了发布的模块给开发者进行发布的版本管理</p> | 主要适合于代码的追踪，而不适合创意的记录                                                                                           |
|    Bitbucket   |  5,000,000 | <p>1. 一直提供无限免费私有仓库<br> 2. 对hg和git都支持 <br> 3. 支持中文 <br> 4. 第四方的git工具SourceTree比GitHub for Windows好用</p>                | <p>1. 功能相比Git少很多 <br> 2. 对于开源不够彻底</p>                                                                          |
| Mercurial (hg) |   Unknown  | <p>1. 学习门槛低，比git容易上手<br>2. 能够实现完全回到某个历史版本<br> 3. 具有SVN的影子，对SVN用户友好，零学习成本</p>                                          | <p>1. 分支管理不灵活，对于大一些的团队项目会造成权限混乱 <br> 2. 分支种类过多，匿名分支法、具名分支法、书签法、克隆版本库法等等，不方便使用 <br> 3. 没有命名空间，团队中谁提交的代码搞不清楚</p> |
|      Trac      |   Unknown  | 非常灵活，可以随心所欲控制可以和SVN集成                                                                                                 | 功能不是很强大                                                                                                        |
|    Bugzilla    |   Unknown  | 免费，有中文版支持                                                                                                             | 快速搜索结果不准确。只能管理缺陷。                                                                                              |
|  Microsoft TFS |   Unknown  | <p>1. 微软出品，和Visual Studio深度结合 <br> 2. 任务版内容详尽，有需求和任务进度等，对小团队而言更加方便有效<br> 3. 集成了项目管理、版本控制、BUG 跟踪等特性</p>                | <p>1. 上手困难，搭建和维护TFS复杂 <br> 2. 基于ASP实现，访问相比而言慢一些</p>                                                            |

## 源程序管理软件上手实践

### Git

首先肯定是最常用的 Git：\
![git add commit push](https://i.niupic.com/images/2020/03/08/6Z3r.png)\
![git checkout branch](https://i.niupic.com/images/2020/03/08/6Z3w.png) ![git reset HEAD^](https://i.niupic.com/images/2020/03/08/6Z3x.png)

Git 是 Linus 为了更好的控制自己的 Linux 源代码的管理而创新出来的管理工具，其核心思想是充分的分布式，特性之一是允许离线操作。Git 通过将工作区分为三棵树的方式来管理自己的代码进度。\
第一棵树是自己的 **工作空间**，修改代码肯定首先是在自己的工作空间发生变化；\
第二棵树是 **暂存区**，是一个临时保存的区域，需要通过 `git add file/dir` 的命令来将自己的工作空间中的修改保存到暂存区；\
第三棵树是 **HEAD**， 始终指向最后提交的结果，运行 `git commit -m "explanation words"` 来讲暂存区下的修改提交到 HEAD上；\
三棵树保证了Git是一个可以本地离线运行的源程序管理工具，开发者可以随意回到之前的任意一个 commit 的版本中去。\
最后在在线的状态下，可以通过 `git push` 将本地的HEAD提交到远端的仓库中，保存本地的修改。

这种思想对于初学者来说**简直就是灾难**。我在一年前学习面向对象和操作系统的时候才开始接触Git，一开始上手太难理解为什么要构建三棵树了，觉得为什么不直接本地保存然后同步到线上呢？但随着使用的时间的推移也发现了这种构建的好处，特别是可以回到任意一个commit是开发者的福音。还有 Git 的 branch 也是对于项目开发特别友好的设计，可以生成 Debug、Release、Develop 等等分支，在分支上进行随心所欲的操作，都不会对主分支造成任何的影响。\
今年有幸担任了面向对象课程的助教，在第一周的上机实验中，从学弟学妹们的身上看到我自己的身影。~~没有经历过 `git push` 不被允许的报警是不完整的~~ 很多人一个实验两个小时也完不成基本的 Git 操作，要么在分支上出现了问题，要么在关联的远端仓库上出了问题，要么在ssh\_key 上出了问题，等等等等。\
如果单纯能够使用 Git 的话，学习并且使用一段时间就熟练了，但要是想彻底弄懂 Git，估计需要 Linus 的智商吧。

### Mercurial(hg)

既然 Git 这么劝退，我们就尝试一下据说门槛低，较易上手的 **Mercurial**。\
关于 Git 和 hg 的对比，为什么 hg 比 Git 好上手，[这个博客](http://www.voidcn.com/article/p-ojbxfqge-bev.html)是我找到的最完整的介绍。\
![hg init](https://i.niupic.com/images/2020/03/08/6Z3y.png)

尝试了一会儿 hg，注册了 BitBucket 的账号，但发现貌似 BitBucket 现在全面支持 Git 了，半天愣是没有找到如何使用 hg 初始化仓库，于是从 [hg Guide](http://hgbook.red-bean.com/) 中 clone 了一个hg说明书的仓库使用。\
在已经对 Git 熟悉之后，对 hg 上手是特别快速的，要说有什么特别的地方，hg 也有自己的 `hg addremove xxx` 和 `git add xxx` 非常相似，两者的 `commit` 都是一样的，但是经过我的查阅之后发现，是因为我现在的仓库规模不够大所以感受不到 hg 的方便之处。\
hg 的优势经过总结有以下几点：\
1\. hg 给用户的信息较为友好、轻便。比如 `hg log` 查看日志的功能就特别简单清新，比如：

```bash
    changeset:   0:2b106112869d
    user:        q2l
    date:        Sun Mar 08 01:59:07 2020 +0800
    summary:     add one add three
```

与 Git 的 SHA-1 编码制作的 commit\_id 相比显示简单，但这里 Git 里面蕴含了 Linus 的个人的执念——“通过SHA编码可以让你未来任何时候都能回到你想要的任意一个版本”。\
2\. hg 提供了很多继承的命令，比如 `hg update`, `hg ci`, `hg serve` 等等，可以直接使用，其中我尝试了以下 `hg serve`，如果仓库是网站，可以直接部署到 localhost 上，如果不是网站则可以来显示这个仓库的有关信息，比如可视化的 branch 和 commit 等等。\
![hg serve](https://i.niupic.com/images/2020/03/08/6Z3z.png)

可能对于每个人的习惯不一样选择的工具也是不一样的，在查阅hg 和 git 的对比和优缺点的时候，既有放弃hg转向git的，也有从git到hg的，但现在总体的大趋势是更多的源代码管理仓库偏向git，比如 bitbucket、github、gitlab，而hg已经被 Atlassain 收购，主要和 Atlassain下的工具进行集成。总之选择自己喜欢的就行，也不是有很多喜欢 Git 的死对头 CVS 吗？

## 参考链接

1. [邹欣 | 现代软件工程讲义](https://www.cnblogs.com/xinz/archive/2011/11/27/2265425.html)  &#x20;
2. [周舜钦：学习金字塔的误解](https://www.douban.com/note/344117673/) &#x20;
3. [Grading by Category](https://arxiv.org/ftp/arxiv/papers/1304/1304.0222.pdf)
4. [维基百科 | 没有银弹](https://zh.wikipedia.org/wiki/%E6%B2%A1%E6%9C%89%E9%93%B6%E5%BC%B9)  &#x20;
5. [《There is a Silver Bullet》](https://www.drdobbs.com/there-is-a-silver-bullet/184407534/) &#x20;
6. [《Biting the Silver Bullet》](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.20.5628) &#x20;
7. [Assessment and Control of Software Risks](https://www.amazon.com/Assessment-Control-Software-Risks-Capers/dp/0137414064) &#x20;
8. [所谓的敏捷开发是一个坑吗？ - vczh的回答](https://www.zhihu.com/question/31157532/answer/633444690) &#x20;
9. [微软的program manager主要要求什么样的核心素质](https://www.zhihu.com/question/20165440/answer/14188711) &#x20;
10. [常用的四大绩效考核方法以及优缺点](https://zhuanlan.zhihu.com/p/46520033)&#x20;
11. [Git 有哪些缺点？](https://www.zhihu.com/question/20401926)  &#x20;
12. [一不留神 这对兄弟搞出了全球第一个电脑病毒](http://news.mydrivers.com/1/576/576550.htm)
13. [Linus 在 2007 年 Google Talk 上介绍 Git](https://www.bilibili.com/video/av34867224) &#x20;
14. [就是她，写出了让阿姆斯壮成功登陆月球的代码！](https://linux.cn/article-4778-weibo.html) &#x20;
15. [Wikipedia | Comparison of source-code-hosting facilities](https://en.wikipedia.org/wiki/Comparison_of_source-code-hosting_facilities#cite_note-github.com-62) &#x20;
16. [git - 简明指南](http://rogerdudler.github.io/git-guide/index.zh.html)  &#x20;
17. [為什麼比 GIT 更好－－理解 Mercurial 版本管理系統](http://www.voidcn.com/article/p-ojbxfqge-bev.html) &#x20;
18. [Mercurial笔记（hg命令）](https://www.bbsmax.com/A/LPdojA4O53/)    &#x20;
19. [Git Reset 三种模式 —— hard, soft, mixed](https://www.jianshu.com/p/c2ec5f06cf1a) &#x20;
