2020软件工程作业_02
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/fzu/SE2020 |
---|---|
这个作业的要求在哪里 | https://edu.cnblogs.com/campus/fzu/SE2020/homework/11167 |
这个作业的目标 |
|
学号 | 031802233 |
一. PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 60 | 90 |
Estimate | 估计这个任务需要多少时间 | 180 | 180 |
Development | 开发 | 120 | 150 |
Analysis | 需求分析 (包括学习新技术) | 120 | 150 |
Design Spec | 生成设计文档 | 20 | 30 |
Design Review | 设计复审 | 10 | 30 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 20 | 30 |
Design | 具体设计 | 60 | 90 |
Coding | 具体编码 | 60 | 50 |
Code Review | 代码复审 | 30 | 60 |
Test | 测试(自我测试,修改代码,提交修改) | 30 | 60 |
Reporting | 报告 | 30 | 30 |
Test Report | 测试报告 | 10 | 10 |
Size Measurement | 计算工作量 | 10 | 20 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 10 | 30 |
合计 | 770 | 1000 |
二. 解题思路
单纯做题,QQ传文件:
- 看到题目之后,下载示例测试数据,发现为json格式,之前学习python时了解到python对于这类文件的处理比较方便 ——> 复习python的json处理方法
- python对于一个文件夹下所有json文件的处理 ——> os模块复习
- 观察到格式要求为:
python如何处理此类命令?python3 GHAnalysis.py <--init|-i> <path to data>
了解到python有对应模块argparse ——> 学习对应模块argparse - 单元测试学习:
因为之前并没有接触过“单元测试”这个概念,所以对于我来说单元测试相对算是一个全新的内容。
了解到python有对应模块 unittest 和 coverage ——> 学习对应模块 unittest、coverage - 编写代码过程:
学习python编码格式规范。
做完之后,GitHub传文件:
-
git一大堆命令 ——> 学习git,掌握基本命令
一开始是懵的,比如:
- git 为什么要先 add 再 commit ?
- 为什么删除不需要先 add 再 commit ?
- 回退过程什么情况下不能够回退? ——任何情况下都能回退
- 不同情况下回退的命令都是什么?
-
学习git和github连接
- git 和 github 用 ssh 连接,为什么不用 http ?
- 为什么要先 git init 再 git remote add ?
- git clone 和 git pull 的区别是什么?
- pull request 是什么意思?为什么取这么奇怪的名字?
- pr是最后“交卷”,那一开始就pr和最后才pr的区别是什么?
- 为什么使用 ssh协议,GitHub知道公钥就能验证我的身份?
- 为什么我在宿舍生成的ssh密钥,用校园网就验证不了了?
- ...
push 的时候发生过各种各样奇奇怪怪的错误...
最后谢谢各类博客和StackOverflow。 -
学习 GitHub 的自动化流程:
- github的 Action 是什么?workflows是什么?
- .yml 格式又是什么?
- .gitignore 格式又又是什么?
三. 设计过程
四. 代码说明
添加命令行参数
def argInit(self):
# 初始化参数
self.parser.add_argument('-i', '--init')
self.parser.add_argument('-u', '--user')
self.parser.add_argument('-r', '--repo')
self.parser.add_argument('-e', '--event')
命令解析,并根据命令执行 初始化/查询 过程
def orderAnalyze(self):
# 初始化
if self.parser.parse_args().init:
self.data = Data(self.parser.parse_args().init, 1)
return 0
else:
# 无数据重新加载
if self.data is None:
self.data = Data()
if self.parser.parse_args().event:
if self.parser.parse_args().user:
# 查询某用户在某项目某事件
if self.parser.parse_args().repo:
res = self.data.getEventsUsersAndRepos(
self.parser.parse_args().user, self.parser.parse_args().repo, self.parser.parse_args().event)
# 查询某用户某事件
else:
res = self.data.getEventsUsers(
self.parser.parse_args().user, self.parser.parse_args().event)
# 查询某项目某事件
elif self.parser.parse_args().repo:
res = self.data.getEventsRepos(
self.parser.parse_args().reop, self.parser.parse_args().event)
else:
raise RuntimeError('error: argument -l or -c are required')
else:
raise RuntimeError('error: argument -e is required')
return res
初始化过程
def __init__(self, dict_address: str = None, reload: int = 0):
# 需要重新加载数据时
if reload == 1:
self.dataLoadIn(dict_address)
# 数据地址为空且无加载数据时
if dict_address is None and not os.path.exists('user.json') and not os.path.exists('repo.json') and not os.path.exists('user_repo.json'):
raise RuntimeError('error: init failed')
# 某用户的某事件数量
x = open('user.json', 'r', encoding='utf-8').read()
self.__4Events4PerP = json.loads(x)
# 某项目的某事件数量
x = open('repo.json', 'r', encoding='utf-8').read()
self.__4Events4PerR = json.loads(x)
# 某用户在某项目的某事件数量
x = open('user_repo.json', 'r', encoding='utf-8').read()
self.__4Events4PerPPerR = json.loads(x)
def dataLoadIn(self, dict_address: str) -> bool:
json_list = []
# 遍历文件夹
for root, dic, files in os.walk(dict_address):
for f in files:
# 处理目标json文件
if f[-5:] == '.json':
json_path = f
x = open(dict_address+'\\'+json_path,
'r', encoding='utf-8').read()
# json文件转换为数组, 元素为一行json格式的数据
str_list = [_x for _x in x.split('\n') if len(_x) > 0]
for _str in str_list:
try:
json_list.append(json.loads(_str))
except:
pass
records = self.__listOfNestedDict2ListOfDict(json_list)
self.__4Events4PerP = {} # 存 某用户某事件
self.__4Events4PerR = {} # 存 某项目某事件
self.__4Events4PerPPerR = {} # 存 某用户某项目某事件
for i in records:
if not self.__4Events4PerP.get(i['actor__login'], 0):
self.__4Events4PerP.update({i['actor__login']: {}})
self.__4Events4PerPPerR.update({i['actor__login']: {}})
self.__4Events4PerP[i['actor__login']][i['type']
] = self.__4Events4PerP[i['actor__login']].get(i['type'], 0)+1
if not self.__4Events4PerR.get(i['repo__name'], 0):
self.__4Events4PerR.update({i['repo__name']: {}})
self.__4Events4PerR[i['repo__name']][i['type']
] = self.__4Events4PerR[i['repo__name']].get(i['type'], 0)+1
if not self.__4Events4PerPPerR[i['actor__login']].get(i['repo__name'], 0):
self.__4Events4PerPPerR[i['actor__login']].update({i['repo__name']: {}})
self.__4Events4PerPPerR[i['actor__login']][i['repo__name']][i['type']
] = self.__4Events4PerPPerR[i['actor__login']][i['repo__name']].get(i['type'], 0)+1
# 写入保存查询文件
with open('user.json', 'w', encoding='utf-8') as f:
json.dump(self.__4Events4PerP,f)
with open('repo.json', 'w', encoding='utf-8') as f:
json.dump(self.__4Events4PerR,f)
with open('user_repo.json', 'w', encoding='utf-8') as f:
json.dump(self.__4Events4PerPPerR,f)
return True # 数据加载处理成功
五. 性能优化/测试
1. 性能测试截图
2. 性能优化
在数据规模量高达 10 Gb的情况下,加之python一直以来的“慢”,IO速度可能惊人,想到要做些什么改善性能。
了解到python可以利用 多线程+队列 同时读取多个文件改善IO速度,但这一部分代码看的有些模糊,暂未学会...
六. 代码规范
链接:https://github.com/2441461233/2020-personal-python/blob/master/CodeStyle.md
七. 总结
- 通过这次的学习,高压之下用两三天就把之前学了大半年没学会的GitHub的基本使用学会了。
- 学做一个项目是一个发散式学习的过程,一个不懂的问题可能引申出十个不懂的问题。
eg:从一个报错 “Hi XXX! You've successfully authenticated, but GitHub does not provide shell access.” 到 ssh 协议的细节...
... - 做项目不能不分析,直接扎进去就会一头雾水。
- 将项目拆解之后需要分开专注于各自的细节:利用“模块化”思维,不仅程序要模块化,项目流程也要模块化 —— 分步拆解、逐个解决。