作者归档:贺 利华

关于贺 利华

正在学习编程,享受编程 热爱文学,闲来读读《读库》 有思想,没理想 正在学会专注

什么叫创业心态?

从坚持了整整4年的喜讯离开了,肩上的担子一下轻了下去,自己角色转变还蛮快的,倒也没有觉得有什么不适,感谢我们武雪同学在离职的当天晚上还给我做思想工作,让我别想太多不要太难过,要快乐地度过这段离职缓冲期。

在喜讯四年多,从一个什么都不懂的愣头青小子到如今依然懵懵懂懂的一个程序员,四年里头自己坚持得最多的可能概括起来就是『用创业的心态去做事情』这么几个字吧。

现在有很多的企业都在宣称要去中心化,要精英团队,在大公司内部提倡小团队在公司内部创业,例如『金山软件』将所有的大部分拆分成各个小的子公司,让各个自己公司『重新创业』,也确实看到了『猎豹移动』这样快速成长的上市子公司,成绩非常斐然。同时我们也看到了『腾讯广研』团队创造出来的『微信』神话,这些都是非常好的大公司小团队创业成功的例子。包括百度也在提倡要狼性,无非也就是要求大家要忘却自己是大公司的身份,要重新给自己定位,要有创业的心态。

这些公司和团队都提倡一个『创业心态』,那么『创业心态』是啥?我自己的理解就是『把公司分配给你的任务当成自己的事情来做』。这句话读起来非常简单,感觉也挺好做到的,但是在自己跟着公司创业的这4年多时间里,委实觉得要做到实在不易。

『把公司分配给你的任务当成自己的事情来做』要求自己做到两点:

1. 要有责任感,只有拥有强烈的责任感,才可能把事情做到位,未来才有可能会有更多的任务和责任分配到自己的头上。例如公司让你完成某个项目中的A功能模块,那么怎么才能顺利把A功能完成呢?这个时候可能会碰到以下问题:

  • A功能是自己之前从未遇到过的一个技术难题,需要自己苦心钻研几天才有可能找到解决问题的方法,但是项目进度要求非常紧张,如果花费几天搞定这个问题,成本太高;
  • A功能跟某个B功能是有非常强关联的,如果需要做A的话,需要调整B功能,B功能一直是其他的某个同事在负责,但是目前该同事也有较重的任务在身上,无法脱身来协助调整B功能;
  • 等等类似的问题都可能会出现,举例只是想说明在我们处理任何问题的时候都可能不只是一个简单的花费多长时间,通过工作量就可以搞定的。

那么在这些情况下我们要怎么才能按时按质按量完成A功能呢?好吧,其实我也不知道具体的解决方法是啥啦,因为大家碰到的问题可能千奇百怪的,所谓『家家有本难念的经』,谁知道尼玛你会碰到什么狗逼问题啊。但是,在我们碰到类似的困难的时候,只要认定这个事情交到自己手上,自己一定要想办法搞定他,遇到技术难题迎难而上,加班加点肯定不是什么稀奇的事情,遇到需要其他同事协同处理,努力跟对方沟通协调时间,对方实在没空可以考虑跟对方沟通确实调整方案自行修改,如果实在自己能力有限,确实无法在指定时间内搞定该问题,或者自己根本就完全没有办法搞定这个问题,那么及时反馈到团队负责人那儿,大家一起来想办法。

公司给大家发薪水,大家需要体现自己的价值,解决公司的问题是每个团队成员必须具备的基本素质。在创业团队中更是如此,因为团队建制较小,每个人都需要独当一面,甚至独当多面,那么公司交给你的事情,一定要尽最大的努力完成,因为团队中其他的成员默认这个事情交给你就是需要你来搞定,团队中其他环节的安排都会以你默认可以搞定这个事情为前提去开展,如果出现自己无法搞定而又未能及时反馈到团队,最终造成团队内部消耗,有个几次团队其他人便会认为你完全没有责任心,或者也可以说没有能力,交给你的事情完全搞不定,还不及时跟团队沟通。一来二往,你在团队中会失去队友对你的信任,那么未来不太可能再有什么责任交给你,只会给你一些鸡毛蒜皮的事情。只有你给团队其他人一种踏实可靠的感觉,大家在分配重要任务的时候,才会想到你,就这样,做一个『靠谱』的人很重要。

2. 要有主人翁精神,说白了就是在有责任心之外,还要多管闲事。为什么要多管闲事呢?其实创业团队最主要的一个资源限制就是人员不够,很多配备上是不完善的,那么你作为一个客户端程序员是否就只关注客户端程序的实现呢?当然关注客户端程序的实现是本职工作,一定要踏踏实实做好,做一个『靠谱』的客户端程序员,除此之外,其实还有很多的事情需要你来参与,正所谓『众人拾柴火焰高』啊,你不负责生火,但是你可以捡柴火啊。

  • 产品设计,虽然客户端程序员不需要承担产品设计的工作,但是作为一个用户,你也可以提出自己的看法啊,认为有可以改进的地方,当然需要主动提出来,供大家参考了,不要觉得不好意思,尼玛产品做砸了,你一样也被用户骂,你一样也没有奖金;
  • 服务端架构,虽然你只是个客户端程序,服务器神马的完全看不懂啦,不要给这么多鸭梨好不好啊?好吧,是有点强人所难,可是难道你真的没有想法吗?如果服务器的架构设计完全不考虑与客户端如何通信交互,这难道也可以?好吧,显然不行,那么就把自己能想到的可能出现问题的地方,尽早说出来吧,这样大家才能一起想办法来搞定这些事儿;
  • 团队文化,感觉好高深的样子,其实尼玛你就是团队成员,你也是这个文化的缔造者啊。所谓团队文化,无非就是团队所有成员在做事情的时候形成的一些共识的做事的方式和方法,那么你自己做事情的方式和方法无疑会给整个团队的文化刻上你的印记。那么自己写代码的时候是不是要考虑把方法名起得简单易懂有意义呢,是否每次提交代码的时候需要写清楚此次提交的注释呢,是否在下班的时候要让自己的电脑关机呢,都是些鸡毛蒜皮的小事情,可就是这些小事情会逐渐形成为整个团队独有的风格,随后加入的成员会慢慢融入到这些风格中来的。

公司有很多岗位,每个人负责的事情可能也不一样,这里也只是简单的举了几个例子,其实每个人在做完自己的本职工作之外,有很多的事情都是可以参与进来的,充分发挥自己主人翁的精神,把公司当成自己的公司,珍惜身边的每个人,认真对待每件事情,其实也可以侧面地让自己更有责任感,既然自己已经是公司的主人了,那么还有什么责任承担不了呢,是吧。

如果自己认为自己只需要把自己的事情做好,其他的事情就应该由别人来搞定,这当然没有什么错,但是这个并不适合在创业团队还没有足够的资源配备的情况,确实就是有很多的事情需要你来参与,一起努力。自己搞定自己的一亩三分地之后,事不关己高高挂起,如此这般,团队中其他人慢慢地就会认为你根本没有把这个团队当成自己的团队,慢慢地你就边缘了,慢慢地你就离团队中心越来越远了,最后你就会觉得自己就像是个外人,说话都插不上嘴,自己也不被团队认同了,你说这能是啥好事吗?

 

Unity3D游戏在iOS上因为trampolines闪退的原因与解决办法

崩溃的情况

进入游戏一会儿,神马都不要做,双手离开手机,盯着屏幕看吧,游戏会定时从服务器那儿读取一些数据,时间一长,闪退了。尼玛问题是神马呢?完全没有头绪,不过大体猜测是因为网络请求导致的,那么好,先排查服务器返回结果是否有问题,最终确认每次客户端崩溃的时候,服务器都成功的返回了格式正确的数据,没有任何异常。那么可以确定问题是出在客户端部分了。 先检查代码,确认逻辑上没有任何问题之后,也倍感无力啊,问题依然在重现。肿么办呢?

确定具体原因

那么好吧,打一个测试版本再来看,然后再等着崩溃,查看崩溃日志吧,最终看到的崩溃日志中,崩溃线程输出信息如下:

Thread 27 Crashed:

0 libsystem_kernel.dylib 0x38e671fc __pthread_kill + 8

1 libsystem_pthread.dylib 0x38ecea4e pthread_kill + 54

2 libsystem_c.dylib 0x38e18028 abort + 72

3 gowonline 0x0178a0c0 mono_handle_native_sigsegv + 312

4 gowonline 0x01779a30 mono_sigsegv_signal_handler + 256

5 libsystem_platform.dylib 0x38ec9720 _sigtramp + 40

6 gowonline 0x00114f48 m_RestSharp_Http_ExecuteCallback_RestSharp_HttpResponse_System_Action_1_RestSharp_HttpResponse + 52

7 gowonline 0x001142b4 m_RestSharp_Http_RequestStreamCallback_System_IAsyncResult_System_Action_1_RestSharp_HttpResponse + 900

8 gowonline 0x00329c60 m_2be7 + 48

9 gowonline 0x00a39d08 m_System_Net_WebAsyncResult_DoCallback + 76

10 gowonline 0x00a29628 m_System_Net_HttpWebRequest_SetWriteStream_System_Net_WebConnectionStream + 536

11 gowonline 0x00a46f84 m_System_Net_WebConnection_InitConnection_object + 708

12 gowonline 0x0101ffac m_wrapper_runtime_invoke_object_runtime_invoke_dynamic_intptr_intptr_intptr_intptr + 200

13 gowonline 0x017792d4 mono_jit_runtime_invoke + 2152

14 gowonline 0x0181b324 mono_runtime_invoke + 132

15 gowonline 0x01820118 mono_runtime_invoke_array + 1448

16 gowonline 0x01820510 mono_message_invoke + 444

17 gowonline 0x018444a8 mono_async_invoke + 124

18 gowonline 0x01844174 async_invoke_thread + 312

19 gowonline 0x0184c580 start_wrapper + 496

20 gowonline 0x018695b4 thread_start_routine + 284

21 gowonline 0x01885750 GC_start_routine + 92

22 libsystem_pthread.dylib 0x38ecdc5a _pthread_body + 138

23 libsystem_pthread.dylib 0x38ecdbca _pthread_start + 98

好的,那么已经确定是在我们使用的一个第三方类库RestSharp中出现的问题,问题是出现在一个Action回调的地方。那么这种问题为什么会出现呢,那我们就得好好得来找找原因了。

关于如何查看iOS崩溃日志,让崩溃日志更加友好,我们可以参考这篇文章,iOS应用崩溃日志揭秘,主要就是要确保你的设备上跑着的这个App的编译和打包的二进制文件要在你用于查看日志的Mac上,这样的话,当我们查看崩溃日志的时候,Xcode会自动将那些无法阅读的函数调用的堆栈信息转化成可读性较强的日志信息,帮助还是很大的。

那么这个时候我们可以通过将设备连接到Mac上,直接通过Xcode将程序编译并运行,多尝试着玩一段时间,当程序再次出现崩溃的时候,我们就能看到更清楚的函数调用关系了,同时也能看到更多的日志提示。

最终能确定每次崩溃的函数就是这个mono_convert_imt_slot_to_vtable_slot,这个看上去就是Mono Runtime在将接口声明的方法指针指向实际实现这个接口的对方的方法,我们可以找到mono_convert_imt_slot_to_vtable_slot这个方法所在的文件查看一下,这个方法就在Mono项目的目录mono/mini/mini-trampolines.c中可以找到。

在Xcode中崩溃时,会输出类似” SIGABRT (ERROR:mini-trampolines.c:183:mono_convert_imt_slot_to_vtable_slot: code should not be reached) “的日志,看着很像是原本是要执行某个方法,但是不知道因为什么原因这个方法就无法访问到了,好奇葩啊。

解决方案

现在虽然已经知道了问题出现的地方,但是貌似完全看不明白的样子,尼玛trampoline都还是第一次听说耶,那么先请教一个我大Google吧,我们总是相信自己不是那第一个吃螃蟹的人,所以我们找到了一位大神的解决方案就在这里,大神的文章写得非常言简意赅,大体意思就是如果你在做Unity3D开发时,特别是在针对iOS和Android平台的时候,你很有可能会碰到比较杯具的就是程序会莫名其妙地闪退哦,不过不要着急,这个通常就是因为你的程序编译的时候给trampoline分配的空间太小,而你的程序中又大量使用了泛型、泛型方法调用和接口实现导致的。然后给出了具体的解决方法,那就是在Unity3D的编译选项Player Setting中有一个AOT Compilation Options条目,在这个选项条目中加上以下编译参数就好了

nrgctx-trampolines=8192,nimt-trampolines=8192,ntrampolines=4096

然后再重新一下,多多测试吧,骚年。关于这三个参数的意思呢,大神也给出了解释,分别如下:

  1. nrgctx-trampolines=8192 这是留给递归泛型使用的空间,默认是1024
  2. nimt-trampolines=8192 这是留给接口使用的空间,默认是128
  3. ntrampolines=4096 这是留给泛型方法调用使用的空间,默认是1024

Mono Runtime AOT机制剖析

虽然问题貌似已经得到解决了,而且我们貌似也搞清楚了具体原因就是因为默认Mono Runtime在AOT编译的时候给的trampoline配置太小,不适合我们这种设计优良,大量使用interface,设计绝对遵照OO思想的稍大一些的项目呢。那么我们以后是不是在做Unity3D开发的时候就尽量少用接口呢?是不是我们就尽量少用泛型和泛型方法呢?

既然这么感兴趣,想问个究竟,那么我们就来好好看看这个AOT到底是个神马东西吧,尼玛为什么就这么复杂,这么隐蔽,这么折腾人,《铁血战神》在App Store上线都5个月了有木有,尼玛这个问题碰到也不是一次两次了有木有,作为程序猿的我们被玩家吐槽了很多次,我们的客服XDJM们为我们背了多少黑锅啊,我勒个去啊。

首先,还是先搞定这个trampoline吧,毕竟问题的根源是在它身上的,那么我们就好好来看看这是个神马东西。我们找到Mono Runtime的官方文档中关于trampoline的描述来看看吧。

Trampolines are small, hand-written pieces of assembly code used to perform various tasks in the mono runtime. They are generated at runtime using the native code generation macros used by the JIT. They usually have a corresponding C function they can fall back to if they need to perform a more complicated task. They can be viewed as ways to pass control from JITted code back to the runtime.

翻译一下吧:

Trampoline是一些手写的非常短小的用来在mono运行时中执行很多操作的组件代码。主要是通过JIT使用到的本地代码宏在运行时动态生成的。它们通常都有与之相对应的C方法,在某些较为复杂的场景中,当trampoline无法胜任时,mono运行时就会将这些复杂的操作交回给这些对应的C方法来执行。这也可以看作是将JIT代码的执行权交回给runtime的一种方式。

好吧,貌似还没有太明白,那么这个Trampoline为什么会导致出现闪退的问题的,这看起来明显是为了提高mono runtime在执行C#代码时候的效率啊。

那么我们再来看看官方文档关于JIT Trampolines和AOT Trampolines的介绍吧,杯具的IMT Trampolines介绍还在//TODO状态中。

JIT Trampolines These trampolines are used to JIT compile a method the first time it is called. When the JIT compiles a call instruction, it doesn’t compile the called method right away. Instead, it creates a JIT trampoline, and emits a call instruction referencing the trampoline. When the trampoline is called, it calls mono_magic_trampoline () which compiles the target method, and returns the address of the compiled code to the trampoline which branches to it. This process is somewhat slow, so mono_magic_trampoline () tries to patch the calling JITted code so it calls the compiled code instead of the trampoline from now on. This is done by mono_arch_patch_callsite () in tramp-.c.

好吧,再翻译一下吧。

JIT Trampolines 这些Trampoline主要是JIT在首次调用某个方法的时候编译方法用的。当JIT在编译一个方法调用指令时,它并不会立刻就编译这个被调用到的方法。实际上,它会先创建一个JIT Trampoline,同时创建一个指向这个trampoline的调用指令。当这个JIT Trampoline在调用到的时候,它会再调用mono_magic_trampoline()方法来编译这个trampoline实际指向的目标方法,然后将编译后的方法的指针地址返回给这个指向它的trampoline。这个过程呢稍微有点慢,所以呢,mono_magic_trampoline()方法会优化调用JIT代码的过程,它会先尝试调用已经通过JIT编译过的方法而不是立即通过trampoline直接进行调用。这些都是通过在tramp-.c文件中的mono_patch_callsiete()方法来完成的。

这就是JIT Trampolines的机制,接下来我们看看AOT Trampolines又是怎么一回事呢。

AOT Trampolines

These are similar to the JIT trampolines but instead of receiving a MonoMethod to compile, they receive an image+token pair. If the method identified by this pair is also AOT compiled, the address of its compiled code can be obtained without loading the metadata for the method.

再翻译一下。

AOT Trampolines AOT Trampolines和JIT Trampolines非常相似,但是AOT Trampolines接受的编译参数不是一个Mono方法而是一个image+token对。如果传入的用于编译的image+token对所指向的方法已经经过AOT编译过了,那么再次编译这个image+token对时,就会直接返回这个已编译方法的指针地址而不需要再次加载这个方法的元数据进行再次编译了。

好吧,看了这么多关于Trampoline相关的内容,貌似只是了解到了非常有限的内容,那就依然是Trampolines存在的价值就是为了减少C#代码在mono runtime中运行时的性能损耗,提高C#代码的执行效率。

还有那个没有出场的IMT Trampolines应该也就是用于优化接口调用效率的小『蹦床』吧。

那么我们在开发Unity3D游戏的时候通常都会发布到iOS设备和Android设备上,而Unity3D在iOS和Android设备上的发布都选择了使用AOT编译机制来实现。那么显然我们碰到的Trampolines问题都是跟AOT Trampolines有关,那么AOT又是神马呢?

AOT就是区别于JIT(Just In Time)的另一个编译机制,全称是Ahead Of Time,就是预先编译好,而不是在代码执行到了某个方法再进行编译,这样的话会有一些好处。

通过查看Mono官方AOT介绍文档,使用AOT编译的有点有以下优点: 1. 加快程序启动速度 2. 更强的内存共享机制 3. 潜在的性能提升

当然也会有一些限制,例如支持平台的有限,支持AOT的Mono版本有限等等,具体信息可以参考Mono官方AOT介绍文档

那么回到我们最开始的问题,为什么我们的游戏就会出现崩溃呢?好吧,现在一点点回顾吧。

我们出现的问题是偶尔会出现闪退,根据崩溃日志我们能定位到是mono_convert_imt_slot_to_vtable_slot这个方法导致的,然后我们再通过Xcode跟踪到了是trampoline无法被访问到的问题。

那么这么高端大气上档次的问题是肿么出现的呢?貌似Mono还算是个不错的产品啊,还是很活跃的啊,也有专门的公司Xamarin在支撑着,怎么就会出现这种问提呢?

好吧,程序都是人写的,有问题也是很正常的。上面的分析已经很清楚了,大体的原因就是因为Mono在iOS/Android等移动设备上使用了AOT这种机制,为什么选择这种机制?原因非常简单,那就是可以针对特定平台编译成在平台优化的字节码,在资源比较紧缺的移动平台上还是有着明显优势的。而使用AOT编译就需要为Trampolines这些小东西留足足够的空间,当然这个肯定是硬编码的某个常数啦,在整个程序加载成功运行之后,该常数就成为了Trampolines运行时的配置。AOT默认编译时给Trampolines的参数有点低:

nrgctx-trampolines 默认为1024

nimt-trampolines 默认为128

ntrampolines 默认为1024

这对于小一些的项目可能是够用的,因为整体项目的结构不会太复杂,使用到的接口、泛型、递归相对也不会太多,但是对于一个稍大一些的项目来说,特别是采用了某些设计良好的第三方库的项目来说,这就比较纠结了。

其实我们在项目中就使用了两个第三方的库,一个是CodeTitan.JSon库,一个是RestSharp,分别用于JSON解析和HTTP请求处理,可是这两个库实在是设计得太好了,各种使用接口,各种抽象,没个两三天我都没法说完全理解了整个库的结构。

就是因为这些设计良好,完全遵循OOP原则,高度抽象的类库将Mono默认的Trampolines的配置耗尽了,所以捏,我们就把这个编译选项开大就好了,解决方案就是上面咱们提到的咯。

Unity3D游戏AppStore审核因为ASIdentifierManager被拒的解决办法

上周末我们的游戏『铁血战神』提交AppStore审核已经快一周了还木有结果,很是着急啊。周六上午终于有消息了,只可惜不是什么好消息,我们被拒了,被拒绝的原因很简单:

“You and Your Applications (and any third party with whom you have contracted to serve advertising) may use the Advertising Identifier, and any information obtained through the use of the Advertising Identifier, only for the purpose of serving advertising. If a user resets the Advertising Identifier, then You agree not to combine, correlate, link or otherwise associate, either directly or indirectly, the prior Advertising Identifier and any derived information with the reset Advertising Identifier.”

Note: iAd does not use the AdSupport framework, ASIdentifierManager, or the Advertising Identifier. Therefore they are not required for iAd implementations and should not be included in your app for iAd support.

Please check your code – including any third-party libraries – to remove any instances of:

class: ASIdentifierManager

selector: advertisingIdentifier

framework: AdSupport.framework

就是我们的游戏中没有任何广告,同时我们也不帮其他的应用做推广,那么好吧,苹果认为我们不应该使用这个专门为广告而设定的接口(真是尼玛没有道理可以讲啊,据说是为了打击积分墙等类似的推广手段,防止刷榜等等)。

那么好吧,先把我们自己使用到ASIdentifierManager处的代码全部干掉,那么这样是不是就可以重新打包然后再提交呢?

貌似不是滴,咱们还是遍历查找一下整个工程的代码吧,看看还有没有别的地方调用到了这个类的某些方法,最终你会发现,Unity3D编译出来的iOS工程中的部分iOS代码使也用到了这个接口,这部分代码在编译出来的工程下,Classes/Unity/DeviceSettings.mm文件中。

不得不说Unity3D的实现还是比较好的,最起码没有包含AdSupport.framework,没有直接引用头文件,也没有直接调用ASIdentifierManager这个类的advertisingIdentifier方法,而是通过动态的查找这个类库同时动态的找到方法再调用,不过貌似这样也木有办法绕过苹果的审核哦。最终还是会现形的,那么最终如何解决呢?

Unity3D的官方论坛上已经有了Unity3D的开发人员给出的Quick Fix了,大家自行前往查看即可,传送门在这里.

大体的思路还是将使用到的代码都删掉,不过为了避免以后每次重新编译Unity3D项目到Xcode工程时,都得手动修改一次,Unity3D的官方人员也提到最好还是一次性搞定Unity3D使用到的模板文件,这个文件就在/Applications/Unity/Unity.app/Contents/PlaybackEngines/iPhonePlayer/iPhone-Trampoline/Classes/下,找到DeviceSettings.mm文件,按照那个Unity3D官方的Quick Fix来修改,以后每次编译出来的新工程中这个文件就不需要再次手动修改了。

修改完了之后,重新打包测试提交,顺利通过审核,感谢所有TV啊。

要开始想些事情了

很多的时候,我们总以为还可以继续天真下去,可是现实会无情而直接地告诉你这不是你想要就能要,尼玛天真就留在那些可以天真的岁月吧。

是时候开始想些事情了,生活不会因为你天真而变得美好。

谈谈理想吧

离开校园快5年了,记得还在学校的时候,我们不时地会畅想一下未来,虽未必在谈理想,起码也算是年少时美好的憧憬吧。

曾经跟宿舍好友们,坐在学校旁边小吃街的小餐馆里头,喝着冰啤酒,吃着长沙火辣的家常菜,不少个夜晚,跟不同面孔的同学,纷纷表达过自己对未来的各种憧憬,也有对未来未知的一些恐慌。

如今,回头看看,还是蛮有意思的。曾经讨厌写程序的GM在毕业之后加入南方测绘公司某旗下子公司,在两年之内成为了研发部门的中坚力量,每日与代码厮磨。我们最可爱的班长–猪头,在成功完成了保送的硕士研究生学业之后,如愿以偿地回到了福建厦门,虽然离他回到老家罗源还有一点距离,但是也算是圆满了。我们的亢芬同学,更是在一年之内终于成功嫁给了一个好老公,成为了光荣的军属。赵姐和赵胖的爱情结晶更是健健康康地来到我们身边,虎头虎脑的甚是可爱。偶像思麦如愿以偿地成为了自己一心想成为的游戏开发者,不知到偶像现在是否依然热爱和享受着制作游戏的那份快感。老比终于打破了这四年来我们一直的疑惑,选择了离开GameLoft前往深圳再次创业去也。刘琪最终没能持续做游戏,与我在喜讯相伴两年之余后,离开加入了Tencent大家庭,工作之余从未放弃为我国GIS行业的互联网化做着实际的工作和思想上的探索。而我,依然还在喜讯这个集体中,辛苦并坚持着。

曾经很多次跟同学聊天,有大学的同学,也有高中的同学,甚至老家的发小,都曾经问过我类似的问题,你们怎么这么辛苦?都这么些年了,你图什么,得到了什么?

首先,我在喜讯这几年确实很辛苦,工作时长平均每周70个小时以上,这没有什么值得炫耀的,说句难听的话,这说起来都是泪啊。
其次,我在喜讯这几年,目前得到了所有我应该得到的,公司给予我的跟我为公司做的,我认为是对等的,甚至公司给予我的多于我目前所创造的,未来会更加平衡一些。
最后,我图什么,其实我也不是特别清楚自己图的是什么,只是这一路走来,自然而然就成了现在的状态。

回到标题,谈谈理想。

在我们曾经年轻的日子里(貌似我现在也还没老哦),我们都曾美好地憧憬过未来,寄予美妙的幻想。我也曾多次问过自己,我的理想是什么?回过头看自己这26年里,自己一直想做的事情,貌似除了写作还真没有什么其他的想法。

在自己还是个小孩子的时候,就曾经梦想自己有一天能著书立作给别人看,除了这个一直保存在内心的小愿望,还有就是有一颗较为强烈的成为有钱人的原始欲望的心。也许是因为从小,家中家境一直不算好,在老家父母二人就是普通的农民,只是父亲自己年轻时候比较愿意学,也确实学过几年木工,所以父亲在老家还算是有一技之长的木匠,家中有我和弟弟两个孩子,父母辛苦大半辈子还算顺利地让我俩都大学毕业了。但是家境并没有因为我和弟弟二人的毕业加入工作之后顿时好转起来,只是已经不再像之前那么捉襟见肘了。正是出于对现实生活很多不确定因素的恐慌,以及多年来看着父母因为物质条件从未能真正地享受属于他们自己的生活,即便如今,二老在家依然劳作,说是趁着自己还能干得动,需要给我们攒点钱,能给我们减轻一点负担算一点。当我每次听到父母这番话时,作为长子长孙的我,我只有一个想法,我要让这个家庭不再那么穷。穷是一个很搞笑的字,看起来就像一个人在天底下,很用力的干活。穷人的姿态也许就是这般吧,我的爷辈,父辈,包括我自己,也许都会一直在天底下以这种姿态长时间地存在着。

不过,我跟我父亲一样,我们相信只要自己努力付出,总会有所回报,我的父母通过自己勤劳的双手,将我跟我弟弟送入大学,而且从未让我和我弟弟在生活上感觉到非常的困窘,他们真的很了不起。我想我起码应该在我父母给我创造的基础上,延续我父母的成就吧,也就是确保我能给我的后辈一个更好些的基础。多么原始和简单的欲望,纯粹就是出于本能的欲望。但是,不可否认的是这个欲望支撑了我很久,直到现在这个依然是我愿意付出我所有努力来达成的首要目的。

作为小学生的我,初中生的我,高中生的我,大学生的我,从未想过自己将来会成为科学家,警察,军人等等,唯独曾经梦想过的就是成为一个可以写作给很多人看的人。如今作为一个程序员的我,过得也非常开心。我有一个非常理解我的女友,有一个非常支持我的家庭,有一份我觉得满意的工作,有一群我觉得可以托付的同伴,真的很难得。

理想很多的时候感觉像是奢侈品,可望而不可及。跟身边很多的人都聊过类似的问题,大部分人的第一反应是“哪儿来的理想啊?”,大家普遍都会谈到很多现实的问题,然后最终得出一个结论就是自己即便是有理想,那都是空想。其实从侧面来看,其实每个人都是有理想的,只是大家通常认为因为现实的各种压力,我们已经没有机会实现自己的理想了。当然我也不能免俗,我也经常这么认为,认为自己不可能实现理想,甚至都认为自己根本就没有理想。只是在随着社会大流,一步一步地走到今天,成为一个社会最基层的建设者,默默地在自己的岗位上发光发亮,兴许会被人发现,当做一颗璀璨明星,兴许就如此慢慢黯淡下来。

现实诚然如此,在成长的路上,我们看到了很多风景,总是梦想有一天自己也能如此享受此般美好,殊不知时间的美好就只有那么多,人人都想拥有,谈何容易。所以我们说要奋斗,只有奋斗才能改变自己的命运,才能让自己站到人生的塔尖,看到更多更美的风景。于是,就有了很多个奋斗之后享受成功喜悦的梦。我自己也有过这样的梦,很直接很直接的梦,梦想有一天自己所在的创业公司能上市,自己作为初创团队的一员,在公司上市之际直接晋升到塔尖。WTF,多美美妙的一刻啊,此时站在塔尖望着下面还在为我此时享受的这一刻奋斗的人们,多么的惬意啊。

成功变成了我们的梦,我们的理想呢?我想即便到了那一时刻,其实离我儿时唯一的理想还是很远,我完成了自己的一个期望也完成了一个作为家族长子所背负的期望。也许那个时候我也会很快乐,可是谁知道呢。

在喜讯创业已经3年有余了,成功的影子慢慢显现,但是能否最终成真没有人能说得清。只有靠自己的努力,靠一众兄弟姐妹们的努力,兴许可以成功。喜讯的成功是不是我的理想?我想在目前的阶段里,这肯定算是我的一个很重要的目标,但是远谈不上理想。创业成功对于有些人来说是理想,对于我而言是手段,这是我摆脱经济困境的唯一手段,我为此会付出所有我能付出的东西。获得成功能让自己获得经济自由,是否我就会开始寻找儿时的理想呢?其实我也不知道,儿时的理想如果真的有如此强烈的话,也许我现在已经开始朝着这个方向前进了,可是我没有。

所以有的时候我就在想,其实理想可能真的跟初恋很像。很刻骨铭心,但未必会是最终的相守,她永远会占据你内心的某个角落,偶尔还会跳出来给你带来一阵阵的瘙痒,让你阵阵地感怀。时间一过,所有一切如常。

也许我真的没有什么理想,有的还就是短时间之内的各种目标,结婚,生子,赚钱,养家,等等。坚持自己有一个理想,无非是想偶尔能让自己显得不是那么的俗不可耐,给自己脆弱而又自负的内心些许救赎性的安慰。告诉自己,这些丑陋的社会现实,这些完全不能理解我的人们,他们不知道我内心想要的是什么,我做不好这个事情其实是因为我的理想根本就不是做这个事情,我要做的是更美好更高尚的事情。多美好的理由啊,还是允许像我这般渺小的人类拥有如此可笑的理由吧。

放下那个远大而崇高的理想吧,回到地球上来,为现在能努力做到的事情多尽一份心,多出一点力,踏实走每一步路,也许哪天真的会跟那个理想再次重逢,就跟结婚多年以后与初恋重逢那种释然的感觉,两者相视而会心一笑。