项目 内容
这个作业属于哪个课程 软件工程
这个作业的要求在哪里 结对项目-最长英语单词链
我在这个课程的目标是 学习软件工程的一般方法并实践
这个作业在哪个具体方面帮助我实现目标 实践结对编程方法,锻炼工程能力

在文章开头给出教学班级和可克隆的 Github 项目地址。

  • 教学班级:周四上午
  • 项目地址:https://gitee.com/mamba0824/buaapaireprogramming
  • 项目成员:20373974 阮正浩, 20373447 朱承烜

在开始实现程序之前,在下述 PSP 表格记录下你估计将在程序的 各个模块的开发上耗费的时间。

见文末表格

看教科书和其它资料中关于 Information Hiding,Interface Design,Loose Coupling 的章节,说明你们在结对编程中是如何利用这些方法对接口进行设计的。

这三个概念联系紧密,信息隐藏指的是类或函数对外只暴露必要的部分,保护内部复杂或敏感的信息,这需要良好的功能抽象与模块化。接口设计便是模块化工作中意义最重要的一步,优秀的接口应当能将功能抽象成逻辑分明的多个子模块,便于编程和测试,同时由于接口的隔离各模块能够松耦合。

编程过程中我们将任务先分为输入、计算、输出三个逻辑模块,模块间用合适的接口隔离,再对各模块进行进一步的细分,例如将输入分为读文件和解析参数两部分,直至任务规模较小。每个模块间仅通过设计的接口进行数据交换,不关心各自的实现细节。

计算模块接口的设计与实现过程。 设计包括代码如何组织,比如会有几个类,几个函数,他们之间关系如何,关键函数是否需要画出流程图?说明你的算法的关键(不必列出源代码),以及独到之处。

整体流程图:

具体解释:

EXPORT_DLL int gen_chain_word(char* words[], int len, char* result[], int head, int tail, int banned,int enable_loop);
EXPORT_DLL int gen_chains_all(char* words[], int len, char* result[]);
EXPORT_DLL int gen_chain_char(char* words[], int len, char* result[], int head, int tail, int reject, int enable_loop);

计算模块对外开放上述三个函数作为接口,分别对应三个主任务。

选择以单词为节点建图,节点存储邻接数组,两层循环复杂度 O ( V 2 ) O(V^2) O(V2)。

若为-n,由于要输出所有单词链,直接dfs即可。

若为-w,由于仅要求最大链,考虑优化方法。对于无环情况,我们发现可以利用DAG图的拓扑性质进行dp解决问题。首先进行拓扑排序检测环路同时得到拓扑序(复杂度 O ( V + E ) O(V+E) O(V+E)),令dp[i]代表以节点i为结尾的最大单词链长度并初始化为1,按照拓扑序进行遍历更新dp[i]。

具体的方法是对于节点i,依次考虑接在其后的所有相邻节点,相邻节点取j时,若dp[j] < dp[i] + 1,则更新dp[j]为dp[i] + 1, 并记录dp[j]的前置节点为i,否则不进行操作,遍历完成后取dp表的最大值并根据前置节点恢复整条单词链即可。这种方法之所以能成立是由于拓扑序保证了处于遍历序列后面的节点不可能到达前面的节点,所以也不会造成更新。

考虑附加参数,-t容易处理,若节点i尾字母不合要求,考虑最大值时不计算dp[i]即可;-j和-h需要对图进行一定的重构,-j可以遍历所有节点将首字母不合要求的排除(代码实现上是用disabled标记),-h稍微复杂一点,有-h时唯一影响答案的情况是非指定首字符的单词作为链的头部,所以只需要再通过一次拓扑排序的过程将首字母不合要求且入度为0的节点排除即可。

对于-r的有环图,上述优化失效,目前还未找到正确的线性方法,直接类似-n使用dfs暴力搜索,同时对附加参数进行处理,这部分抽象至gen_chain_loop方法进行处理,比较常规便不赘述细节。

展示在所在开发环境下编译器编译通过无警告的截图

阅读有关 UML 的内容,画出 UML 图显示计算模块部分各个实体之间的关系。

计算模块接口部分的性能改进。 记录在改进计算模块性能上所花费的时间,并展示你程序中消耗最大的函数,陈述你的性能改进策略。

一开始我们基于-n的暴力dfs方法对-w,-c的情况进行了简单实现,初步验证了正确性,但是对每个节点进行dfs的开销巨大难以接受。

于是我们希望利用剪枝或dp方法进行优化,并发现DAG图的拓扑序具有良好性质,能够保证dp的简单性和正确性,通过前文提到的具体算法,我们成功地将无环情况的求解复杂度降到了线性,小于建图的 O ( V 2 ) O(V^2) O(V2)复杂度,这种情况下消耗最大的函数为:

Node *create_graph(char *words[], int len) {Node *nodes = (Node *) malloc((len + 5) * sizeof(Node));if (nodes == nullptr) return nullptr;int idx = 0;for (int i = 1; i <= len; i++) {char *word = words[i];auto tmp = new Node(word, i - 1);nodes[idx++] = *tmp;}for (int i = 0; i < len; i++) {int h = nodes[i].get_head();int t = nodes[i].get_tail();for (int j = 0; j < len; j++) {if (j != i) {if (t == nodes[j].get_head()) {nodes[j].ind_inc();nodes[i].add(j);}}}}return nodes;
}

-n或有环情况下,dfs函数成为消耗最大的函数:

void dfs(Node node, string str, int cnt, Node* nodes, vector<string> &ans) { //-nint size = node.get_oud();for (int i = 0;i < size ;i++) {int to = node.get_to(i);if (!nodes[to].is_used()) {nodes[to].set_used(true);dfs(nodes[to], str + " " + nodes[to].get_body(), cnt + 1, nodes, ans);nodes[to].set_used(false);}}if (cnt > 1) {ans.push_back(str);// cout << str << endl;}
}void dfs_r(Node node, int cnt, Node *nodes, vector<int> &tmp, vector<int> &ans, int &maxlen, int type, int tail) {                                             //-rint size = node.get_oud();tmp.push_back(node.get_id());if (type == 1) {cnt += 1;} else if (type == 2) {cnt += node.get_len();}for (int i = 0; i < size; i++) {int to = node.get_to(i);if (!nodes[to].is_used() && !nodes[to].is_disabled()) {nodes[to].set_used(true);dfs_r(nodes[to], cnt, nodes, tmp, ans, maxlen, type, tail);nodes[to].set_used(false);}}if (cnt > maxlen && (tail == 0 || node.get_tail() == tail)) {maxlen = cnt;ans = tmp;}tmp.pop_back();
}

这部分我们做了一定力所能及的优化,如dfs过程中动态构建string便于输出单词链等。
改进计算模块性能上所花费的时间大致有3-4小时。

阅读 Design by Contract,Code Contract 的内容,并描述这些做法的优缺点,说明你是如何把它们融入结对作业中的。

契约式编程将接口进一步标准化, 调用者必须提供正确的参数,被调用者必须保证正确的结果和调用者要求的不变性。 双方都有必须履行的义务,也有使用的权利,这样就保证了双方代码的质量,提高了软件工程的效率和质量。但是设计良好的契约需要充分的经验和编写技巧,同时也会造成一定的时间开销,设计不完全的契约反而可能为编码带来困难。

由于语言本身并不支持契约,考虑到自己编写精密的契约开销较大而且难以保证质量,我们选择在设计接口时利用契约的思想考虑前置条件、不变式以及后置条件来指导编码。

计算模块部分单元测试展示。 展示出项目部分单元测试代码,并说明测试的函数,构造测试数据的思路。将单元测试得到的测试覆盖率截图 ,发表在博客中。要求总体覆盖率到 90% 以上,否则单元测试部分视作无效。

使用CLion+GoogleTest编写单元测试,分别对输入、计算、输出模块进行测试,主要检验各接口函数。

构造数据的思路:首先测试函数在正常输入下功能的正确性,然后构造对应不同异常的测试数据检验鲁棒性,再结合分支覆盖率探查未测试到的分支,对测试数据进行补充。

以参数解析部分的测试为例:

TEST(inputTest, parse_para_1) {  //基本功能char *path = nullptr;int len = 10;char *argv[15] = {" ", "-w", "input0.txt", "-h", "a", "-t", "b", "-j", "c", "-r"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, 0);EXPECT_EQ(cal_type, 2);EXPECT_EQ(head, 'a');EXPECT_EQ(tail, 'b');EXPECT_EQ(banned, 'c');EXPECT_EQ(loop, 1);std::cout << path << std::endl;
}//各种异常情况
TEST(inputTest, parse_para_2) {char *path = nullptr;int len = 1;char *argv[10] = {""};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -1);
}TEST(inputTest, parse_para_3) {char *path = nullptr;int len = 2;char *argv[10] = {"", "-n"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -7);
}TEST(inputTest, parse_para_4) {char *path = nullptr;int len = 5;char *argv[10] = {"", "-n", "input.txt", "-w", "input.txt"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -9);... 本部分共26个单元测试,以达到高覆盖率

整体覆盖率截图:


如图,在所测试的core,input,output模块以及参数解析para.cpp中均达到了较高的覆盖率。

计算模块部分异常处理说明。 在博客中详细介绍每种异常的设计目标。每种异常都要选择一个单元测试样例发布在博客中,并指明错误对应的场景。

我们总共支持了十六种异常,以下是针对每一种异常做的单元测试。

参数中不存在文件路径

当参数中不含有文件路径时,会反馈"Missing file path" 。

单元测试代码如下:

TEST(inputTest, parse_para_3) {char *path = nullptr;int len = 2;char *argv[10] = {"", "-n"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -7);
}

参数中未指定任务

在一个参数序列中没有指定任务,会反馈"Missing working parameters"。

单元测试代码如下:

TEST(inputTest, parse_para_24) {char *path = nullptr;int len = 3;char *argv[10] = {"", "-h", "i"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -1);
}

参数之间存在冲突

对于参数 -n,并不支持和其他参数共同使用,此时会反馈"-n Can only be used alone".

单元测试代码如下:

TEST(inputTest, parse_para_4) {char *path = nullptr;int len = 5;char *argv[10] = {"", "-n", "input.txt", "-w", "input.txt"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -9);
}

参数指定了多个任务

参数 -n 、-w 、-c 分别代表需要执行的三个任务。在一个参数序列中只允许存在一个任务,违反则会反馈"Repetition of assigned tasks"。

单元测试代码如下:

TEST(inputTest, parse_para_5) {char *path = nullptr;int len = 5;char *argv[10] = {"", "-c", "input.txt", "-w", "input.txt"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -2);
}

重复指定首字母

当出现多次使用 -h 参数时,会反馈"Repeat the specified parameter -h"。

单元测试代码如下:

TEST(inputTest, parse_para_6) {char *path = nullptr;int len = 7;char *argv[10] = {"", "-c", "input.txt", "-h", "a", "-h", "a"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -3);
}

重复指定尾字母

当出现多次使用 -t 参数时,会反馈"Repeat the specified parameter -t"。

单元测试代码如下:

TEST(inputTest, parse_para_7) {char *path = nullptr;int len = 7;char *argv[10] = {"", "-c", "input.txt", "-t", "a", "-t", "a"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -3);
}

重复指定不能出现的字母

当出现多次使用 -j 参数时,会反馈"Repeat the specified parameter -j"。

单元测试代码如下:

TEST(inputTest, parse_para_8) {char *path = nullptr;int len = 7;char *argv[10] = {"", "-c", "input.txt", "-j", "a", "-j", "a"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -3);
}

重复指定允许有环参数

当出现多次使用 -r 参数时,会反馈"Repeat the specified parameter -r"。

单元测试代码如下:

TEST(inputTest, parse_para_9) {char *path = nullptr;int len = 5;char *argv[10] = {"", "-c", "input.txt", "-r", "-r"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -3);
}

参数格式不合法

当命令中存在既不是任务参数,又不是附加参数后的合法字母的字符串时,会反馈"Illegal parameter format" 。

单元测试代码如下:

TEST(inputTest, parse_para_10) {char *path = nullptr;int len = 4;char *argv[10] = {"", "-c", "input.txt", "aa"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -4);
}

指定首字母不合法

当指定 -h 参数时,如果后面的字符并不是大小写字符,会反馈"Lettering information is not legal" 错误。

单元测试代码如下:

TEST(inputTest, parse_para_12) {char *path = nullptr;int len = 5;char *argv[10] = {"", "-c", "input.txt", "-h", "0"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -6);
}

指定尾字母不合法

当指定 -t 参数时,如果后面的字符并不是大小写字符,会反馈"Lettering information is not legal" 错误。

单元测试代码如下:

TEST(inputTest, parse_para_13) {char *path = nullptr;int len = 5;char *argv[10] = {"", "-c", "input.txt", "-t", "0"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -6);
}

指定不能出现的字母不合法

当指定 -j 参数时,如果后面的字符并不是大小写字符,会反馈"Lettering information is not legal" 错误。

单元测试代码如下:

TEST(inputTest, parse_para_14) {char *path = nullptr;int len = 5;char *argv[10] = {"", "-c", "input.txt", "-j", "aa"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -6);
}

文件名不合法

当文件后缀不是 .txt 时,会反馈"File path is not legal"

单元测试代码如下:

TEST(inputTest, parse_para_11) {char *path = nullptr;int len = 3;char *argv[10] = {"", "-c", "input.txp"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -5);
}

附加参数后无字母信息

当-h,-t, -j参数之后没有写单词时,会反馈"Missing letter information"

单元测试代码如下:

TEST(inputTest, parse_para_15) {char *path = nullptr;int len = 4;char *argv[10] = {"", "-c", "input.txt", "-h"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -8);
}TEST(inputTest, parse_para_16) {char *path = nullptr;int len = 4;char *argv[10] = {"", "-c", "input.txt", "-t"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -8);
}TEST(inputTest, parse_para_17) {char *path = nullptr;int len = 4;char *argv[10] = {"", "-c", "input.txt", "-j"};int cal_type = 0, head = 0, tail = 0, banned = 0, loop = 0;int r = parse_para(len, argv, cal_type, head, tail, banned, loop, &path);EXPECT_EQ(r, -8);
}

单词中存在隐藏环

当传入的单词表中存在隐藏环且未指定 -r 参数时,会反馈"Find Loop,but !enable_loop!"。

单元测试代码如下:

TEST(coreTest, LOOP_CHECK)
{char* words[4] = { "gg", "abc", "cde", "ea"};char* result[10];int r = gen_chains_all(words, 4, result);EXPECT_EQ(r, -10);r = gen_chain_char(words, 4, result, 'a', 'z', 0, 0);EXPECT_EQ(r, -10);r = gen_chain_word(words, 4, result, 'a', 'z', 0, 0);EXPECT_EQ(r, -10);
}

-h与-j参数附带的字母相同

当同时使用-h与-j参数时,若这两个参数后的附加字母相同,会反馈"-h -j has the same char"

单元测试代码如下:

TEST(coreTest, HJ_CHECK)
{char* words[2] = { "abc", "cde"};char* result[10];int r = gen_chain_char(words, 2, result, 'a', 0, 'a', 0);EXPECT_EQ(r, -11);r = gen_chain_word(words, 2, result, 'a', 0, 'a', 0);EXPECT_EQ(r, -11);
}

界面模块的详细设计过程。 在博客中详细介绍界面模块是如何设计的,并写一些必要的代码说明解释实现过程。

界面设计采用Python中的ttkbootstrap库实现

主界面:

在左部文本框内进行所需要解析的单词文本的输入,或者通过Import File按钮从本地导入文件,导入文件时会自动清空文本框内的已有内容,导入的文件内容也会显示在文本框中,对于文本框中输入的文本也可以通过Save File按钮保存到本地。

在右边界面进行参数选择,其中-n,-w,-c参数为三选一且必选项,通过RadioButton组件实现,-h,-t,-j-n参数为可选项通过checkButton组件实现,对于前三个参数必须选择后其后面的输入框中输入一个字母。在正确选择和填写参数后可以点击submit按钮提交调用解析函数开始解析。

若未选择必选参数或者选择前三个附加参数后未填写字母或-h-j参数后的字母相同,则在submit是会有对应的报错信息提示用户。

结果展示界面:

计算结束后答案将反馈到文本框中,用户可点击Save File自行下载使用。

关闭此界面后将返回单词输入界面。

界面模块与计算模块的对接。 详细地描述 UI 模块的设计与两个模块的对接,并在博客中截图实现的功能。

界面模块与计算模块的对接主要通过下面的函数:

char* call_by_cmd(int len, char* cmd)

参数cmd是一个命令行命令的字符串,len是这个字符串的长度。

该函数的实现在solve这个模块中的gui_cmd.cpp文件中,首先从cmd参数中提取出任务和文件路径,之后该函数内部会调用solve函数,并将计算的答案重定向输入到solution.txt文件中,若有异常则会将异常信息通过返回值的方式进行反馈。若不存在异常则反馈空串。异常信息在计算过程中会保存在error.log文件中,在返回之前会读取这个文件将异常结果返回。

界面模块中将通过python导入dll的方式导入libsolver.dll模块,调用其中的call_by_cmd接口,从相应文件中读取异常信息或计算结果信息之后展示到界面中。

描述结对的过程 ,提供两人在讨论的结对图像资料(比如 Live Share 的截图)。关于如何远程进行结对参见作业最后的注意事项。

我们的编程水平比较接近, 对编程语言的掌握也都不算太好,此外我们都是第一次用C++写多文件的项目。因此,初期我们主要是一起讨论算法,研究如何实现第一阶段基本的功能,同时各自进行C++的回顾与学习如何利用CMake运行C++项目。算法和整体架构敲定后我们开始结对编程,主要我的队友来敲代码,我进行代码复审,有不懂的地方或者不对劲的地方另一人都可以随时提出来。编写代码有时会遇到一些想不到的bug,比如指针相关问题,这时我们会一起搜索如何解决这个问题。我们两人在结对编程过程中都积极交流,遇到一直解决不了的问题也会相互帮助相互鼓励,所以我们的合作也十分愉快。

看教科书和其它参考书,网站中关于结对编程的章节,说明结对编程的优点和缺点。同时描述结对的每一个人的优点和缺点在哪里。

下面是一些结对编程的优点:

  1. 程序员互相帮助,互相教对方,可以得到能力上的互补。
  2. 可以让编程环境有效地贯彻设计。
  3. 增强代码和产品质量,并有效的减少BUG。
  4. 降低学习成本。一边编程,一边共享知识和经验,有效地在实践中进行学习。
  5. 在编程中,相互讨论,可能更快更有效地解决问题。

当然,结对编程也会有一些不好的地方:

  1. 对于有不同习惯的编程人员,可以在起工作会产生麻烦,甚至矛盾。
  2. 有时候,程序员们会对一个问题各执己见(例如代码风格),争吵不休,反而产生重大内耗。
  3. 两个人在一起工作可能会出现工作精力不能集中的情况。程序员可能会交谈一些与工作无关的事情,反而分散注意力,导致效率比单人更为低下。
  4. 两个人的代码经验或是编码能力相差过大时,难以起到互补作用反而会互相掣肘。
  5. 有经验的人更喜欢单兵作战,找个人来站在他背后看着他可能会让他感到不自在,最终导致编程时受到情绪影响,反而出现反作用。

我的优点:

  • 设计的算法流程比较清晰
  • 有一定开发C的经验,指针等技巧可沿用至cpp开发
  • 习惯合作,交流比较畅通

我的缺点:

  • 缺少cpp开发经验,容易犯低级错误

队友的优点:

  • 编程基础比较扎实
  • 善于倾听,能与我较好地交流
  • 有一定gui编写经验

队友的缺点:

  • 同我类似,缺乏cpp开发经验

在你实现完程序之后,在附录提供的PSP表格记录下你在程序的各个模块上实际花费的时间。

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

结对项目-最长英语单词链-20373974阮正浩相关推荐

  1. 结对项目-最长英语单词链

    文章目录 结对项目-最长英语单词链 项目信息 PSP 表格 接口设计参考理念 Information Hiding Interface Design Loose Coupling **计算模块接口的设 ...

  2. 软件工程结对项目- 最长英语单词链

    项目 内容 这个作业属于哪个课程 2023年北航敏捷软件工程 这个作业的要求在哪里 结对项目-最长英语单词链 我在这个课程的目标是 学习现代化的软件开发方法 这个作业在哪个具体方面帮助我实现目标 对结 ...

  3. 结对项目——最长英语单词链

    项目 内容 这个作业属于哪个课程 https://bbs.csdn.net/forums/buaa-ase2023 这个作业的要求在哪里 https://bbs.csdn.net/topics/613 ...

  4. [2022软工第三次作业]结对编程项目——最长英语单词链

    项目 内容 本作业所属课程 2022年北航敏捷软件工程教学实践 本作业要求 结对编程项目-最长英语单词链 个人课程目标 学习到软件工程的方法论,了解整个过程,并进行亲自实践 本作业在哪个具体方面帮助我 ...

  5. 结对编程项目——最长英语单词链

    目录 结对编程项目--最长英语单词链 1. 项目地址 2. PSP 表格记录花费的时间 3. UML 图 4. 计算模块接口的设计与实现过程 5. 参考资料中 Information Hiding.I ...

  6. 结对编程项目-最长英语单词链

    项目 内容 这个作业属于哪个课程 2022 年北航敏捷软件工程 这个作业的要求在哪里 结对编程项目-最长单词链 我在这个课程的目标是 学习软件工程相关知识,提高自己的代码能力与团队协作能力. 这个作业 ...

  7. 「软工结对编程」:最长英语单词链

    项目 内容 这个作业属于哪个课程 2023年北航敏捷软件工程社区 这个作业的要求在哪里 结对项目-最长英语单词链 我在这个课程的目标是 学习有关软件开发的方法论,熟悉基本的软件开发流程,通过" ...

  8. 2023软工第三次作业-最长英语单词链

    结对项目-最长英语单词链 项目 内容 这个作业属于哪个课程 2023北航软件工程 这个作业的要求在哪里 结对项目-最长英语单词链 我在这个课程的目标是 帮助我初步建立软件工程敏捷开发的整体流程和概念, ...

  9. 北航2022软件工程第三次作业——结对编程(最长英语单词链)

    软件工程第三次结对编程作业 项目 内容 这个作业属于哪个课程 北京航空航天大学2022春季软件工程(罗杰 任健) 这个作业的要求在哪里 结对编程项目-最长英语单词链 我在这个课程的目标是 学习软件工程 ...

最新文章

  1. JavaScript基础笔记集合(转)
  2. 怎么请假显智商高?评论区亮了! | 每日趣闻
  3. ssh暴力破解解决方案
  4. ASCII码对应表chr(9)、chr(10)、chr(13)、chr(32)、chr(34)、chr(39)、chr(..
  5. F4 value help and HANA native SQL
  6. ASP.Net页面刷新后自动滚动到原来位置
  7. activiti 生命周期_一文让你读懂什么是Activiti工作流
  8. Linux6.8 ssh开启,CentOS 6.8升级 ssh到最新版SSH-8.2p1
  9. python 数据结构转换层_python – 具有Maxpooling1D和channel_first的Keras模型
  10. 【Elasticsearch】elasticsearch 段 segment 段合并
  11. 常用的网络操作系统有哪些?它们各具有什么特点?
  12. sig值怎么计算_T检验、sig.值
  13. refreshToken的作用讨论及几点疑惑
  14. 程序员如何写简历?程序员写出牛逼简历的5大技巧
  15. antd mobile在微信公众号开发中使用笔记
  16. 微信开发,微信开发者平台
  17. 插入图片的时候,总是只是能漏出一点点其他部分都看不到,改变格式从插入型改成浮于文字上方才能完全显示,但浮于文字上方的格式最后不好排版和编辑,稍微一改,整个就乱了,求助如何让插入型的文字图片完全显示出来
  18. 怎么在宝妈论坛引流?宝妈论坛如何引流?如何引流宝妈群体
  19. android 微信朋友圈头像,微信进阶玩法,这样设置朋友圈和头像,个性又好看
  20. error C4996: ‘strcpy‘: This function or variable may be unsafe. Consider using strcpy_s instead.

热门文章

  1. 我的JAVA笔记--线程
  2. 如何修改After Effects模板
  3. Python计算机二级操作题-综合应用(一)
  4. GEE:计算土地利用覆盖数据中的各个地类的面积/占比
  5. 【Tableau】Tableau制作圆环图
  6. 基于matlab的mk2三自由度机械臂轨迹规划及控制器仿真设计
  7. odcl 转lisp_AUTOLISP编程心得_2.pdf
  8. MDI-jada化工软件导入.txt实验数据
  9. CAD图纸如何提取标注的方法
  10. poj 1989 The Cow Lineup 最短非子序列问题