2020

距离上次写年终总结已经过去4年了。上次说到15年去了很多地方,有点巧,19年也去了蛮多地方的,快暑假的时候照例回国了一趟,8月底9月初的时候去了趟冰岛环岛自驾,感恩节的时候去了巴黎巴塞罗那跟马德里。在巴塞罗那终于看到梅西现场踢球了。15年去的时候梅西4分钟受伤下场的时候我还在球迷商店买买买。后来16年百年美洲杯阿根廷在湾区有比赛,可是梅西当时受伤还没恢复,坐在了替补席上。这次在诺坎普看到梅西踢球,而且还是一进球两助攻,甚是满足。这两次在欧洲玩,可以分别单独写两篇,但拖延如我,也不知道什么时候才能写完。

上次写的总结最后提到当时公司很多狗血的事情,果然,16年4月的时候,因为一些公司政治,我所在的组以及老板都被laid off了。不过当时也没有很慌张,exit interview完了大概中午,跟组里的同事互相留了联系方式拥抱后就早早回家陪luke玩去了。哦对!16年3月份我领养了一只猫叫luke!然后第二天就开始跟各种recruiter打交道,面试啥的,最后选择去了Tinder。

一晃我在Tinder也待了快4年了,经历了好多好多以前根本不会想到发生的事情,写本书都不为过。当时去了没几个礼拜,因为种种原因,公司里好多人走了或者被赶走了,做Android的只剩下4个人,还都是刚刚进来没几个月的。一周上六天班家常便饭。但是突然有一天觉悟到,周一要release,周五还有25个bug要修,我拼死周末加班修掉10个,剩下还有15个bug,周一也没法release,就觉得好没意思,开始质疑是不是很多压力都是自己带来的,于是就很少再在周末加班了。4年后,虽然狗逼倒灶的事情还一直有,但Android team现在也四十多人外加十几个opening,每天5、6点就下班,压力也没有当时那么大了。4年,在tech industry大家都心知肚明意味着什么。16年17年的时候公司招了一大批人,大家一起grinding,一起hangout,一起吐槽有的没的,很多同事于是都成了很好的朋友,所以2020会是一个非常interesting的一年,就看看会发生啥吧。

19年subscribe了一些新的podcast,NPR的how I built thisthroughline应该是这些新订阅的podcast里最喜欢的两个了吧。How I built this一开始觉得应该不会太感兴趣,只是因同事的推荐听了slack跟bumble的两集,然后开始听一些tech industry里的人或者自己熟悉的品牌比如five guys/jetblue的发家史,后来觉得即使是听不熟悉的人物的故事也特别有意思。最喜欢Guy Raz每次都会问的问题,你这些成功有多少是因为运气有多少是因为自己努力。

19年看的剧里,最好的就是Chernobyl了,Succession也很好。也pick up了一些老的喜剧比如Seinfeld跟Curb your enthusiasm。书的话,19年第一个quarter还看得挺多的,后来大概因为Red dead redemption 2跟Borderlands 3接连上市,就没有时间了哈哈哈。看过的这些里,Bad Blood确实挺不错。The hard thing about hard things挺真诚地讲了做business很多时候是没有简单答案的。The color of law讲述了在造成今天社区是个好区还是坏区中,美国各个政府制定的各种法律条文所担任的重要角色,非常有意思。

19年了拼了好几个乐高,千年隼就快要完工了。七千多片,买来快2年了一直没有动,圣诞新年假期也没啥出去玩的计划就想着订个小目标把她拼完。但其实拼布加迪威龙应该是最好玩的,高度还原了车里悬挂、16缸引擎、驱动系统等等系统是怎样工作的,非常有劲!

2020年,想想还挺复杂的,慢慢来吧。

在美国飞Drone的几个常见问题

最近心血来潮买了个DJI Spark,飞了几次,也研究了很多东西,特别是在美国对于drone的一些regulation,写在这里,备个忘。

首先,需要向FAA(美国联邦航管局)注册吗?

不需要。简单来说,如果只是自娱自玩,是不需要的,但如果是以商业为目的话就需要。至于怎么区分是不是商业,这里有简单的描述。之前确实有FAA的规定说要必须注册,然后贴个注册的贴纸在drone上才能飞。但是根据今年(2017年)5月联邦上诉法院的一项裁决,自己玩玩的drone不需要向FAA提交注册,详细的可以看这里:https://www.faa.gov/uas/getting_started/registration_deletion/

那我就能随便飞了?

🙄不行。虽然不用注册,但是FAA还是列出了几项基本规定,比如在机场5-mile范围内如果没有事先说明是不能飞的。还有比如虽然是个人飞,但是如果drone超过55磅也还是需要向FAA提交注册。FAA网站上给drone写的Getting Started页面可以作为初步参考。另外,FAA也专门给个人自娱自乐型玩家写了一些guideline,比如低于400英尺,保持drone在视线之内,不要在有比赛的体育场上方飞,永远给有人飞机让行等等。

呀!我家附近就有一个机场,怎么办?

美国大大小小的机场有很多,很可能你家附近就有一个local的机场。在飞之前,查好,提前通知就好。FAA自己做了个app叫B4UFly(Before you fly),可以根据当你所在地点显示是什么regluation,也可以搜索一个具体地方的regulation以便给目的地做功课。也有直接给当地机场塔台通知的功能,填写下要飞多高多远多长时间点发送即可。

这个B4UFly app好烂!

额。。。是的。。所以我个人更推荐AirMap。实时更新的地图数据库,比如什么时间在哪里有体育比赛,也有向机场塔台通知的功能,还有质量不错的iOS/Android app。网页版有个”Fly for Fun”的filter就很实用。不会像B4UFly,连医院警察局的直升机起降机场都算在内很容易让新手觉得intimidating。

国家公园呢?

所有的国家公园都是禁飞区(除非有permit,但没见到有拿到的),违反的话目前是最高6个月的jail以及5000块的罚款。另外有一点,这里所说的国家公园并不仅仅只是像黄石大峡谷这种热门或者面积大的国家公园,只要归national park services管的都算。比如金门大桥(隶属于Golden Gate National Recreation Area),或者Malibu海滩(Santa Moica Mountains)。

差不多就是这些了,这些法律法规时不时就会变,每次出行规划的时候得查清楚以避免不要的麻烦。最后上传今天在Hermosa Beach拍的日落:

2016

2015这一年,印象最深的就是去(浪)了很多地方。

  • 3月先是胆战心惊地去了次Tijuana续签签证,胆战心惊主要是被宣传了很多那里的都市传说,索性一切还算顺利。
  • 4月底5月初去了北九州(博多长崎福冈熊本和由布院),来到了拉面的故乡博多,拉面吃得是再也不要吃了,然后在东京玩了几天。
  • 8月初又去了次Tijuana,为什么呢?因为我护照丢了。。。去洛杉矶中国领事馆重新办了新护照(花了3个礼拜,呵呵)。但是因为下个月要去德国西班牙没有有效美国签证stamp是回不来的,也没有补办签证这一说只能重新办,所以就又去了Tijuana办签证,谁叫那是离我最近的美国大使馆呢。还是走正常的流程,跟签证官说了情况后,她叫我不要再弄丢了就通过了。
  • 8月末去了次纽约,主要是因为DroidCon NYC这个Android程序员的会,票价相比别的convention实在是便宜太多就去了。看了本以为很文艺会看不懂其实很十三会笑全场的The Book of Mormon。
  • 9月下半月就去了德国跟西班牙,出发前2天刚刚拿到的签证。一共只待了10天,德国就在法兰克福周边玩玩,科隆大教堂确实比较震撼,租了两天车开了下没有限速的路,去了逼格很高的徕卡总部。尝了很多好吃的,猪肘啦啤酒啦大香肠啦。还有两只超可爱的猫Joy和Lingling!西班牙就去了巴塞罗那,终于看了一场巴萨的球,可惜梅西4分钟就受伤离场,而且那个时候我还在巴萨纪念品店里买买买,就什么也没看到。巴塞罗那印象最深的就是好吃的东西很多,海鲜饭tapas还有Jamón ibérico!
  • 11月回了趟国。中途先去了日本,带爸妈在东京京都大阪走马观花玩了一周,感觉就是时间像飞一样刹那间就到了要回上海的那天。在上海的两周,基本天天都在下雨,空气倒是蛮好的,有几天特别冷,还问我爸借了衣服穿。面基了很多新老朋友,相谈甚欢,关键,吃了很多好吃的。
  • 圣诞节的时候去了三藩,其实15年三藩大概去了三四次了,这次是去Lake Tahoe滑雪。以前在波士顿的时候没有机会,今年趁着加州大雪,尝试了skiing,第一天下来是走不动路的。

工作上呢,公司里发生了很多狗血的事情,目测2016年会继续,我也就静观其变了。这一年算是全职写Java/Android的一年,本来很讨厌这两样东西的,但这一整年下来慢慢地发现太多有意思的东西可以琢磨,现在想叫我换别的方向我还不太愿意了。

这一年有点遗憾的就是我的Gibson摸得越来越少了,希望明年能够重新拾起来,不要到时候连Green Day都不会弹了(。

2016年,想做的事情还有很多,慢慢来了就。

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来的)。其实这个数字各大报税软件基本都是一样的。如果觉得不满意数字,就得用高级版本来找是不是有别的项目可以退税。不过个人觉得如果需要用上高级版本的话,还不如找个会计师报了。

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

Disclaimer: I do not provide tax, legal or accounting advice. This material has been prepared for informational purposes only, and is not intended to provide, and should not be relied on for, tax, legal or accounting advice. You should consult your own tax, legal and accounting advisors before engaging in any transaction.

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初探

在前几天的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.