搞竞赛的时候特别瞧不起做 web 开发的,现在接触了 djangospring boot,我改变了一些看法,很佩服搞出这些轮子的人,也不再认为 web 开发是个垃圾职业了。虽然我还是认为开发岗、尤其是前端岗,本身跟搬砖没什么区别。—— IceBound 学长

一、序言

今天下午成果验收完毕,标志着长达四个月的小学期结束了。趁机会和朋友去新四吃了顿饭,简单庆祝了一下(应该请的,怎么还让人家A了),又整好提到了博客的事情。回来想了想,确实好久没写博客了(不是懒,真没时间 但仔细想了想感觉还是因为懒),趁着这么一件事情结束,就简单写几笔,记录一下这件不大不小的事情。

当然,写这篇博客的灵感还是来自于前几届 IceBound 学长的博客,学长在他的博客里提及了很多学习经验的分享,这也让同专业的我十分受益。当年大一暑假的时候,一边在宿舍里抠脚趾、一边看学长的这篇 2019小学期作业反思 | Icebound 用着我从未接触过的高端框架、还大谈自己有多菜,心里除了羡慕还是羡慕。

现在轮到我自己去写这样主题的博客,又重温了一遍学长写的内容,果然当年不会的东西还是不会。但即使愚笨如我,也能从小学期里面学到什么东西的吧。


二、上半场

整个小学期是分两部分进行的,前半段是在大二下的期末后一礼拜,后半段是在大三上国庆那段时间。由于是三个专业(电商、电管、物联)随机组一个十人的队完成一个项目,所以如果运气好,能抱上一个大腿那就爽翻了,但这个还是得看脸。

我们的项目是要求设计一个迷宫探索系统,简单来讲就是迷宫里面有一个宝藏,电管专业的要去设计一个智能车走迷宫,把宝藏的照片拍出来;物联要用物体识别技术(CV)识别出宝藏的类型,电商专业负责的是设计一个网站的前后端,把这些信息展示出来。我负责的内容就是网站。

然后典中典之,我的两位队友不太懂代码这些的,虽然不太懂但人都很好,我做啥都很支持我)所以抱不到大腿的我打算搞一个“伪”全栈开发,努力成为一个小腿给我的队友抱。

之所以说是“伪全栈”,是因为老师小学期教的前后端技术是 Servlet+JSP,基本上与时代脱节了。但由于之前看过 IceBound 学长的博客,这个信息我很早就知道,但为啥最后还是用了这么一个老掉牙的技术去做小学期,而不是转向更成熟更牛逼的 SpringBoot+Vue 呢?理由当然也只有一个,那就是我懒的学)主要以后的方向还是想做 AI 相关的工作,前后端的知识虽然对码农很重要,但你要我真花时间系统性地学一遍我是坐不住的。

总言而之,听了老师讲了两节(90分钟)满满的前后端干货之后,我就开始了狠狠的自学+实践之旅,到了小学期结束的时候还算是成功搞了一个还算能看的东西出来。


1.1 前端

看 Icebound 学长前端用的是 Bootstrap 框架,我如法炮制也尝试了一下,结果发现这玩意儿是真的香。首先最重要的就是,他是基于 HTML / CSS / little JS 实现的,这表明了它背后的技术很简单,不用像 vue 一样,即使是速成也得耐下心思读一堆手册和语法。

除此之外,Bootstrap 的网格排版非常舒服。他将页面划分成十二栏,你排版的宽度是取决于你分配多少栏位给他的,这样就保证了当你拉伸网页的时候,由于栏的长度也会动态变化,页面里面的组件就可以做到自适应的拉伸,它的整体布局就不会发生改变。 哎呀我也讲不清楚,反正很牛逼就是了!

然后 Icebound 学长在总结反思的时候,提到了他们小组的前端比较烂,所以老师不太喜欢,给打了低分。所以确定是使用 Bootstrap 搭前端之后我做的第一件事,就是全网搜罗好看的前端模板,没想到真给我找到了一个叫做 "Start BootStrap" 的东西,这玩意儿就像他的首字母缩写一样,完全就是傻瓜式前端搭建,非常之无脑,只要你能忍受 ctrl+CV 的痛苦,基本上都可以搭出来一个还算好看的东西。


最终网站的主页展示

哦对了还有,之所以说是伪前端,还因为这个 JSP 根本就不能说是在写前端。 由于你可以在里面掺杂乱起八糟的 JAVA 代码,所以这个网站的前端和后端就像口香糖沾到鞋底一样分离不开,但由于我是单人小学期玩家,所以即使没有完全分离也没有影响游戏体验,不如说当你发现你可以在前端天马星空地写后端代码,这种感觉真是令人舒畅啊(不是

总体看来,写前端的时候没遇上什么大麻烦,即使有什么麻烦 GPT 也帮我解决了,难以想象几年前没有 GPT 的时代大学生是怎么完成他们的小学期的)

还有一件小事,我在学长的博客里面看见他提到了 “模板引擎” 之类的字眼,但本人没接触过 react、vue 之类的技术,如果有读者能言简意赅地在评论区解释一下,鄙人感激不尽)


1.2 后端

后端用的是 Servlet,有一说一我用下来感觉 Servlet 真不复杂,把几个层一分就清清楚楚,反观还是 SpringBoot 一堆乱起八糟的注解和映射才让人头大吧(暴论 感觉以后会被打脸。

这地方还是得夸两句的,我觉得信息黄埔这个名号含金量还是有的,至少从小学期老师教的内容上来看真不差。虽说是过时几百年的老技术,但是比起技术本身,老师的教学内容更多放在了 “思考方式” 这个方面。老话说得好,“计算机世界的本质就是抽象,一层抽象不够就再加一层”, 这个后端分层的想法我觉得也多多少少借鉴了一点。

在小学期项目的后端框架中我设计了四层,我们自上而下地看。首先最顶层是 Servlet 层,它直接负责了与页面(HTTP 请求)的交互。当渲染一个网页时,他会向后端调用 doGet 方法,将一些必要的元素(比如用户昵称,探索总次数等)递交至前端展示;当提交表单时(修改密码,发起一次探索请求),会调用 doPost 方法,执行另一套逻辑。

其次是 Service 层,借助下层 DAO 层提供的接口,为上层 Servlet 提供服务。但其实绝大多数服务都是偷懒直接在 Servlet 层调用 DAO 接口实现的,只有几个逻辑稍显复杂的,出于代码美观的目的做了封装,例如用户登录注册、密码修改。 (笑死,根本没人看代码)

而所谓 DAO 层,全称 Data Access Object,即负责与数据库进行交互,并提供对数据的增删改查操作。这个 DAO 层还是挺重要的,我几乎对于每一张数据库里的表都写了增改查的方法。一开始用老师教的办法写,一个个操作都得手动赋值,写的非常痛苦。然后遛其他人的博客,发现了一个叫做 Dbutils 的工具包,可以方便地对数据库访问的语句做封装,整理之后才发现舒服多了。


DAO 层中实现用户插入的方法

还有一层是独立于其他三层的 VO/DTO 层,其实就是对代码中用到的类(如用户类、探索类、迷宫类等)做了数据封装,他们有人说如果用 JSP 做前端的话,VO 层用 JavaBean 做一层封装会方便许多(可以使用 <jsp:useBean> 的标签等等),但是额哥们儿直接用 Java 硬钢上去了,感觉也还行,就没管这些个花里胡哨的东西。

IceBound 学长在博客里说,这种分层没卵用,Debug 还是从下改到上。但我个人觉得分层这种思想还是很有用的,只要你能保证底层代码不出错,提供的 API 都正常运行,那你在抽象层面上改你上一层的代码,这种体验还是很爽的。有一种从打地基开始、然后搬砖垒墙、最后大厦建成的快感(?

最后一层也不能算层了,Util 属于是一种辅助的工具包。我模仿学长搞了一个什么阿里的数据连接池、MD5 数据库加密,那个连接池感觉挺有用的,进一步优化了我的DAO层代码,但 MD5 数据库加密纯粹是自我陶醉,不仅没啥卵用而且还导致我忘了密码都不知道怎么查(还得找网站做解码


1.3 中期验收

这部分本来感觉从技术层面也没啥讲,但这个博客本质上还是生活分享类的,所以也讲讲所谓的琐事。给我们做中期验收的女老师就是我上文夸的那位,人非常好,当时她一整天都在沙河给我们上课,从早八讲到中午十一点半,吃了个午饭又从下午开始讲课讲到三四点。说是平常不看QQ,但我们有啥问题找她基本上都能即时回复。

可能因为我是一边做一边有问题去问她,老师对我做的东西还挺看好的(但其实本质上就是她讲的那些内容,加了一些花里胡哨的小玩意),最后验收的时候还点名让我到她跟前去验收。要知道一般的组都是找一个助教水一水就过去了,所以那位老师这么关心我,整的我还是挺感动的。

验收是当天上午,八九点就在那里排队等着验收了。我就在哪里叨逼叨,疯狂扣我做的细节在那里扯,然后老师从一些非常宏观的角度问了几个问题,把我问倒了:

  • 当我在解释用户注册的逻辑时,由于我们是机器人走迷宫的系统,要求在注册用户的时候也得注册一个隶属于该用户的机器人。我跟老师讲,我们是先注册一个用户,然后得到了他的用户ID后,再单独在机器人的表中注册一个机器人。那老师就问:“那假设在注册机器人的时候,你的服务器Crash Down了,怎么办?” 我心里一想,我草对啊,如果机器人没注册成功,那你注册用户的操作也得回滚啊!

    之后我在博客里搜了搜,发现 MySQL 确实是支持把两个操作绑在一起,作为一个事务执行的,而事务具有原子性,所以这样就能解决老师提出的问题。但是我太菜了,没弄懂。

  • 我提到用户的功能时,说我们网页支持用户注销,但其实就是把网页重定向到 LoginPage,然后老师就眼尖地说,那你返回上一个网页看看,结果发现还能回到之前用户的页面,这下又烂完。

唉反正除了这两个问题,验收还算是比较顺利的,唉我猜的,我也不知道行不行。但是老师人真的挺好的,按理说上完期末的小学期之后老师就不用管我们了,但是之后国庆我找老师问问题,老师还愿意耐心地跟我探讨这个可行性,这让我觉得挺开心的,如果老师教的是 SpringBoot 我将称之为绝杀,可惜教不得。


三、下半场

按道理小学期到这里,我负责的部分已经写完了,那应该也结束了,但是更痛苦的是你还得负责和电管的小车、物联的物体识别算法对接,,,对接永远是最哈人的事情,因为每个组对于各自的知识都存在一定壁垒,如果不太清楚自己的需求以及对方的能力,很容易就能吵起来)至少我已经看到有些组就在互相甩锅的了。

但平心而论、我们三个专业的真还行。电商就不用说了,我一个人杀穿小学期,其他两个专业有啥问题找我就行,可惜的是出了问题不能甩锅给别人,这一点有些难受;物联的是训一个图像分类模型,他那个可以调预训练模型,而且也就十几行代码,感觉有点水,没想到的是他们组也觉得自己有点水;电管我草,一组全是爹,天天跑学八地下室,顶着潮湿闷热的空气、蹲着看小车跑迷宫,或许有夸大之成分,但不可置否,他们做的工作确实最多,因此小学期主要也是他们专业的在推进度。

辟谣,物联的代码不止十几行)最后验收他们的PPT展示的代码挺多的,每天蹲电脑前等着模型训出来也不容易,这下那个专业最摆一目了然了。

我是快国庆的时候被找上门来的,当时终于要对接了,他们就问我电商怎么一个对接法。我说那我写一个网页,你们开始探索迷宫了我就摁一下开关,结束探索我在摁一下记录到数据里面;图片的话你们看看能不能直接传我本地,我直接读本地的照片展示就行。

电管的叠又问我能不能做实时地图,他们能给我提供三个方位的距离传感器。我心想你给这玩意儿让我咋算啊,然后就说我尽力而为。过了几天他又过来追问一遍,我就摆明了跟他说我不会搞,我顶多写一个能接收照片的页面完事儿了。没想到的是过了一天,他又来问我说这个地图是不是算分的,能不能努力做一下,整的我这个血压陡增啊。我都说了我不会搞了,咋还天天吊打我。为了说明这个东西不是我菜所以做不了的,我把问题还问了老师,老师听完问题也沉思了十分钟,之后跟我说很难实现。那位大哥这才作罢。

其实事后想一想,如果能给我提供坐标信息而不是距离信息的话,或许还是可以做一做的,但当时确实就是懒了,所以也没问他这回事情。后来验收的当天上午看到有的组通过坐标信息实现了实时地图,搞得我还是蛮尴尬的,总感觉是这次小学期的一个小缺憾。

说这个事儿其实目的是想说,这个不同专业的壁垒确实是存在的,所以交流的时候尽量多找找该专业的其他同学,多交流交流,有问题多问问其他同学了解实际情况,明辨是非(?


2.1 电商对接

由于每个专业的对接我都掺和了一点,所以都可以在博客里面聊聊(即使现在已经 4.5k 字了)。电商这个网页就没啥说的了,比较手工:首先选择好迷宫的类型,等到电管的小车在放下去探索迷宫的时候,摁下 “开始探索” 的按钮。

然后我写了一个自动化的脚本,具体是干什么的之后再聊,反正这个脚本最终可以把拍摄到的宝藏以及对应的类型返回到本地的文件夹,然后我刷新一下资源(很关键!),再刷新一下网页,就可以显示在页面上。但这个页面比较丑,就不展示给大家看了))之后只需要摁一下 “结束探索” 的按钮,就可以把数据插入到对应的数据库中,也是比较基础的操作。


“启动探索”界面

2.2 电管对接

电管各组的小车尽不相同,我就聊聊我们组的情况。实时地图的事情之前讲过了,确实没想明白其他组是怎么实现坐标信息的(因为你连初始坐标也不知道吧)。但是听说为了让小车能正常走完迷宫而不被卡住,来来回回调了很多次参数,包括摄像头模块、WIFI模块都非常折磨人,这一点还是很感谢电管同学的付出的。

最后为了实现探索迷宫的自动化,我们采用了将图片发送至网页,并且借助爬虫工具将照片爬取至本地的方法。爬虫工具也是电管哪个大叠写的,改了他的代码还被骂了一顿))但当日验收的时候WIFI模块和爬虫都没有爆炸,谢天谢地。


咱们组的小车

2.3 物联对接

由于对机器学习的部分略知一二,因此对物联的工作更感兴趣一些。实际和物联的同学打过交道才发现,一个个都是真的爹啊。

事情是这样的,验收前一天晚上我们打算把原来的手动拍照改成自动拍照了,这就引发了一个问题:因为是每隔 0.5s 爬取一张照片,那么实际包含宝藏的照片肯定很少,大部分估计都是墙壁的照片。那么墙壁的照片会不会被误识别呢?

我们首先找电管的人要了一组小车实际运行过程中的照片,确实如我们所想的一样,140张照片中120张都是墙,只有20张是魔方。我们直接拿原来的模型训了一下,发现墙的照片会有10%的几率被误识别成 book 类别,但即使是如此小的误识别率在极大的基数下也会出现 15~20 张误判的照片,而实际被识别成魔方的只有 11 张,这下烂完了。

那得想办法啊,我一开始的想法是再额外训一个类别叫 wall,然后把这一伯张照片丢进去训练,物联的大叠立刻否定了这个提案:首先你这个照片的数量太少了,正常训练集都是要 1k 左右的数据量的;其次你这些照片都没有做过标注,都用不了。

之后物联大叠的室友给出一个方案:把wall作为空标签训练,这样不用标注,看到 wall 这种样子的照片就直接屏蔽掉,因为也不用作为一个标签,用不到那样子程度的训练集。我们觉得这个方法可以,连夜开始加练模型,两位大叠训到 2 点多,训出了三版新的模型。用新模型测试发现,墙被误识别的概率极大地降低了。


验收前一晚,物联组展开的工作

2.4 终期验收

之后验收部分也就可以几笔带过了,当天的心情确实还挺紧张的,但更多地还是兴奋吧,准备了一点稿子,但最后居然还是脱稿讲的多,感觉口语确实还得练,讲得超过五分钟嘴就开始瓢得不知道再说什么单词了

我们组一开始就展示了小车探索迷宫的功能,博主是一个猪鼻,第一次没连上小车WIFI模块发送的网络,连到 BUPT-portal 去了)但是第一次探索失败后我立马切到了探索展示的页面,并向老师展示了即使因为某些不可抗性因素没有找到宝藏,我们也能在对应的区域输出 “Treasure Not Found!” 的异常处理,应该还是挽回了一些颜面(我猜的

实物展示后就是 PPT 朗读环节,我做了四页纸 PPT,但是我又觉得读 PPT 太无聊了,“Talk is Cheap, show me the Website!” 本着这样的想法,我直接打开网页给老师展示我们实现的各种功能,并且像中期验收一样接着给老师抠细节))结果这一抠不要紧,把我们组的展示时间抠没了,此时物联的还没做展示呢……

然后又挤占了一些时间,让物联的同学把他们的内容展示完,此时老师也没时间问问题了,随便问了问物联训练集的大小之类的问题,验收就结束了。老师人挺好的,我们在配环境的时候也在耐心等我们,结束的时候还夸我们组做的挺好的)

总之,结束啦!


四、后记

感觉后记也没啥说得了,这博客都六千多字,有些哈人))应该收手了。刚开头没想好自己在小学期里学了啥,现在回顾了一遍全流程,感觉除了一些过时的前后端技术以外,还是下半场各个专业对接的时候更让人激动吧。感觉我们组真的有不少大叠,和大叠交流总是让人愉快的。

感觉虽然在组织上大大小小也出现了一系列问题,但是这种小学期的形式还是挺有意思的:让不同专业的同学在一起,各司其职地完成工作,最后汇总到一起真正做出一个还能看的东西,成就感也多多少少会有一点。

嘛,小学期结束了,接下来又会有其他乱七八糟的事情,将本就贫瘠的本科生活冲刷得粉碎吧。从学习中汲取营养、而非向学习输血的日子,又可以在哪里寻求呢?