0%

我并不是一个完美的人,特别有各种各样的小问题,有时候心情糟糕得会陷入抑郁。但正如别人评价我一样,“虽然过程会曲折,但是事情的结果往往都是向好的方向发展”

2017年开始进入到区块链这个行业,陌生的、全新的领域。知道了数字货币的功能后,带着一堆的疑问,一点点地读比特币的开发文档,了解基本原理。接着读一些相关的算法论文,疯狂地吸取区块链行业里的知识。

当时开发区块链项目,要做一个完整的比特币分叉币,共识机制需要修改成为PoC(Proof of capacity)。作为工程师,除了实现核心算法部分外,每天还需要解决一堆又一堆的工程问题,最常见的就是各种编译和兼容,然后就是比特币里的代码地理解和更改。

那一段时间在上海的盛大青春里的出租屋里,基本上连公司都不太去,哪怕只需要步行5分钟,我都乐得在宿舍图个清静。每天就是读论文,改代码,研究代码,制定第二天计划。一直到耗费掉所有的能量,然后去休息,起床后继续。现在回想起来,也是惊奇于当时的旺盛精力。老板也对我的工作的理解,并不要求我一定在公司,给予了足够的自由和信任。

人在研究和学习的时候其实是最开心和快乐的,特别是在这个过程中还能够充分体会到平静。如今再次学习和研究论文的时候,又有这样的感慨,于是记录下来,这些为数不多的能让我感到平静的事情。

学习区块链的笔记

最近在开发Spacemesh的矿池程序,整套核心的代码现在已经完成了将近70%。为了能保证所有的代码的正确性,使用测试驱动开发这种方式将各模块都使用不同的测试用例进行覆盖,以此来最大程度的保证写出来的代码的正确性和有效性。于是整个开发的过程就是在不断的验证和调试,直到所有的测试用例通过,最终将项目推进到接近完成的状态。测试,日志和调试,都是为了保证程序最终执行结果正确的重要手段。

测试

当需要开发一个稍微有一些些规模的项目,经常性的会陷入到对程序是否能够被正确执行的怀疑中,不管人有多聪明,记忆力有多好,当项目增长到一定的规模时,都会掉入这个陷阱中。使用测试驱动开发,可以说是一种非常好的针对这个问题的解决办法。

所谓的测试驱动,是指我们先写好一个功能的基本接口,添加针对该接口的测试用例,然后继续接口的实现的开发,直到所有的测试用例通过测试,步步为营,最终完成。测试用例似乎成为整个开发的主角,而涉及业务代码,却是保证测试用例正确性的桥梁。

使用了GoogleTest作为测试框架的测试程序运行结果

程序开发是一种组合方式,由各种大小部件组合成一个更大的部件,每个不同的部件都有各自的运行逻辑,测试用例则是为了保证某个部件的逻辑的正确性而存在的。

举个简单的例子:我们有一个函数,它可以把两个数字相加,然后把结果返回。于是,针对这个逻辑,我们写一段程序来验证,是否能够返回我们真正想要的值,这段程序就是一个简单的测试用例。

首先我们假定函数的接口是int Add(int a, int b),于是我们测试程序就可以写为EXPECT_EQ(Add(10, 20), 30),EXPECT_EQ是GoogleTest中的一个宏,它假定给入的两个参数的值是相等的,如果不等,它会打印出测试失败的信息,如果相等则表示测试通过。使用不同的测试框架,测试的代码不尽相同,可以查阅对应的测试框架的文档。我们可以为这个做加法的函数写很多个测试用例,来测试各种情况,比如带入负数相加,其中一个参数是零,或两个参数都是零,然后验证是否能获得想要的结果等。

日志

日志就是在程序运行中,打印到屏幕或文件中的一些和当前程序运行相关的信息。程序日志是一种必不可少的记录工具,它会在程序最初运行就开始将程序状态记录下来输出至指定的设备,当程序出现错误甚至宕机时,开发员可以从这些日志里分析出程序错误原因直至修补错误。日志类型有很多种,常见的有:Debug, Info, Warning, Error, Critical。

一开始我对于这些日志的类型是有点模糊不清的,后来在Stackoverflow上专门查阅了一些关于日志分类的说明后,大致可以这样理解:

  • Debug – 输出一些帮助调试的信息,没有特殊要求的情况下,该类型的日志不显示
  • Info – 输入当前程序的状态,比如收到了什么信息,然后正在进行什么操作等
  • Warning – 当一些操作有可能导至程序错误时,使用这种类型的日志来记录这些操作,作为警告
  • Error – 当程序发生错误时,这些错误还没有大到会导致程序运行失败的结果,但是已经是作为错误发生了,有可能需要针对它进行程序修补
  • Critical – 有时候这种类型会被称作Fatal,出现这种类型的日志时,往往程序已经无法再继续下去,该日志记录导致无法继续的原因

合理的在程序中的不同地方嵌入日志,可以让开发者更加容易的找到程序中存在的问题并且定位问题位置直到解决。在写代码的过程中,有意的培养自己对于代码日志编写的规范和合理,是一件值得投入精力去做的事情。

调试

当程序出现问题时,或和预期出现不一至的表现时,比如某个测试用例没有通过,我们就需要找到错误的原因然后对程序进行修改,然后将这个问题解决掉,这个过程就是调试的过程。

调试的手段会有很多种,比如:使用调试器来挂载程序,然后设置断点来进行跳转到有可能出现问题的代码处进行单步跟踪和运行,在过程中查看相关的变量,判断程序走向是否正常。或者,通过查看程序的日志来分析和尝试定位问题的位置等。

关于调试,Linux的作者Linus Torvalds就在一篇内核讨论的信中表示过,他完全不会用任何的调试器来调试代码,因为他认为,当一个你完全没有头绪的bug出现时,你要么变得更加的小心,要么去抱怨调试器(Oh. And sure, when things crash and you fsck and you didn’t even get a clue about what went wrong, you get frustrated. Tough. There are two kinds of reactions to that: you start being careful, or you start whining about a kernel debugger.)。其实我是很认同他的这一个观点,甚至不觉得这个观点有什么偏激之处。当我们太依赖调试器的时候,特别在碰到一些奇怪问题时,往往调试器展示给你的结果和实际的问题差得很远,而且一些在多线程中的宕机问题,往往调试器无法很好的帮助你去解决问题。

代码的正确性

关于如何保证代码的正确性,就是永远清楚自己在做什么,小心翼翼的写下每一个逻辑,做好每一个测试用例和日志。不要做多余的工作,不要把代码写得不必要的华丽,永远都要保持简单,并且多件事情分割成不同的小模块。写必要的注释,方便未来的人阅读,而这个未来的人往往就是自己,所以善待自己从写高质量的代码开始。

事实上,测试用例虽然和最终交付的代码看似没有什么直接关系,但是一堆好的测试用例,会帮助开发者省去大量的调试工作,并且帮助他们更好的理解这些代码。而好的日志,将会在程序的生命周期中不间断的产生有效的信息来帮助开发者们理解并处理未来将要发生的问题。

以上三大手段很有效的减轻了开发过程中的心智负担,但是,如何把这三大手段用对用好,是一个需要长期练习的过程。

“独步天下,吾心自洁,无欲无求,如林中之象”。十多年前看了《Ghost in the shell》后就非常喜欢这句诗,十多年后,仍然感叹。只不过,我暂时还没有办法做到如林中之象那般强大,于是我也无法悠然自得,继续努力吧。

一款名为Darq的游戏

Darq》这款游戏做得非常的棒,Unfold工作室的作品。其实工作室基本上就是作者一个人。从完全没有做过游戏,从零开始学习3D建模,学习程序设计,到做出这款游戏一共花费了近5年的时间。现在该游戏已经登上了各大平台,包括掌机Switch,并且获得了非常多的奖项。

Darq

游戏与学习

以前想要做游戏,总是害怕自己没有美术基础,无法做出漂亮和让人满意的画面,其实,在现在互联网如此发达的世界,只要能够上网,那么各种各样的教程真的是可以随便挑选。对于无基础的任何人都可以学习并掌握一定的美术知识,然后经过一段时间的学习,就能做出具有一定表现力的画面。能把这些东西做出来,对我的诱惑非常大,哪怕只是简单的低多边型的模型。

建模软件使用了开源的Blender,无费用,不需要找破解,非常自由,并且这几年它的发展非常的好,在业内很多人都开始选择使用它来进行建模,相关的教程也非常的丰富。从一开始的点线面开始学习,了解建模的基础知识,了解一些建模的规则和为什么,学习低多边型的模型制作,一直到开始尝试雕刻,再拓扑回低模,再学习贴图。期间还学习了解人体结构特别是头骨结构等。非常的享受这一过程,特别是在做雕刻的时候,可以进入一种完全沉浸的状态。

折腾了一两个月下来,突然感觉能做的东西多了,想做中世纪的古房子,想还原漫画里的角色,想在Unreal里渲染出自制的模型,使用不同的灯光和材质,想做精致的UV贴图,还想让人物动起来。虽然现在做的东西还非常的粗糙,虽然还有非常非常多的细节没有能做好,虽然还没有能够做出自己满意的游戏模型,但是这一个学习的过程就足以让我收获很多的满足感,至少让我确定了这一条路是可以为之付出努力走下去的。

低多边形建模

一个低多边形的小房子,最开始学习建模的时候做的一个模型。

一个低多边形的小房子

雕刻

下方是我自己自学雕刻,然后做出来的人的基本头部模型,第四张图是进行拓扑后的网格线,第五张图是通过UV帖图添加了基本的肤色和头发。

头雕刻视角1 头雕刻视角2 头雕刻视角3 低模 Low 上色和头发
头雕刻 头雕刻 头雕刻 头雕刻 头雕刻

这两年最痛苦的可能就是花时间重新审视我与其它人之间的关系后,得出我和其它人的关系其实并没有自己想像中的那么好这件事情。其实不止是花了时间审视,还亲身经历过不止一次的鸡毛事件后才痛苦的得知了这个结论。

为什么会是这样,是和自己懒惰不去思考有关系的。哪怕有时候会有一些不好的预感闪过,自己却仍然懒惰的不去深入思考而把赌注押在对方道德在线这一概率不高的事件上。

所以,相信什么都好,不要相信奇迹,并且把拥有平均道德水平的人的被发现当作一种神奇的事情来看待,有时候反而会显著提升自我的幸福感。

今天下午一边看《The VVitch》一边给冰箱除霜。

说是除霜,其实就是把冰箱的电给断了,打开冷冻室的门让冰自己慢慢融化,然后不定时的一遍遍的拿着抹布把化出来的水给吸掉再拧干。

《The VVitch》讲的是中世纪1630年的新英格兰土地上,父亲因为同村里的教会有着无法调和的矛盾而被驱逐出种植地,然后全家接二连三死亡及大女儿消失的故事。导演并没有在剧中证实所有的发生的事情都是事实,因为故事的最终全家人都死亡或消失,理论上来说没有任何人可以知道到底是发生了什么。这像极了是一个经人口述的“别人家”的恐怖故事,而往往这样的口述在听者的脑海里往往都不存在“真实”这一说法。于是,按照这样的逻辑来看,剧中唯一消失了的女主,最终变成女巫的这一段剧情也就不一定是真实发生的了。而这正好也和这个电影的名字《The VVitch》相呼应,女巫的英文单词应该写作Witch,而电影名字用了两个VV来代替了W,很有意思的暗示了观众,请不要随便相信看到的事情。

基督教基本上说来就是一个父权的宗教。在当时那个环境下,一旦发生了不好的且无法解决或无法理解的事情,然后人们会把问题怪罪给女巫,而找出身边的“女巫”却成了唯一的解法。

在看恐怖片的过程中,冰箱里不断的有融化了的冰块掉下来的声音,好像还挺应景。在《The VVitch》看完后,最终还是烧了一壶水,用小茶杯浇到了冰霜上以加速这个“除霜”过程,终于再过了十多分钟后才顺利清洁好了冰箱重新通上了电。

一直觉得依靠突然切换的画面或声音来达到让别人害怕的恐怖片都比较低级,其实挺没有技术含量。而这次看《The VVitch》后发现,它并没有使用这些低级的方法来捉弄观众,反而可以让观众在看完后有一些思考。

主演是安雅,在《Split》这部电影中她有非常精彩的演出,虽然她在《Split》中只是一个配角。因为她,我把《Split》的前传《Unbreakable》后传《Mr Glass》都补完了。

最近她主演的新剧《Queen’s Gambit》也非常的火,值得一看。

Anya from The VVitch