实验三 软件工程结对项目
项目 | 内容 |
课程班级博客链接 | https://edu.cnblogs.com/campus/xbsf/nwnu2020SE/ |
这个作业要求链接 | https://www.cnblogs.com/nwnu-daizh/p/12521474.html |
我的课程学习目标 | 学习软件工程中结对编程(Pair programming) |
这个作业在哪些方面帮助我实现学习目标 | 软件开发流程中的结对编程的方法内容 |
结对方学号-姓名 | 王志成-201771010130 |
结对方本次博客作业链接 | https://www.cnblogs.com/847118824wang/p/12587400.html |
本项目Github的仓库链接地址 | https://github.com/Wei-Ron/epidemic-user-message |
任务一 阅读《现代软件工程—构建之法》第3-4章内容,理解并掌握代码风格规范、代码设计规范、代码复审、结对编程概念。
(1)代码规范
代码规范风格的原则是:简明,易读,无二义性:
标识符直观且可以拼读,可望文知意,不必进行“解码”。
标识符的长度符合“min-length && max-information”原则。
命名规则尽量与所采用的操作系统或开发工具的风格保持一致。
程序中不可出现仅靠大小写区分的相似的标识符。
变量的名字可使用“名词”或者“形容词+名词”。
全局函数的名字可使用“动词”或者“动词+名词”(动宾词组)。类的成员函数应当只使用“动词”,被省略掉的名词就是对象本身。
用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。
(2)代码复审:
代码设计有比较周全的考虑。首先,程序对输入有详细的处理,对输入的格式进行了检查,并对输入的数字大小进行了判断。程序还有周全的错误处理,把错误信息输出到ErrorLog.txt中。
代码有较高的可读性。代码根据功能分为了几个不同的类,对功能的划分较为直观,关键部分有详细的注释,但有些部分仍缺少必要的注释,存在一些难以理解的代码。由于代码的分工十分明确,所以易于维护。
代码的每一行都必须保证执行并检查过了。
(3)结对编程
两个程序员在一个计算机上共同工作。一个人输入代码,而另一个人审查他输入的每一行代码。两个程序员经常互换角色。
任务二 两两自由结对,对结对方《实验二 软件工程个人项目》的项目成果进行评价
代码复审
项目的开发者:王志成
项目的复审者:孔维滢
1、概要部分
(1)代码符合需求和规格说明么?
代码基本符合需求,代码基本符合规范说明。
(2)代码设计是否考虑周全?
考虑基本周全,但是认为设计内容还不够全面。
(3)代码可读性如何?
可以顺利读懂。
(4)代码容易维护么?
容易维护。
(5)代码的每一行都执行并检查过了吗?
检查过了,没有错误,每一行都可以执行。
2.设计规范部分
(1)设计是否遵从已知的设计模式或项目中常用的模式?
遵从
(2)有没有硬编码或字符串/数字等存在?
没有
(3)代码有没有依赖于某一平台,是否会影响将来的移植(如Win32到Win64)?
没有,不会影响移植。
(4)开发者新写的代码能否用已有的Library/SDK/Framework中的功能实现?在本项目中是否存在类似的功能可以调用而不用全部重新实现?
可以用,部分功能可以调用而不用全部重新实现。
(5)有没有无用的代码可以清除?(很多人想保留尽可能多的代码,因为以后可能会用上,这样导致程序文件中有很多注释掉的代码,这些代码都可以删除,因为源代码控制已经保存了原来的老代码)
基本清除完毕。
3.代码规范部分
(1)修改的部分符合代码标准和风格么?
符合。
4.具体代码部分
(1)有没有对错误进行处理?对于调用的外部函数,是否检查了返回值或处理了异常?
对错误都进行了处理,没有任何异常。
(2)参数传递有无错误,字符串的长度是字节的长度还是字符(可能是单/双字节)的长度,是以0开始计数还是以1开始计数?
无错误。不涉及字符串。
(3)边界条件是如何处理的?switch语句的default分支是如何处理的?循环有没有可能出现死循环?
没有出现死循环。
(4)有没有使用断言(Assert)来保证我们认为不变的条件真的得到满足?
没有。
(5)对资源的利用是在哪里申请,在哪里释放的?有没有可能导致资源泄露(内存、文件、各种GUI资源、数据库访问的连接,等等)?有没有优化的空间?
在对数据库进行操作之前申请数据库连接资源,操作完毕之后释放申请的资源。不会导致资源泄露。可以使用断言来保证我们认为不变的条件。
(6)数据结构中有没有用不到的元素?
没有。
5.效能
(1)代码的效能(Performance)如何?最坏的情况如何?
达到了任务二的基本要求。
(2)代码中,特别是循环中是否有明显可优化的部分(C++中反复创建类,C#中 string 的操作是否能用StringBuilder 来优化)?
没有。
(3)对于系统和网络调用是否会超时?如何处理?
没有出现超时的现象。
6.可读性
(1)代码可读性如何?有没有足够的注释?
可以顺利读取,注释较为全面。
7.可测试性
(1)代码是否需要更新或创建新的单元测试?针对特定领域的开发(如数据库、网页、多线程等),可以整理专门的核查表。
不需要更新或者创建新的单元测试。可以继续开发,添加更多的功能。
任务三 采用两人结对编程方式,结合我校师生疫情每日上报系统使用体验,设计开发一款符合我校疫情防控工作需求的信息系统。
需求分析
(1)实现西北师范大学所有学生以及教职工每天的疫情信息填写;
(2)实现师生对个人所填信息的查询;
(3)设置信息管理员对于全体师生疫情信息的多样化以及可视化查询;
(4)实现人机交互界面。
设计说明
(3)message表中name是师生姓名,college是学院,hot_messege是否感染,where_wuhan是否接触过武汉籍人员,where_hubei是否接触过湖北籍人员,come_wuhan是否来自武汉,come_hubei是否来自湖北
(5)代码说明
Logup//用户和管理员登录界面
UseLog//用户登陆后跳转到信息填报界面
UseManagement//管理员登录后跳转界面
BarChart//生成柱状图
UseAdd//实现添加学生信息的一个类
query//实现查询全部信息的一个类
UseQuery//实现通过学号查询信息的一个类
time//实现通过日期查询信息的一个类
UseHot//实现查询所有患病人员信息的一个类
UseUpdate//实现更新信息的一个类
UseDelete//实现删除信息的一个类
- 信息更新
- 信息删除
- 关键代码如下
public Logup()
{
try{
Class.forName("com.mysql.cj.jdbc.Driver");
}
catch(ClassNotFoundException e){}
try{
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=utf8","root","123456");
sql = con.createStatement();
}
catch(SQLException ee){}
}
@Override
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand()=="退出")
{
System.exit(0);
}else if(e.getActionCommand()=="登录")
{
if(!jtf.getText().isEmpty() && !jpf.getText().isEmpty())
{
//:当点击登录按钮时,首先与数据库建立连接
//:如果选中管理员登录
if(jrb1.isSelected())
{
try {
queryman();
} catch (SQLException e1) {
//:TODO Auto-generated catch block
e1.printStackTrace();
}
//:首先判断是否存在该用户,即是否得到了密码
if(pwd ==null)
{
this.clear();
}else
{
//:调用登录方法
this.manlogin();
}
}else if(jrb2.isSelected()) //:用户登录系统
{
try {
queryuse();
} catch (SQLException e1) {
//:TODO Auto-generated catch block
e1.printStackTrace();
}
//:首先判断是否存在该用户,即是否得到了密码
if(pwd ==null)
{
this.clear();
}else
{
//:调用登录方法
this.uselogin();
}
}
}else if(jtf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入用户名","提示消息",JOptionPane.WARNING_MESSAGE);
this.clear();
}else if(jpf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入密码","提示消息",JOptionPane.WARNING_MESSAGE);
this.clear();
}
}else if(e.getActionCommand()=="重置")
{
this.clear();
}
}
//:清空文本框和密码框
public void clear()
{
jtf.setText("");
jpf.setText("");
}
//:用户登录判断方法
public void uselogin()
{
if(pwd.equals(jpf.getText()))
{
JOptionPane.showMessageDialog(null,"登录成功!","提示消息",JOptionPane.WARNING_MESSAGE);
this.clear();
//:关闭当前界面
dispose();
//:创建一个新界面
Uselog usel = new Uselog();
usel.setVisible(true);
usel.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}else if(jtf.getText().isEmpty()&&jpf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入用户名和密码!","提示消息",JOptionPane.WARNING_MESSAGE);
}else if(jtf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入用户名!","提示消息",JOptionPane.WARNING_MESSAGE);
}else if(jpf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入密码!","提示消息",JOptionPane.WARNING_MESSAGE);
}else
{
JOptionPane.showMessageDialog(null,"用户名或者密码错误!\n请重新输入","提示消息",JOptionPane.ERROR_MESSAGE);
//:清空输入框
this.clear();
}
}
public void queryuse() throws SQLException{
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=utf8","root","123456");
ResultSet rs = sql.executeQuery("SELECT* FROM list_1 WHERE name='用户'");
if (rs.next()) {
userword = rs.getString(3);
pwd = rs.getString(4);
System.out.println("成功获取到密码和用户名from数据库");
System.out.println(userword + "\t" + pwd + "\t");
//:调用登录方法
}else
{
JOptionPane.showMessageDialog(null, "没有此用户,请重新输入!", "提示消息", JOptionPane.WARNING_MESSAGE);
}
}
//:管理员登录判断方法
public void manlogin()
{
if(pwd.equals(jpf.getText()))
{
JOptionPane.showMessageDialog(null,"登录成功!","提示消息",JOptionPane.WARNING_MESSAGE);
this.clear();
//:关闭当前界面
dispose();
//:创建一个新界面,适用于管理员来管理用户
UseManagement useM = new UseManagement();
useM.setVisible(true);
useM.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}else if(jtf.getText().isEmpty()&&jpf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入用户名和密码!","提示消息",JOptionPane.WARNING_MESSAGE);
}else if(jtf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入用户名!","提示消息",JOptionPane.WARNING_MESSAGE);
}else if(jpf.getText().isEmpty())
{
JOptionPane.showMessageDialog(null,"请输入密码!","提示消息",JOptionPane.WARNING_MESSAGE);
}else
{
JOptionPane.showMessageDialog(null,"用户名或者密码错误!\n请重新输入","提示消息",JOptionPane.ERROR_MESSAGE);
//:清空输入框
this.clear();
}
}
public void queryman() throws SQLException{
con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=utf8","root","123456");
ResultSet rs = sql.executeQuery("SELECT* FROM list_1 WHERE name='管理员'");
if (rs.next()) {
//:将管理员的用户名和密码取出
userword = rs.getString(3);
pwd = rs.getString(4);
System.out.println("成功获取到密码和用户名from数据库");
System.out.println(userword + "\t" + pwd + "\t");
//:调用登录方法
}else
{
JOptionPane.showMessageDialog(null, "没有此用户,请重新输入!", "提示消息", JOptionPane.WARNING_MESSAGE);
}
}
}
public class query extends JPanel implements ActionListener{
Connection con; //与特定数据库的连接(会话)。
Statement sql; //用于执行静态 SQL 语句并返回它所生成结果的对象。
JButton b1,b2;//定义两个按钮
Object[] columns={"编号","姓名","学院","是否确诊患病","是否在武汉","是否在湖北","近期是否到达武汉","近期是否到达湖北",
"是否与武汉人员接触","是否与湖北人员接触","时间"};//字段
Object[][] data=new Object[200][11];
JTable table;
JScrollPane sc;
query (){
try{ //:错误处理机制
Class.forName("com.mysql.cj.jdbc.Driver"); //:通过 Class.forName为数据库管理系统加载一个JDBC驱动程序。
}
catch(ClassNotFoundException e){} //:如果加载驱动失败 控制台抛出异常
try{ //:如果加载驱动成功, 调用驱动连接特定数据库
con=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=utf8","root","12");
sql=con.createStatement(); //:调取con成员方法获取Statement对象
}
catch(SQLException ee){}//:异常处理块
setLayout(new BorderLayout());//:布局为边框布局
JPanel p1=new JPanel();//:定义一个面板的对象为p1
table = new JTable(data, columns);
table.setPreferredScrollableViewportSize(new Dimension(400, 300));
sc = new JScrollPane(table) {
public Dimension getPreferredSize() {
return new Dimension(1300, 400);//:括号内参数,可以根据需要更改
}
};
p1.add(sc);
add(p1,"Center");
setSize(350,300);
setBackground(Color.pink);
b1=new JButton("查询全部");
b2=new JButton("清空");
//:给两个按钮添加监视器
b1.addActionListener(this);
b2.addActionListener(this);
//:将两个按钮添加到面板p1
p1.add(b1);
p1.add(b2);
}
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==b1){
try{insert();}
catch(SQLException ee){}
}
else if(e.getSource()==b2){
((DefaultTableModel) table.getModel()).getDataVector().clear(); //:清除表格数据
((DefaultTableModel) table.getModel()).fireTableDataChanged();//:通知模型更新
table.updateUI();
}
}
public void insert() throws SQLException{
int i,j;
con=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/useruseUnicode=true&
characterEncoding=utf8","root","12");
ResultSet rs = sql.executeQuery("SELECT* FROM message" );
i=0;
j=0;
while(rs.next()){
data[i][j++]=rs.getString("id");
data[i][j++]=rs.getString("name");
data[i][j++]=rs.getString("college");
data[i][j++]=rs.getString("hot_message");
data[i][j++]=rs.getString("where_wuhan");
data[i][j++]=rs.getString("where_hubei");
data[i][j++]=rs.getString("come_wuhan");
data[i][j++]=rs.getString("come_hubei");
data[i][j++]=rs.getString("touch_wuhan");
data[i][j++]=rs.getString("touch_wuhan");
data[i][j]=rs.getString("time");
i++;
j=0;
}
con.close();
}
}
PSP | 内容 | 计划完成需要的时间(min) | 实际完成需要的时间(min) |
Planning | 计划 | 20 | 30 |
*Estimate | 预计开发时长,规划大致工作步骤 | 15 | 20 |
Development | 开发 | 400 | 500 |
*Analysis | 需求分析 (包括学习新技术) | 60 | 90 |
*Design Spec | 生成设计文档 | 30 | 30 |
*Design Review | 设计复审 (和同学审核设计文档) | 10 | 15 |
*Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 5 | 5 |
*Design | 具体设计 | 100 | 120 |
*Coding | 具体编码 | 400 | 500 |
*Code Review | 代码复审 | 60 | 30 |
*Test | 测试(自我测试,修改代码,提交修改 | 60 | 120 |
*Reporting | 报告 | 50 | 60 |
*Test Report | 测试报告 | 60 | 70 |
*Size Measurement | 计算工作量 | 5 | 5 |
*Postmortem & Process Improvement Plan | 事后总结 ,并提出过程改进计划 | 30 | 30 |
总结
这次实验,我们基本上完成了一个疫情管理系统。该系统主要分为用户和管理员两个模块,用户可以对每天的个人疫情信息进行填写,并且查询自己所填报的信息,而管理员可以对所有的信息进行查询、修改、删除、更新。但是对于提醒填报的通知功能我们没有实现.但是,对于这次的工作,我还是觉得两个人协作会有更有效、更好的效果,而且和我合作的同学能力比我强,我也学习到了很多。