在写文章前容许我啰嗦一下:对于软件开发,我走了不少弯路,有时觉得自己作为API侠,无所不能,有时又觉得自己很多LeetCode题写不出来,无能为力。我有一个博客,但是写满了自己的絮絮叨叨,真正有本领的东西九牛一毛。

我甚至没有自己的“代表作”,因为我是一个急性子,想马上得到结果(事实上计算机真能马上给出结果,但开发过程不行)。我经常在“造自己的轮子”和“用别人的轮子”之间徘徊,“造自己的轮子”比较有成就感,但是难度其实很大,需要踩很多别人踩过的坑;“用别人的轮子”则没有什么成就感,做出来也不像是自己做的。而平时工作中,每天都在用别人的轮子,自己真正从比较底层开始实现的情况是非常少的,导致我在闲暇时间也不想用别人的轮子。

啰嗦一下自己的经历:

2004年,我家买了电脑,我也接触了很多电脑上的游戏。但是也许是我心浮气躁或者没有游戏天赋,我总是在游戏里输,总是追不上邻居小伙伴;

2008年,我萌生了“自己写一个什么东西”的想法。

2009年夏,小学毕业的我开始摆弄魔兽地图编辑器,虽然一点脚本都没写,做出来的游戏也粗制滥造。也开始查找“如何创建一个个人网站”。

2010年,在和初中新同学混熟之后,我们打算做一个班级网站,我找了一圈发现5566和phpwindy有免费的论坛可以注册,我们注册了一个论坛,并且想把每天的作业更新发布上去。但事实上那位同学仅发布过一次作业。

2011年,我利用爸妈给我的打游戏的时间,将网页保存下来,咬着牙研读里面的html标签,然后给我当时加入的一个魔兽争霸群做了一个纯html的“官网”。在某免费空间上注册了一个只支持asp和基础web的免费空间,用8uFTP把网站上传上去。

2014年,在学校的图书室,我昧着良心在寻找Dreamweaver的教程书,还真给我找到了。但是我根本没有自己的电脑,只能对着书发呆脑补。

2015年夏,我高中毕业,填志愿的时候几乎把“软件工程”和“计算机科学与技术”都填的满满的。我查了资料发现“软件工程”比“计算机科学与技术”学费更贵,在询问了父母的意见之后,我把“软件工程”填到了第一位,然后和父母说,一定会考上。最后我考上了一个普通的本科,开始学习软件工程专业。

2015年暑假,还有一件事情,我自己注册了(已经失效了的)域名,购买了阿里云的虚拟主机,配置了WordPress服务器,在上面写博客文章。仅仅是备份就花了一周,然后终于拿到了自己的备案号。我永远不会忘记第一次用自己的域名打开自己的网站那一刻的快乐。

2016年春,我推开软件学院大楼某间实验室的大门,然后就我大学一年级就和学长们一起做项目,当时团队里缺人写html页面,而我正好已经算是html css入门了(完全不会js),开始仿写各大网站。然后想自己写一个象棋游戏,结果找资料就找了一个下午,最后不了了之。

2017年夏,我跟着课程开始研究蚁群算法,最后实现了论文的内容。现在回想起来,对着论文依葫芦画瓢其实没什么技术含量,当打包运行并且在台上汇报之后,我真的觉得很快乐。不过,我并没有学到什么“真才实学”。

2017年秋,在Java课上,我带领团队(其实开发就我一个人)用Bmob作为后端,安卓作为前端,开发了一个“今日特价” app。我对着github上的一个高仿微博的项目,拼命的抄各种代码。而最后我觉得写的太差,而把代码都删除了,真是太可惜了。

2018年,我有了很多很多想法,但是都没有执行下去。

  • 我想自己从零搭建一个博客,用新学的SpringMVC,替换掉WordPress。
  • 我想做一个网站,叫做“预言”,简单来说就是让用户发表一些对未来的猜测,并且定一个时间,然后系统到了那个时间会提醒用户确认是否预言成功
  • 我想做一个安卓app,像三国志11一样,将所有三国的人物,历史事件,城池信息,战役,单挑,舌战都完整地汇总在里面,然后再像游戏一样,将“官渡之战”、“赤壁之战”、“夷陵之战”都像三国志11一样活灵活现地展示在地图上。
  • 当时我觉得做网页做系统已经很没有意思了,所以我决定做机器学习,深度学习。
  • 我想考研,因为不太满意自己的双非学历。
  • 那时候LPL竞猜挺火的,我和朋友商量写一个统计各队伍各选手的评分的系统。当时我先用jQuery写了前端,拼命的append html标签,导致我自己写完的时候都不知道自己在写什么。

2019年春,考研没考上,但是数学二确实也让我复习了高数和线代。借助这点基础,我选了一个“手写汉字识别的研究”的题目,然后开始学习吴恩达的机器学习入门,学习深度学习Tensorflow,学习卷积神经网络等等,然后由于自己的电脑的显卡是1050ti,有点不够用,我就花钱去租专门用于训练的服务器,印象中要6块1小时。那时候为了一个好的结果,,花了不少家里的钱。

2019年春夏之交,我的论文提交给了一个不太懂机器学习的老师,老师一看就觉得我在抄别人的论文。给我的建议是,我要么一意孤行继续这样答辩,但可能延毕;要么就把手写汉字识别改成某个系统,走需求分析,UML设计,数据库设计,开发,测试,结论的框架。当时我感到了深刻的绝望,自信心几乎被击垮,支离破碎。仗着自己之前也曾一个人咬着牙实现过不少系统,我决定把这个算法的研究都丢掉,转用百度提供的手写汉字识别api,包装成一个笔记系统,手写的笔记拍个照就转储成汉字。

2019年秋,我入职某软件公司,我终于会写Vue了。在之前我总是写jQuery。我甚至以为jQuery是最好的解决方案。也许2015年前是,2015年后就不是了。

2020年,我虽然是Java开发工程师,但是做了很多很多前端的内容。我被迫花很多时间去调CSS,去抄别人的js来完成移动端的h5网页的展示效果。我感到非常的厌恶,觉得自己的能力被封锁了。领导想弄区块链,想提供API接口给其他公司使用,但现在看来根本没有任何优势,仅仅是困兽之斗。另外,为了能把智能客服的问答预料快速查找,我学习了ElasticSearch数据库的用法。为了爬取一些信息,我学习了Python开发。

2020年秋,我被“发配”北京,每天都过得很不开心,回家遥遥无期。本来说好的出差一个月,到了地方之后却要求长期驻地开发。而那套系统的代码很乱,找到机会我马上就离职了。

2021年,我来到上海,接触了游戏服务器开发。我第一次发现服务器是如此的庞大。

  • 我学习了新的架构:Actor架构。
  • 我受到网上的信息“蛊惑”,觉得hibernate已经过时,但在游戏这个场景里,hibernate比mybatis更适合。
  • 我以前不理解Zookeeper到底用来做什么,他们总是只教我存和取,现在我知道可以配置系统信息;
  • 我自学过netty,但是不理解为什么要用netty,现在我知道了,封包解包,NIO这些情况用netty确实快人一步。
  • 我以前觉得mysql能力有限,但是在mysql前加一层缓存的话,速度就会成倍提高。还有索引和主键的配置也是有考究的,慢查询也是可以分析的。并不能武断的认为mysql能力不行。
  • 还有一些完全没听过的,比如protobuf,akka,集群,ticker,在我之前的认知里只有json是唯一通信的结构。

2022年,我回过头来发现,我好像是从2021年之后,才真正打破“啥都会,啥都不会”的尴尬局面。在此之前,我好像什么都会:

  • Web前端:html,css,js基础语法,jQuery的用法,简单的WebPack打包,简单的Vue
  • Java后端:SpringMVC过渡到SpringBoot,MyBatis
  • 移动端:基础的Android开发
  • 数据库:使用过关系型的Oracle,mysql,也使用过非关系型的mongodb和ElasticSearch
  • Python:爬虫相关
  • 服务器:只会简单的java -jar部署,netstat -nlp看端口,然后给我所有的电脑都装好双系统。

又啥都不会:

  • Web前端不会最有技术含量的React
  • Java后端不会hibernate,HashMap的底层逻辑,Java虚拟机的垃圾回收机制都是用背的。
  • 移动端:不会用kotlin写安卓,也不知道最新的安卓有什么内容
  • 数据库:从没有仔细学习mysql背后的存储优化原理,也没有上手实操过
  • 服务器:以为服务器只是java -jar,而没有研究过docker,zookeeper,jenkins等更优秀的工具和中间件。装双系统也就装的那一刻用一下,真要做事还是用虚拟机多开……
  • 没有研究过消息队列。

总的来说就是,都是浅尝辄止。当跑完hello world,把环境搭起来的时候,我就觉得自己行了,牛了,然后关掉编译器去玩了。

不过有意思的是,2021年我在10年工作经验的主程面前点开8uFTP的时候,他惊讶地问:“woc你怎么在用这个东西?太老了这个,可以换一下Filezila”。而我会心一笑。后来团队发生了变动,换了个新主程。在闲暇时间我和他攀谈“网页三剑客”,向他展示我2015年就搭建起来的博客,和他开玩笑说,我和他是同一个软件开发时代的人,我是Young OG!

但也仅此而已了。也许我真的是Young OG,但是我总是缺了点什么很关键的东西。以前我觉得自己不懂坚持,总是半途而废,而现在,在上海工作了一年多之后,我发现我的能力并没有任何问题,我的问题在于不知道怎么将工作切分,不知道怎么保存自己的体力,不知道自己的目标是什么。

不管是写LeetCode,写项目,还是研究某个新框架,都需要安排时间,都需要统筹自己拥有的资源。特别是写项目,写项目有一点像写小说。只有将小说里每个章节都完成并且有所关联(长篇小说),才能是一部优秀的小说。长篇小说家也不是一朝一夕能写完一部大作,我们软件开发人员自然也不能一朝一夕写好一个系统,更何况我们还需要测试自己的代码。

所以我们需要对任务进行切分。

任务切分的方法和意义

最近两三个月,在工作中,我开始使用画图工具来画一些流程图或者架构图。这些图不是标准的UML图,但是是我自己能看懂的图。

简单说一下本次系统做了什么。 我平常会看LPL比赛,尤其是季后赛或者国际赛事。这些赛事一般是BO5(五局三胜制),一局比赛一般30分钟,加上休息的10分钟,如果打满5局大概4个小时多。如果中途出了点差错,还有暂停的时间。 而最好看的比赛往往不是前两三局,而是第四局或者第五局。因为如果第三局就结束这场BO5,只有可能是3-0碾压,没什么意思。而如果打到第四局,必然是2-1,这时领先方再加把劲就赢下整场比赛,而落后方已经站到悬崖边,这时候的比赛是最好看的。 但要打完3局,至少也要两个多小时了。如果我手头上有一件其他的事情要做,那么我就需要经常点开某个APP检查比赛是否到了2-1?又或者我对两队的实力很信任,我相信他们一定能打到2-2进决胜局,那我就很可能需要在三个小时内不断的抽时间查看比赛进度。这会影响我手上的事的效率。 所以,不如写一个系统,每隔好几分钟去请求一下LPL的接口,和数据库的预定比赛信息比对,如果到达了我预定的比赛比分,或者到不了我预定的比分,就发邮件提醒我。我只需要开着QQ,等着右下角提示就好了。

技术选型

回到上一节说的“造自己的轮子”和“用别人的轮子”的讨论,我平时的工作用Java进行开发,如果用SpringBoot,在路由,操作数据库逻辑,发送邮件那几块的内容,在数据库设计好了的情况下,我会写的很快。 在这个情况下,“用别人的轮子”就是用SpringBoot,“造自己的轮子”就是用某个自己没学过的语言或者框架,边做边学。 本次我选用的是Go语言和Gin,对标Java和SpringBoot。

语言路由ORM
JavaSpringBootMyBatis
GoGinGorm

系统切分

在这次开发中,我不再像过去一样无头苍蝇乱撞,而是先画了好几个框框,来分析到底自己想做什么事情。

别看内容不多,事实上这一步是非常重要的。我们对于某个需求,可能仅仅是觉得“这个拿出来,然后和那个比一下,有就做这个,没有就做那个”,最后加一句“不就好了吗?”。但在实际操作的过程中,大概率会发现“这个”不好拿出来,“那个”也不太好取出来,取出来不知道在哪里“比一下”,“有”的情况可能不方便“做这个”,“没有”的情况可能不方便“做那个”。

所以不要说“不就好了吗”,对于自己不熟悉的领域来说,做什么都会遇到问题。如果用的是自己熟悉的内容,那么就失去了提升自己的机会了。

首先我先用一句话把我脑中的需求写明白。只要自己看懂就好。 然后我开始幻想前端,前端要做几件事?我列出了5件事:

  1. 获取预约信息
  2. 创建预约
  3. 删除预约
  4. 执行预约
  5. 取消预约

在这个简单的需求中,这5件事就是5个接口(最后开发的时候发现“执行预约”和“创建预约”的功能是重合的,但是无所谓,这里更多的是提供思路)。 而在后端那块,我从前端要做的事情反推后端应该要有什么功能:要发送请求肯定需要路由,要落库肯定要操作数据库和设计数据库。在需求里需要读取比赛到达的某个比分,那么就需要一个轮询的定时器,每隔一段时间发送请求问一下,然后通知就用邮件,因为邮件协议是通用的,而且QQ邮箱的提醒非常醒目。最后业务逻辑也是需要时间进行设计的。

基于前后端的内容,我开始排工作:

  1. 前端页面框架搭建
  2. 前端页面开发及设计(边做边弄)
  3. gin路由基础框架搭建
  4. 基础请求框架编写
  5. 获取赛事接口编写
  6. 数据库设计
  7. gorm数据库操作
  8. 邮件发送逻辑
  9. ticker研究及实现
  10. 开发所有请求
  11. 自己联调前后端

事实上这个工作安排,虽然是11条,但是每一条的工作量并不平均。我感觉在任何项目组,切分工作也不代表工作量是平均的。 现在做完回头看,发现go语言对邮件发送和ticker有自带的支持,然后gorm的逻辑和gin解析json的逻辑几乎一致。其实并没有浪费多久时间。 这次我没有预估具体时间,因为我心里没底。事实上更好的做法是稍微评估一个时间长度。

任务切分的意义在于,任务有时候不像买来的蛋糕,你可以用肉眼看到蛋糕的大小和形状。你手上只有一把塑料刀,对着盲盒里切。 但是有意思的地方在于,任务这块“蛋糕”的结构虽然乱七八糟,但是你大概能找到你知道的位置,然后胡乱的“划一刀”。这种切分可能并不准确,你并不知道你的蛋糕具体是什么样的,但是当你用这种方式多“划好几刀”之后,你的图中会有一个大概的系统模型,这会反过来指导你接下来要怎么划分工作内容。当工作内容越来越细,你就越能准确的评估每一块的时间和困难点。 也就是一件事变成了好几件事。而每一件事都有单独的内容,有单独的评判标准。从而能清楚的知道自己做了多少内容。

关于评估时间,我发现自己经常落入一个陷阱里:认为简单的事情一定能很快做完。但实际情况是,一个任务的时间长度,既取决于难易,也取决于工作量。我经常忽视工作量的大小,乐观的估计比较简单的工作任务。其实在拿不准时间的情况下,可以把时间评估的更长一些,是没有问题的。

挑战性

如果说在公司工作是为了谋生,那么在业余时间做自己的项目就是为了取乐。 如果不是为了取乐,那么也没有必要再浪费时间了。 经过这次的开发,我发现自己的开发内容其实也不少,但是我没有觉得很不开心,相反,我感到很兴奋。 在21年10月我有自学Go语言的语法,但是我不知道怎么去应用于实践。而编写一些基础语法的训练代码,让我觉得很像读书时看着例题做例题。 挑战性不能太高,比如写一个完整的用户注册登录找回密码的体系,然后提供第三方token登录这种,对于一个人开发来说,太难,而且也是重复造轮子的工作。 也不能太低,比如写一个golang的Hello world,包装一个在网页上发邮件的功能等,做出来没有意义。 自己的项目,应该是有点挑战,然后尽可能实用,能在生活中用得到。如此一来,才不会陷入“我做这玩意又没钱赚,学不到东西,我不知道为了什么而写”的错误想法中。

结合上一节写的“任务切分”,当有一个想法在脑中亮起,请你拿出纸笔或者打开画图软件,花一个晚上或者一天做一做简单的功能设计和任务划分,你就能知道自己的想法值不值得做,需要什么资源,做出来是为了什么。

实用性

如果一个需求没有实际的作用,那么就没有必要浪费时间了。如果“实用性”仅仅是为了“让大家知道我有本领”,而没有办法在生活中应用到,或者是让人感到很快乐,又或者能带来收入,那么尽早停止吧。(当然了如果“让大家知道我有本领”能让你升职加薪跳槽,那么就属于“能带来收入”的范畴了)

半途而废

翻看github和gitee,我有很多想法和点子。

  • 凌天战队:2016年最爱玩LOL的时候,想给我们宿舍和隔壁宿舍组个战队,读取他们游戏账号的数据接口,把他们的数据列出来。然后搞个官网招摇显摆;
  • 中国象棋:想自己写一个象棋,能让玩家消耗道具,让电脑帮忙走一步棋,或者悔棋等
  • 自己完整写一个博客
  • 睡眠宠物:安卓应用,根据睡觉时间来提升宠物等级,然后白天宠物出去游历(旅行青蛙)
  • 预言家的网站:写预言然后定时,时间到了发邮件询问预言是否成真
  • 英雄联盟数据平台:记录BO5的双方赢下第几局的胜率最高
  • 三国数据平台:想整理所有三国人物,事件,城池,战役
  • 想学Unity做一个RPG游戏

但真实的情况是,我每次花了一天做一点内容,就觉得浑身难受,没有任何正反馈。比如自己的博客那个,我花了一晚上调style样式,然后已经没力气写后端了;中国象棋我把基础的棋盘和走子逻辑对着书里翻译成kotlin就花了一周的休息时间,界面是用命令行print的,而这一周我一点游戏都没玩!预言家的网站也是用bootstrap写了个基础的主页和个人中心,后端那块就没体力做了。Unity和UE根本不知道怎么入门,或者说看看教程自己弄一下一天也就过去了。

我属于是又想学,又想做,但更想玩的人。我无数次觉得自己是很糟糕的人,因为我有这些想法和点子,却从未付诸实践。

而从前两节的分析上来讲,这几个需求大多都属于挑战性逆天高,实用性几乎没有的需求。而我其实并不特别喜欢这些需求做完之后的具体效果。 自己写网站(凌天战队、自己的博客、预言家的网站)对我来说其实还是很消耗时间的,即使我现在有能力能做的很快。自己的用户体系就算建起来也需要维护,还不如直接作为一个信息发布平台+邮箱联系的模式,作为自己的名片; 中国象棋则是属于做出来就是为了自娱自乐,但是也没有多有趣,因为象棋游戏现在多如牛毛,我要的功能现在天天象棋也有了,如果是为了学习剪枝算法,倒是值得一学,但是为了做一个游戏系统,又不打算捞钱,就是浪费时间了; 睡眠宠物是属于难度特别特别大,需要自己测很多很多轮,但是没什么收益的东西。而且还需要美工的支持,不然就毫无用处和趣味了; 英雄联盟数据平台是属于爬虫爬到数据库+命令行展示结果即可的功能,做一整套系统属实是为了装逼,但事实上代码放到github上,然后在Readme里贴出结果,反而更有范儿; 三国数据平台属实是劳民伤财,挑战性拉满,而实用性还不如百度百科。 学习Unity或者UE,首先应该先学基础,而不是先做RPG,现在根本没办法做好系统设计和切分需求。

有想法是好事,但是现在的情况是,你想到的东西,前人肯定有人也想到了,他们没有做成功,所以才轮到你想到。

而这次做的赛事预约平台,则是我第一次用正确的方式分析、设计、排期、开发、测试,还差一步上线。整个过程里我不觉得有多辛苦,而是觉得这个系统还可以有很多地方可以优化,让他更人性化,甚至让他不再依赖接口爬虫等,保障系统数据来源正常提供。并且这个系统真真切切能为我提供便利,让我能更专注于我的工作内容,又不落下比赛。

我接触代码已有14年之久,但为自己开发一个完整的系统(包括前后端和测试),并且真正用于实际,是头一回。一起拿我不过是个“雇佣兵”,为了学校的学分,为了公司的工资而疲于奔命,而自己的想法又太过庞大。

以此次经验为鉴,今后一定可以有很多有意思的想法,在“任务切分刀”切分之后,逐步完善。成为我自己的“代表作”。