Imrazor's Blog

Stay Hungry, Stay Foolish

程序员进阶之路

今天公司做了一次内部培训,讲师是陆其明,主题是程序员进阶之路。感觉讲的非常好,做个摘要留存一下

程序员进阶的三个要素:

一、专业

没有救世主,不能指望别人,只能靠自己

静得下心,静下心来沉淀、积累,大牛不是一年两年就练就的

钻得进去,钻的深,才能了解真正的原理,而不是浮于表面

如痴如醉,当设计或是完成一个功能时,全身心的投入

系统、全面,当对某个系统足够了解时,你站的高度就会高,对系统的整体运作也会有全面的认识

实战磨练,多多实践,实战岀真知,某种设计是不是有效,只有在使用的时候才知道

总结、积累,善于总结积累,下次遇到类似问题就容易解决了,而且经常总结会慢慢提高

二、分享

勤加练习,如果你天天埋头写代码,连讨论、反思或者学习的时间都没有,你将得不到真正的进步。

eg:你天天开车上下班,但是你永远也不会成为真正的车手

要在磨练工艺宇思考如何提高工艺之间找到一个适当的平衡点

开放的心态,阅读编程相关的博客或书籍,学会读源代码

最好的学习方法就是边做边学

成为杰出的程序员跟写代码没太大关系,坚韧不拔的精神很重要,更重要的是要有良好的沟通技巧

想从优秀到卓越,必须培养起有效沟通的能力,与同事沟通,与老板沟通,与用户沟通,最终与全世界沟通

如何提高沟通能力?写博客是个好方法

三、职业精神

关注公司战略,达成公司目标,与公司共同成长

心态平和,内心有一份坚持,该做什么不该做什么,do the right thing

快乐工作,快乐不是因为拥有的多,而是计较的少

eg:不要同事升职加薪,自己没有就不高兴

软件开发者的工作不是写代码,而是解决问题,关键是解决问题的能力

最后讲师还说了一些转型问题:

从一线开发变为管理,实际并不是晋升,而是转型了

管理者的定义:管理者是通过别人来完成工作的人

成为优秀的管理者要做到两点:确保你的员工能够工作,关心它们(把他们当人看,而不是资源) Keep them busy,make them happy

eg:老师问我,你这两天参加管理课程,你认为你的部下能完成工作的多少,我:50%吧(因为我技术比他们好很多,所以平时核心功能或者难点都是我来完成),老师:你这样不是管理者,而是super doer

组件化之路

前言

随着业务模块及模块间相互调用的需求越来越多,如果解决耦合及方便模块间调用就变的越来越重要,解决这些问题的一个途径便是组件化

比如我们现在有阅读、电影票、泡泡、秀场、电商等等,这些模块都有调起登录、分享、播放器的需求,一些还需要调起其他的模块。如果直接引用进行调起,那模块的独立测试将变得困难(需要把别的模块也加到自己的测试工程中,如果别的模块又饮用了其他,那么最后会把所有的模块都带进来),而且一旦模块接口发生变化,则所有使用的地方都要进行修改

中介者模式

解决耦合的一个比较通用的方式便是使用Mediator,各个模块都耦合Mediator,这样模块间则不需要相互引用了,并且模块间调起都通过统一接口进行,降低了学习成本

第一次组件化

第一次组件化我们的主要目的是解决耦合,于是创建了一个叫engine的模块,所有的模块间交互都通过engine,比如调起登录类似这样:

EngineObj *obj = [EngineObj engineObjWithModule:ModuleLogin type:LoginRegisterType andParams:@{@"info":@"请先注册"}];
EngineCallback *cb = [EngineCallback engineCallbackWithTarget:self action:@selector(registerDone:)];
EngineSend(obj, cb)

这样调起者就可以不用关系调起注册模块的细节,不论注册成功或失败,调用者都会通过registerDone:方法得到结果

而engine会对应模块维护一个协议,比如上面代码中,打开的module是ModuleLogin,那就路由到openLoginModule:方法,具体的调起逻辑由主工程的一个manager实现,这个manager对象在程序启动时注入到engine中,并且实现了engine中的模块协议

第一次组件化的问题

现在看来,第一次组件化是有很多问题的:

1、模块type需要在engine中维护,新增时需要修改engine的头文件(新增一种module type),新增调起协议。这样一来就违反了开闭原则,虽然修改不多,但还是需要去维护

2、在新增模块或模块接口变更时,主工程的manager需要去维护,耗费人力

3、想调起新增的模块必须新增调用代码

第二次组件化

第二次组件化主要解决了上一次的问题,并且模块的创建模块自己最清楚。所以这一次我们改成了注册制

每个模块在对应的模块中进行注册,并实现一个协议,类似这样:

+ (void)load
{
    [Engine resigserID:@"2" withClass:[self Class]];
}

+ (void)launchWithObj(Obj *)obj
{
    //模块内部进行创建;
}

而这个Obj类包含了3个参数:

//服务器原始数据,包含了模块id,及模块所需参数
@property (nonatomic, strong) NSDictionary *serverParams;
//客户端提供的数据,比如新模块承载的ViewController
@property (nonatomic, strong) NSDictionary *clientParams;
//模块退出时的回调
@property (nonatomic, copy) EngineClose close;

调起代码:

Obj *obj = [Obj objWithSP:sp andCP:cp closeBlock:close];
EngineOpen(obj);

第二次组件化的优点

对比第一次,这一次可以说遵循了开闭原则,新增模块engine无需维护;此外,新模块接入时主工程无序添加任何代码;调用方添加一次调用逻辑,即支持了所有模块(包括后续新增的模块)

总结

组件化需要服务器、各模块的支持。入口的统一也方便做一些统计,比如模块的启动次数,记录栈顶模块还可以在崩溃时知道是哪个模块是active状态,从而为崩溃统计提供更多的信息

2015总结

2015对我来说可谓是喜忧参半的一年,喜的是工作上有所进步,忧的得了一场不大不小的病。

什么最重要

其实这一年对我影响最大的,就是这不大不小的病,他可谓给了我重重的一巴掌,让我清醒过来,明白什么才是最重要的。

10年毕业至得病前,我一直觉得事业是最重要的。为了这个,努力和奋斗自然不能少,平日加班,周末做兼职项目可以完全概括我毕业后前两年的生活。连在创业公司时的领导也常跟我说:“睿哲啊,要按时吃饭,我现在的胃病就是年轻时太拼落下的”。现在回过头看,才对领导的话感同身受。

今年3月底,我们又开始了每年的惯例-封闭开发。本来是两人的工作量,最后因为同事的工作任务变更,全部由我一人承担。常年吃饭不规律,爱喝咖啡的习惯已经埋下病根,最后封闭开发的巨大压力及繁重工作让病彻底显现出来。封闭开发结束时,工作可以说是非常好的完成了,而我因为吞咽食物疼痛进了医院。

拿到病理报告后才知道病的严重性,如果不加控制,就会从现在的轻度往后发展,如果真到了重度,就再也治不好了。家人很担心,带我去看了中医,此后一直喝中药至今,连牙都喝黄了:)

我所有的年假及调休,全部用在了去医院看病上。老婆辞掉工作在家为我熬药、做早饭,因为担心和着急,她自己也生了一场病。而我也终于明白,最重要的不是事业、钱财,而是健康。没有了健康,其他一切都只能是浮云。

工作

这一年回头看看,工作完成了不少,平台化及模块解耦、数据处理的异步化、Card架构都在基线扮演着举足轻重的角色。领导和同事对我很好,也让我觉得这一年的汗水没有白出。

当App越来越大,接入的业务越来越多,平台化即是必然。业务模块之间不能有耦合,相互之间的消息传递就需要一个中间人来进行,业务模块耦合中间人,从而减少了依赖的对象。

异步化数据处理其实主要是多线程处理,而线程安全在实际开发中还是有难度的。锁的使用、资源释放的时机都至关重要,一个不小心,就会发生开发测试过程中没碰到,到了用户那却被放大N倍的问题。

Card是一种客户端的UI及事件处理都由数据决定的机制,客户端预先实现一些固定的模版及实现,再根据数据类型做特定的展示、事件响应以及数据统计。Card的好处是比较灵活,尤其适用于对运营要求比较灵活的情况。而未来,我们也想做到客户端实现一个解析器,或者将Card机制迁移至ReactNative,直接将新Card模版从服务器那边获取,进而做到不发版就能支持新的Card样式。

生活

这一年因为生病很少骑行,在家宅着就开始琢磨别的东西:将两辆滑板车改成了电动,轮毂电机的一辆,航模电机的一辆。买了一架成品无人机,组装了一架穿越机、一架航拍机,也算进入了航模坑。其实在2015年消费级无人机就有不少新秀出现了,2016年这个市场肯定会继续火爆,像电脑、手机一样,以后人手一架无人机也不是不可能。

这一年老婆也为我付出了很多,为让我的病尽快好起来,联系医生,早起做饭,辞职在家熬药,甚至包揽了一切家务。希望病尽快痊愈,让她早日脱离操劳和担心的状态。

2016目标

2016最大的目标就是让病彻底痊愈,加强锻炼,提高身体素质。此外,不断学习,提高技术能力也是一个开发的根本。

希望2016一切顺利。

创建自己的VPN服务器

首先创建一个Amazon Web Services (AWS) ,新用户有一年的免费试用权,使用free对应的配置,每月可以使用15G流量和750小时,网上有对应申请AWS的教程

服务器使用的操作系统为ubuntu,使用ssh连接到EC2实例;

ssh -i key_pair.pem ubuntu@ip

安装pptpd:

sudo aptitude install pptpd

编辑pptp配置文件:

sudo vim /etc/pptpd.conf

在最后一行加上:

localip 192.168.240.1
remoteip 192.168.240.2-9

使用cubieboard创建热点

最近看到有人折腾树莓派,自己也想倒腾点东西。树莓派性能较差,于是买了个国产的板子——cubieboard

开始

首先是装系统,我装的debian server(下载地址),双卡板系统通过Win32DikImager可以很方便的刷好

接下来要驱动无线网卡,我的usb无线网卡为edup-n8508gs,系统中自带8192cu驱动,是可以支持我的无线网卡的

使用lldb和Hopper破解Reveal的试用限制

本文仅供学习和交流,如有侵权或不妥,请联系我删除

之前写了篇lldb联机调试的文章,恰好Reveal的试用到期了,于是拿来练练手。本文参考了“[原创]破解Reveal购买提示框”,但是去掉了“Free trial has ended” :),并假设你已经了解了一些lldb的基本调试命令

首先用Hopper分析Reveal源程序,搜索关键字trial,首先发现了IBATrialModeReminderPresenter

用lldb调试下,断点在图中内存地址中

(lldb) target create "/Applications/Reveal.app"
Current executable set to '/Applications/Reveal.app' (x86_64).
(lldb) b -a 0000000100094180
Breakpoint 1: address = 0x0000000100094180
(lldb) r
Process 4255 launched: '/Applications/Reveal.app/Contents/MacOS/Reveal' (x86_64)
2014-10-20 19:40:37.548 Reveal[4255:d0b] Unknown class          IBAViewHierarchyCanvasSharingMenu in Interface Builder file at path /Applications/  Reveal.app/Contents/Resources/en.lproj/MainMenu.nib.
2014-10-20 19:40:37.554 Reveal[4255:d0b]  INFO: Log Level Enabled
2014-10-20 19:40:37.554 Reveal[4255:d0b]  WARN: Log Level Enabled
2014-10-20 19:40:37.554 Reveal[4255:d0b] ERROR: Log Level Enabled
2014-10-20 19:40:37.574 Reveal[4255:d0b]  INFO: Reveal Automatic Updates are    enabled!
2014-10-20 19:40:37.862 Reveal[4255:d0b] [HockeySDK] WARNING: Detecting crashes is  NOT enabled due to running the app with a debugger attached.
2014-10-20 19:40:37.863 Reveal[4255:d0b]  INFO: Reveal Crash Reporting is enabled!
Process 4255 stopped
* thread #1: tid = 0x3abbf, 0x0000000100094180  Reveal`___lldb_unnamed_function3544$$Reveal, queue = 'com.apple.main-thread', stop reason   = breakpoint 1.1
    frame #0: 0x0000000100094180 Reveal`___lldb_unnamed_function3544$$Reveal
Reveal`___lldb_unnamed_function3544$$Reveal:
-> 0x100094180:  pushq  %rbp
   0x100094181:  movq   %rsp, %rbp
   0x100094184:  leaq   0xa05c5(%rip), %rsi       ; { /usr/lib/ libobjc.A.dylib`objc_msgSend_fixedup, "alloc" }
   0x10009418b:  callq  *0xa05bf(%rip)            ; { /usr/lib/ libobjc.A.dylib`objc_msgSend_fixedup, "alloc" }

使用lldb调试别人的程序

文章翻译自 这里

这是一篇粗略的翻译文章,只翻译第二种方法

首先我们需要一台越狱的设备,并且安装好了ssh

debugserver是一个用来远程gdb或lld调试的程序,当一个设备被标记为开发设备,那么这个程序会被安装到/Developer/usr/bin/debugserver路径下

debugserver的调用方式为:

debugserver [<options>] host:<port> [<prog-name> <arg1> <arg2> ...]

你可以在Xcode中找到debugserver,比如挂载/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/ DeviceSupport/7.0.3\ (11B508)/DeveloperDiskImage.dmg后,他的路径为:/Volumes/DeveloperDiskImage/usr/bin/debugserver

Hand Off初探

iOS8的一个新功能是hand off,这个功能可以允许用户在多端继续他的某个任务,比如iPhone上写笔记写了一半,到家后使用iPad,从锁屏或后台打开程序自动导航到记笔记界面,并且可以继续刚才的笔记内容写。

Alt text

Hand off功能要求用户的几个设备有相同的iCloud账号,打开蓝牙。对于开发者,我们的应用必须是在同一个team ID下,程序拥有相同的iCloud container。

KMP模式匹配算法

在写程序时,我们常常会用到从一个字符串找出子串的位置。

比如,在某个句子快速找到某个你感兴趣的词:“csscsdn”中找到csdn

以下是查找算法,注意:下标为1代表第一个位置,以此类推,跟数组不同

一、朴素模式匹配 朴素模式匹配是从第一个字符开始,依次向后匹配,这里我们假设游标起始点为1

c s s c s d n
| | ?
c s d n

当i(主串的游标) = 3,j(子串的游标) = 3时,字符出现了不等,于是i回到2,j回到1

c s s c s d n
  ?
  c s d n

分析微信来优化自己的应用

文章内容仅供学习交流,如有不妥,请联系我删除:)

用到的工具:Reveal,Charles,Hopper,越狱设备

流畅的列表滑动可以很大的提升用户体验,尽量减少程序控制的透明色(GPU发现某层是不透明的,就不会计算它下面的层来显示了)和阴影都能提升UITableView滑动的流畅性。实时计算的圆角(CALayer的cornerRadius)也会加重GPU的运算,可是我们的程序经常会遇到需要用圆角的情况,所以如何高效的进行圆角显示就变得非常重要。

Stack Overflow上也有一些优化的方案,比如让设计师提供带圆角,内部是透明色的图片;或者直接在服务器生成圆角图片等等。第一种方案不”优雅”,并且依然有透明色,第二种方案太死板,并且需服务端的支持。

看到微信的聊天列表页也有头像是圆角,服务号头像是圆形,通讯录又没有圆角,而且滑动也很流畅,很好奇微信是如何实现的,于是打算使用工具分析一下。