人生代码大作业初体验
在大学也呆了一年了,终于遇上了第一个需要多人合作的写代码项目。从四月底分组完成,任务部署下来到七月初接近尾声,在这两个多月的时间里,也算是经历了不少,学到了不少。
项目背景
项目的主体是一个公交车的自动调度系统。公交车行驶在一个环形的轨道上,站点均匀的分布于其上;系统需要支持在每个站点上创建顺时针上车、逆时针上车和下车三种请求,并调度公交车按照一定的策略前往这些站点处理请求。
在一开始我还以为这个策略需要自己优化,通过比较不同组之间调度完成请求需要的时间来决定优劣,想着还有点可怕,后来明确策略的规则是由老师指定。
不过要是真的按照策略的优化来比较程序之间的优劣,想想还是很有趣的一件事情,不过用在一个计算机专业第一节专业课的大作业上显得就有点那啥了。
项目要求使用C语言实现一个控制台中的核心版,再采用 C/C++
相关的图形化框架实现一个动画版。
整个小组由三个人组成。剩下的两个人有 Dev C++
的经历,对于C语言的语法还算是比较熟悉。
项目的管理
构建管理工具
在开始一个项目之前,应该先选择一个合适的技术栈。在选择的时候,不能光考虑自己平时的习惯和技术的先进性,还得考虑组内所有人的合作效率,不能让代码就在你一个人的电脑上能跑起来,同时这个技术得是所有人都比较熟悉的,不能说你在那里吭哧吭哧的都把代码写完了,其他人还搁那看文档和教程。
在 C
语言项目的管理上,我首先排除了一个文件打天下的“传统”生产模式。这个方案的优点是所有人的十分熟悉,不需要任何额外的技术,也对 C
语言的IDE没有任何的要求,不管你是用初学者的常用的 Dev C++
,还是宇宙第一IDE Visual Studio
,都可以打开这个单独的文件然后编译运行。但是,这个方案也就这一个优点了。且不论手工合并很多人撰写代码的复杂繁琐,光是一个长达1000行的文件就看得人头疼欲裂了。
其次我排除了 Visual Studio
,虽然VS也算是一个开箱即用的开发平台。第一,我自己对 Visual Studio
不熟悉,如果在合作开发中遇到了一些VS的问题,我可能也不知道该如何解决。第二,我们验收使用的OJ平台采用的是 GCC
编译器,不同于 MSVC
编译器,虽然编译器行为不同的情况很少遇见,但为了避免这些一遇到就是纯玄学的问题,我还是采用 MinGW64 GCC
编译器,这个编译器也算是我常用的编译器。
最后我选择了利用 cmake
组织项目,MinGW64 GCC
作为编译器的方案。虽然 cmake
还是一个比较新的玩意儿,但是只要编译的模板在一开始写好了,就基本上不用再修改了,并不需要所有人都熟悉 cmake
。其次,cmake
对于IDE没有依赖,几乎所有的主流 C/C++
IDE都支持利用 cmake
管理 C/C++
项目。我这次的推荐IDE是 VSCode
,如果使用 cmake
进行项目的管理,只需要安装一个插件就可以进行开发了,避免了很多麻烦的问题。
Git
本次开发中老师提供了 gitlab
作为代码托管平台,因此在开发过程中我们顺理成章的采用 Git
作为版本管理的工具,虽然组里的同学完全不会。
为了避免对于 Git
的学习占用了过多的开发时间,我没有在项目开始之前花费大量的时间指导他们学习 Git
,而是再讲解了基本的 Git
操作流程,比如 commit push pull
之后就直接开始项目的开发,让大家在开发项目的过程中逐渐熟悉这个工具的使用,在工作中遇到问题再解决对应的问题。同时为了避免合并冲突等比较复杂的情景在早期出现,在最开始开发的时候我让大家都在不同的文件上工作,在后期必须要在同一文件上工作时再来解决合并的问题。
我一直以为,在开发的过程中学习才是进步最快的方式
而且采用 Git
还有一个好处,采用 Github
的 Insight
功能可以轻松的看出大家的贡献值()。
一些技术上的收获
面向对象永远的神
在这次的开发过程中,核心版要求完全使用C语言进行开发,而在动画版中则可以采用C++进行开发。在编写动画版的代码时,我没有简单的重用核心版的代码,而是利用面向对象的方法完全重写了一遍,虽然重写耗费了我不少的时间,但是在重写了之后,程序中不再使用全局变量;控制公交车通过抽象为三个虚函数,不同的策略对这三个虚函数进行不同的实现来达到不同的调度效果,这样核心的控制流只用编写一遍,个人认为优于核心版中几种策略的控制流虽然大体相似但是在细节上均有不同。
/**
* 获得当前公交车应该前进的方向
* @return 公交车前进的方向
*/
virtual int GetBusDirection() = 0;
/**
* 获得公交车在当前指定的策略下应该处理的请求
* @return 请求指针
*/
virtual bus_query_t *GetTargetQuery() = 0;
/**
* 获取公交车现在可以顺便处理的请求
* @return 请求指针
*/
virtual bus_query_t *HandleBTWQuery() = 0;
然而我还是没有对象
Qt
具体参见初学Qt的一点小笔记,QProperyAnimation
那个的多重继承是真的惊艳到我了,感觉在 C++
这样复杂又精妙的语言面前我还有很多可以学习的地方。
单元测试
在这次的开发过程中我引入了 Google Test
单元测试框架以进行单元测试,虽然并不是所有的模块都编写了对应的测试集,但是单元测试的引入真的帮助我们在开发初期解决的很多的小问题。
TEST(rail, CreateRails)
{
rail_node_t *head = CreateRails(10, 10);
rail_node_t *p = head;
for(int i = 1; i <= 10; i++)
{
EXPECT_EQ(p->id, i);
EXPECT_EQ(p->next_node_distance, 10);
EXPECT_EQ(p->last_node_distance, 10);
p = p->next_node;
}
p = head->last_node;
for(int i = 10; i >= 1; i--)
{
EXPECT_EQ(p->id, i);
EXPECT_EQ(p->next_node_distance, 10);
EXPECT_EQ(p->last_node_distance, 10);
p = p->last_node;
}
}
脚本
在开发的过程中总有一些重复性的简单工作,这时 Python
这些脚本语言的妙处就展示出来了。由于核心版是采用线上的OJ平台进行测试,在提交的时候代码为单文件,于是我编写了一个脚本来帮助我完成这个工作。
2021 - 2024 © Ricardo Ren, 由 .NET 8.0.10 驱动。