小系统或单个模块的设计文档
「一句话描述」的标题
文件名或标题最好使用「一句话描述」,如:
- 观测云新 Event 数据结构及处理逻辑设计
- 观测云云关联处理逻辑设计
- 疫情期间健身房现场人数控制设计
需求描述
需求来源与价值概述
- 来源1
- 来源2
- 来源3
- 再加上竞品分析
这一块要把需求来源 和 竞品分析情况讲清楚
需求场景分析
- 客户场景分析
- 解决方案场景分析
- 还有一些 自己补充
新冠疫情期间,健身房控制现场会员总数,要求会员需要提前两天在网站上预订,预定从午夜开始。如,2021年04月01日的预订将在当地时间2021年03月30日00:00 AM开放。需求量很大,只有在午夜预订才能成功,决定写一个程序来为我做预订。
- 自动提前两天在半夜预订健身房
- 程序启动后不需要人工交互,应该具有容错性,能够进行合理的重试
- 可以在Mac电脑上运行
- 用户可以指定用户名、密码、预约的项目、日期和时间等
不在考虑范围内: - 只提前1或2天预订,或当天预订
- 容忍操作系统或网络问题
- 在预约服务器停止运行后还要能够工作
- 在网站结构(HTML)改变后,还要能够工作
设计
概要设计-整体方案设计
这里一般分
- 架构方案实现原理
包含 架构设计 或 UCD设计 这种 - 整体方案细化分析
浏览器自动化 vs 模拟请求
浏览器自动化是指通过程序来控制真实的浏览器,并在GUI上自动化操作。模拟请求是指让程序通过HTTP与服务器交互,这个程序就像是一个Web浏览器(而不是控制一个浏览器)。
- [优点] 浏览器自动化启动了一个真实的浏览器实例,所以我们知道程序运行时发生了什么,它使调试和开发更加容易。
- [优点] 网站需要JavaScript加载控件,而这较难通过编程实现,可能需要控制一些渲染引擎。
- [缺点] 浏览器自动化依赖于HTML结构,而模拟请求依赖于HTTP API,API相对稳定,不太可能改变。
考虑上面几点,浏览器自动化比模拟请求更好。
系统概述
这里也可以用下面这种进行描述,具体写明「用户做了什么操作,系统进行了什么处理,最后发生了什么」。
一般是流程图加上列表描述的方式
详细设计
- 整体设计思路(图加上列表描述)
- 现状分析(限制条件,哪些实现不了的 因为什么原因)
- 实现思路(时序图—加上描述)
- 数据模型(接口链接、请求参数模型、响应参数模型)
- 处理流程
用户输入
用户名、密码、日期等都是从命令行参数中输入的。
重试
程序将捕获所有异常(页面未加载等)并重试100次直到预订成功,成功的预订通过确认DOM元素进行识别。
浏览器选择
我们需要使用主流浏览器之一。我考虑并测试了Chrome、Firefox和Safari,Safari和Chrome都需要额外的步骤来使用相应的Selenium驱动程序,所以我选择了Firefox。它也需要一些来自操作系统设置的认证,但只需要在最初几次确认就可以了。
日志
程序自动执行浏览器操作,就像是由用户发起的一样。本质上,它将在循环中执行以下操作:
查找某个元素
对元素进行操作(输入文本、选择选项或单击)
等待预期结果,然后返回1
因此,每个日志记录将有两项内容:
- 执行了什么
- 在等待什么
这样的日志记录将使调试变得容易。
保持电脑持续运行
如果操作系统在程序启动到午夜之间进入休眠状态,则程序在午夜就无法运行了,Caffeinate可以防止这种情况发生。它是一个命令行工具,我们在Python中把它作为子进程启动:
subprocess.Popen([‘caffeinate’, ‘-d’, ‘-w’, ‘%d’ % os.getpid()])
定位控制
Selenium提供了一组方法[5]来访问特定的DOM元素,其中xpath的表达能力最强。因此,我们将使用find_element_by_xpath来定位DOM元素,如按钮、输入框等。
只要有可能,我们宁愿依赖DOM的内部文本来定位它们。相对于DOM结构和属性(类名等),内部文本的优势并不是说它不太可能更改,而是如果它们发生更改,更容易调试。当然,我们必须对DOM结构做一些假设,比如我们需要点击class='control'分区(div)下的class='logon'的第二个按钮。
等待页面加载
在发送每个HTTP请求后,程序需要等待加载页面(通常是2~5秒,是的,这个站点很慢)。这是由WebDriverWait API[6]完成的。例如,以下代码将等待120秒,直到 <button ng-reflect-router-link= ' /Appointments ' >
被加载并成为可被点击的按钮。
book_btn = WebDriverWait(driver, 120).until(EC.element_to_be_clickable((By.XPATH, “//button[@ng-reflect-router-link=’/Appointments’]”)))
如果按钮在120秒内加载失败,将引发异常。
更多的实现细节
选择正确的日期。假设我们想预定4月14日,我们无法在预订日历上选择文本为‘14’的单元格,因为3/14的单元格有类似的属性。当前月份的单元格必须包含有class cal-in-month。
调整月份。预订日历显示的是当月的当天,而不是我们打算预订的月份。如果两天后就是下个月,这就会有问题。因此,我们必须添加另一个步骤实现在这个边界情况下选择正确的月份。
数据定义
业务流程中产生的业务实体,必须明确所有的字段、字段类型、取值范围、数据来源等信息。
字段 | 类型 | 必须/默认值 | 说明 |
---|---|---|---|
code | String | 必须 | 课程编号,全局唯一 |
name | Enum | 必须 | 课程名称 |
... |
注意:表格中说明不宜过长,对于某些需要复杂说明的字段,应当为其单独开设下级标题进行详细描述
对 JSON 数据,可以直接使用 JSON 格式展现,如:
{
// [必须] 课程编号,全局唯一
"code": "CLASS-001",
// [必须] 课程名称
"name": "语文 1",
// [必须] 课程类型,可选值:文科=`liberal`、理科=`science`
...
}
操作流程
这里还可以写更小白一些 但一般大多数人不会这样去写
假设我想预订4月14日的游泳池,需要在4月11日的任意时间运行以下命令:
python book.py --username xxxxxx --password xxxxxx --day 14 --time ‘5:00 PM’ --sport small_pool
程序将每休眠1秒钟被唤醒检查一次时间,这个检查不会有任何明显的CPU消耗。Caffeinate将阻止操作系统进入睡眠状态,直到午夜时分。
在4月12日午夜,它将启动Firefox浏览器,并自动完成预订。之后,Caffeinate进程和主进程都将退出,操作系统将正常进入休眠状态。
4月12日的早上,我会看一下日志,看看预订是否成功。
一个有趣的事实
竞争确实非常激烈,通常在第1分钟预约就结束了。每个时段总共只有6个名额,毫无疑问,在早上6点预订是不可能的。
更复杂的设计文档
需要增加更多内容来说明
一、拆分大型系统的设计文档
将文档划分为层级:
1、基本设计:描述系统整体架构,不涉及具体功能内部的细节
2、详细设计:描述具体功能模块、具体功能所涉及的业务实体、处理流程、字段定义等
二、概念解释
文档中出现的的概念、业务实体需要明确的定义,避免误解。如:
- 课程class:指的是包含课件、教材的「课程内容」,如:「云计算入门」
- 场次activity:指的是某一个课程在特定时间地点进行的活动,如:「云计算入门 2021 年上海第一场」
并配合示例示例进行说明。如:
- 后台管理员创建并录入「云计算入门」课程(这里操作的是「课程class」)
- 讲师根据排课表,选择「云计算入门」开课,并指定开课时间(这里操作的是「场次activity」)
- 学生根据已经开设的课程,选择城市和时间进行报名(这里操作的是「场次activity」)
- 优于疫情,取消了 2020 年所有的培训(这里操作的是「场次activity」)
- 云计算已经深入人心,没有继续开课的必要,「云计算入门」下架(这里操作的是「课程class」)
三、架构图
无论是系统整体设计,还是单个功能模块的设计,都可以附带架构图方便读者理解。
DataFlux Func 中「订阅器」的架构图
四、项目文件目录
已经成型的项目,添加项目文件目录进行说明:
- 一方面为了让新人能够快速掌握项目整体情况;
- 另一方面为了规范后续开发工作;
DataFlux Func 项目目录说明
五、后面再补上参考链接
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类