说转型 - 转载
【覃超的回答(91票)】:
说“转型”可能我还不够资格,因为我从工作开始就直接在做mobile,只是之前在大学里面搞过一些程序竞赛和TopCoder的组件开发在桌面电脑上面,所以从一开始我就是还没完全定型的程序员,基本上什么东西都需要从头学习。第一次真正开发mobile程序还是在CMU读master的时候,那时做毕业论文,研究Android系统的安全性,于是第一次装了Android的文档和自己照着样例写了一个,感觉还挺不错(其实就是写Java)再后来就是进入Facebook后,从Boot camp毕业后就进入Mobile team,当时公司里面大部分人还是搞PHP的,但是公司鼓励大家做Mobile开发,说是以后的方向,于是我从一入职就开始了全面的Mobile开发。
个人的经验如下:
技术方面: 我个人感觉Mobile上面更加注重程序的效率,程序要简洁,速度快,同时复杂度要尽量低。另外就是在写程序时具体要注意的事项,由于Mobile的处理能力不及桌面电脑,所以要格外注意将非UI相关的操作放入到worker thread。相比开发桌面程序或者web app,亦或者是现在的iOS或者Android开发,MVC模式已经深入人心,它的本质就是把代码按照其做的事情分类,坐不同工作的代码在不同的模块里; Thread分类和它也类似。刚开始进行Android Facebook和Facebook Messenger开发的时候,我们的Tech Lead -- Jon Perlow 就在code review中不断指出我的很多操作还是像桌面程序一样放在主线程中,而Android下主线程即 UI thread,这样就很可能降低程序的流畅性。而且很多时候,也其中蕴藏着一定的平衡和折中。因为移入worker thread后,程序会出现很多async method call和callback function/class, 这样对代码的可读性和以后的维护都是挑战,同时线程的切换和对于共享资源的同步也是会带来性能的损失,所以在写的时候要具体问题具体分析。比如说大规模I/O操作和上百万次的循环,自然不用说;但是在很多情况下,就没有如此明显吧,比如说判断一个文件是否存在, new File(getDucumentFolder + "/xyz").exist() 也算I/O操作,那到底要不要移入worker thread呢?另外很多时候,你最开始的函数里面,可能操作非常简单,就直接在Main thread里就可,可是后来其他人在refactor的时候,将这些操作放开到好几个function里面去做,然后在以后的版本中,由于加入了新的feature,每个function里面都比之前要做更多操作的时候,就逐渐逐渐地让Main thread的负担加重,搞到最后给用户的感觉就是这个App功能是变多了,但也越来越笨重,越来越容易crash。所以说,不要在UI thread里做事这点,想必只要智商上80的人都懂,但是真正要执行的时候并不是如此得显而易见,而同时,公司里的项目都是多人作战,每个人一般都着眼于自己做的那一块,这样很容易就造成最后UI Thread里面的工作量远比开始设计的要多。
现在主要的手机平台就是Android和iOS,所以建议两个都要去了解,然后专注于一个平台。如果Android的话,除了看Google官网外(http://developer.android.com/training/index.html ), 很多时候当你具体要调用一个API,但是文档上面有疑惑的时候,最好的办法肯定还是能回到代码里面去确认。通篇浏览Android的代码肯定不现实,我个人(也是公司里面)觉得最有用的办法就是安装plugin:https://chrome.google.com/webstore/detail/android-sdk-reference-sea/hgcbffeicehlpmgmnhnkjbjoldkfhoin ,然后搜到文档后,页面上直接有一个链接 (View Source)来方便查看代码。回到上面那个线程切换的问题,Android有三种办法:AsyncTask, Handler, Executor. 在代码里面(还有Stack Overflow上面的讨论),AsyncTask是最差的办法,它属于Google自己加入的一个Hack,大量在自己的Android App里面使用会发生阻碍程序性能的奇怪问题(因为你对它的worker thread pool没有任何控制);Handler比较简单,适合将单个任务快速丢到另外的thread里面执行,但是从源代码就可以看出Handler本质上也是在调用executor。最后就是Executor自己了,它的坏处是比较复杂,不注意容易出错,但是好处就是性能好,而且功能强大。可以自己定义queue的属性,指定thread pool的大小,和筛选并处理
或者取消还没被执行的任务等等。所以只有在源代码里面去确认后,才会对每个模块在使用有直接和全面的了解。这样就能理解为什么公司里面Android的编程规范里面来一句“Don't use AsyncTask"是什么意思。(很多人问我为什么不能用AsyncTask,其实在Android API的document里面就有http://developer.android.com/reference/android/os/AsyncTask.html#execute(Params...) , 看它自己的注释。另外还有一个blog:http://commonsware.com/blog/2012/04/20/asynctask-threading-regression-confirmed.html ) 多提一句,如果两个平台都做的话,还可以比较在iOS下面对线程切换的做法,iOS上鼓励的是使用GCD (grand-central-dispatch)。他们各有自己的特点,但是个人认为iOS的GCD更加简单,也更加符合人的思维。
另外就是UI方面,我做过Facebook Messenger for iOS的UI,但是设计毕竟不是来自本人之手,所以只当是自己的拙见。个人觉得UI越简洁越好,另外就是在设计UI的不要进入误区:认为app的Android版本和iPhone版本UI要一模一样。还有一些自己在做UI的时候,designer给我的细节性的建议:“比如text一般加一个pixel的半透明的shadow“, 按钮(透明)的实际大小一般比贴图再大一些,这样更方便用户触摸。
上面都是在讨论的时候,即兴想到的东西,没有太多整理。不过这两年在FB的打磨让我觉得最重要的不是你的技术多牛,写代码写得多快,而是适应力要强,能够也愿意push自己去转型。我见过不少人,之前对某一技术或者某一领域炉火纯青了,就一直想呆在自己的领域里,说是精益求精也好,说是吃老本也好,更有甚者就是想用老本的技术来用于新的领域。Mobile上面跑HTML5的离线App我觉得就是其中一个,具体细节我整理一下,放到另外一个问题里。
【陈彧堃的回答(69票)】:
应邀作答,抛砖引玉了。
对于技术人员来说,怎么从互联网向移动互联网转型?基础技术是相通的,C++/Java/LAMP这些基本功,如果拿到移动上就不能用了,码农的日子未免太苦逼。
似乎「技术转型」一说太重,我更倾向于说「工种转型」。
技术为产品服务,产品依托于生态系统。第一,在移动生态系统中,手机对于人的可识别度是超过传统互联网的,传统的cookie跟踪方法带来用户定位的模糊性,给数据清洗和挖掘带来了很大的限制。而在移动上,imei和udid是更干净的用户标识方式,基于此,可想象的数据挖掘空间更大。第二,移动设备占据的是用户的碎片化时间,用户行为更丰富;第三,用户目前还习惯于一个应用只干一件事,需要App非常体贴用户才能长期占有用户的时间。
举个例子,地图应用中的Local Search,用户随时根据自己的位置查询附近的餐厅POI(Place of Interest)。这个在Web上当然很常见,但移动环境中用户位置高频变化,越来越习惯随时随地查询,这就难搞了。甚至出现了新的查询方式:查询周围的人。人的位置不断变化,给后端查询的索引系统在时间和空间复杂度,扩展性等指标提出了更高的挑战。Quad-Tree,R-Tree这些高维空间索引结构也越来越多应用在工业产品中,MongoDB和MySQL对R-Tree的支持就是例子。
这三个特点集中体现在社交应用或者包含社交元素的应用中,这和友盟最近的观察是不谋而合的:移动应用的社交化正在成为趋势。社交元素的加入,使移动应用的社区化和用户粘性得到大幅提升。硅谷一个投资人Fred Wilson以前提了一种说法叫「MobileFirst Web Second」:http://www.avc.com/a_vc/2010/09/mobile-first-web-second.html,最近他又跳出来写了篇文章叫「RethinkingMobile First」:http://www.avc.com/a_vc/2012/12/rethinking-mobile-first.html,就是在强调移动对于消费者和社交导向产品的重要程度,这和我们的观察契合。
那么对技术人员来说,移动+社交会带来怎样的挑战呢?如何「工种转型」?
第三方信息抓取技术,个性化推荐,和社交关系图谱
在社交化之后,用户的兴趣和标签可以从站内行为分析,也可以通过多个社交平台的API取得用户公开的数据进行交叉挖掘和分析,这是个性化推荐的基础。个性化推荐会让应用变得情感化,一个让用户觉得有感情的应用,当然在设备上留存的时间也变长了。每个应用都有自己的用户体系和用户行为,有一套自己的用户模型。但不能只依靠站内行为,原因有二:
- 站内行为不能解决冷启动问题
- 社交平台上(如新浪微博,腾讯微博等)上有大量的用户数据,和站内行为互补,甚至远远超越站内用户行为。用户的挖掘工作可深可浅,浅的简单抓用户自定义标签,把设备和人等同起来;深的可以考虑:第一,为用户标签建立语义化模型。一堆标签不足以代表用户,想了解一个人需要建立层次化,归类化的用户属性模型;第二,考虑设备和人的多对多关系,目前主要指单用户使用多设备,手机,平板,用户行为有很大差异;第三,区分用户的转发和原创等细节行为的语义区别;第四,应用内用户属性的扩散挖掘。社交用户比例不太可能是100%。但可以通过已知社交用户数据和站内信息交叉来扩散,用户会和信息交互,会产生大量的用户和信息之间的关系,也初步构建了站内的社交关系图谱,站内社交关系一旦生成,便可以将大量的社交信息扩散到非社交用户上,成为个性化推荐的基础。谈到个性化推荐,就不得不提Amazon在十多年前提出的协同过滤,经过这么多年的发展,目前已经成为工业界个性化推荐的标配技术,以及学术圈中一大研究方向。协同过滤的无数变种和改进也被广泛应用在不同的产品中,但残酷的是,推荐算法的应用是个骑驴找马的长期抗战过程,会参合进用户属性,用户习惯,用户历史行为等很多因素,是需要长期反复训练才能不断完善的。
碎片化时间,复杂环境使用体验,和海量数据
根据友盟最近的统计数据,移动互联网真正进入高速发展不超过3年,国内Android设备到达1.4亿,iOS设备到达6千万,用户增长速度远高于PC。移动设备占据了用户的碎片化时间,用户的启动次数和使用环境更为复杂。这对开发人员有几点考验:
- 客户端适配复杂使用环境,比如要考虑强光弱光和交通工具振动环境下的可用性。
- 用户行为构成大量流数据,对后台的数据处理,分析,以及产品迭代都造成了更大压力, Hadoop被广泛应用在移动系统的分布式数据处理工作中,另外近期Google的Dremel和Cloudera的Impala也在为更实时的海量数据查询系统探路。
- 用户使用时间的分散也会给运维人员施压。根据友盟的数据报告,夜里22时,用户的使用会达到高峰,大量的使用会持续到凌晨2点。留给运维的用户透明时间明显缩短了,这也要求开发出更加自动化,智能监控的运维系统。
- 产品的开发模式要变革,用户对于应用和内容新鲜感的需求更强烈。Scrum,测试驱动,站会等不一定满足快速迭代的需求,但单枪匹马不可能保持持续的战斗力,所以需要团队在打磨中能摸索出符合自己产品的开发方式。
【季逸超的回答(60票)】:
后端方面请拜读彧堃同学的回答,非常赞!我就从前端/客户端说说自己的拙见吧;-)
记得当时iPhone出来后,让人们看到了一个与传统的“窗口”完全不同概念的逻辑:界面方面一个应用占满整块屏幕,程序方面代码也都是在严格的沙箱内运行。当时我就意识到这将是一整套全新的规则体系,后来渐渐从表面往深层看,写了几年烂代码慢慢我也有了点心得:
1.淡化文件的存在,而凸显应用和工作流。
2.尽量避让主线程/UI线程,避免锁界面。因为桌面应用锁UI的话只不过是一个窗口,而移动应用会给人感觉是“手机”这个整体挂了...
3.能迅速完成的操作/运算就不要指望后台,自己的程序随时可能被kill掉。后台只留给VOIP、网络操作之类的。
4.尽量加快启动速度。移动产品用的频繁,但单次使用远比桌面要短,所以不要出现Photoshop那样让用户傻等的情况。即使用个“假象”也要让用户觉得启动挺快的。
5.同一个功能最好有多种交互/操作方式。不像Windows一统桌面江湖,现在各个版本的android、iOS用户之间使用习惯迥异,最好能让人们的习惯都能work。
6.最好不要让UI控件太显眼(比如街机游戏中硕大的摇杆遮住了人物),但也别太隐晦(猛犸浏览器4,哈哈哈)。
7.用户其实很在意耗电和发热量,桌面用户从不在乎…
8.很多功能别人说做不到或说平台不允许不开放的时候,总有人用匪夷所思的奇葩手段实现了…
个人拙见请勿轻信哈~
还有个最近的风气,个人觉得有些纠结:每次各种app更新完后,一启动就是几幅小清新图片+几句看不太懂的忧桑文字,其中最后一张带个按钮"开始体验"...而且不点掉"分享到微博"的话你就中招了...
【刘铁锋的回答(36票)】:
因为具体的开发场景不一样,目标的读者的经验各不一。因此,没有具体分享特别具体的技术经验和教训,分享一点转型过程中,所需要补充的知识点和逻辑上的转变。
移动开发和PC上的开发带来了哪些不一样?
在我看来,从2002年之后,传统桌面的开发者基本都转向了J2EE/.NET/LAMP等以Web技术或者服务器端开发技术为主的开发方式。使用C/C++/MFC/Delphi等开发C/S模式的用户越来越少,甚至工作的需求也开始变得越来越少。
这样在技术体系上,开发者的经验开始基本上覆盖在:
- HTML + CSS + JavaScript
- 各种脚本语言(PHP/http://ASP.NET/JSP/Python/Ruby)操作服务器API
- 服务器数据处理逻辑(O/R Mapping, 数据库连接池,各种如AOP等设计模式,甚至DSL等等)
- 大型服务器的架构设计(分布式架构,各种负载均衡,服务器连接优化)
- 数据库(分布式数据库,事务处理,大规模数据的存储、查询优化)
- 大数据处理(Hadoop, Hive)等等。
那对于移动开发上需要什么?
不管是Android / iOS /WP , 其实对于开发的需求上逐渐回到了2002年之前,大概类比MFC/Delphi的时代,更加合适。
移动开发者的技能需求发生了转变,需要的经验变成了:
充分理解各移动平台的进程架构和程序生命周期逻辑(程序启动,程序被系统suspend/kill, Services)
- 界面设计(各种UI控件,事件处理)
- 数据处理逻辑(客户端缓存、多线程并发)
- 网络数据处理
- 平台相关特性(系统API调用,系统通知机制等)
- 各种性能处理。
因此,在学习的路线和需要的经验上有了不同。
如果需要从非移动开发者往移动开发者进行转型,哪怕同样使用的是Java语言,需要的就是了解不同的库以及处理不同领域的具体问题。
在移动设备的开发上,我归结为三大类问题:性能的问题,界面响应的问题,产品的稳定性。这些是技术人员可以需要最为注意和保障的。
【王思达的回答(11票)】:
从桌面端转向移动端,一定要认识到二者不同的侧重点。桌面端包括web更侧重于逻辑复杂,高级的任务,而移动端的娱乐性明显更强。
就从操作方式说起吧,桌面端主要靠鼠标键盘和touchpad,所以操作精度要高得多,很容易将很多功能集成到一个界面里;但同样的思路就完全不适用于移动端了(反例我是实在想不起来了,大家可以帮忙想想),相信一个cluttered ui的app,就算功能再强大,用户盯着你的界面超过3s就会头晕,点击某个button要点好几下才会成功,也必定是一个糟糕的app。
那什么样的操作方式是适用于移动端的呢?ListView的滑动操作就是一个很好的例子,不需要用户任何的思考,只需顺着期待的内容出现的方向滑动,这样intuitive的设计便是王道。类似的设计还有来自Tweetie的下拉刷新,Android 4.0引入标准库的ViewPager等等。上述的操作都有一个共同特点——手势操作。既然移动端(不管是手机还是平板)是拿在手上的设备,那手势操作成为其杀手锏就毫不奇怪了,自然也就成了区分移动端和桌面端的一个重要特质。PeakJi大神的猛犸浏览器和输入法(忘记名字了)同样也体现了这一点。
有了简单直观的手势操作,还有一个不得不提的feature——push notification。用户很懒,一台机器装了上百个app,可能一个月你的app也就被打开一两次,这当然不是你希望看到的。如果你的app是网站客户端性质的,那么push notification就是一个很好地利器了。怎么做呢?我总结了下面的流程:
1. 与社交网络连接,获取用户资料,分析用户兴趣
2. 记录用户在你的网站或客户端的使用习惯,逐渐逼近用户真正的兴趣
3. 根据得到的用户兴趣,推送他感兴趣的内容
可以看到,不仅仅是“通知”那么简单,像新浪微博那样的,一天一条的palm news,多了只能让人感到annoying,并不能起到和用户很好的沟通的效果;只有推送用户感兴趣的内容,才会引起他们的注意,增加你的app在用户心中的权重。
最后一点我认为很重要的,就是consistency,和操作系统要保持操作习惯的一致性。比如左上角的返回button,Android 4.0的ViewPager滑动换标签等,这样做最大的好处就是降低了用户的学习成本,让你的app和OS融为一体。当然在OS的大框架下,也不乏有新意的app,比如Android下的一款类siri应用Maluuba,大胆地采用了Metro风格的设计,但操作起来并不会觉得陌生,最大的原因就是ViewPager的滑动操作被保留了下来。这样的例子还有很多,一时想不起来了,欢迎大家补充。
话痨打开了就有点收不住了,就这么多吧。
原文地址:知乎