盗賊の極意

Feed Rss

上海,我来了!

04.07.2014, 11 条评论, 未分类, by , 4,893 views.

五一回家,机票多少钱也要回!

用cocos2d-html5重现一个示例的时候,总是出现各种诡异的显示bug。一开始不够重视,只是让自己的代码越来越接近原本的示例代码,但眼看我整个复制粘贴都不能重现,我就急了。
示例是cocos2d自己的大sample,有一部分framework的,我不能全复制,所以我开始还是怀疑框架中某部分我没有做到。但是朝这个思路走怎么也走不通,甚至一点点苗头都没有,我折磨得肚子都疼了。
真的,因为心急而导致如此明显的生理反应,这已经是多少年不见了……搞不好是第一次遇到这种情况(汗)。
好,你不仁,莫怪我不义。于是开始逐行深入地跟踪,对照着同时单步调试可以正确运行的示例和我的程序。
突然!我发现在让程序停在某个断点处再重新执行的话,断点后面的部分就可以正常显示了!我靠,还有这种bug?我最先想到的是多线程bug,但是在想不通这框架哪里需要用到多线程呢。一边琢磨,一边拿到firefox下试了试,同样是断点后的程序执行正常,排除了跨平台bug的可能。有这个线索就好办了,我一行一行移动这个断点,找到一个关键行“default_item.setSize(default_button.getSize());”。调试时发现getSize值正确,把断点下在下一行,set的结果为0。这样看来是setSize比较可疑吧。一看,setSize果然不是单纯的赋值操作,里面根据几个flag,行为会完全改变的!其中有一个根据this._running来改变行为的逻辑,我想了想,是不是多线程,让这个_runnding时false时true,所以我得到的结果时好时坏呢?朝着这个方向又调试了半天,无果。至此,我调试中作出的每一个预测都落空了。我终于对自己失去了信心,开始无脑单步调试。最后发现getSize的返回值是0(刚才为什么不是0!欺骗我的感情!)。再进一步,是图片取到的size是(0,0)。到这里,我总算是正确理解到问题的原因了。回头想想,确实,helloworld那种只有三张图片的程序里都有一个resource.js文件,还正儿八经的预读了一下,看来预读是很有必要啊。再细追踪了几步,确实是取的图没有在cache里,从这里开始和示例程序的执行流程不同了。这就可以了,不跟踪了,三两下填上预读列表,再试,成功。
其实我之前所在的C++3D射击游戏项目组一直是异步读取图片的(我估计大型游戏都需要异步读取资源)。明明有轮询资源读好了没读好了没的模式的编程经验,自己遇到时却完全没有想到这个原因。反省了一下,应该是我平时自己写程序规模都太小,全是同步读取资源,这么多年思维定势严重了。得赶紧找个大项目参与一下,换换脑子了。

最近写代码的积极性非常差,想想去年白天读代码,晚上学D3D9的旺盛斗志,深感惭愧。

于是今天买早饭时顺便买了速溶咖啡和咖啡用牛奶,准备尝试一下传说中的程序员的觉醒剂了。

咖啡这东西,高中时代为了晚上不困,整包倒嘴里当药吃过几次,无奈当时作息是雷打不动的10点45睡4点55醒,咖啡也没能改变什么。而且现在看来,当时根本是黄金作息,我为什么要尝试晚睡呢,莫名其妙。
印象最深的一次咖啡生效是硕士论文截稿前冲刺的时候,靠同学的一桶咖啡,连写了31小时论文,又因为后劲,最后达成40小时不眠的个人记录。当时真的是感觉到自己进入了一个神器的状态,虚弱,但不困不累,平时活跃得烦人的各种突发奇想都平静了,脑中只处理主业相关任务,有点像考试时的高度集中状态。当然,那肯定也和事关毕业与否的外部条件相关...
总之这次是重新开始挑战咖啡了,希望它带我回到疯狗一般的麻木开发状态。

有人看到我的名字在那个项目组的程序员名单里了,哈哈~

现在这个项目做完,学了php、sql,还有运营时要考虑的一些东西。基本上编程技术没什么提高,但也算是开阔了一下眼界,知道服务器端的事了。如果4月真的能去用Unity做游戏的话,因为还是要用这次的这个网络库,所以我非常有可能继续负责服务器部分。又能动Unity部分,又能做服务器端,不要太开心啊,哈哈哈哈哈!

 

之前为了写node.js的服务器端,根据回调式的编程风格,设计了一种OperationNode(简称Op,而不是On,防歧义)概念,然后用它写了很多代码。不过后来我的服务器端就越写越慢,越来越没有干劲,明明目标很清楚,实现也完全不难,但就是不想动手。怎么办呢,我停下来仔细品味了一下当时的心情,好象是因为代码写不优雅,自己不甘心,觉得写起来没劲,或者是隐约感觉到自己在一条错误的道路上行走,本能的不愿意快走。

那好,”怎么写你(我)才会开心嘛,你写个样子出来看看呗“。这是我设计代码的时候经常用到的一种战术,就是先写一些(有时是很多甚至全部)上层代码,感觉这么写舒服了,再去想怎么实现底层,才能让刚才写的代码生效。我看了看我的卡牌游戏里经常出现的询问玩家是否怎样怎样的AskYesNoOp,至今为止的语法是这样的:

// 询问意向,时限10秒,超时等于选否

this.game.pushOp( new AskYesNoOp( opts, "是否发动场地效果?", 10 ), function( error, result ){

    if ( result ){

        /* ... */

    }else{

        /* ... */

    }

} );

选是的话,后面还要套很多层逻辑,而且每层逻辑都要新写一个Op类,挺痛苦的。理想的写法显然是

var result = asyncAskYesNo( opts, "...", 10 ) ;

switch ( result ){

case ASK_YES_NO_RESULT_YES:

    break;

case ASK_YES_NO_RESULT_NO:

case ASK_YES_NO_RESULT_TIMEOUT:

    break;

}

所以我需要异步功能同步写法。

这种写法我以前常常写的,在lua里,这个叫coroutine,协程。

稍微搜了一下,node.js里就有Fibers库来实现协程功能嘛,安装也很简单,功能也和lua的一样。好,接下来就是逐步割爱换下我的Op,再设计一套coroutine的包装了。估计最后是Op管理大的逻辑,coroutine负责随处可见的琐碎异步。

以前我是听说C++语言里没有协程,所以还挺开心自己掌握了一个少数人可用的秘技,后来搜了一下服务器部分的coroutine,似乎也是有一些的。嗯,又一个扑空了的蓝海,唉。

 

我费了好大功夫,组织了一个特别漂亮的语法,来解决“有则更新,无则插入”的SQL语句,结果不能完全满足需求,现在不得不分拆成: 1)select取所有当前值 2) 分析当前值和新值,该插入插入,该更新更新。非常的朴素。
好吧,我知道这部分浪费掉的时间是错在我的自我满足上,工作还是应该以效率为第一优先,自我学习提升次之。

p.s.: 那个漂亮的MySQL专用语法是 INSERT INTO table_name (`col_01`, `col_02`) VALUES( 1, 1 ), ( 2, 2 ) ON DUPLICATE KEY UPDATE `col_01`=VALUES(`col_01`), `col_02`=VALUES(`col_02`)
后来判断重复还需要参照其他表了(字符串用的都是key,实际值在另一个表里查找),我看太复杂了,还是把工作还给php吧

编程遇到问题的时候,为了解决问题而查东西和尝试性编程时,是可以进入和打lol时一样的亢奋状态的,有这种状态时可以通宵。
另外就是UML已经设计完成,只剩编码时,可以连续长时间内写出大量代码,而且编写时可以分神,听音乐看电视剧什么的,都不太影响编写。这种状态和素描画好型以后上调子时的状态很像,属于体力劳动。

不过我现在是在公司,打开UML工具太明目张胆,直接写呢,就感觉进展比较慢,一边要设计一边要实现,设计受限于已经写好的代码,不好大改,实现也因为设计的小改动而不得不反复跟着改接口。

总之就是很泥泞,粘滞,导致心情不好。

为了缓解烦躁的心情,听了一天きゃりーぱみゅぱみゅ的歌,结果更影响思考了。设计程序时果然只能听纯音乐啊。

听音乐的时候我注意到きゃりー的歌好像词曲总是同一个人——田中やすたか。查了一下,直接震惊了!这人是きゃりー所有作品的词曲作者,同时也是Perfume所有作品的作者,还给一大堆人写过歌,自己还有自己的音乐作品,这……

除了佩服他的造神能力,我更在意的是他这种不正常的产量。作为创作者,高产是美德,也是长期活跃的必要保证。我每天一两百行的低产问题,需要解决一下了。是不是每次都挑战未知领域,所以进展缓慢又耗费热情?我确实不屑重复自己已经习得的技能,不过这里好像还不太一样。应该是,没有清晰明确的目标,一直随手写,大部分时间在关注接口优雅和可重构的地方,所以进度一直是停的。为什么在公司干活,我就能精神亢奋地直奔主题呢。笃志也说过在公司是和策划讨价还价,定下来以后就不想着改策划,一门心思直奔实现去了,自己写则会在意设计细节,在反复重构和推倒重新设计中浪费时间。所以我很想要一个人专门帮我写策划啊!但是我还在服务器端的框架设计阶段,这种技术向的东西没法让人给我写策划啊它又不是界面UI!

那也需要一个固定的目标,这个目标定好了就不能动了。之后以达成这个目标为里程碑开发。不管合不合理,只要实现了里程碑,就可以了。我需要清晰的目标。确实,以前也有过“关掉电脑的时候写程序最快”的感觉,因为那时候可以做纯设计,一旦设计可以定案,之后的实现就只是体力和时间的问题了(干活时可以走神呢~)。今天代码就写到这里,拿起纸笔设计目标吧~

长话短说

03.03.2014, 2 条评论, 未分类, by , 2,906 views.

2月已经过去,无论结果如何,挑战还是要继续。

失败只有一种,就是半途而废。

 

今晚11点30分 20:30 20:00 离开公司。立贴于此。

公司的工作闲了下来,继续弄我的卡牌服务器。

在公司开发服务器端的时候用的是php,公司在所有人都没有可以单步调试的IDE的条件下,仅靠着var_dump啊print_r什么的,竟然也开发完了一个网页游戏。我写了几天,就被自己满屏的print_r给恶心坏了,花了半天时间,装上了eclipse和pdt和xdebug,在自己的虚拟机里快快乐乐的单步调试了起来。

现在回到我的卡牌游戏,相比逻辑简单而且只是一问一答的php,我的node.js游戏内逻辑的调式环境可说是更加险恶了。
因为至今为止规模都不大,所以我一直没有搞单步调试环境,全靠输出log来排错。但是今天在我的一个稍微底层的地方出现了逻辑错误,为了排错,我不得不添加了大量的console.log输出代码。虽然最后总算是把bug排掉了,但log信息已经海量到没办法轻易查找其他小地方不定时出现的错误信息。顺便说一下,我觉得看log排错是一种很恶心的体验= =

接下来怎么办呢。因为是开发阶段,我搞个单步调试环境应该不难,但是听说因为服务器一旦开起来,轻易就不好关了,想收集生产环境中出现的错误,拿到本地再现,改正,然后在短暂的停服更新期间打补丁的话,log输出方面的设计就必须重视起来。

嗯,可是我刚和log大战了30分钟,正犯恶习,现在不太想深入思考这个话题。再说这次只是个练手作品,处处都抓就坑了。总之先记录下来,至于解决方案,就容我暂时搁置一下吧。

程序员的交流能力还真是非常的重要。

情况是,tableA有N个逻辑列,另外还有两个列存储在tableB上。本来tableB上的这两个列和tableA上的逻辑列地位完全一样,就应该放进tableA里的,但是因为想兼容操作tableB的代码,所以这两列不得不和tableA分着家。
同事让我在去tableA的值的时候也可以取到这两列,我就在根据给出的逻辑列id取对应值的函数里做了一点改动,让存储在tableB中的数据像tableA上的虚拟数据一样访问,对使用者透明,而且没有任何额外的查询和处理效率上的额外负担。举例来说:
以前是 getRow( keyId, [ col_1, col_2, col_3 ] )
现在可以用 getRow( keyId, [col_1, col_2, col_3, virtual_col_4, virtual_col_5] )来取那两个值了。
但同事表示他希望另做一个总是取所有列的函数,在那个函数里单独select这两列,最后合并为结果返回。我说如果有人想单取这两个值,也不得不取所有值吗(因为是逻辑列,实际上是分布在多个table上的很多行,取所有值的代价很大)。他想了想,说那可以再做一个专门取这两个值的函数。
他的意思是让每个操作都尽量简单,但是getRow这个函数已经是一个一行的函数了,非常的简洁明了原子。本来这两个值在概念上就是和其他列同等的,做成虚拟列比单取更优雅。他则坚持他的观点。我用日语跟他争辩,本来就很耗费精力,再加上他年纪比我大,就更不想跟他争了。最后我说这是编程哲学上的分歧了,如果你想这样做,那我就这么给你实现吧(说的时候尽量露出笑容)。他大概看出我的不满,还在给我解释为什么那样好,我只好硬挺着微笑着跟他说,这件事是こだわり(个人执念)方面的问题,我不想继续讨论这个问题了。
确实是个人执念的问题。事实上,就在之前,我们已经彻底废除了tableB的原有功能,所以兼容已经不是理由了。这时候如果他说把这两列写进tableA里,我还可以接受,可是在项目代码本身并没有统一的设计风格,我代码已经写成,可以正常运转的情况下要我撤下现有设计,改换接口和所有相关调用,实在只能用こだわり来解释。

在这种程序设计的选择方面,如果充分交流,我有信心证明自己的做法更优越,但当时就突然觉得很累,心理资源暂时性用尽,于是放弃了交流。我写过的大部分代码都是一个人完成,没有人插手的,所有实现和重构都由我一个人统一风格,结果上也总是能达到我预期的灵活性和接口的优雅美观。如果项目本来有统一的风格,我肯定是要遵守现有风格的,可现实并不是这样。
放弃交流,最先影响到的是热情,这个我对现在的山寨外包工作本来就没抱有,所以没什么。既然没什么,那就算了吧。
现在上班是为了积累经验,好用到下班后的项目里。等个人作品完成以后,跳槽去个让人更有热情的公司去吧。

说到个人作品,现在越发觉得是个越挖越大的坑。我历来勇于挖掘,怯于填埋。这次这个卡牌游戏我本来是想只做个服务器端,好拿去找工作的。后来越想越多,要跨PC,android,ios平台,在后来看到cocos2d-html5了也想跨到网页版了。结果,坑大了,前面望不到头了,进度反而慢了下来。最近开始收小阵地,客户端只用javascript命令行,做一个文字版的卡牌客户端先。要限制欲望的膨胀。要做一个Demo,只关注我所关注的部分——服务器端。

今天又下了一遍笃志的代码,wc -l统计了一下行数:引擎8w多行,棋牌5w多行(不含depend)。这些都是业余项目啊(望向我1800行的服务器端)。一个月要写1w行的话,一个工作日要写500行。我现在的下班时间和周末已经完全被lol占满了,每天凌晨4点睡,周末上午7、8点钟睡已经是家常便饭。服务器端的代码每天只能在单位写一点点,照这样下去,到我预计的5000行,怕是要等到下半年了。可跳槽要趁早啊,我TOEIC和N1都考出来了你就给我说这个?

冷静。回想一下研究生时代,这又是新一轮的拖延型消沉。当时我自责了两年半,不仅没有解决问题,还让情况越发严重,精神痛苦,最后一年几乎是哭着等待毕业的。痛苦是可以熬,但是这种自责带来的痛苦并不是熬完了就能解决问题了。首先它也熬不完,我会严厉的批评自己一辈子不动摇的,这种倾向很明显。其次,这和解决问题是完全相反的方向,它从最开始就不值得我忍受。

要用力原谅自己。
我对人太严格挑剔了,对自己尤甚,看谁都有无法容忍的缺点,也就很少能在哪个集体里感到自在放松。别人可以不接近我,但是我没办法和自己保持距离,接近自己又被批得太痛苦。我为自己一天不能写14个小时程序而怒其不争,而事实是我现在在假日里连14分钟的程序都写不了,怎么可能满足这么高的自我要求?

什么事一深想都会牵扯出一套自责的理论来,要么自责,要么自责自己的自责。这种时候最需要的,就是把脑袋空一空。玩就玩了,该高兴就高兴。不过其实玩游戏并不能带给我真正的快乐,按知乎上看到的理论,游戏属于被“渴望”系统刺激出的欲望,让自己有强烈的“做了就会快乐”的错觉,而事实上去做了也不会获得快乐。

我需要区分“渴望”和真正的快乐。我始终逃避的工作之外的“集体活动”、“与人相处”等等,实际上却总是会为我带来超出预期的巨大快乐。以后做事时先回忆一下以前做玩类似事情之后留下的是快乐的回忆、还是麻木的回忆。忍耐带给我麻木的“渴望”,忍耐逃避可以创造快乐回忆的活动的冲动。

具体来说就是,(逐步)减少lol的时间,出席社团的chat会议,约朋友出去吃饭看电影,早睡早起(意外地会带来好心情),给朋友打电话。