软件开发规范
什么是软件开发规范?
好的设计项目目录结构,就和编码风格一样,是每个程序员都有的风格,但是在流水化标准化作业过程中,个性和风格是
不被鼓励的。如果你去维护一个非常不好读的项目,虽然实现逻辑并不复杂,但是对后续的维护者来说就是灾难。
一个层次清晰的目录结构,可以提高程序的可维护性:
可读性高:
后续维护人员可以一眼看懂目录结构,不必为复杂混乱的层次耗费大量精力。测试文件在哪,配置文件在哪会被放置在规范操作的地方,可以让后续人员快速的了解这个项目。
可维护性高:
看清目录架构之后,维护者可以将后续新增的文件和代码按照规范放置在规定的地方,虽然后续代码和文件增多,但是项目目录并不会混乱,仍然能够快速组织良好
按照分级目录规范模拟博客园系统
一个py文件下的博客园系统:
import json,time,os
print('欢迎使用博客园系统')
flag = 1
msg = """1.请登录
2.请注册
3.进入文章页面
4.进入评论页面
5.进入日记页面
6.进入收藏页面
7.注销账号
8.退出整个程序
"""
login_information = {"username": None, "status": False}
def login(func=False):
"""
登录函数
:param func: 函数名默认为False
:return: 无返回值
"""
time.sleep(0.1)
user_name = input('请输入你要登录的用户名')
pwd = input('请输入登录密码')
landing_info = {}
global login_information
with open("userinfo.txt", "r", encoding="utf-8")as f1:
for line in f1:
x = line.strip()[:-2]
num = int(line.strip()[-1])
name = x.split(':', 1)[0]
password = x.split(':', 1)[1]
landing_info[name] = [password, num]
if user_name in landing_info:
count = landing_info[user_name][1] + 1
if count == 3:
print('你的账号已锁定,请联系管理员解锁')
else:
while count < 3:
if pwd == landing_info[user_name][0]:
login_information["username"] = user_name
login_information["status"] = True
print("登录成功")
if func:
func()
break
else:
print(f"你的密码输入错误,剩余次数为{3 - count},请重新键入")
pwd = input('请重新输入密码:')
landing_info[user_name][1] = count + 1
count += 1
else:
print('你的账户已锁定,请联系管理员处理')
with open('userinfo.txt', 'r', encoding='utf-8')as f1, open('user.txt', 'w', encoding='utf-8') as f2:
f1.seek(0, 0)
for i in f1:
if i.strip().split(':', 1)[0] == user_name:
i = i.strip()
content = i[:-1] + "3"
f2.write(content + '\n')
else:
f2.write(i)
os.remove('userinfo.txt')
os.rename('user.txt', 'userinfo.txt')
else:
print('你输入的账号不存在,请先去注册')
def wrapper(f):
"""
操作认证
:param f: 操作函数
:return:
"""
def inner():
time.sleep(1)
if login_information["status"]:
f()
else:
login(f)
return inner
def registration():
"""
注册函数
:return:
"""
user_info = {}
num = 3
while num:
user_name = input('请输入要注册的用户名:')
pwd = input('请输入要注册的密码:')
num -= 1
lst_name = list(range(65, 91)) + list(range(97, 123))
for i in user_name:
if (i.isdecimal()== True or ord(i) in lst_name) and 6 <= len(pwd) <= 14:
pass
else:
print('用户名或密码无效,请重新输入')
if num == 0:
print('注册失败')
break
else:
with open('userinfo.txt', 'r+', encoding='utf-8')as f:
for i in f:
i = i.strip()[:-2]
k, v = i.split(':')
user_info[k] = v
if user_name in user_info:
print('用户名已存在,请重新输入用户名')
if num == 0:
print('注册失败')
continue
else:
f.write(f"\n{user_name}:{pwd}:0")
choose = input('你已经注册成功,是否重新注册(重新注册键入1)')
if choose == '1':
num = 3
else:
print('注册成功,你可以去嚯嚯了')
time.sleep(1)
num = 3
break
@wrapper
def article():
"""
文章页面
:return:
"""
global login_information
print(f"欢迎{login_information['username']}进入文章页面!")
@wrapper
def comment():
"""
评论页面
:return:
"""
num = 1
global login_information
print(f"欢迎{login_information['username']}进入评论页面!")
with open('com','r',encoding="utf-8") as f:
for i in f:
s = i.strip()
print(json.loads(s))
num += 1
choose = input("是否评论Y or N")
if choose == "Y":
com = input("请输入评论:")
with open('com','a',encoding="utf-8") as f2:
com1 = f"{num}楼 - {login_information['username']}:{com}"
f2.write(json.dumps(com1,ensure_ascii=False)+"\n")
@wrapper
def diary():
"""
日记页面
:return:
"""
global login_information
print(f"欢迎{login_information['username']}进入日记页面!")
@wrapper
def collect():
"""
收藏页面
:return:
"""
global login_information
print(f"欢迎{login_information['username']}进入收藏页面!")
@wrapper
def off():
global login_information
login_information["username"] = None
login_information["status"] = False
login_information["count"] = 0
print("账户注销成功!")
def drop():
global flag
flag = 0
print("欢迎下次光临")
func_information = {'1': login, '2': registration, '3': article, '4': comment, '5': diary, '6': collect,
'7': off, '8': drop}
while flag:
print(msg)
choose = input("请选择数字使用对应功能选项:")
if choose in func_information:
ret = func_information[choose]
ret()
else:
print("你的输入有误,请重新输入")
此时我们所有文件都写在一个py文件下,如果代码量多且都在一个py文件中,那么对于代码结构不清晰,不规范,运行起来效率也会非常低。所以我们接下来一步一步的修改:
1.软件配置:
我们的博客园系统中出现了多处这样的相对路径,如果我们用户注册表位置发生改变,我们需要一处一处修改,那么我们是否可以统一相同的路径,也就是统一相同的变量,在文件的最上面写一个变量指向userinfo注册表的路径,代码中如果需要这个路径时,直接引用即可。
userinfo_path = r"E:\Python\week3大作业\userinfo.txt"
# 我们博客园系统中出现的相对路径均用userinfo_path替换即可
2.划分文件:
一个小型的博客园系统已经这么多代码了,如果我们开发一个项目,可以想象我们的py文件该有多乱了,我们可以将这些函数进行分类,分文件而治,我们将上述py文件依据功能划分以下几类:
settings.py: 配置文件,就是放置一些项目中需要的静态参数,比如文件路径,数据库配置,软件的默认设置等等(如我们上面提到的用户注册表表文件)
common.py:公共组件文件,这里面放置一些我们常用的公共组件函数,并不是我们核心逻辑的函数,而更像是服务于整个程序中的公用的插件,程序中需要即调用。比如我们程序中的装饰器wrapper,有些函数是需要这个装饰器认证的,但是有一些是不需要这个装饰器认证的,它既是何处需要何处调用即可。比如还有密码加密功能,序列化功能,日志功能等这些功能都可以放在这里。
src.py:这个文件主要存放的就是核心逻辑功能,你看你需要进行选择的这些核心功能函数,都应该放在这个文件中。
start.py:项目启动文件。你的项目需要有专门的文件启动,而不是在你的核心逻辑部分进行启动的,有人对这个可能不太理解,我为什么还要设置一个单独的启动文件呢?你看你生活中使用的所有电器基本都一个单独的启动按钮,汽车,热水器,电视,等等等等,那么为什么他们会单独设置一个启动按钮,而不是在一堆线路板或者内部随便找一个地方开启呢? 目的就是放在显眼的位置,方便开启。你想想你的项目这么多py文件,如果src文件也有很多,那么到底哪个文件启动整个项目,你还得一个一个去寻找,太麻烦了,这样我把它单独拿出来,就是方便开启整个项目。
除了上面提到的几个py文件,还有几个非常重要的文件,类似于userinfo用户注册表的数据库文件,以及以后将拓展的logging日志文件,此外,随着项目功能的扩展,还会多出许多的用户数据表,个人信息表等等,因此,随着项目的增多,单个文件夹下存放各种py文件看起来已经非常烦乱了,此处便可以引出标准版本的项目目录结构了:
按照标准项目目录规范化博客园登录系统:
配置启动文件:
import sys # 导入sys模块 import os # 导入os模块 BASE_DIR = os.path.dirname(os.path.dirname(__file__)) #__file__获取当前文件绝对路径,整体获取blog系统绝对路径 sys.path.append(BASE_DIR) # 将blog目录添加到环境变量 from core.src import run # 从core文件夹src.py文件导入run函数 if __name__ == '__main__': # 程序启动接口 run()
配置settings.py文件:
import os # 导入os模块 BASE_DIR = os.path.dirname(os.path.dirname(__file__)) # blog系统绝对路径 userinfo_path = os.path.join(BASE_DIR,'db','userinfo.txt') # 通过拼接获取用户注册表绝对路径 com_path = os.path.join(BASE_DIR,'db','com.txt') # 获取评论绝对路径 msg = """1.请登录 2.请注册 3.进入文章页面 4.进入评论页面 5.进入日记页面 6.进入收藏页面 7.注销账号 8.退出整个程序 """
配置common.py文件:
from core import src # 从core文件夹导入src主逻辑模块 import time # 导入时间模块 """ 操作认证 :param f: 操作函数 :return: """ def wrapper(f): """ 操作认证 :param f: 操作函数 :return: """ def inner(): time.sleep(1) if src.login_information["status"]: f() else: src.login(f) return inner
调整后新版博客园:
程序启动模块:
import sys
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
sys.path.append(BASE_DIR)
from core import src
if __name__ == '__main__':
src.run()
配置模块:
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
userinfo_path = os.path.join(BASE_DIR,'db','userinfo.txt')
com_path = os.path.join(BASE_DIR,'db','com.txt')
msg = """1.请登录
2.请注册
3.进入文章页面
4.进入评论页面
5.进入日记页面
6.进入收藏页面
7.注销账号
8.退出整个程序
"""
公共组件模块:
from core import src
import time
"""
操作认证
:param f: 操作函数
:return:
"""
def wrapper(f):
"""
操作认证
:param f: 操作函数
:return:
"""
def inner():
time.sleep(1)
if src.login_information["status"]:
f()
else:
src.login(f)
return inner
主逻辑模块:
import json,time,os
from conf import settings
from lib import common
print('欢迎使用博客园系统')
flag = 1
login_information = {"username": None, "status": False}
def login(func=False):
"""
登录函数
:param func: 函数名默认为False
:return: 无返回值
"""
time.sleep(0.1)
user_name = input('请输入你要登录的用户名')
pwd = input('请输入登录密码')
landing_info = {}
global login_information
with open(settings.userinfo_path, "r", encoding="utf-8")as f1:
for line in f1:
x = line.strip()[:-2]
num = int(line.strip()[-1])
name = x.split(':', 1)[0]
password = x.split(':', 1)[1]
landing_info[name] = [password, num]
if user_name in landing_info:
count = landing_info[user_name][1] + 1
if count == 3:
print('你的账号已锁定,请联系管理员解锁')
else:
while count < 3:
if pwd == landing_info[user_name][0]:
login_information["username"] = user_name
login_information["status"] = True
print("登录成功")
if func:
func()
break
else:
print(f"你的密码输入错误,剩余次数为{3 - count},请重新键入")
pwd = input('请重新输入密码:')
landing_info[user_name][1] = count + 1
count += 1
else:
print('你的账户已锁定,请联系管理员处理')
with open(settings.userinfo_path, 'r', encoding='utf-8')as f1, open('user.txt', 'w', encoding='utf-8') as f2:
f1.seek(0, 0)
for i in f1:
if i.strip().split(':', 1)[0] == user_name:
i = i.strip()
content = i[:-1] + "3"
f2.write(content + '\n')
else:
f2.write(i)
os.remove('userinfo.txt')
os.rename('user.txt', 'userinfo.txt')
else:
print('你输入的账号不存在,请先去注册')
def registration():
"""
注册函数
:return:
"""
user_info = {}
num = 3
while num:
user_name = input('请输入要注册的用户名:')
pwd = input('请输入要注册的密码:')
num -= 1
lst_name = list(range(65, 91)) + list(range(97, 123))
for i in user_name:
if (i.isdecimal()== True or ord(i) in lst_name) and 6 <= len(pwd) <= 14:
pass
else:
print('用户名或密码无效,请重新输入')
if num == 0:
print('注册失败')
break
else:
with open(settings.userinfo_path, 'r+', encoding='utf-8')as f:
for i in f:
i = i.strip()[:-2]
k, v = i.split(':')
user_info[k] = v
if user_name in user_info:
print('用户名已存在,请重新输入用户名')
if num == 0:
print('注册失败')
continue
else:
f.write(f"\n{user_name}:{pwd}:0")
choose = input('你已经注册成功,是否重新注册(重新注册键入1)')
if choose == '1':
num = 3
else:
print('注册成功,你可以去嚯嚯了')
time.sleep(1)
num = 3
break
@common.wrapper
def article():
"""
文章页面
:return:
"""
global login_information
print(f"欢迎{login_information['username']}进入文章页面!")
@common.wrapper
def comment():
"""
评论页面
:return:
"""
num = 1
global login_information
print(f"欢迎{login_information['username']}进入评论页面!")
with open(settings.com_path,'r',encoding="utf-8") as f:
for i in f:
s = i.strip()
print(json.loads(s))
num += 1
choose = input("是否评论Y or N")
if choose == "Y":
com = input("请输入评论:")
with open('com','a',encoding="utf-8") as f2:
com1 = f"{num}楼 - {login_information['username']}:{com}"
f2.write(json.dumps(settings.com_path,ensure_ascii=False)+"\n")
@common.wrapper
def diary():
"""
日记页面
:return:
"""
global login_information
print(f"欢迎{login_information['username']}进入日记页面!")
@common.wrapper
def collect():
"""
收藏页面
:return:
"""
global login_information
print(f"欢迎{login_information['username']}进入收藏页面!")
@common.wrapper
def off():
global login_information
login_information["username"] = None
login_information["status"] = False
login_information["count"] = 0
print("账户注销成功!")
def drop():
global flag
flag = 0
print("欢迎下次光临")
func_information = {'1': login, '2': registration, '3': article, '4': comment, '5': diary, '6': collect,
'7': off, '8': drop}
def run():
while flag:
print(settings.msg)
choose = input("请选择数字使用对应功能选项:")
if choose in func_information:
ret = func_information[choose]
ret()
else:
print("你的输入有误,请重新输入")
run()
README的相关内容
这个我觉得是每个项目都应该有的一个文件,目的是能简要描述该项目的信息,让读者快速了解这个项目。
它需要说明以下几个事项:
- 软件定位,软件的基本功能。
- 运行代码的方法: 安装环境、启动命令等。
- 简要的使用说明。
- 代码目录结构说明,更详细点可以说明软件的基本原理。
- 常见问题说明。
在软件开发初期,由于开发过程中以上内容可能不明确或者发生变化,并不是一定要在一开始就将所有信息都补全。但是在项目完结的时候,是需要撰写这样的一个文档的。