今年2月公司将去我的母校Syracuse University做校园推广和招聘,我有幸能代表公司回学校去与在校学生做交流并发掘合适的人选来面试。这不免让我想起来当时在学校找工作时候的茫然和紧迫,所以写点心得经验分享给大家希望能够帮助大家获得更多机会。不过这些经验主要针对北美的软件工程职位,更精确点则是湾区的科技公司。

这篇文章里将主要介绍一下简历的准备。下图虽然不是百分百准确,但是也基本反映了简历过滤的条件,特别是对于校园招聘这类基数十分的巨大的申请,没有太多时间去了解每一个人,只能快速的浏览简历并匹配到相应的职位要求上,进而提供面试机会。简历是让对方了解的自己的第一门面,所以要装饰好这块。

resume_comic

 

基本模板

可以参见《This is what a GOOD resume should look like》,上边详细罗列了简历中应该有的几部分信息。格式和排版不用保持一致,但是一定要做到分类明确。有些内容我个人并不喜欢,比如罗列课程,语言和工具,但是有时候也可能因为上过相关课程而招人也不一定。

 

特别注意:

  • 所有描述要用过去时,因为是已经发生的内容;(基本的语法)
  • 格式一定要保证统一,比如时间不要“May 2012”,“2012/08”这样混搭;保持一致缩进,行距,段落间距;(体现严谨性)
  • 字体不要超过两种,可以用粗体活斜体,链接以外不要用下划线;(体现整洁个性)
  • 不要超过一页;(体现语言组织能力)
  • 不用写Summary或者Objective;(自我评价不可靠)
  • 不熟悉的语言或者技术,不要为了被注意到而硬凑,如果对方看到相关技术进行提问而你回答不出,这会造成简历作假,直接就被淘汰出局了。

 

由于英语不是我们的母语,所以经常会犯比较低级的英语语法错误,虽然有时候招聘人员并不会太在意,但是当简历和其他简历放在一起对比的时候,显然会选择更加清晰的一份。

对于这些问题,每个学校都有Career Service之类的机构有专门的人帮忙审核修改。比如SU的Student Center里就这个部门,他们提过10-15分钟的drop in的咨询时间,不用预约当场可以签到并安排人来交流。我当时就是多次过去找他们来帮忙看简历,并修改语法和排版的问题,非常有帮助。

项目经验

学校的Career Service是服务于全校雪城,所以他们的建议都比较笼统,不会基于某个专业提供针对性的意见。这里我分享一下对于申请Software Engineer职位时在简历中可以包含的内容。

其实找工作都是看“经验”,简历中的内容就是为“经验”提供证明,而按有效程度从高到底排应该是:工作经验(Work experience),个人项目(Side projects),课程项目(Academic projects)。

 

工作经验也要跟申请的职位和专业相关,销售工作显然不该放在软件工作的申请简历里。但是工作也不局限于行业工作,如果给老师当做助教、助研,亦或只是批改作业也是很合理的工作经验,因为这已经体现出你比其他同学要优秀了。

个人项目则因人而异,有些人喜欢课外做点事情作为兴趣爱好就可写得多一些。此外现在在线课程很多,如果你上了这些课程并有证书,也算是课外学习项目。

课程项目就很统一了,基本上一起上过课的同学都会做一样的内容,所以往往在校招时很难体现。但是直接去网上投简历,就会有别于其他申请者。

 

对于经验的内容和语言组织会比较麻烦,这方面的审核找授课老师会比较有帮助。我在Syracuse的时候,Jim Fawcett就给予了我最大的指点。不无尴尬的说,当我第一次把我简历给Fawcett看时,被他批评的体无完肤,大部分内容基本都被划了叉。不过修改之后,确实赏心悦目了很多。

 

加分项目

  • LinkedIn

上边提到简历只能有一页,所以内容要被反复压缩,但是LinkedIn在线简历则没有约束,可以罗列更多的内容。所以从简历中上链接到LinkedIn页面可以让招聘者在需要时了解更多的信息。因为找工作时要好好维护LinkedIn主页。

  • GitHub

如果LinkedIn是每个人的在线简历,那么GitHub就是软件工程师的在线简历。其实招聘人员并不会自己去看上边提交的代码,但是如果你有项目在上边,并且有持续贡献,必然是一个不错的程序员。

即使没有个人项目,也可以像我一样把课程项目(SU-Courses)放在GitHub上,不仅方便回头参考,也能体现结构组织能力。而且这远比罗列上过的课程更加有效。

另外,每个公司都会用版本控制系统(Version Control System),而Git是最常用的版本控制工具。提前学习一下对将来正式进公司工作也非常的有帮助。

 

最后推荐《The Google Resume》这本书,它也算我当年找工作的启蒙之书。这本书已经停止发售了,但是网上还是很容易能找到PDF版本来免费阅读。

 

Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInEmail this to someone

solid-oop_wall-skills

一开始学编程的时候,都是在学习程序语言,觉得学好了这门语言就可以写好程序;渐渐地发现算法和数据结构更加的重要,因为语言只是细胞,要依附这些行程肉体才能产生作用;但到了实际生产应用的时候,又会察觉整个好像缺少灵魂,常常只能像僵尸般往一个方向前进,缺少驱动力来动态调整,这力量就来自各种设计模式和开发原则。

经历了越多开发中的痛楚,也越来越发觉“S.O.L.I.D.”开发原则只用几句话所概括出来的真谛和内涵。它们对于软件开发是如此有意义,当然具体的实现依然还是依赖于那些基于需求形成的数据结构和算法,只是利用这些开发原则作为灵魂,让程序走得更远更自由。

 

Single Responsibility Principle(SRP)

A class should have one, and only one, reason to change.

Open Closed Principle(OCP)

You should be able to extend a classes behavior, without modifying it.

Liskov Substitution Principle(LSP)

Derived classes must be substitutable for their base classes.

Interface Segregation Principle(ISP)

Make fine grained interfaces that are client specific.

Dependency Inversion Principle(DIP)

Depend on abstractions, not on concretions.

 

References:
  1. ArticleS.UncleBob.PrinciplesOfOod
  2. SOLID (object-oriented design) – Wikipedia
  3. S is for the Single Responsibility Principle
  4. O is for the Open/Closed Principle
  5. L is for the Liskov Substitution Principle
  6. I is for the Interface Segregation Principle
  7. D is for the Dependency Inversion Principle
  8. (后5个是基于Android开发对这些原则做的阐述)

Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInEmail this to someone

oh-my-zsh

电脑一开始起源于终端(Terminal),通过键盘输入简单文字,在黑白界面上输出字符。直到图形界面(Graphical User Interface, GUI)的出现,有了更加直观的视图显示,有了更简单的人际交互,电脑才真正普及成个人电脑。

在我的工作经历中,我一直从事都是前段开发。从最早的网页开发,到现在的Android开发,基本上所有代码都在本地电脑运行,所以我很少需要去使用终端来输入指令来执行操作。虽然也学习了Vim,但是绝大多数时间都是使用强大的可视化IDE,例如Visual Studio、Android Studio等等。简单的编辑也会倾向有Sublime Text之类的应用程序。

可视化的应用程序可以让人很快上手操作,通过鼠标寻找菜单目标,或者更新设置都是非常简便的操作。视图窗口也会提供更多不同的内容显示来反馈各类信息。

但是随着开发越来越深入,我越来越感到使用鼠标,以及切换各类视图让我的工作效率变得越来越慢。特别是开始使用多个屏幕进行工作时,鼠标需要被拖动的距离也变得越来越长;每当我在Chrome中打开无数个网页窗口,寻找到想要的页面也越来越难。这其实也反应了费茨法则(Fitts’ Law)

因此我越来越希望我的手指能够保持在键盘上,而不用在键盘和Trackpad直接来回切换。于是我开始习惯通过各类程序的快捷键来操作,倾向在终端输入指令来进行操作,使用GNU Readline来移动光标。这样大大提高了我的效率,但是依然有很多时候,我花时间来回切换。再者因为我的主业在Android上,我还是不会

前阵子我上了Jim Meyering一堂关于如何高效使用终端的课,一下子又让我对终端变得非常着迷:键盘指令满屏幕地飞;无需拖动光标就能进行文字选择;随时随地都可以Vim指令……太多太多好玩又高效的功能。

于是我开始研究起终端的知识,从Mac默认的bash切换到zsh;安装了Oh My Zsh;学习tmux的指令和配置……

但是在接下来的一周里,我的效率没有提高反而降低了好多:我要花大把的力气重新为zsh配置我的初始指令;tmux完全不支持Mac专有的指令;使用Vim的页面指令并没有滚动鼠标来自自然流畅。

我渐渐怀疑使用终端是否是个退步的表现,研究这些指令是否真的对我有帮助?我想来想去,想出了一个比拟:

现代人基本都会开汽车,汽车简单的操作让更多人接受这个工具;但是仍然有很多人喜欢开摩托车,喜欢不一样的速度与激情。从效率上讲,汽车比人力要快很多,也能承载更多的人;但在交通拥堵的街道上,摩托车却又更为有效。

汽车的功能变得越来越多,然而操作变得越来越简单,让更多人可以接受和使用;摩托车的功能却被其空间所局限,操作也很复杂。

这样对比,我就变成了在想:我要学摩托车吗?于是答案就变成了:我学。而且我也真的有考了摩托车驾照。因为开摩托很酷。

所以为了酷这个原因,我也要深入研究终端指令。最近,这些指令也为我带来了极大的帮助:

我在重构一些Java代码,需要重命名某个包(package),而那个包下有数百个文件,还有很多引入(import)该包下的class也需要更新。虽然Intellij有重构的功能,但由于代码量实在太大,Intellij既不能承受这量度,也无法完全的更新所有文件,特别是一些不被Intellij识别的文本文件和资源文件。于是我花了些时间写了脚本,直接用grep来查找,用sed来修改,要是错了就用版本控制撤回,一切是如此的高效而又可重复。

现在就因为zsh那强大的路径补全,我也越来越离不开它;也渐渐地习惯了tmux的指令操作。

Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInEmail this to someone

做Android开发的时候,经常会需要截取设备的屏幕甚至录制设备屏幕,来让同事知道提交的代码实现的功能,或者让他们知道产品中出现来什么问题。截取Android设备的屏幕有很多方法,比如在Nexus系列同时按下“电源”和“音量调低”按钮来截取,也可以用第三方程序来完成。通过另一部手机来拍照录像也是可行的方案。但是这些方法还需要想办法将文件传输到电脑上,又要多一步麻烦的操作。

Mac电脑上也有一些应用程序可以截屏Android设备,但是我更喜欢用终端指令,令人开心的是Android自带的 adb 已经提供了截取屏幕录制屏幕的指定:

  1. $ adb shell screencap /sdcard/screen.png
  2. $ adb shell screenrecord --verbose /sdcard/demo.mp4

不过生成的文件依然保存在设备中,还需要用adb pull指定来转到电脑上

为了让整个过程更加的便捷,我将这些指令包裹在bash方法中,然后一个指令来完成截取和传输的工作。

截取Android设备当前屏幕并保存到执行指令的电脑目录上:

  1. # capture screen of android device
  2. andrdroidScreenCapture() {
  3. curTime=`date +%Y-%m-%d-%H-%M-%S`
  4. tmpeName="$curTime.png"
  5. [[ -n $1 ]] && fileName=$1 || fileName=$tmpeName
  6. devicePath="/sdcard/$tmpeName"
  7. adb shell screencap -p $devicePath
  8. adb pull $devicePath $fileName
  9. adb shell rm $devicePath
  10. }

录取Android设备屏幕活动,结束后将视频文件保存到执行指令的电脑目录上:

  1. export ADB_SHELL_SCREENRECORD_ARGS='--verbose --bit-rate 2000000'
  2. # record screen of android device
  3. androidScreenRecord() {
  4. echo -e "\033[1m(press Ctrl-C to stop recording)\033[0m"
  5. curTime=`date +%Y-%m-%d-%H-%M-%S`
  6. tmpeName="$curTime.mp4"
  7. [[ -n $1 ]] && fileName=$1 || fileName=$tmpeName
  8. devicePath="/sdcard/$tmpeName"
  9. adb shell screenrecord $ADB_SHELL_SCREENRECORD_ARGS $devicePath
  10. sleep 1 # wait for video encoding finish
  11. adb pull $devicePath $fileName
  12. # Don't delete copy in device.
  13. # adb shell rm $devicePath
  14. open $fileName
  15. }

较短的指令别名,并通过提供的文件的扩展名来决定是截屏还是录制:

  1. function asc() {
  2. if [[ -z $1 ]]; then
  3. echo "Please provide a filename."
  4. echo "Provideing .png extension for capturing the device screen, and providing .mp4 for recording the device screen."
  5. return
  6. fi
  7.  
  8. if [[ $1 == *.png ]]; then
  9. andrdroidScreenCapture $1
  10. elif [[ $1 == *.mp4 ]]; then
  11. androidScreenRecord $1
  12. else
  13. echo "Filename with unknow extension, only .png and .mp4 are supported"
  14. fi
  15. }

完整脚本代码可以在Gist上找到,把它们加入到Mac电脑的~/.bash_profile中,连接上开启了“开发者模式”的Android设备就可以方便截图了。

 

References:
  1. Capture or record android screen, pull file to Mac when it’s completed
  2. ADB Shell Commands | Android Studio
  3. Android Debug Bridge | Android Studio
Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInEmail this to someone

常说“隔行如隔山”,每个行业都只有该业内人士才懂的术语。软件行业里也有很多别人听不懂的话,比如有个笑话就说:所有讲不清楚的过程都叫做“算法(Algorithm)”。但其实即使身处在软件行业里,也任然有好多模棱两可的的概念,常常被混淆使用。就让本文来梳理一下这些概念的细微区别。

function vs. method

函数(function)和方法(method)在编程中的概念就很相近,经常被互换着称呼,但它们的区别主要是在定义的位置上。

function是一段通过名字调用的代码,它可以接受数据进行操作,并可能会有返回值。
method是一段通过关联在对象上的名字调用的代码。

从这段解释上看函数和方法基本一致,只是方法是属于对象的一部分,所以在面向对象语言中才有概念。如果是C语句,就只有函数的说法。

方法是附属于对象的,相对于函数可以接受传入参数,对象本身也会作为隐性参数可以在方法中被调用。在返回值方面,方法不仅可以选择返回数据,还可以将数据赋予其所属的对象。

(在我看来,计算机函数的概念应该与数学的“函数”概念是相通的,只是数学上的函数必须要输入和输出。如果考虑到计算机函数的参数的类型,以及异常(Exception)的情况,则感觉与数学的“映射”更接近了。)

References:

parameter vs. argument

parameter和argument都被翻译成“参数”,它们也经常被混淆。其实很好更精准的翻译应该是“形参(formal parameter)”和“实参(actual argument)”。

parameters是定义函数时定义的那些变量,它们是函数类型识别(type signature)的一部分;
arguments是调用函数时传入到函数中的那些变量,它们是函数的输入值。

这称为也是相对的,比如说下边的例子:

  1. void foo(int x, int y) {
  2. bar(x, y);
  3. }

xy对于foo函数来说是形参(parameter),而对于bar来说是实参(argument)。因此也可以说argument是parameter的实例。

References:

declaration vs. definition

申明(declaration)和定义(definition)这两个概念应该缘起于C/C++,因为写C/C++程序会分头文件(header files)和实现文件(implementation files)。方法和变量的申明部分一般放在头文件,定义部分则在实现文件里。

所以很容易理解

declaration是描述变量、方法、类的类型标识,它没有具体的实现;编译器看到申明部分不会分配内存,而是从其它地方找到其实现的定义。
definition是真正实例化变量,实现方法和类。编译器看到定义部分时就知道如何分配内存,在运行时分配相应大小内存去存放内容。

比如下边这些代码都属于申明:

  1. extern int bar;
  2. extern int g(int, int);
  3. double f(int, double); // extern can be omitted for function declarations
  4. class foo; // no extern allowed for type declarations

而下边的代码是对上述“申明”的具体“定义”:

  1. int bar;
  2. int g(int lhs, int rhs) {return lhs*rhs;}
  3. double f(int i, double d) {return i+d;}
  4. class foo {};

不严格的说“定义”也包含了“申明”的部分,应该单看定义中变量,方法和类的名字部分,那些可以算是“申明”。

 

在Java中并没有“申明”的概念,所有内容都是“申明”即“定义”。如果实在要说细分“申明”,不严格的讲可以把接口(interface)和抽象方法(abstract method)看做“申明”。但实际中我们还是会说“定义接口”,“定义抽象函数”。

References:

Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInEmail this to someone

universal-principles-of-design

As a front-end engineer, or specifically, an Android UI Engineer, I have a lot of time to work with designers. But there are a lot of concepts in design I am not familiar with. So I asked them how I can learn design, but not being a designer. Then they recommended this book to me.

I read it, and feel it’s really helpful and useful. It’s not only about UI design, many principles can apply to other designs as well: software design, landscape design, product design, option design. After read this book, I learned the explanation on how certain design decisions are made.

I would definitely forgot most principles, so I wrote this post to transcribe all principles and short description from the book, later I can just come here to recall them.
Continue reading

Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInEmail this to someone

做移动开发总是离不开在移动设备上做测试,虽然说Android设备单机可能比iPhone便宜,但是真要各种设备集齐也是不小的开支,再加上要试验不同的Android版本那组合起来又有好多了。所以一般开发者往往只在特定几个设备中做检验。需要测试不同版本也会求助于模拟器(Emulator)

Google为Android提供的自带模拟器的效果以前实在惨不忍睹,随着Android Studio 2.0出的模拟器倒是提高了不少,但依然挺糟糕的。
android-avd

大多公司都会购买Genymotion使用,可以创建多种不同版本的模拟器,即使是最新的版本也能很快支持。虽说价格抵上一部真机,却得到好多不同版本和厂商的设备,而且效果优越、功能丰富,真实物超所值。
genymotion

由于某些纠纷,Genymotion默认没有Google Play Services,就无法使用Google的Play Store,Account等等。不过网上也有很多攻略教大家怎将其么安装到Genymotion上,于是都可以在上边打《炉石传说》了。

真机和模拟器各有下边这样那样的缺点:

真实设备 模拟器
  • 价格昂贵
  • 不易携带多个
  • 同一设备不支持多种版本
  • 容易没电
  • 老设备会断货
  • 无SIM卡
  • 无摄像头
  • 不支持推送
  • 多手势不方便
  • 使用习惯不一致

Continue reading

Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInEmail this to someone

已经看过了万能的final关键字在Java中的不同用法和效果,其实static关键字的的用处也很广泛。它的用法更多涉及到面向对象设计(Object-Oriented Design)的思想,有时更加让人迷惑。许多是否应该使用static关键字的决定也常常基于工作经验中形成的约束和规范。本文就来帮助大家解锁static的正确使用姿势,写出更加清晰的代码。

为了更好的了解Java程序,就需要了解代码被编译后的样子,所以下边会涉及到javacjavap这些指令的使用,不用担心都是比较简单直接的用法。也需要借助一些反编译(decompile)工具来查看.class文件,这里用到的是JD-GUI

Static Variable

静态变量(Static Variable)在Java中只有静态成员变量,不同于C++、PHP等,它不允许在方法内定义局部静态变量。静态成员变量也称为类变量,相对的是对象成员变量。这些变量是属于定义的类,而非某个对象实例,但是该类的所有实例都可分享该变量。

用个简单的例子会比较直观一些:

  1. package com.iderzheng.statickeyword;
  2.  
  3. public class StaticField {
  4. public static int sField;
  5. public int mField;
  6.  
  7. public void print() {
  8. System.out.println(
  9. String.format("%s{sField: %d, mField: %d}", this, sField, mField)
  10. );
  11. }
  12.  
  13. public static void main(String[] args) {
  14. StaticField one = new StaticField();
  15. StaticField two = new StaticField();
  16.  
  17. one.sField = 7;
  18. one.mField = 7;
  19.  
  20. two.sField = 21;
  21. two.mField = 21;
  22.  
  23. one.print();
  24. two.print();
  25.  
  26. StaticField.sField = 49;
  27. // Error: non-static variable mField cannot be referenced from a static context
  28. // StaticField.mField = 49;
  29. one.print();
  30. two.print();
  31. }
  32. }

编译运行这段代码得到如下结果:

com.iderzheng.statickeyword.StaticField@34469729{sField: 21, mField: 7}
com.iderzheng.statickeyword.StaticField@6d172f8f{sField: 21, mField: 21}
com.iderzheng.statickeyword.StaticField@34469729{sField: 49, mField: 7}
com.iderzheng.statickeyword.StaticField@6d172f8f{sField: 49, mField: 21}

很清楚的看到变量twosField的修改影响了one中的sField值。而mField在两个对象中是独立互补影响的。也看到可以用类的名字来引用静态变量,这是提倡调用方法,不应该直接用对象变量来引用静态变量,这样做不明确调用的是静态变量,很容易带来副作用。

Static Final Variable

一般在程序中不常定义静态变量,因为静态变量的可被访问和使用的地方比局部变量和对象变量要多,维护起来更加困难。更多时候是跟final结合起来定义常量,对于无法修改的只读变量,就不用担心维护问题了。

对象变量也可以用final修饰定义为常量,只不过每个对象的常量只属于对象自己,而且每个对象都需要分配内存给这些常量。而属于类的静态变量则只需要一份内存甚至无需存储变量的值。所以如果对象变量在每个对象中都是一致的,那么就可以考虑转为静态常量。转成静态常量也能方便地用类名直接进行访问,省去创建多余的中间对象。

Java编译器对于常量会做优化,在引用它们的地方会将它们的值直接嵌入,这样就不需要内存来长期存储这些值,更不要从内存地址中寻找,所以效率要高很多。

还是做一个简单的例子:

  1. package com.iderzheng.statickeyword;
  2.  
  3. public class StaticFinalFields {
  4.  
  5. static final int CONSTANT_INT = 7;
  6. static final String CONSTANT_STRING = "iderzheng.com";
  7. static final int[] CONSTANT_ARRAY = { 7, 21, 31 };
  8.  
  9. final String name;
  10. final int constantInt = 21;
  11. final boolean constantBoolean;
  12.  
  13. {
  14. constantBoolean = true;
  15. }
  16.  
  17. public StaticFinalFields(String name) {
  18. this.name = name;
  19. }
  20.  
  21. public static void main(String[] args) {
  22. StaticFinalFields finalFields = new StaticFinalFields("Ider");
  23. System.out.println(finalFields.name);
  24. System.out.println(finalFields.constantInt);
  25. System.out.println(finalFields.constantBoolean);
  26.  
  27. System.out.println(CONSTANT_INT);
  28. System.out.println(CONSTANT_STRING);
  29. System.out.println(CONSTANT_ARRAY);
  30. }
  31. }

对于上边的代码,通过javac进行编译后得到StaticFinalFields.class,再讲其通过JD-UI打开,会看到编译后代码的
static-final-inline

  1. package com.iderzheng.statickeyword;
  2.  
  3. import java.io.PrintStream;
  4.  
  5. public class StaticFinalFields
  6. {
  7. static final int CONSTANT_INT = 7;
  8. static final String CONSTANT_STRING = "iderzheng.com";
  9. static final int[] CONSTANT_ARRAY = { 7, 21, 31 };
  10. final String name;
  11. final int constantInt = 21;
  12.  
  13. final boolean constantBoolean = true;
  14.  
  15. public StaticFinalFields(String paramString)
  16. {
  17. this.name = paramString;
  18. }
  19.  
  20. public static void main(String[] paramArrayOfString) {
  21. StaticFinalFields localStaticFinalFields = new StaticFinalFields("Ider");
  22. System.out.println(localStaticFinalFields.name);
  23. localStaticFinalFields.getClass(); System.out.println(21);
  24. System.out.println(localStaticFinalFields.constantBoolean);
  25.  
  26. System.out.println(7);
  27. System.out.println("iderzheng.com");
  28. System.out.println(CONSTANT_ARRAY);
  29. }
  30. }

从编译后的代码可以看出对于原始类型的变量,在用final进行修饰并内嵌初始化后,使用这些变量的地方就直接用这些值进行了替换。虽然也有非static修饰的对象常量被智能优化后直接内嵌,但是为了代码的维护性,依然应该显示地申明成static

至于对象变量,它们并非真正意义上的常量,对象的创建后的地址也总会不同,而且对象的内容依然可以被修改,所以这些变量加上static final也无法用其值在使用的地方进行替换。

另外还看到通过block进行初始化的对象变量虽然也是常量,但是因为放入了block,编译器觉得它的初始化比较复杂,所以就没有将其引用直接替换。

直接内嵌常量的可以提高运行的效率,但是也有一些弊端:比如项目A中使用了项目B中的静态常量,成功编译后的A会直接使用那些常量;要是B的常量值被人修改了之后只编译了B而没有重新编译A,那A就不会得到新的值。好在现代的编译器都很智能,可以发现这些依赖关系并正确编译。
Continue reading

Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInEmail this to someone

前阵子更新了一下系统和软件,打开Chrome浏览器发现插件(Chrome Extension)的显示位置变了,原来显示在Omnibox里的Page Action突然跑到了Toolbar上跟Browser Action厮混在了一起。

于是开始在网上搜索原因才发现原来Chrome对插件的按钮显示做了改版(见”Introducing Chrome 48! “,” Upcoming UI Change“,”What happened with pageAction “),将它们都归到了Toolbar上并且可以隐藏到Menu中。

chrome-extension-menu

我以前也一直觉得Browser Action和Page Action是那么的相似,在Browser Action的监听事件中也能获得当前页面的信息,何必要分成两种让开发者做选择呢。现在Google也是有意要将两者归并,甚至可能在未来淘汰其中一个来简化冗余界面对用户造成的困惑。因为在新的设计下,对Page Action进行hide不会像以前那样将图标真的隐藏,而转为变灰表示其不可用。这在但这API显然不能真实反映其效果,很有可能会为了统一而淘汰它们的使用。

另一些变化是即使插件不用Browser Action和Page Action,也会在Toolbar上显示灰色的图标已表示其被安装使用着。这样可以更明显的提醒用户在浏览器上现在都有哪些插件,来防止恶意插件被用户忽略。

Chrome的插件也只能使用Browser Action和Page Action之一,如果在manifest里同时定义了两者,就会得到“Only one of ‘browser_action’, ‘page_action’, and ‘app’ can be specified.”的错误。

哎,以前写的关于Chrome插件开发的文章就这么被过时了,好在基本的结构和方式没有大的变化。

Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInEmail this to someone

实用Mac的Dictionary应用程序》已经帮助我们翻译英文单词,提高了阅读的能力,但是“听”和“说”还是大问题。发音要是不标准,念出来给别人听可能还是得不到理解。Mac也想到了这个问题,所以自带了发音程序来,当然机器念出来的英语还是会有不流畅的感觉,有些发音也可能不到位。

在许多原生Mac应用程序中,都很好的集成了发音选项,只要选取想要电脑阅读的段落,然后选择“Start Speaking”就可以听到朗读开始了。
speech-on-page

在System Preference里也可以为Speech设置快捷键,这样无论在哪里选中文字都可以让电脑来阅读:
speech-shortcut
Continue reading

Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInEmail this to someone