2014年度H1B报税

又到了一年报税的时候,本着早报税早省(拿)心(钱)的原则,一拿到W2开始着手报了。

2014年度,一整年都是H1B,就不再享受那个适用于学生的中美$5000 Treaty,但是已经是税法意义上的居民,所以就可以用居民friendly诸如Turbo Tax/H&R Block的报税软件来节省很多时间。看了the wirecutter上针对报税软件的评测后,决定就用他们认为最好的:Turbo Tax。

像我这样就W2跟一些简单的1099-INT, 1099-G的话,直接用turbo tax免费版本就可以了。免费版本其实就是帮你填写1040EZ/1040A,如果更复杂些的,就得额外付费买更高级版本了。另外免费版本仅仅包括报联邦税,如果州税要一起报的话,是额外要花钱的。因为我在加州,网上报州税的系统超级简单,就不用额外再花钱了。只需在联邦税填完后跳过州税,如果不小心使用turbo tax报了州税的话,可以在overview的时候去掉。Turbo tax用起来还是非常简单的,如果你的W2上有control number的话,直接就可以导入了,无需再手动输入各种数字。然后按着向导,把州税的1099-G,利息税的1099-INT依次填上就可以了。信息都填完之后,会直接显示会退多少税(一般是按standard deduction来的)。其实这个数字各大报税软件基本都是一样的。如果觉得不满意数字,就得用高级版本来找是不是有别的项目可以退税。不过个人觉得如果需要用上高级版本的话,还不如找个会计师报了。

今年报税就是这样。我自己非常“不幸”,兴冲冲地去报税,最后不仅没有拿到退税,还要补交税。:(

Android JDK 7签名问题

前一阵要发布一个新Android版本,在发布的前一天晚上,QA突然跟我汇报说无法在一些Android设备上安装apk。看了下logcat说是INSTALL_PARSE_FAILED_NO_CERTIFICATES

百思不得其解中,想起前不久刚在Jenkins上把Java 6升级到Java 7(终于!)来编译Android app。Google了一番,发觉原来是用来给apk签名的jarsigner在Java 7中默认使用SHA-256和SHA256withRSA算法,而Android还没有完全支持,需要在用jarsigner的时候指定MD5withRSA为签名算法以及SHA1为摘要算法即可。比如如果是Maven作为build system的,在maven-jarsigner-plugin中的arguments节点里设置就行了。

<arguments>
    <argument>-sigalg</argument><argument>MD5withRSA</argument>
    <argument>-digestalg</argument><argument>SHA1</argument>
</arguments>

2015

2014年就这样过去了。刚刚去机场把lulu送回东京,也没什么心情写总结。心神不宁地网上乱转,都是上海跨年踩踏的消息。

这一年换了个工作,算是一个比较大且开心的事情。出远门玩了几个地方,东京魔都阿拉斯加还有大峡谷什么的。花了5个月看了本Steven Pinker的大部头「The Better Angels of Our Nature」,还是云里雾里的。今年演出明显看得少了,财务问题好像略微改善了些。还有些别的,其实也挺重要的,但还是留给自己好了。

2015年,也没有什么特别想在这里说的,但感觉要做的事情还是很多的,一件一件慢慢地来吧。

在Android项目中启用ProGuard

最近不得不面对Android 65k method limit问题,所以启用ProGuard来除去一些没有被调用到的方法来降低被引用的方法总数(referenced method count)是一个不错的暂时的解决办法。

启用ProGuard
如何启用其实非常简单。如果项目是用Maven作为build system的,在app项目的pom文件里的android maven插件的节点下加入:

<proguard>
    <skip>false<skip>
    <config>proguard-project.txt</config>
</proguard>

proguard-project.txt即是配置文件,待会儿会详细讲。如果是Gradle的话,可以在buildTypes里加入1

runProguard true
proguardFiles file('proguard-project.txt')

启用后,每次build一般都会生成四份文件,dump.txt/mapping.txt/seeds.txt以及usage.txt。

  • dump.txt:包含了最终在.apk文件里的类结构
  • mapping.txt:如果启用了混淆代码的话(默认是开启的),这个文件里会列出原来的类/方法/成员的名字与混淆后的对应
  • seeds.txt:列出了没有混淆的类及其成员
  • usage.txt:列出了那些被去除的代码

配置ProGuard
在Android SDK的tools/proguard文件夹下有两个默认的配置文件,proguard-android-optimize.txt和proguard-android.txt。从文件名中可以看出一个是启用了优化另一个则是普通的配置文件。按需选择一个对一般的app来讲就足够用了。不过如果是因为64k问题而选择proguard的话,肯定也是个不一般的app,所以需要根据自己app的情况添加一些规则。这里有完整的ProGuard用法。那接下来说下我自己添加的几条规则供参考:

  • Warning: can’t find superclass/interface/referenced class:一般来讲,这是启用proguard最先会遇到的警告。这个警告说的是无法找到父类/借口/被引用的类,出现这个有可能是真的所需要的类没有被找到,需要指定包含这些类的jar的所在位置,但对于Android来说,很多情况下只需要使用-dontwarn规则来关闭这些警告就可以,因为在Android的编译过程中会自动指定所引用的jar。
  • -dontobfuscate:混淆代码后会使debug非常困难。即是是发布的版本,如果使用Crashlytics,最后收到的crash报告也是混淆后的,还是会使debug变得非常困难。虽然可以用retrace脚本来转换混淆后的stack trace,但是这样多做一步并不是很值得。不过如果你的app因为安全原因必须要混淆代码,那也只有这条路可以走了。
  • Automated Instrumentation Testing:如果你的项目里有Instrumentation测试,需要加入-keep public class * extends android.app.Application这样一条规则。因为每个测试项目会自动生成一个android.app.Application类,而ProGuard则认为这些Application类没有在任何地方被调用就自动剔除了,所以测试就没法在ci服务器上运行。这点我当时花了一天时间才最后解决的。:-(
  • Play Services:这个庞大的库本身就占用了大概两三万的方法数,虽然这个库在Android开发中算是必须的,但其实大部分都未必用得到,于是就造成了浪费。Google对于这个库有它自己推荐的规则,直接添加进来就可以。好消息是Play Services下一个版本6.5将会模块化。
  • Reflection:用到reflection的地方也是需要添加规则来保留这些类的。

Android 65k
现在我们来吐槽下这个65k问题Davlik是Android的运行时,其指令里有一个method reference index的变量,就是Davlik里最多能调用的方法数量。Android从出生到现在这个变量的大小从来没有改变过,就是16 bit,也就是令人发指的65536,从此,臭名昭著的65k限制由此而生。除了使用ProGuard外,还有一种比较流行的办法是multi-dex。

Ambitious New Android Developer

Multi-dex
随着app体积越来越大,即使用了ProGuard也还是会导致引用的方法数超过65536,于是有人就想到那我就编译多个dex文件,其中一个是主要的dex文件,然后在运行时再载入其他所需的dex。在Android新的运行时ART发布之前,这是非常繁琐低效的。随着ART的发布,multi-dex有了原生的支持,多个dex文件会在app安装的时候被编译成一个.oat文件让ART来执行,所以也不需要在运行时才载入所需的dex。而在ART之前的版本,Google也发布了支持multidex的库。详细的设置可以看这里:Configuring Your App for Multidex with Gradle。但这个归根到底还是一个hack,而且还是有很多限制,比如不怎么支持Android 4.0之前的版本,极大地增加了编译时间等等。

虽然看上去65k问题的实质很简单,但既然Google这么多年都没有能够修复,或许这真的是一个很难搞的bug。但话又说回来,随着移动领域越发地火热以及迅速地发展,不很好地解决这个问题实在很说不过去。


  1. Gradle指定ProGuard配置文件的时候还有类似getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'这样的写法,直接从SDK里找到默认的配置文件再与自己项目特定的配置文件整合在一起,这点是Android Maven插件还无法做到的。

如何在终端下使用Swift

在安装完Xcode 6 Beta之后,首先先把Xcode的Developer tools切换到Xcode 6下。

sudo xcode-select --switch /Applications/Xcode6-Beta.app/Contents/Developer

然后在iTerm/Terminal下输入xcrun swift即可!

Swift初探

在前几天的WWDC上,Apple宣布了Swift这个新的编程语言。花了一点时间读了点文档玩了会儿,总结下一些值得一提的地方。因为也是刚刚接触,如果哪里有错,还请悉心指出。

  • 类型推导:既然Swift作为编译时静态的语言,大部分时候就可以由编译器推断出变量类型,于是比如就可以用var关键字来声明变量以减少拼写,增加代码的可读性。当然,在编译器无法推断出类型的时候,还是需要显示声明对象的类型。

  • 可变字符串:在JAVA/C#里,字符串默认是不可变的,即对于一个字符串对象进行修改,都会创建一个新的字符串对象,而在Swift,如果是声明的变量就可以直接对其内容进行修改。

  • ..来表示一段范围:这个跟Ruby类似,比如循环就可以这样表达:for i in 0..3

  • 多个返回值:跟C#的Tuple类似,不过一般来讲在OOP里,如果需要用到多个返回值的情况,很有可能是设计不当,没有用一个类型来封装这些返回值。但又不得不承认有时候的确这样也会比较方便。

  • 枚举类型:这次Swift的枚举类型功能强大,不仅支持Int和字符串,还支持任意类型的枚举,甚至Swift里的Optional类型也是建立在枚举类型上的。具体可以查看文档的Enumerations章节

  • 闭包:即Clousure, 也就是Lambda表达式/匿名函数/Block,无需多说了。

  • Protocol:或许对于Objective-C程序员来讲并不陌生,但其实也就是OOP里的接口。

  • 结构体和类(Struct and Class):跟C#类似,结构体一般被内存分配在栈上,而类在堆上,结构体值传递,类则引用传递。

  • 属性:跟C#类似,由编译器来生成类型的成员以及getter/setter,不过Swift在属性上还有Observer来反应值的改变。

  • 泛型:是类似C#的真泛型,不像JAVA的泛型,总是需要装箱拆箱,没有很强的类型安全,性能也相比较差。作为一门新的语言,不用考虑向后兼容,这点也是应该的。:p

  • dynamicType:Swift是编译时静态运行时动态的语言,即有些类型在运行时才确定,具体可以看文档的Dynamic Type Expression这一章节。

  • 扩展方法:跟C#类似,可以自由地扩展类型,只是语法上比C#更简洁一些。

  • Optional:就是C#里的Nullable,因为有些类型本身不支持nil的赋值,所以如果在这类类型声明的时候加上?即声明了一个optional value,比如var a: Int? = nil,这样value就是一个初始值为空的Int?类型。有些人会问那不如直接初始值赋为-1好了。但是既然给一个变量赋了一个值,就代表这个值对于程序的上下文是有意义的,而把这个变量设为nil就代表这个变量在这段程序里是暂时没有意义的。另外有了Optional之后,由于每次都需要检查是不是nil会造成if-else语句的层叠影响代码可读性,Swift的Optional Chaining就很好的解决了这个问题。

  • weak和unowned关键字来表达这种情况,以便编译器在合适的时候生成代码回收对象。

总的来说,现代语言该有的Swift都包含了进去,使得写代码效率提高很多,代码也更加易读。这一点上我还是很兴奋的。至于所谓的坑,其实只是语言设计时候的各种取舍。比如JAVA的泛型之所以这么设计就是为了向后兼容,而当C# 2.0推出泛型的时候,就不考虑这一点。再比如Swift的Optional最近就一直让人很困惑受到很多人的吐槽,典型的比如这条推里写的,其实就是没有理解Optional。这条推里的代码声明了一个Optional的变量并且赋了有意义的值,却没有弄明白在if语句里判断这个变量其实是判断这个Optional的变量是不是nil,而不是判断这个变量的值(因为可能这个变量根本没有值)。

至于学习,最好的办法就是照着文档写代码了。目前官方主要有The Swift Programming LanguageSwift Standard Library ReferenceUsing Swift with Cocoa and Objective-C。而这次WWDC里也有很多session是介绍Swift的,还涵盖了文档里没有介绍的一些东西,非常值得一看。全部的视频都已经在上传到了WWDC14的网站。另外有不懂的,也可以去Stackoverflow的swift-language标签下问问题或者看看别人的回答。

以上说的这些,只是基于还在pre-release的文档,所以还会有变化,但初看下来Swift是一门设计得不错的语言。尽管现在看上去只是为了开发iOS和OS X软件服务的,个人觉得不久之后或许就是一门general purpose的语言,因为这门语言本身是有这样的潜力的。另外还希望苹果能开源与Swift相关的工具,比如编译器、REPL等等。C#的编译器都开源了,厨子!

最后引用Swift的设计者Crhis Lattner的一条推:

微软更新.Net源代码检索网站

微软最近更新了查看.Net源代码的网站,.Net Framework团队也发了篇blog: A new look for .NET Reference Source

新的网站体验非常不错,搜索响应非常迅速,还支持”Go to Definition”跟”Find All References”,URL即是链接到某个assembly或者是某个文件的第几行,比如像这样:/#System.Core,或者是像这样:/#mscorlib/system/environment.cs#56。这些都是由还在CTP阶段的Roslyn API(微软的.Net compiler as service)项目构建。另外.Net源代码也可以下载下来,还附带了.sln的solution文件,方便在Visual Studio里直接查看。目前的代码是基于.Net 4.5.1这个版本的,.Net团队意思是以后网站会随着.Net重大更新而同步更新。

这次的更新,还带来了直接在Visual Studio里debug .Net代码的功能。如何在VS2013里设置可以戳这里:”How to configure Visual Studio for debugging .NET framework“。

目前,社区里也有人做了一个Visual Studio的插件,就是按F12直接转到这个网站上相应的代码。

最后值得一提的是.Net源代码的license是MS-RSL(MS Reference Source License)。

“Reference use” means use of the software within your company as a reference, in read only form, for the sole purposes of debugging your products, maintaining your products, or enhancing the interoperability of your products with the software, and specifically excludes the right to distribute the software outside of your company.