结对编程项目总结

1.代码库地址

https://z.gitee.cn/zgca/repos/yolo12318/Elevator

2. 时间预估

PSP 阶段阶段说明预估耗时(分钟)
Planning 计划 10
· Estimate · 估计本次任务所需时间 10
Development 开发 290
· Analysis · 需求分析(包括学习新技术) 30
· Design Spec · 生成设计文档 20
· Design Review · 设计复审 15
· Coding Standard · 代码规范 5
· Design · 具体设计 40
· Coding · 具体编码 120
· Code Review · 代码复审 30
· Test · 测试(自我测试,修改代码,提交修改) 30
  总计 300

3.接口说明

3.1. Information Hiding(信息隐藏)

应用实例
API Client 封装
# elevator_saga/client/api_client.py
class ElevatorAPIClient:
   def __init__(self, base_url: str):
       self._cached_state: Optional[SimulationState] = None  # 隐藏缓存实现
       self._cached_tick: int = -1
       self._tick_processed: bool = False
关键设计
  • 将HTTP通信细节隐藏在_send_get_request_send_post_request私有方法中

  • 缓存机制完全封装,外部只调用get_state(),无需关心是否使用缓存

  • 用户无需了解底层序列化/反序列化过程

优势:客户端代码不依赖具体的HTTP库或通信协议,便于后续升级(如改用WebSocket)


3.2. Interface Design

抽象基类定义标准接口

# elevator_saga/client/base_controller.py
class ElevatorController(ABC):
   @abstractmethod
   def on_passenger_call(self, passenger: ProxyPassenger, floor: ProxyFloor, direction: str) -> None:
       pass
   
   @abstractmethod
   def on_elevator_idle(self, elevator: ProxyElevator) -> None:
       pass

关键设计

  • 使用ABC定义所有调度算法必须实现的事件回调接口

  • 统一的数据模型(models.py)确保客户端和服务器类型一致

  • 清晰的生命周期方法:on_init()on_start() → 事件循环 → on_stop()

优势:算法开发者只需继承ElevatorController并实现抽象方法,无需关心底层事件循环和状态同步


3.3. Loose Coupling

Proxy模式解耦

# elevator_saga/client/proxy_models.py
class ProxyElevator:
   def __init__(self, elevator_id: int, api_client: ElevatorAPIClient):
       self.id = elevator_id
       self._api_client = api_client  # 通过API通信,不直接访问状态
   
   def go_to_floor(self, floor: int, immediate: bool = False):
       return self._api_client.go_to_floor(self.id, floor, immediate)

关键设计

  • 客户端算法通过Proxy对象操作电梯,不直接修改状态

  • 所有状态变更通过API请求完成,服务器统一管理真实状态

  • 事件驱动架构:控制器响应事件而非轮询状态

优势

  • 客户端与服务器完全解耦,可独立部署和测试

  • 支持多客户端同时连接同一模拟器

  • 算法代码不依赖具体的模拟器实现


4.结对编程中的实践总结

原则具体实践协作方式
Information Hiding 一人负责API Client封装,一人负责调度算法 通过清晰的公共接口协作,内部实现独立开发
Interface Design 共同设计抽象基类和数据模型 先确定接口契约,再分工实现客户端/服务器
Loose Coupling 通过HTTP API分离前后端 并行开发,使用Mock数据独立测试

核心收益

  • 降低模块间依赖,便于分工协作

  • 提高代码可测试性和可维护性

  • 支持算法快速迭代而不影响模拟器核心

4. 重要模块接口的设计与实现

核心接口:ElevatorController抽象基类

通过ABC模式定义事件驱动接口,子类只需实现8个关键回调(on_passenger_callon_elevator_stopped等),框架自动处理事件循环和状态同步,实现算法与底层解耦。

算法关键点:SmartElevatorScheduler

核心策略:LOOK算法+BUS模式混合调度

  1. 优先级决策:车内乘客目的地 > 同方向等待请求 > 反方向请求 > 空载巡游

  2. 方向一致性:电梯保持当前方向直到无同向请求才掉头,减少抖动

  3. 永不空闲:借鉴BUS模式,确保电梯始终移动,避免idle状态造成的响应延迟

独到之处

  • 双层目的地维护:通过in_elevator_destinations字典追踪车内所有目的地的计数(支持多人同目的地),避免过早清空导致提前停靠

  • Tick快照机制:每tick刷新等待队列快照(waiting_up/down),避免事件处理过程中集合失真

性能表现

  • 优势场景:上下班高峰、单向流量密集场景(如up_peak),因LOOK算法顺路接人效率高

  • 劣势场景:完全随机的跨楼层流量,因优先服务同方向可能延迟反向请求,不如完全公平调度


5. 需求变化与代码重构

重构实例

当增加"多场景自动切换"需求时,通过在SmartElevatorScheduler中覆盖父类_run_event_driven_simulation方法,添加auto_next_scenario标志位控制场景结束后的行为(自动切换/等待手动),无需修改基类代码。

回归测试

使用框架内置的11个流量场景文件(traffic/*.json)作为测试集,每次修改后依次运行所有场景,对比核心指标(平均等待时间、P95等待时间、完成率)确保无退化,通过Git提交前手动验证保证稳定性。

Pull Request流程

采用功能分支开发模式,本地测试通过后提交PR,由另一人Code Review检查代码规范和逻辑漏洞后合并到main分支,共完成5次主要PR(架构设计、算法实现、GUI开发、性能优化、文档完善)。

遇到的问题:合并时出现过api_client.py缓存逻辑冲突,通过当面讨论确定保留基于_tick_processed标志的版本,舍弃基于时间戳的方案。


6. 代码规范与质量保障

规范共识

采用PEP 8规范 + Google Python风格(docstring格式),通过配置pyrightconfig.json启用严格类型检查,要求所有公共接口必须添加类型注解和文档字符串。

异常处理

  • 网络异常:API Client的所有HTTP请求使用try-except捕获urllib.error.URLError,转换为RuntimeError并带上下文信息

  • 状态不一致_update_wrappers方法检测电梯/楼层数量变化时抛出ValueError,防止状态错位

  • 连接失败:GUI中使用try-except包裹get_state(),无连接时显示友好错误提示而非崩溃


7. 界面模块设计(MVC模式)

GUI实现:Streamlit框架

界面模块gui_app.py包含3个关键函数

  • render_elevator_visual:电梯井道ASCII可视化

  • render_floor_info:楼层等待队列表格

  • render_metrics:性能指标卡片

MVC架构体现

  • ModelSimulationState及相关数据模型(models.py

  • View:Streamlit渲染函数(render_*系列)

  • ControllerElevatorGUI类协调调度器和UI交互

模块对接

  • GUI通过ElevatorAPIClient获取状态(Model层),不直接访问调度器内部

  • 控制操作(启动/停止/切换场景)通过ElevatorGUI封装,调用API Client方法

  • 调度器运行在独立线程,通过线程安全的API通信避免状态竞争

功能截图:界面显示实时电梯位置、方向、载客数、楼层等待队列和性能指标(平均等待时间、P95等待时间、完成率),支持启动/停止调度、切换场景、自动刷新等交互。


8. 结对过程描述

结对编程采用Driver-Navigator模式,一人编码(Driver)时另一人实时审查代码逻辑和规范(Navigator),每30分钟交换角色。关键设计决策(如接口定义、算法优先级)通过白板讨论达成共识后再动手实现。主要协作场景包括:架构设计时共同绘制类图、算法调试时结对排查事件处理逻辑、性能优化时分析不同场景的瓶颈。

lQDPJwqRmE3fR__NDADNEACwRFtXwxiSG-QI1J_-8csZAA_4096_3072

 


9. 结对编程方式与评价

合作方式

采用Driver-Navigator轮换模式,结合Ping-Pong模式(一人写测试用例,另一人实现代码使其通过),核心模块设计采用面对面讨论确定接口后分工实现。

结对编程优缺点

优点

  1. 实时代码审查减少低级错误(如类型错误、边界条件遗漏)

  2. 知识共享加速技能提升(学习对方擅长的领域)

  3. 设计决策质量高(双人讨论避免主观盲区)

缺点

  1. 时间成本高(简单任务两人协作效率不如单人)

  2. 节奏不匹配时易产生摩擦(编码速度差异)

  3. 远程结对受限于工具和网络延迟

伙伴评价

优点

  1. 逻辑思维严谨,能快速发现算法边界条件漏洞

  2. 代码风格规范,注释和文档意识强

  3. 学习能力强,对新框架(如Streamlit)上手快

缺点:过于追求完美主义,有时在次要细节(如变量命名)上过度纠结影响进度

三明治改进法

正面反馈:"你对代码质量的高标准让整个项目非常规范,这是我特别欣赏的。" 建设性意见:"不过在时间紧张时,我们可以先实现核心功能,把命名优化等放到重构阶段,这样能更快验证思路。" 正面结束:"你的这种严谨态度其实也帮我养成了更好的编码习惯,我们可以商量一个优先级标准来平衡完美和效率。"

10. 实际时间消耗

PSP 阶段阶段说明实际耗时(分钟)
Planning 计划 30
· Estimate · 估计本次任务所需时间 30
Development 开发 360
· Analysis · 需求分析(包括学习新技术) 60
· Design Spec · 生成设计文档 20
· Design Review · 设计复审 20
· Coding Standard · 代码规范 10
· Design · 具体设计 40
· Coding · 具体编码 120
· Code Review · 代码复审 30
· Test · 测试(自我测试,修改代码,提交修改) 60
  总计 390
posted @ 2025-10-24 21:00  foss  阅读(14)  评论(1)    收藏  举报