结对编程项目总结

项目 GitHub 地址:https://github.com/LoadStar822/Elevator

Elevator 结对开发纪事:从调度算法到协作关系

仓库地址:https://github.com/LoadStar822/Elevator

这篇文章想做两件事。

一是把这段时间我们在电梯调度项目里沉淀下来的“硬指标”——时间、缺陷、接口约定、策略演进、MVC 分层等——完整记录出来,方便后续写 README、做答辩、或直接放到项目主页当作技术档案。

二是以“亲历者”的角度,讲讲我和搭档是怎么真正把这些东西做出来的:我们怎么分工、怎么决策、怎么吵架、怎么互相把对方拉出坑。老实说,这部分对我来说甚至比代码本身更重要。

为了方便查阅,我把文章拆成几个独立章节,读者可以挑着看:


1. PSP 时间记录

我和搭档从开始就决定:不“拍脑袋做项目”。我们用 PSP 2.1 模板去跟踪哪一块花了多少时间、偏差在哪、为什么会偏差。听上去有点官僚,但实践下来非常值,尤其在后期复盘的时候,很多“为什么后来会这么做”的答案都能在这些记录里找到。

下面是按阶段拆分的预计 vs 实际耗时(单位:分钟)。这些数据覆盖了从第一次提交(2025-10-12)到当前提交(2025-10-18)这一整段主力开发周期,累计约 125.5 小时。

PSP 阶段子任务 / 说明预估时间(min)实际时间(min)误差原因备注
计划阅读项目文档、梳理仓库结构、确认评测口径360320前期资料准备得比较细,沟通成本低我们在一开始就把 core / server / client / traffic 的边界划清了
开发下面是开发期细分项
· 需求分析明确电梯/乘客的事件模型、Tick 驱动方式780720后面拿到了一些补充样例,少走弯路产出了一版接口契约草稿
· 设计文档系统结构、调度框架、关键状态机600540很多架构草图直接复用我们之前的模板文档里包含 UML、伪代码、数据流示意
· 设计复审两个人坐下来过接口和策略一致性240210问题在会前列得很集中一次会就敲定共识
· 代码规范命名、日志、类型注解、格式化约束210180直接采用 Black / isort / mypy 的组合最后沉淀成一个提交前 checklist
· 具体设计把 SCAN、分区调度、应急策略、状态机细化960900若干场景沿用先前分析结论,所以没完全从零想最终落地为状态机和数据结构表
· 代码实现调度主循环、事件处理、HTTP 客户端26402500框架骨架提前搭好,写代码相对顺我们在这一阶段正式引入异步任务和锁
· 代码复审自查 + 对方查420480多线程共享状态讨论出了更多坑我们在这一步补了线程安全
· 测试单测 / 模拟器跑场景 / GUI 联调900961集成回合比预估多一轮我们覆盖了高峰和离峰两种流量分布
报告下面是收尾期工作
· 测试报告整理等待时延分布、能耗指标、异常案例260240指标脚本早期就写好了我们拿到了 95% 等待分位和能耗曲线
· 计算工作量LOC、提交次数、测试样本数量150180统计口径中途改过一次,返工一点点自研增量约 2792 行
· 总结与改进计划README、复盘、后续规划330300开会前我先写了大纲,成稿就轻松很多后面也会用这些素材写公开博文
合计78507531平均误差约 -4.1%≈125.5 小时

1.1 项目指标快照

指标数值说明
新增/修改有效代码行(LOC)2792以提交 f5a9933 为基线,统计我们后续新增或修改的 .py / .js / .ts / .tsx / .css 非空非注释行
签入次数9git log f5a9933..HEAD --oneline 的提交数
测试用例数25来自 pytest --collect-only
周期7531 min也就是约 5.2 天的“真花下去的工时”,不是自然日
缺陷率待补仓库当时没完整维护缺陷清单,之后我们会回填
缺陷总数(交付后)待补同上

1.2 缺陷情况(我们踩过的坑)

缺陷 ID阶段(引入/发现)类型严重度现象修复用时(min)成因修复方式备注
D01设计 / 测试状态机逻辑电梯到顶层后不会正确反向32没考虑边界层行为增加方向反转和等待逻辑是压测才暴露出来的
D02编码 / 自测异步阻塞某些长任务把事件循环卡住了30少写了 await把耗时逻辑拆成协程并 await这次我被同伴现场抓包 😅
D03编码 / 自测数据一致性日志里的乘客数和实际状态对不上18没加锁引入锁 + 原子计数器多线程真是“玄学现场”
D04测试 / GUI性能同时等待乘客 >120 时 GUI 掉帧42重复全量刷新引入增量渲染 + 节流我们后来基本不再全量重绘
D05测试 / 模拟器日志顺序Tick 日志“乱序”20多线程直接往日志写改成队列缓冲、串行输出排查过程挺花心思的

我自己的观察
PSP 看似是“管理的工具”,但它意外帮我们解决了一个很实际的问题:哪一块是真正费时间的。在复盘前,我以为测试只是在末尾跑一跑,但实际我们把接近 1/8 的时间都投在“跑不同场景+找边界行为”上。以后再估工时,我会把“调试与集成”当成和“写代码”同等级别的任务,而不是附属品。


2. 结对编程中的接口设计方法实践

电梯调度听起来是“算路线”,但我们一开始最花力气的反而不是算法,而是接口边界。这个边界定得好不好,直接决定后面合作是顺还是乱。

我们最终沉淀了三条接口设计习惯,我觉得可以长期沿用:

2.1 封装:不让“调度细节”在全项目乱飞

assignment/baseline_controller.py 里,派单逻辑不是直接散在事件回调中,而是收敛到一组私有方法,比如:

  • _assign_request_to_best_elevator
  • _estimate_assignment_cost
  • _ensure_pickup_queue_entry

外层只关心“发生了某事”(比如:有乘客呼叫、有电梯空闲),至于怎么评估代价、谁来接单、队列怎么维护,全压在这些私有方法里。等待中的乘客信息被封装成 PendingRequest,不允许直接乱改队列。

为什么要这么做?因为我们俩都是会“临时加逻辑”的人 😂。如果状态散落在回调里,后期调参就是灾难。把它们圈进一小撮函数之后,连我俩吵架都方便了:讨论只需要指向“我们就改 _estimate_assignment_cost 好不好?”

2.2 统一接口:控制器必须像乐高砖一样可以互换

所有调度策略都得实现同一套控制器接口(ElevatorController 风格的 start() 和一系列 on_* 回调),然后由 assignment/main.py 决定到底用哪一个控制器实例、Tick 间隔是多少、是否启用某些策略。这些参数来自环境变量,比如 ASSIGNMENT_CONTROLLERASSIGNMENT_TICK_DELAY 之类。

这意味着什么?意味着我可以在本地起“朴素贪心”版本,他可以起“预测混合”版本,我们跑的是同一套启动脚本、同一套可视化、同一批测试。谁都不用为了试验一个调度策略去改主循环。这一点极大地减少了心智负担。

我个人非常喜欢这个部分,因为它让“我们俩同时写不同策略”变成一件自然的事,而不是互相挡路。

2.3 低耦合扩展:继承只改“怎么想”,不改“怎么被叫”

后面我们有了一个更复杂的控制器 PredictiveHybridController(在 assignment/predictive_controller.py)。它继承基线控制器,但重点只改写了“成本怎么算、怎么分区、怎么守护某些楼层”等逻辑,而没有去动对外接口。

通俗说:对外还是那些回调,比如 on_passenger_callon_elevator_idle,但里面干的事比旧版聪明得多。

这个做法的好处是:

  • 我可以大胆试算法
  • 我搭档不需要改他的可视化、测试脚本和流程
  • 我们可以直接做 A/B 对比,看看两套策略在同一工况下的等待时间差别

我自己的感受
我们有一整天的讨论几乎都花在“接口到底暴露到什么粒度”上。当时会觉得有点“走火入魔”,但事实证明这是最划算的一天。如果一开始没约定清楚这些接口,后面每次改动都会连锁反应,PR 也会难合得多。


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

下面是几个关键模块,它们几乎定义了我们之后所有工作的“组织方式”。

3.1 assignment/main.py:运行时的“指挥中心”

这个模块负责两件事:

  1. 根据环境变量选择到底实例化哪种控制器(贪心版还是预测版)。
  2. 驱动 Tick 循环,让控制器按固定节奏响应事件。

也就是说,控制器怎么写是策略问题,而“怎么让策略活起来并跑在模拟器之上”是 main.py 的工作。

这个分离让我们可以各自专注:

  • 我可以折腾控制器细节
  • 搭档只要保证运行框架稳、退出优雅、参数可控

我们俩的并行效率就是从这里开始上来的。

3.2 GreedyNearestController:事件驱动的基础调度

基础控制器的套路是:

  • on_passenger_call:乘客按了电梯,先把这个请求整理成 PendingRequest,放到等待队列。
  • on_elevator_idle / on_elevator_stopped:电梯空闲或者刚停下,就尝试用 _assign_next_target 决定下一步去哪儿。
  • 细节判断(距离、载荷、方向一致性)被拆进独立的小方法,方便单测和后续局部调参。

我和搭档当时的共识是:这个版本一定要简单、稳定、可解释。 因为它不只是策略 A,它还是我们后续任何优化策略的“安全回退方案”。

3.3 PredictiveHybridController:在“不会坏”的前提下变聪明

Hybrid 控制器是在基线的行为骨架上,额外加入了“更聪明”的局部决策:

  • _rebalance_zones:根据楼层分布动态给电梯划“负责区”,防止所有电梯都往一楼聚集。
  • _update_floor_guards:给长时间没被服务的楼层挂保护标记,强制调度其中一部电梯去兜底。
  • _estimate_eta:不只看“我离你近不近”,还预估“什么时候实际能到”,这点对高峰流量时很关键。
  • _mark_request_assigned / _clear_request_assignment:手动维护某请求已经被哪个电梯“认领”了,避免撞单。

这部分更多是我在主导,但它能无缝运行起来,完全依赖我们一开始把回调接口标准化了。

3.4 代理层:elevator_saga/client/proxy_models.py

这层对我来说很像“防爆垫”:

  • 我们不直接把模拟器里的原始状态对象丢给调度器,而是包装成只读的 ProxyElevatorProxyFloor 等模型。
  • 调度器只需要把它当本地状态看就好,不会不小心写乱模拟器的内部数据。
  • 测试时我们还能塞入虚拟代理对象,伪造各种极端工况,验证调度逻辑的鲁棒性。

说直白点:这是我们“安全玩数据”的手套。没有它,多线程和网络状态就会在调度逻辑里到处乱窜。


4. 算法关键与独到之处

我们一开始不是奔着“最智能”去的,而是先做“不会乱跳的”,然后逐步往“做聪明决策”迭代。这一节就按这个顺序说。

4.1 第一阶段:就近服务,但别太盲目

基线调度(我一般叫它“贪心调度”)的主要逻辑可以总结成一句话:

“谁离得最近,谁去接。”

不过我们后来发现,“最近”远远不够。现实要考虑至少这几件事:

  • 电梯当前方向是否顺路
  • 这部电梯是不是已经快满员
  • 那个楼层是不是已经有一堆人在等了
  • 某个请求是不是早就等了很久

所以我们把这些因素变成权重,加入到 _estimate_assignment_cost 里面,让“最近”变成“综合成本最小”。这样以后要调参数,我们可以改权重而不是推翻逻辑。

我个人觉得这是策略里第一次“从直觉变成模型化”。

4.2 第二阶段:不是“要不要接单”,而是“我接这个单的后果是什么”

Hybrid 调度是在贪心的骨架上叠加“前瞻意识”。

核心差异是:

  • 贪心:看当下距离最近的活,马上去做。
  • Hybrid:在接这个活之前,先问一句 —— 我接了会不会让别的楼层彻底没人管?会不会导致整栋楼的流量不平衡?我是不是应该先去救火而不是顺路拉客?

为此我们引入了:

  • 分区重平衡_rebalance_zones):电梯之间不是全都“自由接单”,而是动态形成“你管上半区,我管下半区”之类的责任划分。这个动作可以有效避免“全去热门楼层、冷门楼层被遗忘”的情况。

  • 楼层保护_update_floor_guards):系统会盯住那些已经等太久的楼层,给它们打一个“必须优先处理”的标记(我叫它“挂红旗”)。这样可以压低最长等待时间,减少那种“大家平均等得不久,但有一个人崩溃地等超久”的极端糟糕体验。

  • 动态限载:当电梯的占用率超过我们定的阈值(我们使用的是 75% 这个级别),我们会避免继续往这台电梯塞更多新任务。否则就会出现“这电梯到处都说好顺路,我全接了”,然后车厢像移动监狱一样永远坐不空。

  • 同层顺带:电梯既然已经在某一层开门了,能不能顺手把同层等待的乘客一波带走,而不是为同一层来回跑两次?我们在停靠逻辑里加了这个“小抄近路”的优化。

4.3 我们觉得“最妙”的点

我个人最满意的不是某个具体 trick,而是这种节奏:

  1. 先把系统做成不会乱(基线稳)。
  2. 再往里面慢慢加“聪明行为”(Hybrid 特色)。
  3. 每加一项“聪明”,就看有没有副作用,比如 CPU 飙了、某场景下反而更慢等。
  4. 有副作用就把它参数化或降频,而不是直接删。

这个迭代方式让我们能稳步往上走,而不是一口气造一个“看起来很智能,但基本不可调”的黑盒。


5. 性能表现与对比分析

我们做了几轮压测(包括高峰/多电梯协同以及比较平静的低流量场景),然后把贪心版和 Hybrid 版拉到一起对照。

可以总结成三句话:

  1. 高压场景下:Hybrid 更稳。
    在人很多、电梯多的情况下,Hybrid 能明显拉低平均等待时间,而且把“等特别久的那几个人”这个长尾也压了下来。简单讲就是:它救火能力更强。

  2. 平静场景下:贪心更省。
    当流量本来就不大、大家都散得很平均时,Hybrid 的那些分区重平衡、保护机制、能耗考量……其实是多余的计算负担。这个时候贪心策略反而因为“够直接”而更高效。

  3. 区别的根本原因:有没有“想未来”。
    贪心型思路本质还是“眼前就近服务”;Hybrid 把“如果我现在去那一层,会不会导致别的区域无人照顾”这种问题算进来了。所以 Hybrid 特别像“调度+调度管理”,而贪心是“调度执行员”。

我的感受是:我们没有哪一个“碾压式的赢家”。我们更像是得到了一个在不同场景下可切换的策略库。这点非常现实——在真实部署里,也不会永远只有一种人流模式。


6. 重构与协作实践

这章是我个人最想讲的,因为它直接关系到“我们俩是怎么把项目活着送到现在的”。

6.1 我们怎么分工

我们把任务拆成两条主线:

  • 一条是“调度大脑”(调度循环、派单策略、状态一致性),
  • 一条是“可视化与控制台”(Web 面板、指标展示、启动/停止控制、测试场景切换)。

但我们从来不是“一人负责一条线,互不干涉”。我们用的是轮换式 pairing:这小时我写策略、他盯我;下一阶段他改 Web API、我盯他。
这种轮换有两个好处:

  1. 双方都对两条主线足够熟,不会出现“只有某个人能改那块”的单点。
  2. review 不会流于形式,因为盯的人真的知道上下文。

6.2 当需求变了,我们怎么不崩

一个真实案例:后来我们需要把“能耗”也纳入考量,并且支持动态流量模式。这个需求一出来,意味着老的成本估计函数要被拆得更细。

我们没有直接在老代码里“打补丁”。而是先把基线控制器里的大块逻辑(比如 _estimate_assignment_cost_is_elevator_capacity_full)抽成更细、更小、更可单测的函数,然后在 Hybrid 控制器里重写这些点位,接住新需求。

这个做法看上去慢,但它带来的回报是:外部接口完全没变,原有测试基本不用动。也就是说,我们引入新特性的时候没把现有稳定性打碎。这种“先拆→再覆写→不动外壳”的策略,是我们俩协作中非常重要的一个共识。

6.3 回归测试怎么帮了我们守住底线

每重构一轮、甚至每次比较大的 PR,我们都会把整套 Pytest 跑一遍。我们重点盯的用例包括:

  • tests/test_greedy_controller_assignment.py:贪心分配行为有没有被改坏
  • tests/test_controller_switch.py:调度控制器切换是否安全
  • tests/test_simulator_boarding.py:上/下客流程是不是稳定

如果某个修改会影响边界场景(例如:最后一名乘客走了以后系统是否能顺利停下来),我们就现写断言,把那个行为钉死。

我以前写测试的动力,说实话,没这么强。现在我理解了——当两个人共用一套代码库的时候,“我相信你,但我更想看绿色的测试结果”是很健康的关系。

6.4 合并流程和冲突化解

我们用的流程是:功能分支 → 写明背景和影响 → 提交 PR → 对方审 → 合并到主干。

有一次(非常典型的一次),GUI 那边为了展示等待队列,往 PendingRequest 里加了一个新字段;调度那边同时也在改那块代码的逻辑。这俩提交碰在一起了,合并直接红。

我们没有互相压提交,而是把“多出来的新字段”单独抽成一个独立 commit,PR 里明确解释为什么要这个字段以及它和调度无关,然后才合并逻辑变更。
这听上去像是很小的技巧,但它让合并过程干净很多,也让我们减少了“吵到底谁动谁的文件”的火药味。

我自己的观察
我过去是“先写功能,后想结构”的人。这次我被迫学会了另一种节奏:先把边界划清楚,再往里面堆复杂度。这在多人合作时真的特别关键,因为它让冲突变成“接口怎么协调”,而不是“谁的代码更重要”。


7. 代码规范与质量保障

7.1 基线约束是我们自己定的

项目刚起步的时候,我们就把风格、排版和类型检查定死:

  • 统一用 Black(120 列)+ isort
  • 类名用 PascalCase,变量/函数用 snake_case
  • 能写类型注解的地方尽量写上
  • public 函数/关键模块必须配 docstring 或行内注释

这些不是摆在 README 里给老师看的,而是真正作为“没做到别提 PR”。我很快就发现:这种做法可以极大降低 later review 的情绪摩擦,因为 review 时我们不再在风格上纠缠,直接讨论逻辑本身。

7.2 运行时的兜底保护

在调度的主循环(类似 _run_event_driven_simulation 那个函数)外层,我们包了一个大的 try...except。目的不是隐藏错误,而是确保一旦和模拟器的通信出问题,我们能有序退出、记录日志,而不是整套 GUI/控制进程直接炸掉。

同样地,在 _assign_next_target_mark_request_assigned 等关键点位,我们也保留了可以回滚或打出详细日志的分支。
这在 demo 场景里可能显得“啰嗦”,但在长时间跑模拟时,它是救命的。它可以告诉我们“是哪个请求在什么时候导致了状态不一致”。

还有一个我很认可的点:Hybrid 控制器在读取环境变量失败时,会自动 fallback 到默认值,而不是直接抛异常停机。换句话说,它优先保证系统能继续跑,而不是优先保证“配置的纯洁性”。这是我搭档坚持要加的,我一开始没意识到它的重要,后来觉得这是对可用性极其务实的选择。

7.3 自动化保障

质量工具这块,我们基本形成了“出 PR 前的三件套”:

  1. black / isort 过一遍
  2. pytest -v 过一遍
  3. 静态扫描(giteeScan)跑一遍,看看有没有过长函数、没捕获的异常、潜在线程问题

有些函数因为太长或者分支太多被扫描工具黄牌警告,我们就会当场拆,比如 web_dashboard.py 里做状态汇总的逻辑,后来我们硬是把它分成了“采集状态”“组装响应”两段。

这套流程的副作用是:PR 变得更小、更主题化。我们后来几乎不会再一口气塞十个逻辑变更到一个 PR 里,因为那会很痛苦地过不了这三关。


8. 界面模块设计与 MVC 映射

我们还做了一个 Web 控制台(assignment/web_dashboard.py + assignment/web_static/),用来干三件事:

  • 可视化电梯的实时状态(楼层、电梯位置、等待乘客情况)
  • 显示关键运行指标(平均等待时间、95% 分位、拥挤楼层等)
  • 控制调度器的生命周期(启动、停止、切换场景)

我们在做这个控制台时,刻意靠近 MVC 的分层思路,而不是“前端随便拉后端一把数据就画”。简单说一下三层:

8.1 View(前端展示层)

  • web_static/index.html 把界面分成三大区域:全局状态卡片、实时楼层/电梯舞台、侧边指标栏。
  • style.css 里我们做了变量化布局,电梯数量/楼层数量不同也能自适应。
  • main.js 中有个渲染器(SimpleStageRenderer),专门负责把当前状态渲染成 DOM,包括电梯停靠、乘客上下、排队动画等。

开发顺序上,我们先用静态 JSON 验证布局/动画节奏,之后才接后端。这个步骤对我来说特别重要——它让我可以独立把 UI 的结构和交互打磨清楚,而不需要后端“实时喂数据”。

8.2 Controller(业务控制层)

web_dashboard.py 用 Flask 写了一组路由:

  • /dashboard/start:启动调度
  • /dashboard/stop:停止调度
  • /dashboard/traffic/*:切场景
  • /dashboard/state:聚合状态并返回给前端

这个模块除了充当 HTTP 入口,还有一件很关键的事:帮我们托管调度进程本身
我们不是每次点“开始”就让前端直接拉起某个线程,而是由后端统一管理 _start_controller / _stop_controller,并且用锁控制状态,防止两个“开始”按钮并发点导致重复起多个控制器进程。

这一段是我搭档写的主力,我从他那里学到了一点:UI 层千万别直接操心“线程是什么状态”,那属于控制器的责任;UI 只要问“我能不能开始?我能不能停?”就行。

8.3 Model(数据和指标层)

后端通过 ElevatorAPIClient 去拿模拟器的实时状态(电梯里有谁、每层等了多少人、电梯现在在哪一层、门开没开等等),并汇总成结构化 JSON 返回给前端。

这里我们还计算了一些指标,比如等待时间分布、95% 分位、每层排队长度。UI 不直接算指标,而是拿指标展示。这保证了前端相对“傻”,逻辑集中在后端,后端逻辑再往下集中在模型.

我后来回过头看,觉得这个决定很自救。因为我们确实在后期往指标里加过新东西(例如长尾等待情况),而前端基本不用改架构,只是多展示一栏。

8.4 小插曲

我们在调 Dashboard 的时候踩了两个经典坑:

  • 性能:当排队乘客太多时,前端如果每一帧全量重绘,直接卡到 10 fps。后来我们加了增量更新(谁变了才重画谁),并且对刷新节奏做了节流。
  • 状态竞争:后端那边如果没加锁,可能出现“还没停干净又被启动”的竞态。这个是搭档第一时间发现并修掉的,我很庆幸他一直盯这一块,否则我大概会在后期才意识到这个隐患。

9. 结对协作方式与伙伴画像

这一段是我个人视角,不是官方报告。

9.1 我们的合作模式

我们的模式不是“你写 A,我写 B,合起来就是项目”,而更像是“双人驾驶同一辆车”。

我们轮流当 Driver 和 Navigator:

  • Driver = 正在动键盘、敲实际代码的人
  • Navigator = 一边看大方向、一边当场 review 的人

我们会在合适的时间点切换角色,比如一个子功能完成、或者连续专注到脑子开始钝了(通常一小时左右是真的会钝)。

这个模式对我影响很大,因为它逼着我在写代码时把思路讲出来,也逼着我在当 Navigator 时认真审别人的逻辑而不是“点个赞了事”。

9.2 我眼里的搭档

优点我先说三条(其实远不止三条):

  1. 架构视角强
    他会在一开始就问:“这个接口未来会不会变?如果会变,那我们要不要提前把边界切清楚?”
    这种习惯实际上救了我,因为我比较容易一股脑往里塞逻辑,没太想“未来会不会后悔”。

  2. 对稳定性的执念
    我有时倾向“先让它能跑起来再说”。他则更愿意先想清楚异常路径、并发冲突和以后怎么 debug。
    我一开始觉得“好慢啊”,但后来意识到:我们之所以在后期没有被线程问题搞到自闭,他的提前预防起了很大作用。

  3. 写得出解释性的文档
    很多人写文档是“补手续”,他不是。他会在写代码前先画数据流;我们本篇文章的章节骨架,最初也是他整理的脉络。这种人是那种能把复杂情况讲清楚的人,合作体验非常好。

我也会提一点我自己的建议给他,我也当面说过:有时候他太想把事想到极致才肯下手。我个人会更倾向于“先出一个最小可运行版本,然后不断迭代”。我们后来慢慢达成折中:先做出能跑的最小块,然后用 PR 的方式一块块升级它,而不是憋到“大而全才提交”。

事实证明这个折中方案非常奏效。我们后期有关“能耗策略”和“保护楼层”的改动,就是按这种“渐进式 PR”推进的:小步提交、一直有可运行版本、同时还能往更智能的方向逼近。

9.3 对我自己的冲击

这次协作让我清楚看到自己的一些盲点,比如:

  • 我以前太习惯“我脑子里有图,所以我理解这个系统”。现在我开始习惯把接口契约、状态机的关键转移条件、线程访问规则写成手册式的说明,确保对方不需要进我脑子里才能继续做事。

  • 我以前默认“测试是最后写的”。现在我愿意在写功能时先想“我要怎么证明它真的对”,然后把这个证明固化成 pytest 里的断言。这不是为了老师或 CI,而是为了当对方改我的逻辑时,我们不用靠吵架来决定谁对。


10. 我的个人复盘

写到这里,我想把“这次项目教会我什么”说清楚,因为它对我后面怎么写代码、怎么跟人合作,影响非常大:

  1. 接口不是代码细节,是协作契约。
    我以前觉得接口是个技术问题,现在我觉得接口首先是个团队问题。你把接口定义清楚,其实是在告诉对方“你可以放心动到哪一步,不会踩雷”。这在多人并行时是安全感的来源。

  2. 测试不是收尾工作,是沟通工具。
    当我们往调度逻辑里塞越来越多“聪明行为”的时候,测试用例成了我们讨论的依据。它们不仅在验程序对不对,也在声明“我们到底认不认这个行为是正确的”。测试在这时候非常像是一张白纸黑字的合同。

  3. 图形化视角极大地帮助我们理解算法。
    Web 控制台最开始只是为了“好看一点”。但后来我发现,它其实变成了我们的“观察诊断台”。我在 UI 里一眼就能看到某层长期没人服务、或者某电梯在瞎跑,远比看日志直观。这个体验彻底改变了我对“要不要可视化”的态度——我现在是强烈的“要”。

  4. 结对不是两个人分摊工作,而是两个人互相校准。
    单兵作战时,我的某些习惯其实是危险的(比如先写一坨逻辑再想怎么测);搭档的某些习惯在时间紧时也会拖慢推进(比如想太完整才愿意动手)。我们放在一起,恰好互相修正。
    我从这次合作里得到的,不只是功能、代码和分层结构,还有对“我作为一个工程师的工作方式”的升级。

  5. 最后的最后:这个项目让我确认一件事——写代码不是一个人对着屏幕的孤岛活动。
    我过去对“协作开发”的理解更多停留在“我写我的模块你写你的模块”,但这次是第一次感觉到“我们俩在同一张桌子上共同塑造一个活的系统”。
    这是我非常想保留下来的感觉。


如果你看到这里,感谢你花时间读完这篇既技术又带点情感浓度的长文。

我希望它既能作为我们 Elevator 项目的档案,也能成为一份“我以后回头看还能学到东西”的记录。
接下来我会进一步把能耗策略、分区守护、可视化控制台这些部分拆成更聚焦的文章,单独展开讲“怎么做、为什么这么做、坑在哪”。

如果你对任何细节(包括调度策略、Dashboard 实现、结对开发节奏)感兴趣,欢迎继续交流。

界面效果(博客配图)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

合作照片

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值