-
对软件工程M1/M2做一个总结
软工课一开始,我踌躇满志,下决心力挣高分,我按时上课,认真听讲。终于迎来了第一份作业——单词频度统计程序,拼尽全力后还是被完败了,同一个输入,别人的4s,为何我的迟迟不出结果?难道就因为别人用了C#我用了C++,肯定不是。原来人家用了hashmap我用的是红黑树。。。
好,我期待复仇的第二个程序——电梯调度算法终于到来了,不料小小的一个问题竟然会如此复杂,只得按照最简单的算法来进行——半傻瓜调度。
我不甘心,我自以为擅长C++,擅长算法,结果都被完败。
团队项目来了,我几经周折找到了主子,他就是我们的PM——孙**。分给我的任务是搜索功能,我挺高兴,因为对搜索也比较感兴趣。我暗自决定要认真完成分配给我的任务,尽量做得完美,不辜负别人对我的期望,从第一天开始我就严格按照老师的要求进行——每天两小时,并汇报工作进度。说实话,一开始,真的把团队项目的任务看得非常重要,觉得不能拖累大家。几天过去了,我还在看代码,我确实是在看代码,因为接触到新的东西,不得不上网各种学习。一周过去了,我还没开始敲我自己的代码,因为学长的那个代码出了点问题,迟迟找不到原因,所以一直不能正常运行。我也开始着急了,索性就开始自己从头来写,参考了官方文档的实例,自己捉摸了很久,终于写出一个可以出结果的版本。但是要用到项目中还是很困难的,遇到了各种无法解决的问题,比如多个对象同时操作一个文件等并行异常。无奈只得回过头来该学长的代码,才发现原来不懂的地方为什么要这么写。后来,一个给力的队友跟我说那个搜索部分是上一届一个专门的团队开发的,已经写好了,我才焕然大悟,原来这部分的代码是一个团队开发的。在改了几个地方后,终于可以用了。又修改了几个地方终于赶在alpha阶段发布前可以正常的搜索问题了。期间由于其他课的大作业,耽误了几天,但是总的时间并不在要求之下。可是最大的问题是,这一个月来,我一直在完善搜索,
而且还在不断制造更多的问题出来。
我怀着愧疚的心情进入了Beta阶段,期初我想一定要在Beta阶段多付出一些里弥补一下。但心有余而力不足。各种大作业要截止,各种考试逼近,我根本没法应付软工的作业。大多数队友也都停下手中的活了,但仍有十分给力的队友完成了不少工作。当我稍微缓和之后迅速又投入到了软工中,发现队友已经发了N多更新集,对此我很是感动。然后接下来的几天集中解决了搜索文档的功能,好景不长,考试又来了。。。
我觉得我在软工的中主要学到了有关搜索的技术、asp.net网站的架构、sql server数据库和c#这四样东西,虽然我的个人付出对团队并不大,但确是核心的功能。
-
链接到以前提问题的博客
-
请说明哪些问题现在自己已经清楚了,请阐明一下,是如何通过看书,实践,或者讨论弄清楚的。
-
哪些问题还不明白,请分析
- 字符集还没有搞懂,其实这个问题跟软件工程本身没啥关系。这个学期确实又被字符集困扰过,就是在网页—sevlet—数据库的传输过程中很容易就出现中文乱码。一般都能在网上找到解决方法,虽然暂时可行,但我未能从根本理解问题的本质,很可能下次遇到了还是不知道怎么解决。
- 没有解决,我以前在vs里面用C++开发过简单windows程序,做出来的界面很丑,对于那些漂亮的界面依旧不了解,据说C#可以写出很漂亮的界面;以前也做过java界面的开发,说实话java开发出来的界面不咋地,也就像eclipse那样,但是用java写界面应该是最方便的了吧;
- 我参与的团队主要做网站,所以对于asp.net开发网站的框架算是知道一些了吧;此外,这个学期上的安卓课上我作为PM主要负责做一个安卓app,对安卓应用的架构也算熟悉了。
- 通过浏览网上一些文章,大概了解到软件架构师是要具有丰富的项目经验;要对项目开发涉及的所有问题领域都有经验;要备领导素质,优秀的沟通能力;要精通构架设计的理论、实践和工具,并掌握多种参考构架、主要的可重用构架机制和模式;要具备系统设计员的所有技能。我们在大学期间以增强编程技能,拓广知识面为主。其中有一条“掌握多种参考构架、主要的可重用构架机制和模式”正是我在软件工程课上最为关注的,但是让我苦恼的是很少能接触到那些具有参考价值的架构,不知道常用的架构具体到底怎么用。
- 至今不明白前期的设计文档到底有多重要,实际的项目真的都有必要先浪费相当长的时间在设计文档上吗?也许是目前我所接触的项目都太简陋,以至于完全没必要花太多功夫来写文档,当项目足够复杂的时候,文档能作为实现的时候的指导,这样想的话确实没有文档不行。另外,当开发完成时,一份文档的重要性,我深有体会。一方面,当花其他人来维护的时候,有利于快速理解整个系统的设计;另一方面,发现bug的时候需要搞清楚问题的根源,此时就需要反思设计上是否存在缺陷,与一行一行看代码项目,有文档会方便很多。
-
产生了哪些新的问题,请提出
- 要快速提高从事软件工程的能力,自己从头做一个东西出来和阅读一个成功的开源项目源码,哪一种更有效?因为要初学者做一个稍微复杂一些软件出来,我们往往摸不着头脑,不知道整个程序如何组织比较合理,不知道功能的划分,不知道怎么做界面等等。我们团队的任务是完善上一届学长的学霸网站,虽然很多人在说学长的代码太烂,但我觉得整个网站的架构很合理,而且用到了很多开源的组件,比如lucene等,要是完全自己开发估计有点悬。个人感觉虽然没有为团队贡献太多,但是从学长的代码中确实学到了不少的东西。
- 燃尽图真的有用?虽然我不是PM,但从PM处得知,燃尽图并不实用的。
- 在团队中如何公平的衡量成员的工作量?要准确地衡量团队中各个成员的付出确实很困难,团队项目Beta阶段将各个成员的代码量作为最后评价个人贡献的依据之一又很不妥。有的人写的代码冗余而且质量并不高,而有的人非常注重代码的简洁,这就会造成评价的不公平。
- 频繁的短期任务是否一定比持久的长期任务效率更高?老师的要求是没人每天至少两小时,要求确实不多,但实际上,每天只用两小时几乎啥也也干不成,可能两个小时只够发现某个错误,所以我一般都是一周干两次活,每次都在7、8个小时以上。
-
同时我们还读了8篇软件工程相关的论文或博客,你回头再看看这些文章,有没有新的体会?
当时读的时候对作者所讲的东西不太理解,经历两个月的团队项目后,虽说理解有所加深了,但还有诸多地方不太明白,要真正领会估计需要长期从事软件开发才能做到。
下面我结合在参与Xueba网站开发的经历重点说一说我对第一篇文档的体会:
所谓银弹,就是在软件项目开发中,没有任何一项技术或方法可以能让软件工程的生产力在十年内提高十倍。作者详细分析软件工程中的四个无法回避的困难,这些困难也是我深有体会的。
复杂性
——任何两个软件系统都没有完全相同的部分,这就使得软件工程比计算机硬件、建筑哪些具有高度重用性的工程复杂得多。
一致性
——不同的人写出来的代码千差万别,整合需要花费大量的时间和精力。
可变性
——需求千奇百怪,时刻在变。
不可见性
——软件是虚拟的,开发人员整天面对着成千上万行代码。
软件在开发过程中,功能的增多增加了程序逻辑的复杂性,同时类之间的复杂关系也使得他们不能够被割裂开来看待,而是必须关联起来考虑。不合理的数据结构应用增加了程序的时间和空间复杂度,进而让程序跑起来很慢,负担很重。有时候多人合作设计出了复杂的逻辑,考虑到了所有的情况,使用了特殊的数据结构以及在特定情况下才成立的算法,结果发现在日后需要对程序进行扩展的时候难以进行,推翻重来又不甘心,但是进行扩展势必更加复杂甚至出错,还有可能造成回归测试无法通过,带来更大损失。软件更新得很频繁,软件发布之后,即便经过了单元测试以及内部测试修复了大部分问题,但是面对世界上不同的用户,软件开发者仍然可能每日收到大量的投诉以及修改建议,这些事情使得软件必须经常进行维护和更新 。例如手机端的qq和微信等软件,基本上过几天就要发布新版本集中修复几个或者几十个问题,而结果往往是用户对于新的界面不买账,或者是发现原有的一些功能不见了,也就是说用户体验还不如原来好,例如最近新浪微博的网页版更新了,而我却发现其中有一些以前有的功能现在居然不能用或者不好用了,这就会让软件开发者感到无所适从以及头疼不已。此外,硬件的更新以及使用平台的更改以及多样性也使得软件开发者不得不开发多平台的应用以及适应日新月异的硬件更改,例如苹果手机的硬件更新,微软系统的更新换代,都逼迫着软件开发者不断更改程序以适应新的需求。拿我的电梯项目距离,我估计下一次结对项目很有可能就是对这次电梯的设计提出新的要求,到时候又需要新的更改,势必也要进行回归测试,想想都很麻烦,等于是麻烦事永远没有终止,噩梦一次次重复地降临而你却无从避免。虽然作者认为软件工程的复杂性是从软件开发的本质上就决定了的,但是他仍然抱有希望,列举了一系列他认为潜在的银弹,这些东西的出现已对解决软件工程中的难题起了明显的作用。我谈谈对高级语言的感想。
- 方便性:虽然我们学习的语言都是c语言、java语言等等高级语言,但是我们也曾经接触过汇编语言,明白这种较底层的语言使用起来比较复杂而且容易出错,最主要的原因就是太过繁琐低级。虽然低级语言运行效率较高,但是低级语言庞大的代码量以及难以维护的程序结构,使得我们在编写和调试的时候都感到十分头疼。而使用高级语言之后,很多底层的设计不再需要程序员考虑,而是由编译器和汇编器进行处理。这样我们就可以在高级语言层面上实现概念模型,加之不太耗时的调试就能够完成工作,这无疑是增加了软件开发的可靠性、降低其复杂性,尤其是现在很多的语言编译器本身自带强大的 静态或动态检查功能,甚至是大量的自动代码的生成 ,乃至现在各种各样代码框架的出现,例如java 的spring框架,ruby的rails框架等等,这些都使得我们的软件开发变得更加便捷快速而有安全性的保证。
- 模块化:模块化设计看起来也更加明了,像现在经常写的java和c#都是模块化设计了,不可能说把所有的内容都写在一个类里,一个方法里,那样不便于测试,别人也不容易理解你的代码。抽象数据类型是在面向对象建模技术课程中接触的。当时上课一直都在讲抽象,弄得我都烦了,现在c#、java等面向对象的程序写多了就感觉到,自己写程序的过程中经常在进行抽象,把现实的对象抽象为程序中的类,封装好成员变量和操作方法,然后就可以拿来用了,这样很轻易地就把复杂的问题划分开来,每一个类有他自己需要负责的部分,各个类之间通过信息传递来交互,使得程序的复杂性被划为对象以及他们之间的关系,而UML图无疑更加帮助开发者明确程序结构和类之间的联系,将具体复杂的问题抽象出来之后,站在更高的层面审视问题,往往能够发现一些关键。
- 抽象:继承层次是有利于代码重用的,同时体现了多态性,其实有点像接口和实现类之间的关系。接口实际上就是抽象的结果,抽象出对象必要的成员和方法,规定好规格,便于他人调用,降低了程序集成时出现接口不对等的可能,从软件开发的根本上解决了一些复杂性和风险。 事实上,很多程序员使用的很多语言都是使用面向对象的思想,包括我们现在平时做项目,也都是用的面向对象的语言。而抽象数据类型和继承层次,都是面向对象的基本思想,由此也可见面向对象编程在现代软件工程中的作用,它简化了很多东西,消除了不必要的麻烦,让程序员们在抽象层面,使用统一的接口进行交流沟通。
-
请问你们在项目的 需求/设计/实现/测试/发布/维护 阶段(一共6 个阶段)中都学到了什么 “知识点”, 每个阶段只要说明一个知识点就可以。
1.需求——nabcd model
我们在开发软件的时候,总想知道用户到底想的是什么, 对各种功能的偏好是什么, 掌握这些信息,我们就可以按部就班地去满足用户的需求。在团队项目一开始就做了NABCD分析,依次是:
Need(需求)—现在市场上未被满足但又急需满足的客户需求是什么?
Approach(方法)—要满足这种需求,我能够提出什么独特的方法吗?
Benefits (收益)—该方法给顾客提供的便利是什么?
Competition (竞争) —对于竞争对手和其他可选择的方案来说,这种单位成本收益的优势在哪里?
此外,老师还补充了一个deliver(推广)。
这些都是项目初期需要调查分析的。
2.设计——规格说明说
我么团队接手学霸网站的时候并没有任何规格说明说,每个人都浏览了一遍代码,才逐渐看懂这个系统的架构。如果有规格说明那会容易得多,因此在项目快接近尾声的时候我么就着手写一份技术文档,以指导下一届继续做学霸的同学。而且规格说明里只包含一些关键的信息,时时进行更新,以保证简明、易懂、易修改。
3.实现——敏捷流程(agile)
团队工程在老师的指导下按照敏捷开发的原则进行。包括定期进行的scrum meeting、每天画燃尽图、极限编程等方法。
4.发布——alpha&beta release
众所周知,一个软件都会发布很多版本,比如α(Alpha)、β(beta)、trial、unregistered、demo等测试版本和release、registered、standard、deluxe、Enhance、reference、professional、enterprise、Ultimate等正式版。作为整个软件开发周期中的第一个主要阶段,Alpha版本主要供内部测试,其功能亦未完善,但是可以满足一般需求。Beta版也是测试版本,与alpha不同的是它用作公测,目前我们还没有发布。
5.维护——复审、软件可维护性
在个人作业结束后我们进行了复审。虽然没有在复审中发现更多的bug,但是复审也是一种相互学习的方式,而且培养了阅读代码的能力。
在团队项目中,我了解了软件可维护性。虽然学长已经做得差不多了,但我们也没有完全按学长的设计实现,因此存在不少设计上的缺陷或者是由于需求在变化而不得不进行的改变,从底层的设计包括数据库,web service到页面的修改包括去掉主体颜色的切换等都进行了脱胎换骨的改变,可以说我们整个团队从一接手就一直在不断维护。
6.测试——单元测试(Unit Test)
当编写完了自己的模块,正确与否就要靠单元测试了。从面向对象建模课到软件工程课,老师都要求我们进行单元测试,面向对象建模课甚至要求我们写出类的正确性证明,确定不变
式以及一系列输入输出的要求,以从抽象层面保证类和模块的正确性。团队中的每个成员负责相关的模块,最后在集成的时候,如歌保证整个系统的正常运行,首要的就是要保证每个人自己的模块不出任何差错。而单元测试就是一个很好的工具,我以前习惯直接在main里面对整个类进行测试,其实与单元测试的作用类似,也就是要保证提供给客户的接口的正确性。虽然单元测试的用例设计比较麻烦,因为需要考虑到各个方面,而且难免会有疏漏;其次要为数目庞大的类和方法逐一编写测试程序也是一件很可怕的事情,测试的时间甚至比编程的时间还要长。但单元测试这种思想很好,而且我也从中受益匪浅。