软件工程结对作业

一、项目GitHub地址

https://github.com/yifuhao/RuanGong

二、各个模块耗费的时间

PSP2.1Personal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning 计划 30  
· Estimate · 估计这个任务需要多少时间 30
20
Development 开发 1200 1300
· Analysis · 需求分析 (包括学习新技术) 120 140
· Design Spec · 生成设计文档 30 40
· Design Review · 设计复审 (和同事审核设计文档) 5 5
· Coding Standard · 代码规范 (为目前的开发制定合适的规范) 20 5
· Design · 具体设计 60 120
· Coding · 具体编码 720 480
· Code Review · 代码复审 180 60
· Test · 测试(自我测试,修改代码,提交修改) 180 300
Reporting 报告 150 60
· Test Report · 测试报告 60 30
· Size Measurement · 计算工作量 30 10
· Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 60 20
  合计 1500 1380

三、接口设计

In computer science, information hiding is the principle of segregation of the design decisions in a computer program that are most likely to change, thus protecting other parts of the program from extensive modification if the design decision is changed. The protection involves providing a stable interface which protects the remainder of the program from the implementation (the details that are most likely to change).

信息隐藏能够很好的保护程序和用户信息的安全性,只给外部提供程序的使用接口而不让他们了解程序的内部构造,这样有利于我们的编程。在作业中,直观表现为将不同程序封装成一样的接口,方便进行耦合。

 

User interface design (UI) or user interface engineering is the design of user interfaces for machines and software, such as computers, home appliances, mobile devices, and other electronic devices, with the focus on maximizing usability and the user experience.

接口设计的目的在于将程序的使用方法展现出来,但又不将程序的构造暴露。就像是将一瓶水塑封然后留下一个开口,用户可以通过开口喝水,但他不需要知道我们“造水”的过程。

 

In computing and systems design a loosely coupled system is one in which each of its components has, or makes use of, little or no knowledge of the definitions of other separate components. Subareas include the coupling of classes, interfaces, data, and services.[1] Loose coupling is the opposite of tight coupling.

松耦合是要求通过提供必要的接口来降低系统的耦合性。在本次作业中,大家的程序可以相互调用,耦合性很低,很好。

 

以上注解均来自维基百科。

 

四、接口设计与实现过程

public int gen_chain_char(string[] words, int len, string[] result, char head, char tail, bool enable_loop)

public int gen_chain_word(string[] words, int len, string[] result, char head, char tail, bool enable_loop)

接口主要就是作业要求的接口,为了方便C#使用改动了一下。

 

主要使用的类:

public class WordChain { public List<Word> wordChain; private int weight; private static char word2end;

}

public class Word { private char head; private char tail; private string allWord; private static int weightChosen = 0;

}

使用单词类来进行存储string和相关参数,方便进行运算。使用WordChain也是同样的理由。weight和word2end都让我的程序有了一定的便捷性。算法的独到之处是,我选择了拓扑排序来进行无环图的求解,但与常规拓扑序列不同的是,这一次的题目是允许自环的(即头尾相同的单词),虽然同一开头的单词只允许有一个自环,但是这个自环往往会影响到求解的过程。由于拓扑排序是不允许走回头路来修正之前的数据的,所以我将自环排在每一类单词的最前面,这样一开始就会使用掉它,也就不会影响之后的算法。

 

五、UML图

 

六、性能改进

我所做的最大改进就是将一开始的深度优先遍历算法改为后来的拓扑排序算法,由于这两者没有并存,没有办法进行性能分析。但复杂度从O(n^2)变为O(V+E),优化了许多。

 

七、契约式编程

Design by contract (DbC), also known as contract programming, programming by contract and design-by-contract programming, is an approach for designing software.——Wikipedia.

契约式编程的核心思想是将软件系统的各个元素比作商业生活中“客户”和“供应商”,将其协作运行比作“合同”。该合同在语义上等同于Hoare三元组,该条款规定了义务。这可以通过设计师必须在合同中重复回答的“三个问题”来概括:

  • 合同期望什么?

  • 合同保证什么?

  • 合同维持什么?

用编程语言来讲,就是“前提条件”是什么(expect);“中间保证”是什么(guarantee);“后期实现”是什么(maintain)。契约式设计有三个关键词:前置条件(precondition),后置条件(postcondition), 类不变项(class invariant)。为了调用函数,需要保证必须为真的条件,在其违反时,函数坚决不调用;函数会有一个完成的状态,不会无休止的进行下去;永为真的条件,在函数内部过程中,不变项可以改变,但在函数结束之后,不变项一定不会改变。这样的编程模式保证了程序的独立性和健壮性,当前置条件和后置条件不满足时,程序将会抛出相应的异常,这在保证程序不崩溃的同时很好的反馈了错误的信息。

在此次编程中,我负责的部分有处理命令这一项,比如说,我将对head和tail的命令对应为'a'-'z'和'#',在输入其它字母的情况下便会抛出异常。但是,为了让程序有一定的容错性,我将'A'-'Z'设定成抛出异常但会转成对应的小写字母。这一点与我查到的契约式编程不尽相同,不过我认为应该是可行的。

 

八、计算模块

 

[TestMethod()] public void gen_chain_wordTest3() { string filePath = ("test3.txt"); char head = 'a', tail = 'r'; string[] words = Read_file(filePath); coreBuild core = new coreBuild(); int result=6; try { result = core.gen_chain_word(words, 0, words, head, tail, true); } catch (Exception e) { Console.WriteLine(e); }

        Assert.AreEqual(result, 5);
  }

 

举一个例子,测试程序是r, rr, rrr, rrrr, rrrr, rt, ar。这里是判断其能否接受自环,能否在指定的尾部结束程序。

 

九、计算模块异常处理

我处理的主要异常有:

  • 文件不存在

  • 命令不规范

  • -h和-t的指定字母为大写英文字母

[TestMethod()] public void gen_chain_wordTest2() //有-r。-w { string filePath = ("testNull.txt"); char head = 'A', tail = 't'; string[] words = Read_file(filePath); coreBuild core = new coreBuild(); int result = core.gen_chain_word(words, 0, words, head, tail, true); Assert.AreEqual(result, 6); }

 

十、GUI设计

 

 

功能: · 读入指定路径文件中的内容(单行) · 输入自定义的内容(多行) · 提供计算方式的选择:-w 或者 -c · 提供是否指定首尾字符的多项选择(当输入框中不只包含一个字符时,取第一位字符) · 提供是否允许包含隐含环的选项 · 单击生成后即时于输出框显示结果 · 可通过图形化界面选择导出文件位置 该界面通过 Windows Form 框架和可视化控件实现。

 

十一、界面接口

GUI对外提供创建GUI界面的接口:

public static void showGUI()
{
  Application.EnableVisualStyles();
  Application.SetCompatibleTextRenderingDefault(false);
  GUI g = new GUI();
  Application.Run(g);
}

GUI通过调用计算模块的get_chainByLine函数获取处理之后的单词链,并予以显示:

coreBuild core = new coreBuild();
WordChain wc = core.get_chainByLine(textInput, char_h, char_t, b_r, c_wc);
foreach(Word word in wc.GetWordChain())
{
  textOutput += word.Get_allWord();
}
//输出指结果框
textBox5.Text = textOutput;

 

十二、结对过程

由于结对过程的特殊性以及自己是第一次接触的原因,我们小队在最后几晚基本上是一起度过的。图中为在队友的宿舍一起探讨学习。

 

十三、结对编程的优缺点

结对编程(英语:Pair programming)是一种敏捷软件开发的方法,两个程序员在一个计算机上共同工作。一个人输入代码,而另一个人审查他输入的每一行代码。输入代码的人称作驾驶员,审查代码的人称作观察员(或导航员)。两个程序员经常互换角色。

结对编程的优点:

  • 两个程序员,他们在编程的优势和短板都不尽相同,可以互帮互助,两个人同时出现盲点的概率较低;

  • 结对编程的过程中,可以学习到对方所掌握的一些知识;

  • 在学习的过程中,遇到麻烦的时候,有些人选择暂时性的回避,在结对编程中将会有相互督促的效果;

结对编程的缺点:

  • 有些人习惯单独编程,参与结对编程可能对自己和同伴都不是好事;

  • 私下关系不错时,难免会在工作中讨论起其余的话题;

  • 由于是两个人的小团队,一方脾气暴躁的话,有可能造成不愉快,毕竟没有与其他同事交流的选项;

个人的优点:

  • 写代码负责,不会拖延团队的进程;

  • 愿意交流,不会造成沟通上的不及时等状况;

  • 会督促团队进程,类似于团队项目中的PM;

个人的缺点:

  • 对结对项目不太理解,觉得彼此独立工作或许效率更高。

 

在生成链算法中,要求head和tail只能是'a'-'z'和'#',如果有大写字母则化为小写并报错,但仍会执行,其他则报错并返回

posted @ 2019-03-14 23:03  吴昊1606  阅读(255)  评论(4编辑  收藏  举报