<![CDATA[时光屋]]>http://villadora.me/Ghost v0.4.2Thu, 13 Nov 2014 08:18:39 GMT60<![CDATA[Multitasking in Mobile]]>最近看到几篇几年前的文章,关于多任务执行在移动设备上设计。

http://blog.rlove.org/2010/04/why-ipad-and-iphone-dont-support.html

这篇谈到iOS上为什么没有想android那样去做multitasking,他的观点是认为android有着良好的api去保存程序状态,有着一整套复杂的程序组件状态机,以及能够很好的去管理在不同状态之间的切换。而iOS在iphone/iPad上实现这样一套系统会非常复杂,而android则是一开始就考虑好的。

个人认为到应该不是这么回事,苹果的工程师绝不会一个这样的系统都无法在iOS上做出来。只不过双方的设计哲学有所不同。

无论是andorid还是iOS的设计者,在移动设备上用户只能关注于一个应用上这个观点保持了一致。而感觉android是倾向于给予程序更多的自治权利:我提供功能众多,开发者在其中选取自己需要的,所以你的程序你可以选择在后台运行,这是你的权利。

而可以参考apple文档:

https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4

Apple的风格是:允许程序去申请一小段时间去完成最后的工作(留下遗言),如果你还赖着不肯死,就直接枪毙了。至于可以留下些什么,也是apple限定好的,比如下载,音频,位置定位等。至于别的,啥也别留下。这样的好处是可以控制程序的执行和销毁都在系统的掌握之下。

从apple store和google market的现状就可以看出两者思路的多么不一致。app到apple store都是需要审核而且只能在apple store上发行的,而android app发行的渠道就多了去了,直接下载也是可以的。

下面这篇是android的官方blog里面的文章, 讲android的multitasking的设计理念。可以看到 "all applications are created equal"的哲学,而苹果嘛,恩,自己程序后台跑的好好的呢。

http://android-developers.blogspot.com/2010/04/multitasking-android-way.html

]]>
http://villadora.me/2014/11/13/multitasking-in-mobile/34bd7de2-3bef-48fb-b741-eac476afbc0fThu, 13 Nov 2014 08:14:56 GMT
<![CDATA[Android 学习笔记(3)]]>
  • WakeLock 可以用来唤醒屏幕和CPU,用来做重要事情的通知。微信天天晚上还响个不停是不是就是这种情况?建议是只在真正需要的时候用。影响电池使用,增加耗电。
  • PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    
    PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "WakeLock");
    
    wl.acquire(10000);
    
    wl.release();  
    

    说到耗电,关于老外和国人还有一个梗: 记得最早看到mobile web的时候,google有个研究是研究什么技术在什么网络下比较耗电。国内么,后台进程杀都杀不完,某app晚上经常唤醒手机导致屏幕一闪一闪,某狐app在背后默默的10分钟内用掉了30M的流量, 估计一直在唤醒网络吧。

    • Parcelable, Bundle

    Parcelable表示是一个对象能够包装到Parcel里的一个interface,而Parcel是包裹的意思,这个包裹是用来做IPC通信时传递讯息的,而不是用来储存的。大家收到快递后都会把包裹拆了而不是直接就放到自家的收藏柜里了吧。在官方文档里面也有明确的说明, Parcel不是一个通用的序列化机制,而是为了搞笑的IPC通信传输。

    所以如果是为了持久化和网络传输,应该实现Serializable,而只有是为进程之间,程序之间进行通信的时候才实现Parcelable。

    而Bundle则是Parcelable的一个实现,可以想象成对包裹的标记管理,很多包裹的情况下会给包裹标记上String标签,这样打包的人和收包裹的人就知道如何去放置/读取包裹。

    • ConnectivityManager
    ]]>
    http://villadora.me/2014/11/13/android-xue-xi-bi-ji-3/d647abbd-46de-46a5-9ee0-3b430679c215Thu, 13 Nov 2014 07:59:11 GMT
    <![CDATA[static javascript]]>Velocity2013上有一篇演讲说的是static memory of javascript, 是关于emscripten的应用。除了迁移C/C++的lib到javascript之外,还提到一个观点是关于static memory的。由于在C/C++中的内存都是手动分配和释放,所以在emscripten生成的asm.js中会事先分配一个大heap,之后所有的相关内存管理都在这个heap中进行,就没gc啥事了。

    好处是避免的gc在意料不到的时候进行, 观点合理的手动分配是最高效的。emscripten在游戏方面还是很有用,很多游戏引擎剥离gpu相关的代码之后都是纯计算的没有io操作,在浏览器中执行没有任何问题,然后就是游戏对于使用的流畅性,gc的无法预知会导致一定是有在某个时刻会开始进行gc而导致性能下降,表现就是卡死。这对网络游戏者来说是致命的。

    static memory,管理起来比较麻烦,但是也是说明如果在一个object创建和销毁频繁的情况下,使用object pool是非常有效的。如果在gc上碰到性能瓶颈也可以通过提前预支一块heap来优化。

    然后一直在想的一点是javascript和大部分语言不一样的地方是没有struct,只有array能勉强算作struct,对于object之类的内存结构也无法预知内存空间大小。导致在操作数据方面性能比起java,python等处于劣势。这也是为什么新的要替代javascript的语言typescript, dart都会提供class的原因, 至于之后javascript提供的class提供了语法糖但是并没有阻止prototype上在被定义之后添加新的属性。也就是说只有在运行时可以做优化认为是struct,而不能在编译时确认为struct,从而也没法进行内存的优先分配或者脱离prototype机制运行。

    ]]>
    http://villadora.me/2014/10/28/static-javascript/dfaa2253-25af-4bb6-b573-71bb516ed72aTue, 28 Oct 2014 08:34:03 GMT
    <![CDATA[Package xxx was not found in pkg-config search path]]>这个是pkg-config没有在自己的路径中找到对应的*.pc文件。

    可以通过以下命令查看pkg-config的路径:

    pkg-config --variable pc_path pkg-config  
    

    会列出pkg-config*.pc文件的路径,找到正在使用的对应的目录。

    对于使用Homebrew安装的lib, 去/usr/local/Cellar/**/<version>/lib/pkgconfig下面找到对应的pc文件,然后软链接到之前的路径中。

    ]]>
    http://villadora.me/2014/10/27/package-xxx-was-not-found-in-pkg-config-search-path/eab4f788-fe93-4744-8c7e-78397d05e1eeMon, 27 Oct 2014 01:43:58 GMT
    <![CDATA[fix/spdylay编译过程中碰到'undefined marcos: AM_PATH_XML2']]>发现编译fix和spdylay的时候经常会碰到这样的问题。

    在ubuntu下面安装过libxml2-dev后没碰到这个问题,但在mac上即使用brew install libxml2之后继续autoconf -i还是会碰到这个问题。

    主要是libxml2在brew安装之后没有把自己的libxml2.m4放到/usr/local/share/aclocal里面。

    这个时候我尝试brew link libxml2libxml2中的share里面的东西都link过来,但是出现信息是:

    warning: libxml2 is keg-only and must be linked with --force  
    

    这就是说libxml2是一个keg-only的包,只会放在brew自己的Cellar地窖里,不会对外面的环境进行修改,如果需要修改就要使用--force。估计是因为多个版本共存的关系,否则一升级会破坏之前的所有的依赖包。

    既然我这是第一次装,我就直接手动aclocal了,brew link还会link man/doc/gtk-doc这些。

    手动就直接把libxml2/<version>/share/aclocal/libxml.m4软链接到/usr/local/share/aclocal下面就好了。

    之后果然autoreconf -i顺利通过。

    至于brew的包是怎么定义自己是keg-only的就不知道了。

    ]]>
    http://villadora.me/2014/10/27/fixspdylaybian-yi-guo-cheng-zhong-peng-dao-undefined-marcos-am_path_xml2/c8f39fe8-aff9-47ab-a9e1-5791ddb13a1dMon, 27 Oct 2014 01:26:16 GMT
    <![CDATA[Programmer's Enemy - Dependency Hell]]>In a modular programming world, we have component-based software design, modular programming, etc.

    There are a planty of articles talking about the benifits we can get from the good component design, I'm not going to talk in here.

    When we do modular design, just as we have already done in programming world decades, there is an enemy in our world: dependency hell.

    You should heard of 'DLL Hell'. A common cause is that apps shares libraries in the same location, so once there are two app depended on the same library with different versions, the former one breaks.

    share the same library

    To avoid that, programmers add versions to their libs and many package systems now don't store only one file in the shares folder, they add versions.

    So there are more than one version of lib in the system. That's what bundle, maven do, the libraries will be stored in '.m2/', 'gems/'. That will looks like this:

    with version

    Or another solution is: instead of using shared lib path, using different lib path for each project, like using LD_LIBRARY_PATH, CLASS_PATH.

    with custom path for each project

    Now we have versions, but developers are lazy, people don't like to update their code every time one dependency update, but people want to enjoy the benefits of bug fixes, and in some cases, update your own file helps nothing:

    upgrade chain

    To make people get auto update for a bug fix, many package managers introduce version range, includes npm, rubygem, maven, etc.

    Great, now if a lib my project depends on get a bug fix, I just do a simple upgrade or reinstall via npm install, mvn install, I get bug fixed without any code change.

    upgrade nice

    Great! We are now don't worried some one overwrite my libs! Are we in a safe world? NO.

    Let us take a look at following story:

    Your great project depended on X(1.0.0) and Y, Y also depended on X (1.0.0). Things works fine now, someday, X get upgraded to 1.1.0; it provides a wonderfull feature you have! But, you can not use it, until Y get upgraded.

    deps hell

    What about there are complex dependency tree here.

    worse deps hell

    So people have no choice to re-build the wheel. Wheels can not match each other. I see no package system get ride of that except node/npm.

    Let see how node get ride of dependency hell in next article.

    ]]>
    http://villadora.me/2014/10/17/our-enemy-dependency-hell/2e1c53da-35cd-40c3-848b-64e947a1c8e8Fri, 17 Oct 2014 01:26:28 GMT
    <![CDATA[android模拟器中连接开发机器]]>在模拟器中localhost已经被设置为虚拟机的机器,需要在本地调试的时候,通常需要在app里面连接本地起的server来调试连接和访问。但是localhost已经不能用了,而模拟器是绑定在一个虚拟的网络上的,在android开发网站上有http://developer.android.com/tools/devices/emulator.html#networkaddresses, 说明把10.0.2.2这个地址绑定到了开发机器的localhost。就不用去尝试别的地址了。

    而genymotion则是bind在10.0.3.2这个地址。

    ]]>
    http://villadora.me/2014/10/11/androidmo-ni-qi-zhong-lian-jie-kai-fa-ji-qi/4788ac02-ab8a-441d-944f-55e3f58b7ce8Sat, 11 Oct 2014 01:31:01 GMT
    <![CDATA[Android 学习笔记(2)]]>build from source

    Android是一个开源系统,源码都是公开的, 可以到http://source.android.com/上去下载源码。

    具体的操作都在官网上这了:http://source.android.com/source/building.html

    首先,需要的是一个unix环境,window就装虚拟机装ubuntu吧,很多build的工具也只能在unix环境下用。

    然后是装各种需要的工具和依赖库,包括bison,gmake之类。

    在macos上要注意的一点是mac默认安装的时候都是大小写不敏感的文件系统,而android framework的文件是区分大小写的,官方的说法是大小写不敏感会影响git对文件的处理。所以我们需要一块大消息区分的磁盘区域。

    有些老教程做法是用mac自带的工具去分了一块新的大小写区分的磁盘。千万不要这么做!虽然mac的磁盘工具不会影响你的数据,但新磁盘分区设计到老磁盘分区的大小调整,速度是非常非常慢。中间如果出现断电或者其他异常,就哭吧。 现在官方的推荐做法是新建一个磁盘镜像.dmg文件,对就是你平时看到的软件安装文件,然后再把这个镜像文件挂载到自己的目录下。

    hdiutil create -type SPARSE -fs 'Case-sensitive Journaled HFS+' -size 40g ~/android.dmg  
    

    上面的命令会创建一个大小为40g的大小写区分的磁盘镜像。这个大小是对4.+以上系统的要求,有些老教程会分20G,等到编译的时候就哭了。(是的,我之前就是看了一篇老教程=.= 还是官方的靠谱)

    对于mac上来说,还一个就是设置下文件句柄的数量限制,印象中mac默认设置是256,而在并行编译的过程中打开的文件数很可能超过,所以官方也是建议提高上限:

    ulimit -S -n 1024  
    

    接下来我们就可以去下载源码了。

    AOSP(Android Open Source Project)的源码管理也是用的git, 理论上来说你只要用git也就能clone项目了,但是你还是要去下一个小python脚本repo来帮助你管理源码。为什么? 因为aosp下面的项目实在是太多了,从list上来看目前有684个项目,如果用git来一个个下载管理的话,要多麻烦有多麻烦。

    $ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
    $ chmod a+x ~/bin/repo
    

    下载repo,然后执行

    repo init -u https://android.googlesource.com/platform/manifest  
    

    可以看到这是去访问了一个manifest路径,实际上就是把aosp的项目列表拉了下来,之后还会下载和生成一系列的辅助脚本。执行

    $ repo sync
    

    下载就开始了,repo默认是使用并行下载,也支持断点续传,看起来是基于git branch的。

    之后就是默默的等待代码下好了。

    default apps

    系统默认的app都在android源码里面可以找到,如果只想看这些app的代码的话,可以去https://github.com/android 里面找, 搜索apps的项目就好了。

    比如找Launcher,可以搜到platform_packages_apps_launcer这就是系统自带的默认启动launcher:

    https://github.com/android/platformpackagesapps_launcher

    ]]>
    http://villadora.me/2014/09/28/android-xue-xi-bi-ji-2/d632eaa4-6a5a-4c7e-91a3-12336bdf01edSun, 28 Sep 2014 04:00:34 GMT
    <![CDATA[Android学习笔记(1)]]>Security Sandbox 安全沙盒

    Android操作系统是基于多用户的iinux系统上的,从他的系统架构图就中可以看得很明显:

    Android System Architecture

    所以很多地方Android都直接利用了linux的特性。

    • Android里面每个应用都被当作linux系统中的一个用户,被赋予一个唯一的user ID。这个user ID只有操作系统知道,应用自己是不知道的(当然通过root之后没有什么不可能)。这样应用的文件也就很简单的可以通过user permission来设定。
    • 每个应用都运行在独立的进程里,这样的好处是Android系统对应用的管理可以简化到对进程的管理,如挂起恢复等都可以直接用进程的特性。而内存管理也变得简单,因为不同的应用就是不同的进程,不会相互影响。
    • 另外,每个京城都有着自己独立的虚拟机dvm,也就意味着应用都是运行在独立的虚拟机里的,虚拟机相当于沙盒,互相之间的影响非常小。

    当然应用之间不可能完全没有交流,Android提供了如下几种方式:

    • 两个应用如果是同一个组织个人开发,并且有着同样的签名,那么他们可以要求系统赋予他们一样的user ID,这样他们可以互相访问文件;而android在设计时为了节省系统资源,则认为既然你们都已经有一样的user ID,那么也在也没有必要把这两个应用区分到不同的进程和虚拟机中,所以有着一样的user id的应用会共享一样的linux process和虚拟机。
    • 应用可以访问储存在各种设备上的数据,比如联系人,短信或者sd卡等。这些权限必须在安装时分配user ID的时候就给予之后是不能更改的,而一个应用需要哪些权限,需要通过manifest.xml来声明。
    • 还有一种更通用的方法就是通过系统提供的广播机制,后面会提到的广播,相当于一个系统级的Message Bus。可以通过subscribe和send消息(Intent)来向其他应用程序发布消息。

    Application Components 程序组件

    在Android系统中一个应用主要是由下面四种组件构成的:

    1. Activity: Activity代表了一个单独的screen,是能够响应外界事件的一个最小单位(还不是很清楚activity里面的view的结构,但是感觉很多软件都滥用了Activity,导致在Activities之间切换时每个Activity都需要消耗时间做初始化)。从文档历来看,Activity不应该是UI上的结构,而应该是一个程序逻辑上的结构,程序的Entry point,意味着外部可以不通过应用的其他部分直接访问到这个界面。而如果一个Activity是“私有的”,即不为外界所知也不响应外部消息的,那么应该整合进另一个Activity。
    2. Service: Service是一个后台服务,多用来执行一些长期运行的操作或者需要在另一个进程里执行的操作以避免当前应用进程阻塞。而Service是没有用户界面的。
    3. Content Provider:Content Provider提供了一组可以共享的数据,其他的应用程序可以访问甚至修改。而后面数据可以储存在文件系统,SQLLite数据库或者网络上。同样也Content Provider也可以被设置为私有。
    4. Broadcast Receiver:前面讲到了广播,而Broadcast receiver就是应用响应广播时间的组建,许多广播使用系统发出的,比如:锁频,电池没电等。而应用也可以发布广播,这样应用就可以通过广播相互交流。

    Intent消息

    在Android系统设计中,任何一个应用都可以启动其他应用的组件,可以是activity,也可以是service, broadcast receiver。在android中,应用的entry point并不是唯一的。样程序之间的整合能做的很好,但是现在这样看到的非常少,因为除了基础的功能,很多大家都愿意自己做一套新的而不是利用现有的。

    每个应用都是不一样的,而且你也不知道这些应用是否已经安装,因此直接在代码中调用其他的应用是不现实的。这个时候就需要用到之前提到的message bus,而这个message bus做的还不仅仅是广播。通过向系统发送Intent,系统可以根据Intent的内容执行一定的操作,帮你激活应用。

    Intent可以在components之间发送,不管是在一个应用内还是多个应用之间。对于activities和services,Intent会定义要做什么和对什么数据(通过URL),而对于broadcast receivers,intent则只定义一个一直的动作。而content providerz则是由contentResolver来激活的。

    Manifest File

    Android应用的根目录下都有一个文件*AndroidManifest.xml“, 而他主要做几件事情:

    1. 申明应用所包含的components,这样系统就知道这个应用有多少components,能够对什么消息作出相应,能够如何被激活。同时也会在里面包含这些components能做什么的信息,这样当系统受到一个Intent说要执行actionA的时候,系统就知道要去找谁了。
    2. 申明应用所需的权限,如果没有这些权限应用就无法正常工作,所以在安装是系统就根据=manifest file=里的内容告知用户应用需要这些权限,否则就不给安装。这个步骤不能逐个控制经被诟病蛮久了,很多无关的应用都要求访问联系人短信等权限,你只有不装或者忍受两种选择。
    3. 申明最低系统需求,这个是通过API Level API Level就是一个数字,越新的版本数字越大,所以只要系统的数字大于应用所申明的数字,那么这个应用就可以运行。
    4. 申明需要的硬件和软件功能,如蓝牙,摄像头等。也包含屏幕尺寸啊输入的要求之类的信息
    5. 需要的而外的libraries

    Application Resources

    一个应用除了代码还会有图片音效视频的资源文件,这些文件都被统一管理了起来放在res/目录下。而Android sdk build tools则对每一个资源都生成一个unique ID,并在R.java里面生成这些ID的reference。这样你在代码里就能够直接引用这些资源。并且对于不同的密度,资源也是不一样的。

    ]]>
    http://villadora.me/2014/09/12/androidxue-xi-bi-ji-1/861b100f-86e1-4d00-a669-cc55bc770842Fri, 12 Sep 2014 03:34:58 GMT
    <![CDATA[Gralde Note]]>
  • 使用groovy语法,定义在build.gralde中
  • println "hello"  
    
    • 和makefile,ant一样定义task
    task hello {  
        doLast {
            println "my task"
        }
    }
    
    task hello << {  
       println "shortcut for task"
    }
    
    • 同样可以定义依赖,生成DAG
    task next(dependsOn: first) << {  
        println "my next task"
    }
    
    • 能够在DAG上挂载hook
    gradle.taskGraph.beforeTask { Task task ->  
        println "executing $task ..."
    }
    
    gradle.taskGraph.afterTask { Task task, TaskState state ->  
        if (state.failure) {
            println "FAILED"
        }
        else {
            println "done"
        }
    }
    
    • 通过settings.gradle来配置common behavior,对套嵌的projects进行配置。依赖方式相反,内部project依赖外部的project tasks
    ]]>
    http://villadora.me/2014/09/12/gralde-note/054f4468-11c1-4eb2-bc2d-00fc6955911dFri, 12 Sep 2014 03:26:25 GMT
    <![CDATA[toFastProperties in bluebirds]]>ToFastProperties in bluebirds

    非常有趣的回答,解释了为什么下面这段代码能够提高property access的速度。

    function toFastProperties(obj) {  
        /*jshint -W027*/
        function f() {}
        f.prototype = obj;
        ASSERT("%HasFastProperties", true, obj);
        return f;
        eval(obj);
    }
    
    ]]>
    http://villadora.me/2014/07/29/tofastproperties-in-bluebirds/4ec62de1-c8b3-460c-89ea-743b44e9bfdeTue, 29 Jul 2014 06:33:50 GMT
    <![CDATA[couchdb 1.5/1.6中的Proxy Authentication]]>因为最近要在couchdb中使用Proxy Authentication

    于是参照文档,修改local.ini配置为:

    authentication_handlers = {couch_httpd_auth, cookie_authentication_handler}, {couch_httpd_auth, proxy_authentication_handler}, {couch_httpd_auth, default_authentication_handler}  
    

    但是参照文档中修改配置之后,启动服务,会出现如下错误:

    {
        error: "unknown_error",
        reason: "undef"
    }
    

    最后查看了couchdb 1.6 releae notes发现, proxy_authentication_handler是之后加上的,而之前叫做proxy_authentification_handler。 当然了,我使用的couchdb还没那么潮的更新到1.6,还是1.5的版本。

    就想说升级不能够同样也保留老的名字吗,都1.x了还不注意兼容。

    ]]>
    http://villadora.me/2014/07/28/couchdb-1-6gai-dong/6ec04850-b704-495c-bd7a-9844c2e62bd0Mon, 28 Jul 2014 08:48:44 GMT
    <![CDATA[node中的Readable - flowing/non-flowing mode]]>大家都知道在node中Readable Stream有两种模式: flowing modenon-flowing mode

    对于flowing modeReadable Stream, 我们是没法控制它何时去读数据读多少的,它会去尽快的去消耗data,并emit出来。

    // in lib/_stream_readable.js
    if (state.flowing && state.length === 0 &&!state.sync) {  
            stream.emit('data', chunk);
            stream.read(0);
    

    non-flowing mode的Readable Stream, 则不会主动的去读数据,需要自己显示的去调用read方法才能得到数据。

    // in lib/_stream_readable.js
    // update the buffer info.
    state.length += state.objectMode ? 1 : chunk.length;  
    if (addToFront)  
      state.buffer.unshift(chunk);
    else  
      state.buffer.push(chunk);
    

    可以看到当有数据时,只是将数据放入buffer中,而不是直接emit。

    所以如果想控制stream的读取顺序,大小和时间,应该使用non-flowing mode,而当使用pipe有下游管道对数据进行处理时,这个时候数据的读取和处理应该交给下游管道处理,应该尽可能快的提供数据,所以要使用flowing mode。而这也是node会在attach 'data'事件之后,自动转变为flowing mode的原因,避免错误的使用或者忘记切换模式。

    而pipe时则会注册data事件,所以使用了pipe也会转换为flowing mode

    var src = this;  
    ...
    src.on('data', ondata);
    
    ]]>
    http://villadora.me/2014/07/24/nodezhong-de-readable-flowingnon-flowing-mode/b4991594-e0f1-4c26-839e-36696dc5c618Thu, 24 Jul 2014 02:15:47 GMT
    <![CDATA[扯扯Scala]]>在stackoverflow上看到一个关于Why does IntelliJ IDEA compile Scala so slowly?的问题,顿时感到scala在语法层面做的许多杰出的设计,但是为了和java兼容,最终在一定程度上限制了自己的发展。

    scala可能是为了快速的在各个公司里面推动,选择了完全和java现有代码兼容,而不是只在二进制层面上保持一致。

    scala的sdk和类型系统都建立在java的类型系统之上的,而目标是工业使用的scala语言需要提供大量的内置工具,而一个建立在java类型系统之上的更复杂的类型系统则不得不付出在编译时的开销。

    scala的类型检测对于大型项目非常重要,但是是否能够有选项使得能够某些时候能用来最快速开发,而不做类型检测? 不过scala一开始就不是瞄准着脚本语言去做的,而脚本语言则更容易构建原型系统或执行轻量级的任务。

    没有过大型项目使用scala的经验。所以基本是随便扯扯。

    其实对于大型项目来说,一定是有多个部分(可能是一个人开发,更多的情况是由不同的团队开发)组成的,而组件之间的沟通与协作则是很容易出问题的地方。静态类型语言在大型项目开发上更有优势的地方是程序代替人对代码做了严格检测,以丧失灵活性为代价。这样可以避免一些错误,可以降低程序员的标准,可以大规模的招人,以人海战术来实现企业目标。

    静态类型语言更适合一个牛人写出框架和核心代码,分离出接口,然后将接下来的工作用时间人力来填补。项目进度对于企业来说是可控的。

    而静态类型检测会强迫人以机器的方式去编写代码,实际上很多时候需要做类型转换,数据传递转移等,对于人来说,一些很明确的使用场景需要更复杂的操作来进行,好比写文章的时候有了更多的条条框框,导致笔跟不上大脑的速度。

    scala尝试去提供快速方便的语法糖,隐式的类型推导来方便程序员实现快速开发,然后使用静态类型检测和原有java代码的兼容来方便建立大型系统。

    ]]>
    http://villadora.me/2014/07/23/scalaxing-neng-he-lei-xing-jian-ce/fb6b0fcd-f0a0-4523-86cc-20f0a59b2d1aWed, 23 Jul 2014 13:57:59 GMT
    <![CDATA[Http API设计]]>Heroku团队根据heroku platform api和他们自己内部系统的实践经验总结了一些http api设计的准则,发布到了github上。
    地址:

    https://github.com/interagent/http-api-design

    鉴于见到太多公司的http接口没有按照标准规范来实施,推荐做服务接口设计和前端的同学都看看。

    其中很重要的几条抽出来:

    • 返回正确的状态代码

    不要始终使用200! 201,202对应不同的METHOD是很有意义的。 出现错误是应该返回正确的状态码,是请求参数错误请返回400,是服务器内部出错请返回500,服务器压力过大需要kill连接请返回503,对于行为错误而不是权限问题不要使用401而要用403。这些状态代码本身都有意义,不需要去而外的创建代码或者用额外的属性。

    • 以ISO8601格式来使用UTC时间

    记得使用UTC,同时格式统一,真的需要在每个项目里面去引用moment.js来处理时间?时区和格式足够头痛了,moment.js也不是万能的。

    • 给出结构化的错误信息

    错误不要只返回给状态吗,能够给出一定错误信息的情况下要在body中返回统一的结构化的错误信息。这样客户端也可以做出正确的处理,是等待之后重试还是停止请求通知用户。

    当然还有很多就不一一细列了。去看heroku团队的指南吧

    ]]>
    http://villadora.me/2014/07/11/http-apishe-ji/033dce8c-eb1c-4495-952e-25f49d004c44Fri, 11 Jul 2014 14:00:49 GMT