聊一聊我最近都关注哪些技术点

2020-03-03

引言

这个假期和我以往的假期的最大的不同就是我终于开始真正写代码了,并且没有把写代码这件事当成是某种功利性的东西而纯粹是满足自己的好奇心:我有这个想法,现实真的如我所想吗?我能去实现以下看看吗?这大概就是我想的,这大概就是驱动我码代码的动力吧.

Java

我是从知乎上看到对KikiLetGo/VirusBroadcast这个Github开源项目的介绍,这个项目是基于蒙特卡洛方法,利用随机数来表示离散的随机事件,对现实中的病毒感染和传播情况进行模拟,还有一个用Unity做的也是基于蒙特卡洛方法的仿真模拟程序,这个更加直观.然后我也想写一个这样的Java程序来做仿真模拟,一方面是我想学习Java,另一方面是我对计算机仿真模拟这方面确实也比较感兴趣.毕竟,Java嘛,它支持基于类的编程,就是说凡是现实世界的客观事物我都可以为之相应地在Java源代码里边定义一个类,类还可以继承父类,还有抽象类和接口,Java的抽象能力确实很好地实现了对现实的抽象,说白了凡是事物你能把它看成一个对象(Object),那么你就可以用java.lang.Object及其子类对它进行建模,这是我想用Java来做一个仿真模拟程序的出发点.不过呢后来我开始刷LeetCode,所以呢这个Java的项目我就暂时搁置了,它存在过度工程化的问题,很多东西不管我用没用到,我都先给它定义了一个类,类上面还有抽象类,一开始甚至还有接口,对于这个项目,我确实迷失在了过度工程化的陷阱里,现在搞得太复杂,一百多个类,两千多行Java语言代码,我有点不知道自己真正想要的是什么:是一个病毒仿真程序,是一个帝国时代II的游戏仿真程序,还是一个游戏沙盒框架?其实是自己太贪心了.

知乎上介绍的Unity病毒仿真程序

LeetCode

刚才说到了LeetCode,LeetCode呢是一个学习算法和数据结构的网站,它上面有很多题目,用户在上面可以尝试挑战一些算法实现问题,LeetCode可能会限制你实现的这个算法的时间复杂度不能超过它给出的,当然了正确解答问题是最基本的,LeetCode厉害就厉害在于它有基本上很完善的测试案例,能够涵盖到绝大多数的Edge Case,让你发现:哦,原来还有这种模式的输入,这我原来的算法确实是没有考虑到的,如果你的思路不够清晰,代码写得不够好,基本上就会变成if-else的模型或者switch-case的模型:给每一种Edge Case都在自己的代码中硬编码解法,变成面向case编程,这样子显然是不行的,因为一个优秀的算法必然要具有一定的普适性,它的Special Case应该尽可能少,应该用一种同样的计算方法来处理几乎绝大多数的Pattern.

Leetcode网站

我呢大概在去年夏天也是花了一些时间来解LeetCode题目,不过只是作为一种消遣,画几天时间解了几题,觉得有些累就没坚持下去,这次突然开始解LeetCode题目是因为我新加的一个实验室的QQ群里边有人放出了一个日程安排表,鼓励大家假期再加刷刷算法题目.话说回来,我这次呢大概是花了一个星期多一点解了大概13题吧,大部分都是自己做的没看答案,个别题也没有提供答案,然后大概来说平均提交9次才能获得通过,因为我自己懒得在本地生成各种Test Case,因为我还没想好该怎么做一个Pattern Generator生产不同的Pattern,再针对具体的Pattern利用随机方法得到随机输入,一句话这样比较低效,我还是只喜欢看一下代码,运行一下简单的测试,就Submit给LeetCode让LeetCode做测试了,毕竟各种Edge Case确实是LeetCode的价值和魅力所在.同时LeetCode还有活跃的社区,会有人在里边分享自己觉得还不错的解答,这确实是很好的技术氛围,也有人在里边分享大厂面试的经历,说大厂面试的题大多数还是Medium难度甚至Easy难度的,所以哪怕是Easy的题也值得认真去对待,因为打好扎实的基础对求解Hard难度的题目也是有帮助的.

我目前基本上是顺序的往下做,就按照LeetCode网站给出的默认的题目的顺序,不是很挑Easy,Medium,或者是Hard难度,对我都无所谓,做不出我也会看一下答案,不过有一种情况是我会做,我的算法实现能够通过测试案例的99%,而剩下的1个或2个测试案例提示Time Limit Exceed,有趣的是,同样的算法思路,我看别人的代码和我的差不多,就差几行,它的算法能领先百分之90,而我的就会提示超时,后来我发现一些具体的对数据结构的操作的方法,对性能的影响还是蛮大的,特别当输入的长度变得大的时候,哪怕程序的结构比如循环和控制是相似的.

个人博客

后来嘛,就是这个博客,我也写过一篇文章来介绍这个博客的创建过程,不过一开始我是用GitBook的,我觉得还是Hugo更好一些,同样是静态站,同样是通过编译Markdown文件生产页面,Hugo无论是可定制性还是速度方面都更胜一筹,而学习的难度和使用的难度也没增加多少,目前来说我觉得还是非常简单的,Hugo虽然基于Go,但是即使你不知道太多Go语言的知识,或者根本没用过Go语言(像我),也能用Hugo来轻松地搭建自己的博客.而且用Hugo这样的静态网站生成工具来生成的网站还有一个优点,它天然地是动静分离的,这也正是目前很多现代网站的发展趋势,动静分离的网站可扩展性和可维护性以及性能都是非常好的,这点相信很多人也有会理解.

有人说你一个静态站,面对像是评论系统这种需要互动的和记录用户状态的功能要怎么办呢?我觉得这其实不算是一个问题,因为就像是Hugo官网的文档介绍过的那样,可以用插件解决,插件它实质上就是在页面注入一段JavaScript脚本(当然好的插件甚至也可以不要求站长有JavaScript的知识,像WordPress的插件那样新手友好),也就是通过第三方的API来解决,它和内容页面是独立的,也就是说假如你给你的网站的文章页面下方注入了一段JavaScript代码,这段JavaScript代码通过HTTP方法从第三方网站抓取你这篇文章的评论,那么如果是这个评论系统不可用了,造成的后果最多也就是你的这篇文章无法评论或是无法看到评论,而所有的页面都还是能正常显示,我觉得这已经很好了,毕竟大多数博客网站还是以内容提供为主要功能的.且不说你还可以自己注入JavaScript,自己做要实现的功能的API,这样给了你更好的可定制性,对开发者也是非常友好的.他不像WordPress那样入门容易,但是要自定义WordPress页面需要看很多文档,Hugo的自定义门槛真的变低了,是一个可以让你自由发挥、自由学习的的网站生成工具.

开发环境

Maven和持续集成

我觉得持续集成的有或者没有确实会给一个项目带来非常大的差别,它不仅仅是一套开发流程,它还是一系列的语意,是对整个开发流程,对一个软件生命周期的开发阶段的明确定义.说白了我觉得开发软件就应该这么规范,形式化,自动化,这才是现代的软件开发.

我之前呢写Python也好,C也好,JavaScript也好,基本上都是建个文件夹,里面源文件怎么放就全靠心情了,还美名其曰Keep It Simple,后来我接触Java和Maven之后,我发现事情真的不是这样,特别是Maven,它视图将一个项目视为一个Object,而用对象模型来对一个项目进行建模,来描述一个项目,这无疑是非常高效、非常规范的,容不得人为的不小心的出错,整个开发流程都变得清晰、明确而又严谨.

项目

包括我在学校上的MySQL实践课,老师只是给出了代码的范例,但是没有讲过如何组织项目的文件,我之前也一直都是随意组织项目文件的,而没觉得有什么不妥,但是后来有一次老师要我把项目文件打包发给他,我没注意连通依赖项一起跟踪进Git仓库中,又连同依赖项一同添加进压缩包中,一个一两千行的项目,竞有好几十MiB大,后来有一次实验室的QQ群中有人分享一个爬虫程序,却只发了一个.py源代码文件,而依赖项竟然是要使用者自己看源代码,提示什么就装什么,我也第一时间感觉到了这样不妥,全把piprequirements.txt当不存在了.所以我现在建一个项目,哪怕不用传统IDE,而是用像VS Code这样的带插件的文本编辑器,也会考虑自己建项目,实际上不难,像是要建Java项目的话可以用Maven的mvn archetype:generate功能,建Node.js项目的话可以用npm的npm init功能,建python项目可以用pybuilder,只不过pybuildeer对最新版本python的支持没那么好,然后哪怕是SpringBoot那么复杂的项目,VS Code也有相应的插件来自动生成项目,帮助管理dependency,也就是不需要自己手动编辑pom.xml,告诉对应的VS Code Extension,你要往这个项目中添加什么依赖,都会自动帮你做好的.

总之我觉得在开发什么东西的时候,最好心中还是要有一个『项目』的概念,哪怕再简单的功能,除非自己还是在照着书上的代码做实验和练习,不过我觉得对于那种情况,也适合于自己建一个项目来把自己在那本书前前后后学过写过的代码都规范地组织和整理起来.有了项目之后源码(src/)和目标文件(dist/)就会是天然分离的,而且很多项目管理工具在创建项目时还会顺带着创建.gitignore文件,可以说是非常方便了,这样又更加不会不小心把依赖项和目标文件一同添加进Git仓库了,同时想要分发源码分别编译也很方便,比如说我不需要把五十多MiB的.jar目标文件复制到服务器,我只需把除了目标文件之外的源码和项目描述文件复制到服务器上,再在服务器上进行编译就可以了.当我想和别人分享我的项目时,我也不用额外地叮嘱对方应该安装什么依赖才能使得我的代码可以跑起来,他如果也有同样的知识的话,看一下项目描述文件就全部清楚了.

软件定义的系统

即使是狭义的说,软件开发方面的规范也可以包括很多东西,文档啊,命名规范啊,代码文件组织规范啊,开发工作流程啊,具体到Java里边的注解,JavaDoc,甚至是很多CoC(Convention over Configuration,约定优于配置)的东西,这些东西,实际上,都可以看成是属于规范的范畴.我们都是宇宙的探索者,然而,作为主体,我们的差异在于,面对同样的观测,我们思考的角度和内容都不同.

我们都知道,开发软件,除了具体将程序编码输入计算设备,之前还有一个更重要的过程,即对要描述的事物进行建模,例如,我们用java.lang.Object对现实世界的『对象』进行建模,对象即一个个独立而不可分的实体,它具有原子性.我们用java.util.Queue对现实世界中,我们看到的,排队这一现象进行建模,开发软件,实现特定功能,就是先对客观世界中我们要讨论客体进行建模,将模型及模型符号间的运算及其运算法则输入计算设备,计算设备返回计算结果,我们根据模型的符号的意义,对计算结果进行解释,这可看做是软件开发的一种解释.

所谓『建模』,说了这么多,其实和『数学建模』,也没有太大的不同,它寻找一组符号,一套运算法则,或者一个函数,将复杂的客体抽象为简洁而清晰又有表现力的数学符号/计算机程序/物理定律等待.

那么软件开发方面的规范,就是对开发软件这个过程本身,而非要开发的软件所尝试描述和计算的,进行建模,在诸多建模方法中,我们关注其中的子集,数据建模,或者说软件建模,其实也是差不多的,Maven引入了『项目对象模型』这个概念,企图将开发软件这一客观行为及开发软件相应的过程和组件,仅仅用『对象』,或者说计算机软件语意中的对象,来对之进行建模.

有了符号,就能进行高效的表达,而有了可计算的符号,在此基础上还能进行推理和推演,从而在计算机的世界中,以简洁又统一的方式,描绘出这个纷繁绚丽的世界的一部分.

心得体会talksstory

最小Gulp工作环境的搭建

记我自己的Telegram Bot开发到第一阶段